In Salesforce development training, we often come across various best practices for Apex, such as avoiding SOQL queries in loops and being mindful of governor limits. However, what about best practices specifically tailored for Apex Triggers?
Best Practices for Designing Salesforce Apex Triggers
Limit each Object to a single Apex Trigger.
First and foremost, I urge you: ONE TRIGGER PER OBJECT.
Even if you have numerous business rules demanding Apex handling, maintaining clarity is paramount. Thus, it’s advisable to have only ONE Apex Trigger for each object.
This is primarily due to two reasons:
- When multiple Apex Triggers exist on an object, predicting their execution order becomes challenging.
- Having a solitary trigger makes it significantly clearer to comprehend and debug when the need arises.
Stay considerate; think about those who will need to read your code!
No business logic in the Apex Trigger
As a best practice of Apex triggers, please consider not to write business logic in a Trigger, only do calls to methods located in other classes. This is absolutely necessary to:
- Apply the “with sharing” or “without sharing” behaviors to ensure you’re working on the records you should work onKeep things clear: The developer that opens the Apex trigger only calls to methods in other classes. It’s far easier to read!
Always keep in mind that code in Apex Triggers run on a without sharing fashion. So write the code in a with sharing class if you need to enforce the record visibility in your business rule.
Framework for an Apex Trigger
So, what’s the ideal Apex trigger?
Well, let me share with you the ideal skeleton below that you can copy/paste and adapt to . As you can see, it handles all the events that can be caught by a trigger.
As mentioned below, the calls to other classes must be put at the right place, depending what you want to do: before/after- insert/update/delete/undelete records.
If you take this pattern, it’s good that all your triggers look like this.
/*********************BLACK-FOX.ORG Trigger example***********************************/ trigger ObjectNameTrigger on ObjectName__c (before insert, after insert, before update, after update, before delete, after delete, after undelete){ /* Before Insert */ if(Trigger.isInsert && Trigger.isBefore){ // Put your calls to classes here } /* After Insert */ else if(Trigger.isInsert && Trigger.isAfter){ // Put your calls to classes here } /* Before Update */ else if(Trigger.isUpdate && Trigger.isBefore){ // Put your calls to classes here } /* After Update */ else if(Trigger.isUpdate && Trigger.isAfter){ // Put your calls to classes here } /* Before Delete */ else if(Trigger.isDelete && Trigger.isBefore){ // Put your calls to classes here } /* After Delete */ else if(Trigger.isDelete && Trigger.isAfter){ // Put your calls to classes here } /* After UnDelete */ else if(Trigger.isUnDelete && Trigger.isAfter){ // Put your calls to classes here } }
Example Implementation of Apex Trigger After Update
Here is a short example on how to implement the after update logic in an Apex Trigger on the Account object.
As advised before, you can see that there is nothing but call to code in an other class, which helps to keep the trigger human-readable, clean and easier to understand.
The business logic is handled by the AccountHandler class and it’s better like that:-)
/* After Update */ else if(Trigger.isUpdate && Trigger.isAfter){ AccountHandler.sendEmailAlerts(Trigger.oldMap , Trigger.newMap); AccountHandler.updateAllAccountOpportunities(Trigger.oldMap , Trigger.newMap); }