10 Most important salesforce apex code best practice & error handling

It’s always good practice to follow salesforce Apex best practices. On Today’s post we are going to learn about all salesforce apex code best practice. We must follow salesforce apex code best practice to make system robust.

Here are top 10 salesforce apex code best practice :

1) Never hardcode record Id in apex code as this is apex code best practice :

  • Its always best practice not to hardcode Id in code.
  • Instead of hardcoding Id, try to get it dynamically or utilise custom label or custom metadata.

2) Single trigger per object :

  • Its always consider good practice to have single trigger in one Object in salesforce since easy to control order of execution.
  • Each trigger that is invoked does not get its own governor limits that mean all the trigger on the same object share those available resources and limitation so its good to have single trigger on same object.
  • There might be chance of redundancies of writing same query on multiple places if go with multiple trigger on same object and that may hit the salesforce govt limit.

3) Utilise Apex LIMITS class method to avoid hitting governor limit as part of apex code best practice :

  • Salesforce platform’s Limits class helps to know limit information for specific resource.
  • Limit class also helps to know how many times method got called or the amount of heap size remaining.
  • There are two versions of every method of limit class:
    • First version returns the amount of the resource has been utilised.
    • Second version returns the total amount of the resource that is available.

Here is the example to understand Apex Limit class with Example:

public class ExampleOfApexLimitClass {
    
     public void uderstandLimitsClassMethodsExample() {
        
        /* Lets check no of SOQL queries */
        Integer intQueyUsed = Limits.getQueries();
        Integer intQueryLimit = Limits.getLimitQueries();
        
        System.debug('Total no of Queries used so far' + intQueyUsed);
        System.debug('Total no of Queries LIMIT' + intQueryLimit );

      
        /* Lets unserstand CPU time limitation */
        Integer intUsedCPUTime = Limits.getCpuTime();
        Integer intTotalLimitOfCPUTime = Limits.getLimitCpuTime();

        System.debug('CPU time used so far ' + intUsedCPUTime);
        System.debug('Total CPU time limit ' + intTotalLimitOfCPUTime);
      }
}

There are many more methods are available you can refer to salesforce document of Limit class for more details.

4) Code must be bulkified :

  • As we know handling code bulkification helps to avoid hitting governor limits.
  • Bulkified code improves the number of database operations that improves performance.
  • All the SOQL and DML must handle multiple records instead of just single records.
  • We must always Aggregate records into lists and perform DML outside of loops.

Let’s understand this by taking below example of bulk case updation:

List<Case> lstCasesToUpdate = new List<Case>();

// Iteration over the List i.e bulkification since its not specific to single records
for (Case objCase : [SELECT Id, Subject, Status FROM Case WHERE status = 'Resolved' AND CreatedDate = Today()])  
{
objCase.Description = 'Case has been resolved';
// Adding all the cases into list i.e bulkification     
lstCasesToUpdate.(objCase); 
}

// Doing DML i.e Updating case outside the for loop
if (!accountsToUpdate.isEmpty()) {
 	update accountsToUpdate;
}

5) One Class and One method Principle(Separate Business Logic, Data Access and User Interface) :

  • Witting code with specific functionality in one method and class becomes easy to understand and maintain in future. Also there will be very less possibility that making changes in one part may affect another part.
  • Easy to extend functionality in future i.e scalability of code.
  • We can write our class and method based on different task i.e Business Logic, Data Access, and User Interface.

Let’s take example here to understand this concept via taking this two class with different purpose of both classes and its method:

/* This Class is used to get all the Case Data i.e Data Access Logic */
public class CaseRecordHandler {
 	
        public List<Case> fetchAllCasess () {
        	// Data retrieval logic
        	return [SELECT Id, Subject, Description FROM Case];
    	}
}

/* This class is used to Process Cases i.e Business Logic */
public class CaseBusinessLogicExmaple {

         public void resolveProcessCaseIssue (List<Case> lstCases) {
        		List<Case> lstCasesToUpdate = new List<Case>();

           // Business logic
        		for (Cases objeCase : lstCases) {
			objCase.Status = ‘Resolved’;	
            			objeCase.Description = ‘Resolving this cases as Discussed over the Phone call ';
        	}
}

update lstCasesToUpdate;
}
Note: Here we can have LWC, AURA or standard lightning page for User interface.

6) Utilize Asynchronous Processing wherever possible :

  • As we know asynchronous processing helps to do DML and other operation that takes longer time to complete.
  • Asynchronous apex help to increase higher governor and execution limits as this process in background.
  • On the basis of our requirement we can use @future, Queueable, or Batch Apex job.

