One Trigger to Rule Them All? It Depends
Introduction
Anyone involved in Salesforce development will be familiar with triggers and the religious wars around how they should be architected. My view is that, like many things in life, there is no right answer - it all depends on the context. The options pretty much boil down to one of the two following options:
One Trigger per Object
This approach mandates a single trigger file that handles all possible actions, declared along the lines of:
trigger AccountTrigger on Account ( before insert, before update, before delete, after insert, after update, after delete, after undelete) { // trigger body }
One Trigger per Object and Action
This approach takes the view that each trigger should handle a single action on an objectf:
trigger AccountTrigger_bu on Account (before update) { // trigger body }
...
trigger AccountTrigger_au on Account (after update) { // trigger body }
I’ve read many blog posts stating flat out that the first way is best practice. No nuances, it’s just the right way and should be used everywhere, always. Typically the reason for this is that is how the author does it, therefore everyone should. I strongly disagree with this view. Not that one trigger per object shouldn’t be used, but that it shouldn’t be used without applying some thought.
Note: one trigger per object and action is the maximum granularity - never have two triggers for the same action on the same object as then you have no control over the order of execution and this will inevitably bite you. Plus you’ve striped business logic across multiple locations and made life harder for everyone.
Consulting versus Product Development
The reason I have this view is that I work across consultancy and product development at BrightGen. Most of the work I do nowadays is related to our business accelerators, such as BrightMEDIA, but I still have Technical Architect responsibility across a number of consulting engagements, which are often implementations for companies that don’t have a lot of internal Salesforce expertise, and what they have isn’t the developer skill set.
One message I’m always repeating to our consultants is to have some empathy with our customers and think about those that come after us. Thus we use clicks not code and try to take the simplest approach that will work, so that we don’t leave the customer with a system that requires them to come back to us every time they need to change anything. Obviously we like to take our customers into service management after a consultancy engagement, but we want them to choose to do that based on the good job that we have done, rather than because we have locked them in by making things complex.
Sample Scenario
So here’s a hypothetical example - as part of a solution I need to take some action when a User is updated, but not for any other trigger events. At some point later a customer administrator wants to know if there is any automated processing that takes place after a user is inserted to triage a potential issue.
If I’ve gone with the one trigger per object and action combination, they can simply go to the setup page for the object in question and look at the triggers. The naming convention makes it clear that the only trigger in place is to handle the case when a user is updated, so they can stop this particular line of enquiry (assuming my Evil Co-Worker hasn’t chosen an inaccurate name just to cause trouble).
If I’ve gone with one trigger per object, the administrator is none the wiser. There is a single trigger, but nothing to indicate what it does. The administrator then has to look into the trigger code to figure out if there is any after insert processing. What they will then find is one of two things:
- A load of wavy if statements checking the type of action - before vs after, insert vs update etc - and then calling out to external code. Most developers try to make sure that an external method is called only once, so you often end up with a wall of if statements for the administrator to enjoy
- Delegation to a trigger handler, leaving the admin to look at another source file to try to figure out what is happening.
Now I don’t know about you, but if administrators are having to look at my source code, and even worse trying to understand Apex code to figure out something as basic as this, I’d feel like I’d done a pretty poor job.
Enter the Salesforce Optimizer
The Spring 17 Release introduced the Salesforce Optimiser - an external tool that analyses your implementation and sends you the results - here’s what it has to say about my triggers:
And there’s the dogma writ large again - a big red warning alert saying I should have one trigger per object, just because. Don’t get me wrong, I think the Salesforce Optimizer is a great idea and has the potential to be a real time saver, and that the intention is to help, but it’s a really blunt instrument that presents opinion as fact.
The chances are at some point my customers will run this and ask me why I’ve gone against the recommended approach, even though in their case it is absolutely the appropriate approach. I find I have no problem explaining this to customers, but I do have to take the time to do that. Thanks for throwing me under the bus Salesforce!
In Conclusion
What you shouldn’t take away from the above is that one trigger per object is the wrong approach - in many situations it’s absolutely the right approach and it’s the one I use in some of my product development. In other situations it isn’t the right approach and I don’t use it. What you should take away is that it’s important to think about how to use triggers for every project you undertake - going in with a dogmatic view that there is one true way to do things and everything will be brute-forced into that may make you feel like a l33t developer but is unlikely to be helpful in the long term. it may also mark you out as a Rogue High Performer, and you really don’t want that.
Hi Bob, largely I agree with your points. However, my thought process is, why do we even need an administrator to look at the trigger code? Most commonly, an event handler in an object trigger is doing more than one job. So, simply by switching it off, we just stop all the functions. Rather, I believe, in such scenarios we can come up with a configuration based approach to enable/ disable the functionalities. By no means, I am suggesting it to be the best approach, but the intention is to avoid admin to look under the hood.
ReplyDeleteNice one, I was thinkg abt the same... :P
ReplyDeleteIf we are writing code in favor of Admin Guy then your approach is the good one. But let them ding into code and feel the pain of code reading ;)
ReplyDelete