The 3rd Age of Trigger Frameworks - Part 1


Looking for A Framework?

Trigger frameworks - not something we'd look to change too often. But let's say we're working on a brand new org, or looking for something to complement a change in strategy. Shall we copy-paste that framework which worked well for so long? Or find the one on Github with the most stars?

Let's first put cards on the table - traditional trigger frameworks don't play well with modern development practices in Salesforce.

Why? Under older frameworks, trigger/handler classes typically initialise classes or call methods explicitly, meaning these central components are technically dependent on the logic they call. In a deployment methodology making effective use of unlocked packages (something you'll likely want at some stage in a medium or large org), trigger functionality for an object may well cross more than one package. As packages are deployed separately, techniques are needed for dependency management.

Choosing a new framework today, it's vital to ensure a framework can work well in this paradigm.
 

Traditional and modern trigger architecture


But hang on a sec, that's not what Trailhead taught me to look for!

Maybe not, or not yet, but right now most customers are not ready for a move to unlocked packages. As more orgs take up optimised unlocked package workflows there will be more focus on making sure org design works well with this methodology. Without considering this in our frameworks now we could be making a future migration a lot harder than it needs to be.

Before jumping into innovations around how this is done, let's make a brief foray into trigger history...

In the Beginning

In the earliest days, triggers in Salesforce were something of a wild west. It wasn't uncommon to see multiple triggers on each object, which leads to unpredictable sequence of processing, or to see complex logic being written into the trigger itself, which can't then be unit tested or reused outside of the trigger context.

This kind of approach is unlikely to cause problems with very limited use, but quickly leads to headaches as scale and complexity go up.

The Framework Rennaissance

Before long, ideas coalesced around more sustainable development patterns, and open source frameworks emerged which addressed challenges effectively. Frameworks which gained and sustained popularity around this time include Kevin O'Hara's SFDC Trigger Framework and the Financial Force fflib libraries (actually much more than a trigger framework, but patterns are very effective in this area), both of which came in 2013.

Common features and patterns in frameworks from this era:

  • Single trigger per object to give order of execution control
  • Removing logic from triggers for reuse and testing without record DML
  • Standardisation of trigger handler classes using interfaces or subclasses
  • Techniques to deactivate triggers and prevent recursion

These days, it's very unusual to see an enterprise org without a trigger framework or some kind.

The 3rd Age

With the powerful features of custom metadata, a slow but steady migration towards unlocked packages and a growing appreciation of the benefits of enterprise grade patterns like dependency injection, innovations have sprung up to break technical dependencies between components and business logic.

  • Andrew Fawcett's ForceDI project provides a general mechanism for dependency binding using custom metadata, which could be leveraged by an existing trigger framework
  • at4dx adds dependency injection strategies to the core fflibs frameworks
  • Table-Driven Trigger Management (TDTM) from Salesforce.org enables handler classes in NPSP and EDA orgs to be loosely coupled to triggers through custom metadata records and dynamic type instantiation
  • Recent open source frameworks include custom metadata types to hold records with a handler class name specified in a text field. An instance of the class will be instantiated dynamically when the trigger runs

All of these approaches reduce deployment dependencies, and enable triggers to run successfully with all, some or none of the actual logic deployed in the org - exactly what we need to separate technical dependencies effectively!

Deciding which kind of dependency-free framework is right for your org depends on scale, strategy and existing functionality. TDTM is available out of the box for EDA and NPSP, at4dx is an excellent choice if you already use fflibs patterns extensively or plan to adopt these in a new org. A custom approach may also be right if you'd like to retain full control over the mechanics of the framework.

For orgs without the considerations above though, in my view the best open source custom metadata-based trigger frameworks provide everything needed with minimal technical overhead.

Tell me More!

In the next part of this article, we take a deep dive into two frameworks using custom metadata and dynamic instantiation:

Apex Trigger Actions Framework (Apache 2.0 license) - Maintained by Mitch Spano

Nebula Core - Nebula Triggers (MIT license) - Maintained by Aidan Harding and Nebula Consulting

 

Further Info

Links to projects addressing challenges with dependency management in Salesforce are below:

Apex Trigger Actions: https://github.com/mitchspano/apex-trigger-actions-framework
Nebula Core Nebula Triggers: https://bitbucket.org/nebulaconsulting/nebula-core/src/master/
Appero My Triggers: https://github.com/appero-com/MyTriggers
Andrewy Filonenko SFDC-declarative-trigger-framework: https://github.com/AndreyFilonenko/sfdc-declarative-trigger-framework
Salesforce.org Table-Driven Trigger Management: https://powerofus.force.com/s/article/EDA-TDTM-Overview
Apex Enterprise Patterns Advanced Techniques To Adopt SalesforceDX Unlocked Packages (at4dx): https://github.com/apex-enterprise-patterns/at4dx
ForceDI: https://andyinthecloud.com/2018/07/15/managing-dependency-injection-within-salesforce/