Let’s understand Asynchronous Processing by below example:

/* BatchToProcessCaseData class to process large volume of records */
public class BatchToProcessCaseData implements Database.Batchable<sObject> {

           public Database.QueryLocator start(Database.BatchableContext BC) {

        		return Database.getQueryLocator([SELECT Id, Subject, Status FROM Case      WHERE Case Status = 'Resolved']);
            }

           public void execute(Database.BatchableContext BC, List<Case> scope) {
        	
		     List<Case> lstCasesToUpdate = new List<Case>();
	
                     for (Case objCase : scope) {
	
                           objCase.Description ='Update Case Status as this case has resolved';
                           lstCasesToUpdate.add(objCase);
                      }
       	
                    /* Updating all the cases */
                   update lstCasesToUpdate;
           }
    	
       public void finish(Database.BatchableContext BC) {
             // Post-processing logic for example sending notifications
       }
}

7) It’s always good practice to optimize SOQL and SOSL queries :

  • Optimizing queries will always have less chances of hitting governor limits.
  • Optimizing SOQL and SOSL helps to improve performance and responsiveness of our page.
  • Always try to utilise selective queries i.eWHERE clauses and LIMIT to filter records returned via soql query.
  • Always prefer to use indexed fields in queries to increase performance of soql execution.

// Querying all the cases created today 
List<Case> lstCase = [SELECT Id, Subject, Description FROM Case WHERE CreatedDate = TODAY LIMIT 800];

8) Always try to attempt higher code coverage & Positive/Negative use case testing :

  • As we know Salesforce requires at least 75% code coverage for deploying Apex code to production.
  • As a developer developer its always best practice to make class code coverage higher since at least 75% code coverage needed for deploying Apex code to production.
  • It’s always recommended to perform positive and negative unit testing via code coverage this reduces the risk of bugs.
  • Try to utilise assert to match expected result.
  • Always try to use Test.startTest() and Test.stopTest() to handle asynchronous operations.
@isTest
private class CaseServiceTest {
    	@isTest
        static void testCreateCaseData() {
     	List<Case> lstCasesToInsert = new List<Case>();
        	for (Integer i = 0; i < 800; i++) {
        		lstCasesToInsert.add(new Case(Subject = 'Test Case Subject ' + i));
        	}
        	insert lstCasesToInsert;
        
        	Test.startTest();
	/* Assume We have class name as CaseBusinessLogicExmaple and method a name as resolveProcessCaseIssue as we developed earlier */
        	CaseBusinessLogicExmaple. resolveProcessCaseIssue (lstCasesToInsert);
        	Test.stopTest();
        
        	// Assert that the accounts were updated as expected
        	for (Case objeCase : [SELECT Name FROM Account WHERE Id IN :   lstCasesToInsert]) 
                {
            		System. areEqual (objeCase.Status ,‘Resolved’);
        	}
    
}

9) Proper Naming Conventions and Code indentation is apex code best practice :

  • Naming conventions makes code easily readable and easy to understand.
  • Also its easy to know the purpose of classes and methods for new developer and old code.
  • It’s alwasy prefer to use descriptive names for variable,  methods and classes, trigger, Flows, Email Template, Email Alert and custom components.

Here is the example to understand descriptive name for classes and methods and variables

/* Class to understand descriptive name for classes and methods and variables*/
public class CaseUtilityForServiceTeam {

// Method to update case description
public static void UpdateCaseDescription(List<Cases> lstCases, String strDescription) {

	// Iteration over the cases
for (Case objCase : lstCases) {
            			objCase.Description = strDescription;
        		}

        		update lstCases;
    	}
}

10) Error handling in apex salesforce :

As we know the pain of failing your logic in production, however its always best practice to handle error by try catch and log exception in catch block.

Lets understand Error handling by below example:

try {
    /* Write here code that may cause an exception */
    Account objAccount = new Account(Name ='Test Account');
    insert objAccount;

} catch (DMLException ex) { //Handle exception
    // You can create exception log records here so that we would able to track more details.

} finally {
    /* This is optional and it always runs even if an exception occurred */
}

Here are the salesforce documentation for salesforce apex code best practice.

Thank you for the reading, Please feel free to share your feed back and let us know if we missed anything here.

Having 11+ years of extensive hands-on experience in CRM application development, designing, and coding implementation of Salesforce applications on Sales Cloud, Service Cloud, and Community Cloud.

Leave a Comment