Skip to main content

Salesforce

Top 5 Salesforce Best Practices on Apex Code

Two Businesswomen Working On Computer In Office

Introduction:

This blog is basically to help you go to that next level of coding and what are the things we need to consider while writing Apex code so that your code adheres to the best practices. Apex runs in a multitenant environment that’s why Salesforce recommended Best Practices. It’s been defined over many years by Salesforce developers, Based on their collective experience.

 

1. Avoid Writing SOQL Queries or DML Operations Inside the Loop Statements.

A typical mistake developer makes is that DML statements or queries are placed inside a ‘For loop.’ There is a governor limit that implements a maximum number of SOQL queries. Another implements a maximum number of DML statements such as insert, update, delete, and undelete. When queries are placed inside a ‘for loop’, a query is executed once per iteration, and the SFDC governor limit is easily reached.

Instead of writing the SOQL query outside the ‘for loop’ and retrieving all the necessary data in a single query. By moving queries/DML outside of for loops, code will run faster and is less likely to exceed governor limits.

For(Account acc: Trigger.new){
    for(Contact cont:[select id, name from contact where accountId = :acc.Id]){
   }
}

Solution:

  1. Move the SOQL/DML out of the loop statements.
  2. Query: If you need query results, get all the records using a single query and iterate over the result set.
  3. Update: If you need to update, batch the data into a collection and invoke DML once for that collection.

Here is an example of code with SOQL Query outside of ‘For loop.’

Map<Id, Account> accountMap=new Map<id, Account>([select id,name, (select id, name from contacts) from account where id in:trigger.newmap.keyset()]);
for(Account acc: accountMap.values()){
    For(Contact cont:acc.Contacts){ 
    }
}

2. Write a Single Trigger per sObject Type.

Every Salesforce organization with a strong development team has just one trigger per object. This practice is an outstanding design pattern in Apex.

The principle of only one trigger per object is mainly because, in Salesforce, we do not have any way to guarantee the order of execution for triggers on the same object. Using only one trigger per object gives us the authority to control the flow of execution, which allows for easy management.

trigger NewTrigger on Opportunity (
  before insert, after insert, 
  before update, after update, 
  before delete, after delete) {
  if (Trigger.isBefore) {
      if (Trigger.isInsert) {
          // Call class logic here!
      } 
      if (Trigger.isUpdate) {
          // Call class logic here!
      }
      if (Trigger.isDelete) {
          // Call class logic here!
      }
  }
      if (Trigger.isAfter) {
      if (Trigger.isInsert) {
         // Call class logic here!
      } 
      if (Trigger.isUpdate) {
        // Call class logic here!
      }
      if (Trigger.isDelete) {
       // Call class logic here!
      }
      }
      }

Here’s what’s happening in the template:

  1. Created a new trigger that runs on every possible scenario (before the update, after deleting, etc.).
  2. Use trigger context variables to isolate a portion of your trigger for each possible scenario.
  3. Use the classes in their appropriate trigger scenario.

 

3. Always Bulkify Your Code.

Poor Coding Practice:

  • While processing a set of records, Looping through all the records and processing them one by one is a poor practice concerning performance.
//Note that up to 200 records can be in Trigger.new
for (Opportunity opp : Trigger.new) {
  Task t   = new Task();
  t.Name   = 'Give your prospect a free book';
  t.WhatId = opp.Id;
  insert t;  // You will get an error after the 150th opportunity!
}

Best Coding Practice:

  • You need to write code that can handle multiple records simultaneously and does not process documents individually.
  • Bulkify the code correctly to handle more than one record at a time
  • When a batch of records is to be processed by the apex code, a single instance of that apex code is executed. That one instance of apex code will handle all records in that given batch. This improves efficiency and performance to a large extent.
// insert DML on all tasks at once using a List
List<Task> taskList = new List<Task>();
for (Opportunity opp : Trigger.new) {
  Task t   = new Task();
  t.Name   = 'Give your prospect a free book';
  t.WhatId = opp.Id;
  taskList.add(t);
}
insert taskList;  
// Notice this is outside the loop

4. Avoid Nested Loops.

Nested loops should not be present in Apex controllers try to avoid nested loops in Apex code because they may slow down the page’s processing or hit the page’s governing limits. An easy solution that gives some good structure to the code is to make the inner loop a separate function or minimize using loops altogether. An easy and simple way of avoiding nested loops is using Maps.

For example, we can find or create a key for each item of the second loop and put the key and the value into that Map.

 

5. Avoid Hardcoding IDs.

Deploying the Apex code between sandbox and production environments, or installing Force.com AppExchange packages, is essential to avoid hardcoding IDs in the Apex code. The component we need to reference does not exist in Production; we just created it for the solution we’re building. That component will have a new ID that only exists in sandbox org.

That same component will need to be created in each sandbox lead into Production. Every time that component is made, a different Salesforce ID will be created, and another ID will be referenced.

Three Alternatives to avoid hard coding are mentioned below:-

  1. Custom Label:   Custom labels are custom text values accessed from Flows, Lightning components, Apex classes, and Visualforce pages. While deploying a custom label, the data of that custom label also gets deployed. update the custom label value post-deployment to avoid unexpected behavior in your code.
  2. Custom Setting:  Custom Settings are variables you can use in your code but modify and set outside your code. They are cached. It is especially useful to store information often accessed from Salesforce flow or Apex code, as it will perform must better than a custom object. Custom Settings do not count against SOQL limits when it’s fetched. when you deploy them, it does not bring the data over.
  3. Custom Metadata Type:   Custom Metadata Types are like Custom Settings. its data also gets deployed, while deploying a custom metadata type.

 

Conclusion: 

The above-listed best practices and rules will not guarantee business correctness in the code, but they will surely help you to make your code more readable, manageable, dynamic, and reusable. better chances to not hit generic governor limits imposed by Salesforce.

Practice Makes PERFECT!!

Thoughts on “Top 5 Salesforce Best Practices on Apex Code”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Anshuli Nikhare

Anshuli Nikhare is a Salesforce Developer. She has over 2 years of IT industry experience working as an Associate Technical Consultant at Perficient based out of Nagpur. She is a Certified Salesforce Platform Developer (PD1). Anshuli enjoys how being a Salesforce Developer helps her skillset explore. She is a skilled researcher who can identify opportunities in a given arena, is a supportive teammate, and is an employee willing to go the extra mile to help others.

More from this Author

Follow Us
TwitterLinkedinFacebookYoutubeInstagram