I'm all too familiar with the Kevin O'Hara trigger framework and have used it as a base framework in many projects before.
However, I've recently been doing some in-depth reading about the idea of loose coupling between triggers and handlers, and the use of dynamic metadata based handler frameworks to control which code runs in which context and in what order. The two most common frameworks of this design that come to mind are Apex Trigger Actions Framework and Nebula Trigger Framework
As I look for a new framework to help elevate the large, seasoned org I've adopted, I'm finding myself at an impasse where it's no longer clear to me which is more acceptable as the current standard, or whether or not each approach is still acceptable.
I'm familiar with the "old" way of doing things, where a single Object Trigger calls a method on an ObjectTriggerHandler which extends the TriggerHandler base class, and then runs through each trigger context to call the related context method in the Object Handler. Each context method then does (typically) one large loop through all of the records in the Trigger to identify records that need to have actions taken against them, and then takes those actions after finalizing the loop (usually by passing data to other Utility classes to run reusable logic).
The new dynamic custom metadata style instead appears to have a single Object Trigger and multiple purpose built Object-specific classes which are queried for and then called in pre-arranged order by the MetadataTriggerManager. By leveraging interfaces and custom fields on the custom metadata records, the framework is able to be decoupled from the logic classes themselves, allowing for independent deployment of new logic classes without needing to change core framework classes or other classes outside of your project scope.
While I can see definite value (working with unlocked packages, better dependency management), I still find myself stuck in the middle. Some of my immediate observations of this style were:
The entire contents of
Trigger.neware passed to each method setup to run in that particular context, and so each method must loop through the entire list of records again. This (to me) seems like a lot of redundant processing of the
trigger.newlist multiple times that we could have processed once and split out into smaller working lists. Am I off base with this concern?
Consider a design where you have 4 separate classes that implement the AfterUpdate interface on the Account object. 2 of those classes both want to make DML against existing Contacts that meet certain conditions, so they each loop the
Trigger.newlist, Query for related Contacts, make their changes in memory, and then run DML. Since each method is uncoupled, this would result in 2 SOQL queries and 2 DMLs for the same Object type (Contact). I could see this ballooning out of control in some complex situations.
Ultimately, I think my concrete questions are:
- Do older Trigger Handler frameworks still have a legitimate place in the future of SFDC apex framework architecture?
- Do these newer frameworks somehow account for my duplicate SOQL/DML concerns in a way that I haven't understood?
- If implementing a brand new framework into an existing large organization, is metadata driven frameworks the correct way to go, or is this still up for personal debate between professionals?