Apex Trigger Architecture/Design Framework based on dynamic binding of handler class
Gaurav Jain
Sr IT Architect at IQVIA | Salesforce Certified Application Architect | Salesforce Certified Integration Architect | Salesforce Certified Data Architect | 9X Salesforce Certified | 4X Trailhead Ranger | Copado Certified
In his latest book on Advance Apex Programming , Dan Appleman brought a nice and elegant salesforce trigger architect concept. In the article below I have put together the same architectural concepts, which can be used by technical teams as a reference. ?
Use case – The need:
Before we go deeper into that , let's discuss the advantages and costs of the existing trigger framework.?
There is absolutely no problem in using any well supported trigger framework, but trigger framework only works if it's universally adopted meaning every developer in your org should understand and follow that. If you have a large org and a big team is working on different enhancements , it gets difficult to follow a framework. Educating each developer about the framework which they should use , is quite a tedious task and sometimes not possible. If only half of your team is following a framework and the other half not following the same one, then it is more damaging and defeats the purpose of the framework.?
And In case of smaller orgs following a framework may have more long-term maintenance cost and sometimes not worth to follow it.?
So, in both of these situations it will be a good idea to follow an architecture design , which can be easily understood and can be easy to maintain in future.?
We all know that salesforce recommends one trigger per object. If you have multiple triggers of the same type running on the same object, you can’t control and predict the order of execution of those triggers.
Having a single trigger on an object is necessary to control the order of functionality in a trigger. To control the order , the development team has handlers/helper classes and maintains the sequencing of method calls based on the business need. This creates dependencies ; handlers depend upon triggers and triggers dependent on handlers.
Recommended Architecture:
[Note - This is one time set up and this will be performed by generally technical architect or Tech Lead. This will do the basic framework set up in your org. It will make the development team and admins? life easier. Dev or Admin will easily be able to maintain it by doing only a few things. All these steps can also be put together as part of package and deployed to every org as needed. ]
In the recommended architecture. There is a centralized trigger dispatcher. Trigger dispatcher must dispatch trigger events. Trigger dispatcher dynamically loads the dependencies and in the order in which they are defined. This approach uses design principles such as dependency injection , dynamic binding etc.?
Below is the code prototype. All these are architectural concepts not the exact working copy of code ??.? so please enhance and implement as needed.?
This interface will be common and will be used by every handler.??
public Interface ITriggerHandler?
{
Void HandleTrigger(TriggerOperationType triggerType,?
????List<SObject> newList,
? ? Map<Id,SObject> newMap,?
?????List<SObject> oldList,
? ? Map<Id,SObject> oldMap)
}
2. Create a Dispatcher Class:
TriggerDispatcher class implements the dispatcher functionality and handleTrigger? function of this class is called by every trigger of any type.
Main task in the dispatcher is being performed by getTriggerHandlers. This is returning a list of ITriggerHandler objects.?
This class also uses Type.forName which lets you dynamically instantiate an Apex Class.??
This class is also using a custom meta data (Trigger_Handler__mdt), I will come back to that.?
For now bear with me.?
public class TriggerDispatcher
{
public void handleTrigger(string objecttype,
TriggerOperation triggerType,
List<Sobject> newList,
Map<Id,SObject> newMap,
List<SObject> oldList,
Map<Id,SObject> oldMap)
{
List<ITriggerHandler> handlers=getTriggerHandlers(objecttype, triggerType);
For(ITriggerHandler handler: handlers)
领英推荐
{
handler.HandlerTrigger(triggerType, newList, newMap, oldList, oldMap);
}
}
Public List< ITriggerHandler> getTriggerHandlers(string objectType,TriggerOperation triggerType)
{
List<Trigger_Handler__mdt> handlers=
[select class_name__c, priority__c from Trigger_Handler__mdt where?
objectType= :objecttype..
and Triggertype= : triggerType.Name
order by priority__c
]
List<ITriggerHandler> results=new List< ITriggerHandler>();
For(Trigger_Handler__mdt handler:handlers)
{
System.Type thetype=Type.forName(handler.Apexclass);
Object obj=thetype.newInstance();
Results.add((ITriggerHandler) obj);
}
Return results;
}
?
}
3. Custom metadata - This architecture is based on dynamically binding handler class with the trigger along with their priority order. So, this approach asks you to define a custom meta data in your org and that custom meta data will store information about which trigger handler is associated with which object and which trigger type. That way you can have your own handler class. Once you have tested your trigger you need to have the configuration set in the custom meta data.?
So in that defined custom meta data you will store following -??
Apex_className__c
Object_Type__c
Priority__c
Trigger_type__c
So far whatever I have mentioned , is a one time set up which any senior member can create as a package and make it available.?
Let’s assume the trigger in on Account object
Trigger AccountTrigger on Account ()
{
TriggerDispatcher.handleTrigger(‘Account’,Trigger.OpearationType,Trigger.new,Trigger.newMap,
Trigger.old,trigger.oldMap);
}
...
2 个月Great article Gaurav Jain. Explained a complex framework in a clear and concise manner. I’d like to suggest an additional feature: incorporating an 'Active' field into the trigger handler custom metadata type. This would allow devs/admins to easily enable or disable trigger handlers and help the code determine which ones to use.