Transcript for:
Trigger Frameworks in Salesforce

good morning and good evening everyone welcome in self ascetics our my name is Amit Shah tea and today we are going to talk about that trigger framework and today our speaker is Adam who is going to share his knowledge on trigger framework so let me hand over to Adam all right thanks summit so some statistical comment as I thank you all for joining a apex hours this morning so as I said my name is animal shamsky I'm a Salesforce developer at YouTube I have over 500 trailhead badges and 14 Salesforce certifications but I'm really passionate about helping people learn on the Salesforce platform development specifically I volunteer with rat women which is a program to help female Salesforce admins become familiar with the development side of the platform and presenter at Dreamforce a few times and very very excited to be here with you this morning I feel free to follow me on Twitter Adam 17 amo I also have a blog you can check out Adam to architect calm and if you are still have not migrated over the lightning experience yet and I'm looking for some tips I think Pluralsight has made all of their courses free for the weekend so feel free to check out my course on plural sign up Italy slash lightning migration all right well that let's get into our content for the day so today we're gonna be talking about trigger frameworks we're gonna start a few steps back and talk about triggers in general and then we're going to kind of take one step forward and talk about trigger handlers and eventually get into trigger frameworks I'm gonna go over three different types of frameworks three different examples we'll see some code and walk through what those they're doing and talk about how they work and how you can use them do some comparisons between all three of them I talked about some may be drawbacks things to consider when using trigger frameworks and then I'm going to do a summary and wrap up so with that let's get into it so I'm gonna start a little bit by talking about apex triggers in general just kind of to level set here so as many you may know as database triggers in general are automate responses to database events so we're talking about Salesforce platform obviously the database is going to be Salesforce and so we can have triggers that fire on any number of database events so some activity is happening some sort of safe operation such as an insert and update a delete or undelete he brings something back and their recycle bin and we can also have these triggers set to fire either right before or right after the record save operation so kind of for inserts um that'll be when the record gets its ID for updates it'll be after some of the initial validations and things like that but before some of the post-processing like workflow in email and stuff like that that's we're gonna be focusing on how do you kind of control that mmm and make your lives a little bit easier as I mentioned apex triggers take place in apex code and they can be on just about any object so that it's the most effective you a lot of flexibility I think all custom objects and with the exception of a few standard objects you can have code set to run pretty much any save operation in the Salesforce org in general I've spent too much time on this slide but this is just a list of the order of operations that happened when you initiate that save operation on Salesforce and so that kind of steps we're going to be looking at our steps five and steps nineteen so that'll be our before and after triggers so right before a record is actually saved to the database but after the validation and then after the records save but before all of the assignment rules processes flows and the other things you have as well you can imagine with so many different order or so many different operations happening that can potentially trigger other updates very easy to get into some sort of a cursive state and so we're going to take a look at how do you can actually prevent some of those things as well alright and then the last thing I want to talk about that we're going to be kind of demonstrating and assuming today is the concept of one trigger per object so you may already be familiar with this kind of best practice now you may have put it into place for process builder as well but essentially this is just the notion that you know if you you can technically create five different triggers on the account object but you don't have any way to control which one's gonna fire first and so you end up creating some sort of race condition and so for one user you might have a situation where your trick or two fires first and then trigger for that the user is gonna have trigger three fire first and trigger one and every user gonna have a slightly different experience and that's never really a great stayed to be as a developer makes debugging very difficult and frustrating for everybody and so with one trigger per object you can not only control the order that your codes firing in but you also have a single place to start debugging triggers so if something goes wrong you don't have to go to five different places and try to guess which one was causing the problem you can always start from a single trigger and work on from there it also makes it very easier toggle trigger behavior so if you want to shut down some triggers for an object either permanently or temporarily having one trigger is obviously much easier to stop adding three or four all right and so I'm just gonna go through kind of a basic trigger example here real quick just let me try to zoom in a little bit um triggers not doing anything too crazy but essentially all I'm doing is have a trigger on the lead here we're just gonna operate on before insert for now and all I'm doing is essentially looping through the triggers collecting all the company names and then trying to figure out do I have any existing accounts in my org that correspond to these lead companies that I'm inserting and if any of the lead company names match my existing account names I want to go create a case for that so touch with a couple different objects and we also see this idea that a process just started with the lead being inserted can end up with a different object in this case case is being inserted acid trigger itself isn't too important right now it's keep in mind this is single operation for a single trigger just before insert and it's touching several different objects so we'll see how that comes into play in a little bit and we'll see how we're gonna change this trigger to make it a little bit better for us to expand on long-term and so inevitably with our triggers you know we saw before insert and it was about 30 lines for our leads and that was fine but that could end up growing at some point we might have some more before insert functionality we want to add and we may also have different event types we want to tackle be that after insert before update after updated cetera and as we kind of grow our trigger we may start to find we need to reuse code and a couple different instances so maybe before insert and before update ask some common code that need to run for each one and for keep it in our trigger we basically have to write all of that code twice and test all of that cook twice which is never great for development perspective the other thing we're going to end up with is a very long and a potentially very complex trigger that we're not able to test its unique pieces right because triggers can't really have methods in them you essentially would have to test the trigger all at once and that's not really a place you want to be in the other thing is if there's something you need to debug and you know have to go in through that potentially a couple hundred line trigger and figure out where exactly a problem is happening also not necessarily something you want to be spending your time doing so how do we kind of get around some of these problems and for that we're going to turn to trigger handlers and so I'll trigger handler is essentially an apex class that is going to be handling your trigger logic for you it's going to allow our code to be called from either other code or from task submission of the trigger so we can have discrete methods we can unit tests much easier and we're going to be using specific trigger context and trigger variables to do our routing to kind of control what event fires which part of our trigger handler and the ultimate goal of this handler it's a couple of them number one we want to keep our triggers as simple as possible because they have the most amount of restrictions and what we can and can't do in them just give us greater flexibility in terms of code reuse and testing capability and as I mentioned also it's going to make our unit test much much easier to figure out where a potential problem might be and how we can debug contention to solve it you what our trigger looks like if we move it over to a trigger handler now so I'm going to go back to our code here and I'm going to open up our trigger handle lead trigger Handler and all I've done here it essentially moved all that code we had in a read trigger to a new handle before insert method in our trigger handler class does the same thing checks our leaves checks it against these counts and appending leaves company names match the account names we'll go insert some cases and we're gonna end up passing and a list of leaves which will be our trigger got a new variable and we're not using them right now but we have methods than here to handle all the other conditions should we add them later and then if I go back to our lead here I can comment out the original code that was 30 lines long but we moved it all to our handler so now I can comment out our new trigger code and still gonna be a decent number lines long but each piece is essentially just gonna be repetitive so basically we're just gonna say okay if the trigger is before and the trigger is insert call our handler before insert method if it's after insert call handle after insert and so on it's never were able to handle all the events and our trigger codes really not going to ever have to get any bigger or messier the illness and being able to move it to the handler already we're seeing some potential benefits we can test it easier we can actually reuse code and our triggers gonna be a lot simpler than it potentially would have been before all right so triggers could trigger handlers good let's go into trigger a framework stone so one thing we may have seen right away with the trigger handlers as we still have a lot of duplicated code so in every trigger I'm still going to have to have if trigger is before and trigger is insert call my handler before insert if my trigger is after in trigger is insert call my handle after insert and then in our uh trigger handler itself we're going to have to put all the different methods either at the beginning to make sure we don't accidentally call a method doesn't exist or we're gonna have to end up constantly adding new methods to our handler and updating our trigger which ideal although we wouldn't want to do but either way we're gonna end up with a lot of duplicated code or a lot of unused code or both and so the question kind of becomes how do we simplify things how can we make things better and how can we make our process repeatable so we don't have to have a bunch of pretty much the same code in every single trigger and that's kind of where trigger frameworks come into play so when I talk about trigger frameworks we're talking about this notion that we want to have generic code that can be extended for any object we want to make sure that our triggers are consistently handled and that only the code that's really required is needed and what it's going to give us it's very very simple triggers and simple trigger handlers and it's also going to handle all the routing for us we don't have to put as before is insert is after is insert is before is update and every single one of our triggers potentially making a mistake and causing a problem down the road the framework is going to handle all of that routing for us and we can just really focus on the interesting parts of the code the business logic and the it's gonna be giving real value to the stakeholders the other things that the framework will do is it's going to ensure and force consistent trigger behavior so I'm not gonna have to worry when I'm debugging because the account trigger work differently than the new trigger I'm gonna rest assured it's all using the same framework and therefore it's all going to be behaving the same I don't necessarily even have to look at the trigger code to figure out how the routing is working what conditions are happening I can be pretty confident that I can go straight to skipping a few steps and going into the logic directly because I know the framework is going to handle everything before that for me the other thing the frameworks are going to do is generally we can put in a way to allow for some sort of trigger bypass a couple different ways to do that as well demonstrate the basically some way to have some sort of recursion check you want to make sure that number one our triggers aren't firing multiple times in the same transaction we want to make sure that our triggers aren't firing and one instance wall that are in the middle of finishing up another instance and we want to potentially have a way to turn them off or disable them from running at all and the last thing we're gonna want to be able to do is potentially have different behavior for triggers that start a process versus triggers that kick off in the middle of a process so if you saw the trigger that we talked about at the beginning we saw the operation was about inserting leaves and we ended up inserting some cases which is gonna fire the case triggers and so the question becomes do I want those cases to follow all the same logic as they would if I was creating a new case in the UI maybe I do maybe I don't same question and if I am inserting some leaves and I insert some cases which then by or another process that inserts some more leaves because I'm already in a lead insert operation do I want those subsequent leads to follow the same process or do I want to do maybe something different with them or skip processing all together so the framework is generally going to give us some sort of way to allow us to handle that and force the code to run through different behavior if it makes sense for us to do at the time all right so it's great we talked about trigger preoccupied trigger handlers and we talked about trigger frameworks let's go into a couple different options of how this looks and practice and see some of the code involved with that so as I mentioned there are three options I'm gonna be talking about today the first one is when I'm calling the virtual class option and essentially here we're gonna have a virtual class whose methods will be able to override we're gonna have a constructor that's going to kind of kick things off for us we're gonna have an enum consisting of trigger contexts so that'll be your before insert before update after insert things like that we're gonna call a method called set trigger context - but our framework mate we basically make our framework become aware of what context that's running in so that's going to be the routing part for us we're going to see a bunch of virtual methods that we can override we're going to see a run method that's going to take a look at the trigger context we're in and basically send us to the right spot in our code to execute the business logic and so this code is essentially going to start an hourly trigger just like we did before it's going to go to our lead trigger handler which is then going to call our framework which is going to be a singer single trigger handler class trigger handler is I'm going to reroute us back to our lead trigger handler where our processing will take place so let's take a look at what that looks like so I'm gonna jump back into my code here and I'm going to comment out my trigger handler for a second and I'm going to uncomment out a different version so let's get rid of all this and now we have this so the V is supported the words anymore yeah I was going to in a second I was just making the code changes first in and I can make it a little bit bigger let me just finish commenting this out and then I will make the code easier to see okay I play that all state now and all open missiles okay so let me make this bigger now okay hopefully that's a little bit easier to see so now I've taken my trigger and we started with 30 lines for a four insert and we changed it to 30 lines for the entire trigger that we will never have to edit again hopefully and now I've gone down I changed it to one line that we will hopefully never have to change and this is gonna be calling our framework so all my triggers doing now simply instantiating a new instance of our lead trigger handler and calling the dot run method so if we look at our lead trigger handler we see we're going to extend our framework here called trigger Handler and all I've done here in the lead trigger handler is not really too much the code itself is the same we're doing some stuff over leads we're checking for accounts for inserting our cases so that's all the same one thing you may notice I don't have to pass and trigger it on new anymore instead I have a constructor that is basically taking trigger dot new and casting it to a list of leaves because our framework works on all objects we just have to tell the framework which we're working within any particular time so trigger handler will handle all of the trigger new stuff we just have to reminded hey just a heads up I'm in the lead trigger trigger new is a list of leads and then my extending trigger handler here we're going to trigger this constructor and the constructor is going to call the set trigger context method and again that's essentially going to be our routing piece so if we look at set trigger context that's just calling another method called sector context with an optional billion for test button we are not able to see liqueurs hopefully some of your skin is stuck can you try to put it on of boots in mud or something or no okay what are you seeing right now Dexter yesterday right now some if-else is coming but that is partially visible oh really okay let me try fullscreen yeah now we can see you okay try yes okay okay instead a little bit better much better okay all right all right so anyway our that's the other class here but the trigger lead trigger handler is going to call the constructor of trigger handler and I'm just gonna set our trigger context and so that's essentially going to be our routing piece so set trigger context we'll call this our trigger con set trigger context with an optional mode for test mode if we want to do something specific in our testing and essentially it'll be doing all that routing piece for us so we'll be doing the trigger before trigger as inserter doors after trigger is insert but the difference here versus before is we only have to write this code once and we can use it for any object we don't have to put it in every single trigger we just leave it in the framework we leave it alone and all of our triggers can therefore use it without us ever having to worry about it anymore all these contacts here just come from the enum on the bottom with all the different event types and we're gonna end up basically telling our trigger framework what context are we running in we can then go back up here if you remember when we fired our lead trigger we fired the lead trigger handler run method and so if I go back into our trigger handler now we go to our run method here we know it what our context is because we just sent it so in our case we're gonna worry about the before insert context and then in our run method we're gonna see that because the context is before insert we want to call this stop before insert and in our case this is referring to the instance of trigger handler that's running which is our lead trigger handler and so we're gonna fire the before insert method the other thing to know this is a virtual class with a bunch of different virtual methods so we have a virtual method essentially for every event type and that allows us to Billy to pick and choose the ones we want so in our case if I go back to lead trigger handler we are overriding before insert so that's fine when we call this stop before insert we'll call this method right here and our lead trigger handler before insert and it's you can see that's the actual end of the trigger handler it's just this one method and so because of that that's the only method we're overriding if I were to call any of these other methods I don't have to implement them I don't have to think about them because they're already existing in the framework and so essentially for after insert for example we'll come down here because we didn't override it I'll see that it's empty and then we'll exit and that'll be in the Berger trigger execution so this gives me the ability to come pick and choose what methods I want I don't have to worry about the routing I don't have to worry about implementing all of the methods I can just pick the ones that I have to use for my trigger yes let's go see this in action now so if I go to presentation mode and go into Salesforce all right so I have a lead here I want to insert will insert one for Captain Marvel so I'm going to insert this lead and if I could go look at the debug logs now to put our presentation back up on the side here I'll see that we started off in our lead trigger we called our trigger handler constructor we set our trigger context to before insert we called our run method that routed us to our lead trigger handler before insert method it ran and it did everything needs to do our trigger kept going into the after insert context I went back to our constructor set our trigger context went to the run method and because we didn't have any after insert method implemented doesn't throw any errors just goes to the after insert part of the framework sees there's nothing there and gracefully exits and so nice be straightforward one class framework were able to pick and choose methods we want and don't have to worry about the routing piece and don'ts to worry about remembering to implement all of the methods so the erd for this is pretty simple we create our trigger and we create our object trigger handler for each object and the frameworks going to provide that virtual trigger handler that has the run method sets our trigger context and can go and provide a bunch of virtual methods we can choose to override or we can choose to ignore an object by object basis alright so what did we accomplish with this framework here we saw we were able to get down to a one line trigger which is always great very easy to debug a one line trigger we saw in our hand or we were able to only have to add the handler methods we want to use we don't have to add all of them if we don't want to and we saw that all the routing was handled for us so we instead of setting it up and each and every trigger we put it into the framework and that all gets taken care of for us we don't have to worry about it anymore one thing we didn't talk about in this framework that we will and some of the other ones is some sort of recursion check and that was more for simplicity sake if you I'll give you the link at the end to download this framework off github and there are some extra things in there about trigger bypasses that you can pass in if the lead trigger frameworks already running you don't want it to run again you can pass that in do some checks against it and they also give you the option to set a max loop counter so if you only want the trigger framework for leads to run maybe once or twice in the entire transaction you can set that and the code will respect that as well via the framework all right so let's slightly different direction now and talk about a different framework implementing an interface so the nature of interfaces are essentially they give you a bunch of required methods and if you want to implement the interface you have to implement all the methods and so we'll see what that looks like in a second here we're gonna see a trigger dispatcher again with a run method and then we're gonna see again our trigger handler with all of our context methods as well as an is disabled method that'll give us the option to basically put that recursive check into place or give us the option to shut down the triggers via the framework altogether and so for this one's gonna work a little bit differently but somewhat similarly at the same time we're going to start in our contact trigger here the contact trigger is going to call the trigger dispatcher which will handle the routing for us the trigger dispatcher will then call our contact trigger handler which is going to implement our eye trigger and we're interface and a contact trigger handler is going to basically execute the business logic and so let's go take a look at that one now so I'm going to jump back into IntelliJ here and I'm going to open up a contact trigger and let me put this into a presentation okay so we see once again here we have a trigger on contact once again nice clean one-line trigger and all we're doing here is we're calling our trigger dispatcher that's part of the framework we're calling the run method and we're just going to give it a new instance of our contact trigger Handler so if I go open those up now dispatcher trigger handler Nader I trigger handler interface so the interface nothing too crazy going on and they're just are again all of our different event method types before insert before update after insert etcetera with capabilities to pass in things like trigger dot new trigger that new map trigger dot old map and then as I mentioned there's a another method in here called is disabled that'll let us shut down the framework if we want to as well and then i trigger handler interface we have our contact trigger handler which implements it and this contact trigger handler is what we are actually passing to our trigger dispatcher and so in our contact trigger we called the run method on our contact trigger handler which again is an instance of our interface and the first thing we're going to do is check if this Handler disabled and so if I go look in our contact trigger handler we have an is disabled method and so we can implement this however we want really but the way we're gonna implement it here is it's kind of twofold number one we're going to check a custom setting called trigger settings and check for contacts to see you know what do we from the Salesforce you I just want to shut down the entire framework so in Salesforce I have a custom setting here that essentially for any object I can choose to just disable the entire framework for those objects and with this is disabled method it'll respect that so if I disable it for contact will come in to is disabled here you'll see that this is false or we'll see that this is true rather and this framework should be disabled and our framework will exit gracefully without running any more code if we choose to let the framework run we still have an option to disable it via the static variable so if elsewhere in my code I decide you know what I don't want to run triggers right now I can just set that variable to true and again that will dynamically programmatically shut down the framework as well so with our framework we can rest assured that our we're gonna have some way to disable the triggers at all times if is disabled is false we're gonna keep going in our run method here that's all that's in this class here the run method and after checking for is disabled all this is really doing is our routing so again we're checking our is before is insert as before is update this after is insert etcetera and we are calling the appropriate method so will be passed in in our case contact trigger Handler and so if it is before it is insert and it's not disabled we'll call our and learn before insert method we'll come back here to our contact trigger Handler and we were relatively small before insert method and we're just checking to see if we included test in the last name but this is going to run our before insert code and a trigger framework will run again eventually run our after insert code as well one thing we'll notice here all of these methods are being taken from the interface so that means we do have to implement them but as you can see the one we don't care about we can just kind of leave blank out we will end up with some duplicate code at the same time we'll know that all of our triggers are going to have all these methods we're not gonna have to worry about a potential case where a method is missing somewhere and it keeps our trigger dispatcher nice and clean because we can have a single run method and that's going to run out the same way every time for all of our triggers and so let's take a look at this in action now as well I like a presentation mode and will insert a new contact now so now we're going to sort of contact for Ironman execute that and again if I filter on our debug log we're gonna see we started off from a contact trigger we called our trigger dispatcher the trigger dispatcher got run method checked is our contact trigger handler disabled I was not so it kept going and called our before insert method we then went back to our trigger an hour after insert context again called the run method again checked if it was disabled called our after insert context and then exited and so a little bit more here we saw two classes that the framework is giving us here in our er D we have the trigger dispatcher with a single run method that we shouldn't ever really have to change and we have our interface i trigger handler interface which is going to provide all of our event methods and it's going to allow us the ability to shutdown the framework either via the UI or programmatically and it'll be nice to know that for all of our triggers we'll be able to turn them on and off pretty much any way we want and just like the first framework we saw we have to provide the object trigger we have to provide the object trigger Handler but the framework takes care of everything else the main difference here being is that we now have to implement all of the interface methods in every one of our triggers and here once again we saw we had a one line trigger which is great we saw all of our routing being handled for us again which is great the interface is going to keep all of our handlers consistent and had the same methods and in that way we're going to know that all of our triggers can be turned on and off the same way and we're also going to have potentially multiple ways to deactivate a trigger all right so original classes are great interfaces are great what if we wanted to get the best of both worlds and combine them right if we've a very complex org we might need a lot of them things going on we might want to go for frameworks number three that we're going to talk about today which is going to be a full object oriented architecture framework and as you can see just based on the bullet points that's going to be a little bit more involved than a lot of the other ones we've been talking about so far so this one's gonna have I think five classes in the framework it's gonna be two interfaces and two base classes and the way this is gonna work is we're gonna have a dispatcher interface with all of our required methods we have to implement so that's going to be all the event methods before insert after insert before update etcetera but an we're going to have an abstract to dispatch your base class that's going to implement the interface but in a virtual way but it will allow us to override it and pick and choose methods we want kind of like with framework number one so we'll get kind of both at the same time through the framework we're gonna also have a trigger factory class that's going to do the routing for us and basically figure out which class we need to call a which trigger handler class we need to call to get the process running and then we're gonna have another interface for our actual handler which is going to have two methods in it a main entry and an in-progress entry and this goes back to the concept I was talking about at the beginning what if we want code that kicks off the process for example our leads to operate well a if it's the one that's causing the triggers to fire if we're inserting the cases as part of the lead process maybe we don't necessarily want the main case trigger code to be fire and maybe we just want a scale down validation process for that or if our lead process is already running and something else kicks off the lead triggers again in the same transaction we might want to recognize that and handle that a little bit differently than starting all of the lead triggers all over again and so the interface will allow us to do that once again from that handler interface we're gonna have another abstract Handler base class that will implement the interface and allow us to override it and the other big difference here is that we're actually gonna have events specific handlers whereas the first couple times we've been talking all of our handler code was in one place we had a lead trigger handle or a contact trigger handler we're gonna be working with accounts for this one and we're gonna have a different class for account before insert versus account after insert versus account before up so they're all going to be their own classes and we'll see what that'll get us as we go on here all right so this codes gonna go on a little bit more of a journey than the previous two frameworks did we're gonna start off once again in our triggers which is great triggers are gonna be nicely clean and they're gonna call our trigger factory and our trigger factories I'm gonna do kind of our routing for us and figure out all right where is it that we need to go what object we working with and we're going to fire our account trigger dispatcher in this case because we're working with a count our count trigger dispatcher is going to use our trigger dispatcher base class implementing the I triggered dispatcher interface to figure out all right let's send us to the account before insert trigger handler which is going to extend our trigger handler base which is implementing the I trigger handler interface all right so let's go see all this in action now all right so I'm going to start off in our account trigger again and so once again we see a nice clean one-line trigger and here we're gonna call our trigger factory and so I go into our trigger factory our trigger factory if you saw we passed it the account s object type so basically we're just on our factory hey trigger factory we are firing some triggers on accounts please route us in the right direction so our trigger factor is gonna say that's great thank you for telling me you're working with an account I'm going to go figure out what triggered dispatch or we need to work with accounts and it's going to call get trigger dispatcher down here get trigger dispatcher is basically gonna say alright you're working with a count if you're working with a custom object let's take out the underscore discourse see and we're gonna figure out we need to work with the account trigger dispatcher we have a custom object it might be the custom object trigger dispatcher but either way I want to construct a new instance of our trigger dispatcher and return it so in our case we're going to be working with a count trigger dispatcher and as you see here it's going to be an instance of IED trigger dispatcher so if I open up a count trigger dispatcher it's going to be extending this trigger dispatcher base which as I've mentioned is going to be implementing our I trigger dispatcher interface and I trigger dispatcher it's just again the interface is gonna have all of our event methods so it has our before it insert before update after insert after update all that good stuff we also have a couple other methods we can choose to put in here both before in bulk after in case we have any bulk actions we want to take and we're gonna have an ant finally in case we want to do anything things out and by implementing that interface in our base class this base class here it's going to then implement all those methods in a virtual way that we can choose to override it's also going to have some boolean values here we can use later if we want and in our case we are going to be in the account trigger dispatcher so we can extend that we can pick and choose all right I want to extend override before insert I want to override before update I can override all of them I can override one of them setup up to me but going back to our trigger factory we figure that we need to use account trigger dispatcher that's great we see that it's an instance of I triggered a dispatcher if for whatever reason we don't have a trigger dispatcher for that object again that's fine we'll be able to catch it in our trigger factory throw an error message letting us know we need to create one but if not we're gonna call the execute method on a count trigger dispatcher so we're gonna come down here we're gonna set some trigger parameters which is essentially just a wrapper object to hold trigger a little trigger dot new and all of our trigger contexts and then we're gonna do our routing just like we've seen all the other frameworks so if it's before we start off with oddball before method before insert we call our insert method before update we call our before update method and so on and so in our case we want to call a count trigger dispatcher dot before insert so our trigger factory found the dispatcher figured out where to route us and now we can go into account trigger dispatcher before insert alright so now we're in our for insert method and again we're doing some sort of recursive checks here so basically we're checking to see is this before insert method already running as part of this transaction could we call it a second time if it's not already running great let's tell the framework we want to run it and execute our execute method if we're already running that's fine we're gonna call the same execute method but instead of passing a new instance of our account before insert trigger handler working the pass and null we'll see what that looks like in a minute but as you see here before insert method is calling the before insert Handler before update methods calling it before update handler the after insert method is calling the after insert Handler and so on all right so we did our routing we're in our before insert for our dispatcher and we're figuring out alright do we want to pass in an instance of the before instant Handler do we want to pass a null this execute method and this execute method is gonna be part of this trigger dispatcher base class so if I go back in there our execute method is basically just gonna say ok you passed it in a trigger event forgot to point that out but here we're passing in before insert in our before update method we're passing it before update after insert we're passing it after insert and so on so we choose maybe maybe not pass in and a handler instance and we choose to pass in our event and then we basically say ok did you pass in some sort of handler instance if you did we're gonna set our some variables here to the handler instance that you passed in and if we're not already in that context so for this is the first time our account before insert is running in this transaction we're gonna call the main entry of our handler instance if account before answer is already running and starts running again we're gonna in that case called the in progress entry method of our before insert Handler and again that's gonna give us the option to choose do we want to run the same code do we want to run different code if this code is already running as part of the same transaction or potentially we can configure it away that says is this the code they kicked off the process or not I mean we want to run some different code for that as well so we have that option as part of our framework in our case though we have our account before insert Handler and we're calling our main entry method so if I open up the account before insert trigger Handler we're going to extend trigger Handler base and we're going to implement I trigger Handler and so I trigger handler again an interface main entry and progress entry it also has another method for updating objects that we can use and then trigger handler base once again it's going to implement that interface and allow us to extend it virtually so it has the methods here main entry and in progress entry again implementing the interface and then if we go back to our handler we can override main entry to just do the things that we want and in this case we're going to ignore the in progress entry and the framework is gonna kind of handle that on its own and so the code itself isn't actually doing anything that interesting and is checking for the word test in our name but we basically got here through a very very long journey but at the same time once the framework is in place and we understand it all we have to do is create the classes for the events that we want and we can go right away to implementing the main entry method and putting our logic in there without having to worry about the routing without having to worry about are the dispatchers there or not because the framework will detect if it's not and it'll handle if that's the first time you're running or are we in the middle of a recursive state all right so let's go run this and kind of follow along here as you can see I also get closed out of a bunch of them but there were quite a few classes we ended up opening in that context there so I'm going to go insert a new Marvel account here let's see if we can follow along in our code journey at the same time put it back to keep this now we started off with our account trigger running we went over to our trigger factory we created the instance or we went to our create trigger dispatcher and found the entrance instance of our account trigger dispatcher we then ran did the routing and ran the execute method of the trigger factory and that sent us to the account triggered dispatcher based sorry I sent this to a counter dispatcher before insert which sent us to our trigger dispatcher base execute method which eventually sent us to our account before insert trigger handler main entry method we did the same thing here started with our account trigger or to the factory look at the account trigger dispatcher went to our trigger dispatcher base and eventually ended up in our account after insert trigger a main entry method so quite a few things going on in there and if we look at the erd for this obviously a little bit more complex than the previous ones and we see we have five different classes provided by the frameworks here the two interfaces to base classes and our factory so we had the dispatcher interface it had all of our event methods before insert after insert before update after updated etc we had our base class that implemented the interface that we were able to extend our object trigger dispatcher that we had to provide we had the trigger factory but did all the routing for us and found the trigger dispatcher we needed based on the name and then our trigger dispatcher was able to use the event classes so account before insert handler account after insert handler etc utilizing our trigger handler base class extended or implemented our I trigger handler interface and so that whole part of the framework just had the main entry and in-progress entry that allowed us to choose what part of the code were in what context were in and potentially send us to a different path and then the other thing we need to provide were all of the individual event methods we can pick and choose which ones we need to implement based on what events we want to work with one other thing we didn't actually see but we see here in the ER D is that file in yellow so we talked about at the beginning one of the benefits of trigger handlers in general its ability to reuse code by putting everything out of the trigger and into discrete methods in a single file because we're splitting up all those files into individual event classes we still may want to reuse some of the code and in that case we can potentially create one additional class the account helper or any object helper to have some of those kind of utility methods that we want to use across different parts of the code so we'll still be able to take advantage of that as part of the framework but it'll allow us to separate all of our event code into specific classes all right so all of this get us so once again we saw a one lion trigger we saw that all the routing was being handled for us we kind of had the best of both worlds here we were able to establish all of our methods through the framework but still let us pick and choose which ones we wanted to implement for any particular object on the other thing we saw here are individual event handler methods so if you think about a pretty complex org we had a somewhat straightforward use case at the very beginning and our lead trigger and ended up being certainty lines just four before insert and we talked about potentially expanding that before insert functionality so we may go up to 50 lines 75 lines even 100 lines and our before insert if we start taking this an approach for all the other events after and serve before update after update pretty soon we end up with a 500 lie and trigger handler which once again can be difficult to test difficult to maintain or senator etc especially if we start adding some additional methods for reusability so by splitting it out we can keep our classes a little bit smaller potentially the less complex we could have maybe a before insert handlers 104 lines long we can have 4 update handlers 100 lines long each can be tested individually each can be still easily called by the framework and we don't end up with any classes that are a little overwhelming to look at overwhelming to test and a little bit harder to maintain all right so let's talk about kind of some of the different approaches and things they have in common and where they differ so we saw on all of them we were able to consolidate our triggers down to a single line which is awesome simple triggers are always better we saw all of the frameworks were handling the routing for us and so we do need to implement it once but once it's there we don't have to worry about it anymore we can focus on in the first two focusing on the individual handler methods and in the last one focusing on the main entry method in our event class handler we didn't see it in the first approach but we definitely can implement some sort of recursive check and all three of them making sure that we're not running the same code multiple times in the context of a single transaction or if we are or maybe handling it a little bit differently we can also potentially build into the framework a way to just turn off part of the framework altogether either of me of a UI or programmatically with the bird school approach and the architecture that combined the virtual and interface approaches we were able to get a pick and choose which events we want to implement whereas with the interface you kind of have to implement everything at once again the the benefit of being able to pick your events is you don't end up with any unused code the downside is now you have to be adding new methods to your handlers or in the case of art architecture be adding new classes so pros and cons depending on what works for you and your team and the other thing I guess I'll I guess the next one we saw in our architecture we were looking for a class that had a very specific name so the class had to be named account triggered dispatcher or the framework wasn't gonna be able to find it and this is now I always find naming conventions is one of those things when I first hear about it I'm upset and then later on when something is named properly I also get upset and so it is a little bit of overhead at the beginning but at the same time if I know everything is named the same way I don't have to worry about figuring out how somebody chose to name the functionality for how somebody chose the name of functionality for me I know everything's gonna be named the same every time and they'll save me that time and energy into figuring out how to find the class where my trigger logic lies so sometimes naming conventions can be a good thing but just something to keep in mind I depending on how your team structured the other thing we saw we spent probably twice as much time talking about the third framework as we did the first two and that's because that has a lot more overhead to it a lot more jumping around um and again could be a good thing or a bad thing depending on the size or how your organ structure and things like that so with the virtual interface or the virtual approach we saw just a single files part of the framework for the interface approach we saw two files as part of the framework and the architecture approach saw only five files as part of the framework with a bunch of different individual files for the events and again can be nice to get up and running with just a single file handling all the routing for you could be nice to have maybe a couple different files doing the routing and doing the method implementations but sometimes your code is an org is very complex and you maybe need that additional structure in place and that architecture type framework that might take a little little bit more to get up and running but once it's there you can really focus on the nitty-gritty details in my specific class and my specific type of execution of the before insert operation focusing on what that logic looks like instead of worrying about how things are being routed how things are gonna be working for any particular object so we kind of already touched on this but I'll go through them again some of the drawbacks stress again that no framework is perfect and as we saw with our architecture framework we also have the option to kind of mix and match principles that we want to use and concepts that we don't with the first two the virtual and the interface capabilities we kind of leave ourselves open to extra-large canler's of our orders are very complex and then with the interface method we saw that we have to implement all methods all the time and potentially leaving us with some unused code again it could be a good thing if we always see that the methods are there so we know exactly where to go start implementing them don't have to remember what they're named in the interface to come through already there when you create the class but at the same time it ends up with unused code so kind of a pro and con there with the architecture again naming conventions is again one of those things could be good could be bad but we do have some specific naming conventions and you can kind of the framework to change that however you want to name your dispatchers but the architecture is generally gonna work for some sort of naming convention and that's both for your benefit and easy use for the framework to find what dispatcher you need theoretically if you really wanted to you could put the names and a custom setting or custom metadata and give yourselves a little more flexibility with some of the naming as well but then again everything's named a little bit differently it might be a little bit harder to find where things are happening with the architecture we also saw some code overhead so I think we can get up to about 15 files for a single object that we're interacting with any point in time so there's gonna be more of a learning curve with that one but once we kind of understand how that routing is working we can get down to the real nitty gritty details all right I want to troubleshoot the in progress entry method of my after update contacts for account we're going to be able to find that relatively easily once we understand how the framework works and operates and we can be very specific in controlling how our code is working all right so kind of summary and some final thoughts that I have as we saw we can kind of mix and match strategies no one framework is perfect so if you want to override some methods you can do that if you want to implement an interface you can do that if you want to do both you can do that I generally recommend some sort of recursion check either via salesforce UI programmatically both it also helps when testing if you can turn off some triggers they don't necessarily impact what you're doing maybe I want to turn off my case triggers if I was testing that initial lean trigger functionality so ultimately pick the strategy isn't pick the concepts that make the most sense for your org um one thing I will note and it might be kind of obvious you know I was able to install all of these into a nice plain vanilla developer org and get up and running right away that may not be the case for the order you're working on these things generally are easier to implement at an orange beginning rather than later on but at the same time there's definitely a lot of benefit from implementing things kind of as you're going as well or building new triggers maybe start using the framework for some of those and editing some of the other ones to be built into it later I know I've definitely thought to myself wouldn't it be nice if I could just shut this trigger functionality off temporarily or trigger maybe his name something odd I have to spend a few minutes trying to find it also not a great feeling either and again I want to reiterate that no one framework is perfect their pros and cons to all aspects of all the frameworks so again you know I'm gonna provide some links that you can download the code for all three of these but you know I'd recommend you take a look at them picking to you the concepts like and maybe think about how your org start using them or maybe some principles you want to think about that might make your life easier down the road all right so if you're interested in the my initial trigger code it's not not interesting necessarily but I have it at but not least lead trigger if you're interested in my initial handler we walk through you can get the handler at the deadly slash lead handler and the updated trigger code that we changed at Dudley slash lead trigger final and probably the most interesting parts the actual framework code so the first framework the virtual one is completely downloadable via an unmanaged package from github bit dot me slash virtual trigger framework so you can get Co involved with that the interface trigger framework has been ugly slash interface trigger framework and I don't think that one actually has a downloadable link but they have all the code on that page to be able to copy and paste it into your organ again it's only the two files so hopefully shouldn't be too much there and then there's a link that talks about the architecture of trigger framework as well as a link to an unmanaged package for that one as well and you can get that at bit dolly slash arched order framework alright and so with that thank you so much for having me today again feel free to check me out on Twitter or my blog and I think you all for coming to Apex hours I'll turn it back over to uh on it yeah thank you so much Adam it's a great landing for everyone and I can see couple of questions on the chat window so would you like to open the chat window around sure I mean see I mean exit presentation about here ok right so I mean so it would be recorded and so text editor or text editor i was using IntelliJ with the illuminated cloud plugin so yeah so just to plug in on top of IntelliJ for Salesforce um kind of a screening okay sorry about the screen issues yes so the trigger classes as I mentioned I have some links in here and I think this presentation can be made available and it'll be on YouTube as well with all those links so one method before insert create multiple sub methods how do we implement it in framework to only one method in the before insert for framework two so if I open that one its contact so dirt let me see here so there's only one method in before insert usually we create multiple sub methods how do we do in framework to yeah so basically the framework in this case is going to call them before insert method and then from there you can choose to route it however you want so you can potentially have separate methods for before insert the call either from the same trigger handler from helper class if you want to have separate main entry methods and progress entry methods you can have that as well how will trigger context variables get passed so I think they get passed differently in each of the frameworks and one of them we had the lead trigger Handler where we weren't actually passing any sort of variables but rather because we're in our trigger instance we have access to trigger new and because we know we're in the lead trigger handler we can cast everything to lead so if we were to add right now we just have before insert but if we start adding before update before delete after the lead we're going to expand our instructor here eventually add another list of leads for old leaves for trigger not old this we add some maps old map a new map we just cast them as class variables and then we can use them in the trigger here the contact trigger handler I believe via the interface we always pass in trigger new and trigger that new map an old map and then again we do need to do our casting in the middle of that method just for reminded hey we're working with contacts here in our contact trigger and learn and then in the architecture framework we have a class called trigger parameters that we constructed in our trigger factory that was essentially giving triggered a new trigger not old and assigning it to old list new list old map and new map and so if I go back to our trigger factory we basically constructed this trigger parameters and then when we called our before insert before update etcetera methods we pass in those trigger parameters and so if I go to our account trigger dispatcher we'll see we take those trigger parameters and again we pass them to our class method here so account before insert trigger handler again we pass in those trigger parameters and then we can say alright tp'ed new list CPI new map then we do the casting here but again the framework for the most part is handling all the trigger variables for us the only thing we have to do is cast it for our respective triggers any any more questions for now it was a very wonderful presentation thank you for that um just a couple of questions go ahead and ask yeah so on the interface trigger framework I know you should you know you should have disable the trigger you know through the code as well as through a custom setting um so assume the same as possible with the yeah yeah so the architecture the trigger framework you can definitely include is disabled method like we had here let's see that's probably my favorite way to do it is either via the UI or be a static variable they had one in there as well for us I can find where it was they kind of had something similar where they were checking to see is this already running essentially so we set it to true and then we execute it and then once it finishes we set it to false so if it's already executing and we come back to this block in the code we're gonna be executing our in progress entry method so it kind of handles it that way and if we choose to ignore the in progress entry that it will essentially not do anything but that second time it runs but we can definitely either extend our interface to have like an is disabled method or we can choose to put that in trigger by trigger in depending on what our preferences okay okay um so my other question is I mean you know obviously the architecture trigger framework of things many orders of magnitude complex completely virtual one or a sorry interface one so what would be like a compelling reason to use the one thing that I understand is can detect when the trigger is actually processing which is not possible with the interface to the framework is it correct um nope it's not maybe not possible with the interface trigger framework because we can probably implement something similar if we wanted to I do some sort of sets of them sort of flag kind of like we're doing here that may be called different methods I think the difference there is it allows for more detail so in the interface trigger framework we're essentially saying are you calling before insert great all of the before insert code is going to be here whereas with the architecture trigger framework instead of having a single method for before insert we're gonna have its own class and we're gonna have different methods for main entry and progress entry so it's generally if you're you know org is very robust and you're having hundreds of lines of code for each instance you're not necessarily gonna want a 200 line before insert method you might want to put that into its own class and you might want a more closely target main entry code is here in progress entry code is here so it kind of you know if your organs less complex or you don't necessarily need to worry about having different behavior for the different contexts you're in I would recommend less overhead but that just kind of gives you more granularity and being able to control the different behavior for the different possibilities and pass through your code can take virtual trigger framework is not the same virtual class ease and the presentation can you share with you using a presentation with the lead trigger implementation I thought it was let me go double-check that really quick I thing okay so if I go into github here I think I might have skipped some of the methods but it should be otherwise language go into classes trigger handler so yeah so we have the run method we have a trigger context methods I guess I did change mine a little bit actually so there's some extra stuff in here to validate too with a loop counter validating that it's running getting the handler name I think I might have this negative sign the links for that really quick where'd I put simple okay and it's not it either okay so I have that I guess that I can put that in the presentation almost a bit Dunley slash trigger handler should be the trigger handler for the virtual class that I was using yeah yeah all right unless I took out a bunch of stuff yeah so there's some more stuff in there if you want to look at it but if you want just the scaled-down version I used I can provide the link to that in the presentation as well but that Lee / - grammar any questions for today thank you enough that's a really great session and thank you everyone for the joining us and thank you Adam so and don't forget to sign up our next session that is on asynchronous process so join that to learn about all about batch of feature method Huebel shop and platform events thank you everyone and thank you special thank for you Adam thank you so much my pleasure thanks so much for having me thanks everyone thank you