During Salesforce development training, we hear a lot of best practice around Apex: don’t put SOQL queries in loops, be careful of governor limits, blablabla…
But what about Apex Trigger Best practices?
Salesforce Apex Trigger Best practices: design
Only one Apex Trigger per Object
First of all, please please please: ONE TRIGGER PER OBJECT.
No matter if you have hundreds of business rules to handle with Apex, but to keep things as clear as possible, you should have ONE AND ONLY ONE Apex Trigger per object.
Mainly for these 2 reasons:
- When there are several Apex Triggers on an object, It’s not possible to predict in which order it will execute
- It’s far far clearer to see what’s going on in this trigger when time has come to debug
Be cool, think about people that will have 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 on
- Keep 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.
Apex Trigger Skeleton
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
}
}
Apex Trigger: After Update Implementation example
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);
}