Two interesting ways to architect Apex triggers

I’ve been writing Apex triggers for a while, and recently I ran across two ways to architect triggers that are different from how I used to do things. Both methods have one main benefit–they push all your logic to your classes, and allow the trigger to do just one job–invoke code on data change.

Here’s a trigger architected the first way:

trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {

    if(trigger.isBefore){
        if(trigger.isInsert){
            MyObjectInsertBefore myInsertBefore = new MyObjectInsertBefore(Trigger.new);
        }
        if(trigger.isUpdate){
            MyObjectUpdateBefore myUpdateBefore = new MyObjectUpdateBefore(Trigger.old,Trigger.new);
        }
    }

    if(trigger.isAfter){
        if(trigger.isInsert){
            MyObjectInsertAfter myInsertAfter = new MyObjectInsertAfter(Trigger.new);
        }
        if(Trigger.isUpdate){
        	MyObjectUpdateAfter myUpdateAfter = new MyObjectUpdateAfter(Trigger.old,Trigger.new);
        }
    }
}

As you can see from the trigger, all that we’re doing is invoking the correct class based on the starting criteria–are we an insert or an update, and are we before or after? We’ve got a separate class for each of the four cases.

Here’s what two of those classes might look like:

public class MyObjectInsertBefore {

	//create your variables and data structures

    //constructor
    public MyObjectInsertBefore(){

    }

    //constructor accepting a list of myObjects
    public MyObjectInsertBefore(MyObject__c[] myObjects){
        //call whatever methods you need to get the job done
        someMethod(myObjects);
        .
        .
        .
    }
}
public class MyObjectUpdateBefore {

	//create your variables and data structures

    //constructor
    public MyObjectUpdateBefore(){

    }

    //constructor accepting a list of myObjects
    public MyObjectUpdateBefore(MyObject__c[] myOldObjects,MyObject__c[] myNewObjects){
        //call whatever methods you need to get the job done
        someMethod(myOldObjects,myNewObjects);
        .
        .
        .
    }
}

Key to making this efficient is to have shared methods in a MyObjectUtil class, so that similar operations can be reused across your classes.

Here’s a trigger invoked the second way:

trigger MyTrigger on MyObject__c (before insert, before update, after insert, after update) {

	public enum triggerAction {beforeInsert, beforeUpdate, afterInsert, afterUpdate}

    if(Trigger.isInsert && Trigger.isBefore){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeInsert);
    }
    if( Trigger.isAfter && Trigger.isInsert ){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.afterInsert);
    }
    if(Trigger.isUpdate && Trigger.isBefore){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeUpdate);
    }
    if( Trigger.isAfter && Trigger.isUpdate ){
        MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.afterUpdate);
    }
}

This trigger sends the old and new sets over to a class and passes the way that this was invoked via an enum value (look up enum in the Apex docs if you haven’t used them–I had to). There is only one class, and then the class sorts out what should happen based on the data:

public class MyObjectClass {

	public MyObjectClass()
	{
	}

	public enum triggeredAction {beforeInsert, beforeUpdate, afterInsert, afterUpdate}

	public MyObjectClass(MyObject__c[] myObjects, MyObject__c[] myOldObjects, triggeredAction ta)
	{	

		// BEFORE INSERT
		if (ta==triggeredAction.beforeInsert)
		{
			someBeforeInsertMethod()
		}

		// BEFORE UPDATE
		if (ta==triggeredAction.beforeUpdate)
		{
			someBeforeUpdateMethod();
		}

		// AFTER INSERT
		if (ta==triggeredAction.afterInsert)
		{
			someAfterInsertMethod()
		}

		// AFTER UPDATE
		if (ta==triggeredAction.afterUpdate)
		{
			someAfterUpdateMethod();
		}

	}
}

You can see that you’re basically accomplishing the same thing–getting the class to invoke the right methods based on the invocation, but that we’re doing it in two different ways. In the first example, we’ve got a proliferation of classes, and each class is very simple. In the second example, we’ve got one class that is more complex as it has to handle many types of invocation.

I ran across the second example in the spring and really liked it. Then I ran across the first example last month and now it’s my favorite. I’m going to try to write new triggers that way and see how they go.

Thanks to Matt and Mike for architecting your code in these really interesting ways! I hope you, like me, love seeing how other people do things–it can really improve the way you code so very quickly.

17 Responses to “Two interesting ways to architect Apex triggers”

  1. Scott Hemmeter Says:

    I go with the second approach. Got the approach from Matt Kaufman. I assume that’s the Matt you mention in your post.

  2. Steve Says:

    Yep, that’s the Matt in question. Blew my mind when I first saw it.

  3. Jeremy Ross Says:

    I’m always interested in finding ways to bring traditional good programming practices to salesforce, which is all too often difficult to do.

    In this case, I’m not sure that the second way is much of an improvement. You still have if isupdate/isbefore blocks in both the trigger and the implementation class. Why not move the invocation of the someBeforeInsertMethod-type methods to the trigger? Then your implementation class is cleaner. Just 4 methods sans big ugly if blocks.

    I’ve also used the Command pattern with some success. Doing things the “right” way (here comes the rant) is still troublesome in force.com because creating classes, interfaces, etc. in the IDE is slow and laborious, roundtrip saves are slow and there are no namespaces/packages like Java, .NET, etc. If force.com wants to be considered a serious platform, they have to fix these things. Until then, I’ll prefer to write non-trivial apps on a different platform.

  4. Mike Leach Says:

    I like the enum declaration. Great idea.

    Another thing that helps readability is to just set transaction state in the constructor then call an Invoke() method on the trigger to do the actual work.

    Otherwise the lvalue stuff from the constructor just looks like dead code.

    MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeInsert);
    process.Invoke(); // or alternatively process.Execute();

    Of course, this all begs the question “Does Apex require an lvalue when calling new?” (I don’t know).

    Would be even nicer to use a fluent expression like this:
    new MyObjectClass(Trigger.new, Trigger.old, triggerAction.beforeInsert).Invoke();

  5. Jon Mountjoy Says:

    It strikes me that what is really needed here, to induce the DRY principle, is to have the type of trigger (result of Trigger.isInsert, Trigger.isAfter etc.) available as an Enum in the first place. Perhaps an Idea is called for? Something like: Trigger.triggerAction. Otherwise the skeleton code you have in the second case is going to repeated for each different trigger you write – and worse, you have no alternative but to repeat it.

  6. Mike Leach Says:

    Good question. Why is the public enum declared twice? Does Apex not support global namespace scope?

  7. Steve Says:

    Great idea Jon.

    There are two pieces of data: operation and type. Operation would be an enum for the DML operation, Type could be before or after. Type could be an enum. Or you could just use the isBefore boolean.

    Trigger.Operation enum and Trigger.Type enum (or the current Trigger.isBefore)

    Or you could flatten everything into Trigger.Action, an enum that would combine the two values to “Before Insert” and “After Insert”, etc.

    Sounds like we need an idea.

  8. George Scott Says:

    Interesting post Steve. I’m always curious about different design patterns for Apex code.

    Being a long time Java programmer, I have one question for you. Is there any reason you are performing the logic in a constructor versus a public static method in the class? This is the approach I typically use, no need for enums or multiple classes. For example:

    if(Trigger.isInsert && Trigger.isBefore){
    MyObjectClass.beforeInsert(Trigger.new, Trigger.old);
    }
    else if (Trigger.isAfter && Trigger.isInsert ){
    MyObjectClass.afterInsert(Trigger.new, Trigger.old);
    }

    In the MyObjectClass you just define the methods as static so they can be called without an object instance:

    public class MyObjectClass {

    public static void beforeInsert(MyObject__c[] myObjects, MyObject__c[] myOldObjects) {

    }

    pubilc static void afterInsert(MyObject__c[] myObjects, MyObject__c[] myOldObjects) {

    }

  9. Mike Leach Says:

    On second thought, I’d probably prefer calling unique (possibly abstract) methods for each event type in the Factory container.

    MyObjectClass process = new MyObjectClass(Trigger.new, Trigger.old);

    //switch or if statement block
    process.OnBeforeInsert();
    process.OnAfterInsert();
    process.OnBeforeUpdate();
    process.OnAfterInsert();

    Microsoft really killed their Win32 API with too many macros/structs/enums. .NET corrected this mistake.

  10. Steve Says:

    Thanks for that example George. Static calls make sense, and seem to in this case. Thanks.

  11. Steve Says:

    That’s an interesting take on it Mike. It’s similar to George’s example but passes the sets in the controller. I like that as then you’re only handling them once, and then each method can process those sets appropriately.

  12. Steve Says:

    George, I’ve never gotten my head around when I should chose a static implementation, and when I should make the class one that gets instantiated. In this case, it seems like I Mike’s idea to instantiate and then call individual methods is pretty efficient. In the constructor we can grab the two trigger sets into local variables for use later in the other methods.

    It keeps the signatures of the methods clean, but they can only be called when the class has been instantiated.

    Would love to hear your thoughts on static vs. instantiated in this case.

    Thanks for all the great comments everyone!

  13. George Scott Says:

    Mike’s approach is definitely the more object-oriented approach and a cleaner design from that perspective.

    There are a couple of reasons I would use static methods over the object-oriented approach: maintenance and performance.

    If a lot of people will be editing the code over time (maintenance) and some of them are not professional programmers, it is sometimes best not to introduce object-oriented concepts if they are not needed. This really depends on the skill set of those maintaing the code.

    On the performance side, creating an object has a cost associated with it, both in terms of creation, and later when it has to be garbage-collected by the system. So I tend to avoid creating temporary objects if I can avoid it. This is just a habit after years of tuning server-side Java code, and may not be relevant for Apex.

  14. gokubi.com » Blog Archive » Apex Architecture Says:

    [...] gokubi.com « Two interesting ways to architect Apex triggers [...]

  15. Mike Leach Says:

    It’s always convenient when a static method pops up in autocomplete (or Intellisense) and always worth exploring.

    Thread safety is really the only issue to review when using static methods. Assuming the static method is not dependent on any globally scoped objects, then either approach is fine.

  16. Wes Says:

    Building on Jon’s idea why not make the trigger type available as method a parameter and/or return type? That way frameworks could be developed and triggers would have tiny implementations.

    In the Mike vs George debate I’d side with Mike. I’d disagree with static classes being more easy to maintain. A clean OO class architecture will always win out on the maintainability debate mostly because of potential class hiearchies coupled with good ol’ polymorphism.

    That said I am a fan of static classes, but would usually use them in utility classes or architectures that subscribe to factory patterns e.g. If I were using an enum as you have above I might’ve declared it as static in a utility class.

  17. Interesting ways of architecting Apex Triggers « jonathanrico. Says:

    [...] came across a blog post at gokubi.com (http://gokubi.com/archives/two-interesting-ways-to-architect-apex-triggers) about some interesting ways of architecting Apex [...]

Leave a Reply