4

I'm working in SalesForce and am wondering if anyone can share any pros and cons in regards to utilizing the SalesForce Trigger Factory. Is it better to utilize the triggers individually, or is it better to use the Trigger Factory?

6
  • Always better to use a "Factory" purpose built object oriented code is always better than a basic style format. – Eric Dec 8 '15 at 18:58
  • Is there a specific methodology or package to which you refer? – Adrian Larson Dec 8 '15 at 19:03
  • 1
    @Eric I would say "mostly better" - martinfowler.com/bliki/Yagni.html. – Keith C Dec 8 '15 at 19:08
  • @KeithC Yea, I will learn, eventually, to not use absolutes like always sometime......maybe..... – Eric Dec 8 '15 at 19:13
  • At my current position we use patterns for just about everything and I love it.. At first it was hard to learn but once you get the hang of it it's awesome – EricSSH Dec 8 '15 at 21:04
15

Using a pattern is like using a tool. For example, you use a screwdriver on screws, and a saw for cutting stuff. You'd have a hard time cutting with a screwdriver, and you'd have a hard time using screws with a saw. Each tool has an intended purpose, and you should learn when to use each tool. That said, the trigger factory happens to be an incredibly useful tool, if you can use it correctly. Using it incorrectly can actually lead to problems like excessive query usage, long transaction times, and so on.

So, instead of doing pros and cons, I'm going to do cons and pros, to emphasize that a little carelessness can go a long ways.

Cons

It's Hard To Master

I've read a lot of triggers that look like the following:

trigger ... (before insert, before update, before delete) {
    if(Trigger.isInsert) {
        if(Trigger.isBefore) {
            TriggerFactory handler = new TriggerFactory();
            handler.onBeforeInsert(Trigger.newMap);
        }
    } else if(Trigger.isUpdate) {
        if(Trigger.isBefore) {
            TriggerFactory handler = new TriggerFactory();
            handler.onBeforeUpdate(Trigger.newMap);
        }
    } else if(Trigger.isDelete) {
        if(Trigger.isBefore) {
            TriggerFactory handler = new TriggerFactory();
            handler.onBeforeDelete(Trigger.oldMap);
        }
    }
}

This is not mastering the tool, it's using it like a blunt weapon and hoping it works. This method is inefficient, and requires maintaining the trigger and it's related code over and over again. Adding new DML events requires edits in two places, etc. You're more likely to make mistakes with all the nested if statements, and there's no general pattern or order.

It's Inefficient

As your factory grows in complexity, you'll find that people will call the same query from different functions, or update the same records in different functions, thus causing a higher usage of CPU time than is absolutely necessary, and risking transaction failures from memory limits, DML row/call limits, and/or query row/call limits. At least when all of your trigger logic is inside a trigger, you'd have a better chance of recognizing that the same queries are already in play, etc. However, an even worse scenario is when you use utility methods without a trigger factory within your triggers, which is another common cause of reaching governor limits and longer save times.

It's Overkill

Sometimes, all you need to do for a trigger is three lines of code, and you're pretty sure you'll never need more than that (many custom objects actually fall under this category), in which case setting up an entire factory just for them is complete overkill and actually causes more harm than good. In fact, maybe those three lines of code could have been a workflow rule, validation rule, etc. Going straight to a trigger factory out of habit may actually cause developers to lose sight of things like out-of-the-box configuration options.

It's Not A Utility Class

Utility classes are used to write functions common across many different classes and triggers. Trigger factories are typically designed to be used with one specific object in mind, and yet people will often start using those methods in the factory as general-purpose utility functions, instead of maintaining purity of functionality. So, after a while, you start maintaining your code and you remove a function that you thought was only used for your trigger, only to find that other classes will no longer compile. Using trigger factories, like other patterns, requires discipline to maintain.

It's Slow

Constructing objects is slow. Type-casting is slow. Calling functions are slow. Switching to/from "with sharing" context is slow. The more complex your trigger factory becomes, the greater the risk of it becoming a bottleneck in deployment times and general record save times over coding the logic directly into your trigger.

Cons Summary

So, in summary, don't use them until you need them, and study them before you need them, because otherwise you'll use them in ways they shouldn't be used, leading to maintenance issues, fragile code, and frustrated users.

Pros

Write Once, Use Everywhere

A proper trigger factory can save you tons of time by offering a reusable platform. Here's how I usually write my triggers on an object:

trigger X on Y (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
    TriggerFactory.execute();
}

No mess, no fuss, and I only ever write my triggers once. Even if I don't use all those events, this code runs in about 1/100th of a second if there's no work to do. For a very nominal price in speed, I gain the ultimate maintainability. Set it and forget it.

Common Platform

All triggers can gain a new feature simply by modifying the trigger factory. No longer do I have to wade through a dozen triggers and modify each to use a new feature. For example, you can add the ability to enable/disable some/all triggers using custom settings, without each trigger needing to know, or care, about the functionality. Or, you can make a common error logging framework for triggers that fail, or even decide when/if you want to execute some code asynchronously because you're running out of CPU time/queries/etc.

Reduction Of Deployment Time

A proper trigger factory should include an on/off switch for testing. This allows you to bypass the trigger logic that could cause failures in unit tests, reduce overall execution time by a significant amount (as much as 90% or more in some projects), and write more compact and reusable code. As a side effect, you also get access to...

Functional Unit Tests

No longer do you need to test the same feature across four different objects. You can test the feature once with one object, and know that it works with all the others. You're testing features, not triggers. You can now easily test each individual feature as a unit test instead of testing all features every unit test. End-to-end unit tests are still encouraged, but you're not duplicating end-to-end testing with every unit test you write.

Code Reuse/DRY (Don't Repeat Yourself)

Having your functions all bundled up in separate classes allows you to enable code reuse. Similar to utility classes, trigger factory classes allow code to be potentially reused across multiple triggers/objects, and reduces maintenance, since classes can now be deployed independently of triggers. Code within triggers directly can't be used in other classes/pages/etc, by contrast. Also, you get to implement common trigger features across all your triggers using a common framework.

Pros Summary

In summary, trigger factories are awesome. They give you the ability to implement global trigger actions, consistent logic, potentially faster deployment times (if built to do so), reduced code, and so on.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.