If you were to ask your project manager and your developer to define a trigger, and then compare their definition to yours, you’ll probably end up with three very different answers. Triggers are often a quick-fix for project mangers who know the declarative interface just won’t solve this one.
Raise your hand if you’ve ever heard the phrase “just a quick trigger”? Sometimes? Sometimes, triggers are just that, a quick-fix. But if you ask Developers, you might hear certain Daft Punk lyrics chanted in monotone, “Write it, cut it, paste it, save it, Load it, check it, quick – rewrite it“…
Sooner (rather than later), Developers learn first hand the rabbit hole that a trigger can become. After all, what kind of trigger is being requested? Is the trigger even really needed? How will adding this trigger affect the other triggers already in place? How will existing workflow and validation rules play into the trigger? Will the trigger cause problems with future workflows?
Triggers are phenomenally powerful, but that phenomenal power comes with (potentially) phenomenal complexity. Awhile back, Kevin O’Hara, a Force.com MVP from LevelEleven (They make some fantastic sales gamification software for Salesforce over at http://leveleleven.com/) posted a framework for writing triggers that I like to call Triggers.new.
Kevin O’Hara’s framework is based on big architectural assumptions — Namely that your trigger logic doesn’t actually belong in your trigger; instead, your trigger logic lives in a dedicated class that is invoked by your trigger. Whether you adopt this framework or not, placing your trigger logic in a dedicated class provides valuable structure to triggers in general and makes long term maintainability much simpler. With this assumption in mind, the framework actually changes very little about how you write an actual trigger file.
Inside the logic class, there are methods available to override from TriggerHandler that correspond to trigger execution states. i.e.: beforeInsert(). beforeUpdate(), beforeDelete(), afterInsert(), afterUpdate(), afterDelete(), and afterUndelete(). It’s inside these methods that your trigger logic actually resides.
So why do the extra work?
Not only does this framework help keep your code organized and clean, it also offers a couple of handy dandy, very nice(™) helpers along the way. As a trigger developer, sooner or later you’ll run into execution loops. An update fires your trigger, which updates related object B, which has trigger C update the original object … and we’re off. Kevin O’Hara’s trigger framework has a built in trigger execution limit.
That bit of code: setMaxLoopCount(1), means that the second invocation of a given method i.e.: afterUpdate() within the same execution context will throw an error. Much less code than dealing with, and checking the state of, a static variable. Say it with me now: Very nice!
Perhaps even more important than the max invocation count helper is the built in bypass API. The bypass API allows you to selectively deactivate triggers programmatically within your trigger code. Say what?
Yeah, it took me a second to wrap my head around it. Imagine the scenario: you’ve got a trigger on object A, which updates object B. Object B has it’s own set of triggers, and one or more of those triggers may update object A. Traditionally, your option for dealing with this has been just what we did above, use a setMaxIterationCount(), or a static variable to stop the trigger from executing multiple times.
I believe that trigger frameworks like this one provide quite a few benefits over free-form triggers, both in terms of raw features and code quality. Splitting the logic out of the trigger and into a dedicated class generally increases testability, readability and structure. But this framework is just starting. Imagine the possibilities! What if you could provide your Admin with a Visualforce page to enable or disable trigger execution? Wouldn’t that make your admin giggle and offer you Starbucks? #starbucksDrivenDevelopment
Questions or comments? Leave your thoughts below, or contact us today at firstname.lastname@example.org.