3

Looking for some suggestions/lessons learned, etc., regarding where to add the decision-making code that determines if some code should run after a particular field update in a trigger context.

For example, I'm using this framework for my triggers. The framework provides a [Object]TriggerHandler class, where you have one method per trigger event i.e before insert, before update, etc.

So, this class is responsible for a higher level of decision-making (or abstraction), i.e if the context is beforeInsert, then execute this code, if it's afterUpdate, then execute this other code.

The way I see it, I don't want this class to be responsible for making decisions as to whether a particular piece of code should run because of a field value change.

For example, let's say I have a class called AccountOwnerSettings that should be called when the Account.IsActive field goes from false to true.

This pseudo-code:

if(!AccountOld.IsActive && accountNew.IsActive){...something }

shouldn't be in my TriggerHandler class, but it also shouldn't be in the AccountOwnerSettings class, as this would prevent me from reusing the class in other contexts (web service, batch, etc).

On the other hand, having a separate class for lower-level decision making sounds a bit of an overkill, and it might turn the trigger framework into spaghetti code.

6
  • What's the impetus behind not placing that filtration code in your Trigger Handler class? That's where I would want to place it.
    – David Reed
    Nov 21, 2018 at 17:50
  • I had a similar dilemma, github.com/kevinohara80/sfdc-trigger-framework/issues/14 Nov 21, 2018 at 17:57
  • @DavidReed because I want to keep the class as clean as possible and make it have a single responsibility, which is to determine which code should run on a given trigger context. Whether the actual code meets the requirements to be run (field values have changed, etc) shouldn't be a responsibility of this class, as it would do too much. Essentially, I'm trying to make sure each class in my org has a single responsibility. Nov 21, 2018 at 17:57
  • @PranayJaiswal did you end up with a good design for this? Nov 21, 2018 at 18:02
  • 1
    Force.com Enterprise Architecture by Andrew Fawcett is worth considering - you'll use a service class (callable from domain class, VF controller, Aura controllers, Apex REST clients, invocable methods). The domain class addresses the domain (i.e. sobject, including, but not limited to trigger handlers). See Trailhead and the aforementioned book.
    – cropredy
    Nov 21, 2018 at 22:48

1 Answer 1

3

Normally I use to prefer writing a Service class which will be getting called from Trigger handler.

Those decision making conditions could be added in that Service class.

This class and methods can be reused from other classes even from Visualforce's controller or webservice classes.

6
  • How can that class be used from a visualforce controller if the trigger context variables are not available in visualforce? Of course, you could always have a main API method or entry point to your class, and that method can tell if you are in a trigger context, if you are, do the filtering, if not, just execute. Is that what you are saying? Nov 21, 2018 at 18:51
  • 1
    This sounds very similar to my approach. All service classes that we want to potentially be run in a given trigger context are called, and then the decision of whether or not to actually perform the work in the service class is delegated to the service class itself. The biggest gotcha here is probably that you need to somehow ensure that you query (or otherwise set) all of the fields that you reference in the service class (a good opportunity to implement the selector layer from Apex Enterprise Patterns).
    – Derek F
    Nov 21, 2018 at 18:54
  • 1
    @pgonzaleznetwork The idea here is that your service classes would just take a map or list of your desired SObject. The TriggerHandler would be responsible for performing the filtering on which service classes are executed in each context, and the service classes would just operate on a simple collection (keeping explicit references to trigger context variables out of your service classes). You could pass Trigger.new in and still gain the benefits of a before trigger, or you could construct a List in a controller extension and pass that in instead.
    – Derek F
    Nov 21, 2018 at 18:58
  • @DerekF +1 for your suggestion and approach Nov 21, 2018 at 19:01
  • @DerekF to make sure I'm following: TriggerHandler is responsible for saying class A and B should execute on BeforeInsert. Then classes A and B are responsible for filtering the list of SObject passed to them and determining on which ones to operate on. Is that right? The filtering done by classes A and B (in my case) needs the trigger.oldMap and newMap to be able to tell if the values changed, and obviously, those variables are not available in other contexts (i.e web service). So how do you reuse classes A and B in other contexts? Nov 21, 2018 at 19:12

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .