Best Practices of Salesforce Apex Development

Best Practices of Salesforce Apex Development
Chinmaya By Chinmaya
6 Min Read

Introduction

Apex is Salesforce’s powerful programming language that enables developers to customize applications and create robust business logic.
To write effective, maintainable, and scalable Apex code, developers must follow industry and platform-specific best practices.

Here are some of the best practises – that every developer should keep in mind while writing an Apex Class.

1. Design for Governor Limits

Salesforce enforces strict governor limits to ensure multi-tenant efficiency. Writing Apex that respects these limits is critical.

Some important Governor limits that a developer should keep in mind while write an Apex class are:

      1. Avoid SOQL in Loops:
				
					// Bad Practice
for (Account acc : Trigger.new) {
    List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
}


// Good Practice
Map<Id, List<Contact>> accountContacts = new Map<Id, List<Contact>>();
List<Contact> contacts = [SELECT Id, AccountId FROM Contact WHERE AccountId IN :Trigger.newMap.keySet()];
for (Contact con : contacts) {
    if (!accountContacts.containsKey(con.AccountId)) {
        accountContacts.put(con.AccountId, new List<Contact>());
    }
    accountContacts.get(con.AccountId).add(con);
}
				
			

2. Optimize DML Statements:

Use bulkified operations to prevent exceeding the 150 DML statements limit.

				
					// Bad Practice
for (Account acc : Trigger.new) {
    update acc;
}

// Good Practice
update Trigger.new;
				
			

If you’re not familiar with Governor Limits in Salesforce, I highly recommend exploring the post linked below.
Understanding this concept is very important, as it is a commonly asked interview question.

2. Follow the Bulkification Principle

Apex code should always handle bulk data, even if it’s initially written for single-record operations. Salesforce triggers, batch processes, and asynchronous operations often process hundreds of records simultaneously.

3. Use Custom Metadata and Custom Settings

Hardcoding business logic or values in Apex is a poor practice.
Use Custom Metadata or Custom Settings to make your code configurable and avoid code deployments for simple value changes.

Example:
Instead of hardcoding tax rates, store them in a Custom Metadata object.

				
					Decimal taxRate = Tax_Settings__mdt.getInstance('US').Tax_Rate__c;
				
			

4. Write Meaningful Test Classes

Test classes are crucial for ensuring code quality, meeting deployment requirements, and maintaining platform integrity.

    • Aim for 100% Test Coverage: Salesforce mandates at least 75% coverage, but strive for meaningful test cases that verify logic under various scenarios.
    • Use @TestSetup Methods: Create reusable data setups for your tests to reduce redundancy.
    • Test Positive and Negative Scenarios: Cover edge cases, bulk data handling, and exceptions.
    • Avoid Hardcoding IDs: Use dynamic record creation to avoid dependency on org-specific data.

5. Implement Error Handling

Handle exceptions gracefully to improve maintainability and debugging.

    • Use Try-Catch Blocks:
				
					try {
    update records;
} catch (DmlException e) {
    System.debug('Error updating records: ' + e.getMessage());
}
				
			
    • Log Errors for Debugging:

Use custom logging objects to track and debug errors in production environments.

				
					public static void logError(String errorMessage) {
    Log__c log = new Log__c();
    log.Message__c = errorMessage;
    insert log;
}
				
			

If you’d like to learn more about error handling and exception handling in Apex, I highly recommend checking out this post.
It provides a step-by-step guide on how to handle errors effectively and write robust, maintainable code in Apex.

6. Leverage Salesforce Best Practices for Triggers

    • One Trigger per Object: Maintain a single trigger per object to simplify management and debugging.
    • Trigger Handler Framework: Delegate logic to a separate handler class for cleaner code organization
				
					trigger AccountTrigger on Account (before insert, after insert) {
    AccountTriggerHandler.handle(Trigger.new, Trigger.oldMap);
}
				
			
    • Use Context Variables: Use Trigger.new, Trigger.old, and Trigger.newMap to access context-specific data.

7. Use Apex Design Patterns

Design patterns help create scalable, reusable, and maintainable Apex code.

    • Singleton Pattern: Ensure a class has only one instance in a transaction.
    • Factory Pattern: Simplify object creation logic.
    • Strategy Pattern: Decouple business rules from the main logic.

8. Optimize Performance

    • Query Only What You Need: Select only the necessary fields in SOQL queries to reduce memory usage and improve performance.
				
					// Bad Practice
List<Account> accounts = [SELECT * FROM Account];

// Good Practice
List<Account> accounts = [SELECT Id, Name FROM Account];
				
			
    • Use Collections: Operate on Lists, Sets, and Maps instead of individual records.
    • Use Batch Apex and Asynchronous Apex: For long-running processes or large data sets, use Batch Apex or Queueable Apex.

9. Security First

    • Enforce CRUD and FLS: Always check object-level and field-level permissions in your Apex code.
				
					if (Schema.sObjectType.Account.fields.Name.isAccessible()) {
    // Proceed with field operations
}
				
			
    • Avoid SOQL Injection: Sanitize user inputs in dynamic SOQL queries.
				
					String safeValue = String.escapeSingleQuotes(userInput);
List<Account> accounts = [SELECT Id FROM Account WHERE Name = :safeValue];
				
			

10. Write Clean, Maintainable Code

    • Use Descriptive Variable and Method Names: Clearly indicate their purpose.
    • Keep Methods Small: Break large methods into smaller, reusable methods.
    • Follow Naming Conventions: Use PascalCase for class names and camelCase for variables and methods.
    • Use Comments Judiciously: Explain why, not what, in your comments.

Conclusion

By following these best practices, you can ensure that your Apex code is robust, scalable, and maintainable.

Apex development isn’t just about writing code—it’s about creating solutions that perform efficiently, adapt to change, and align with Salesforce’s multi-tenant architecture.

Share This Article
Follow:
Chinmaya is working as a Senior Consultant with a deep expertise in Salesforce. Holding multiple Salesforce certifications, he is dedicated to designing and implementing cutting-edge CRM solutions. As the creator of Writtee.com, Chinmaya shares his knowledge on educational and technological topics, helping others excel in Salesforce and related domains.
Leave a comment