7

I have a requirement to comment all the code of an apex class called AccountTriggerHandler that I did not code. I have no way of contacting the programmer that made the class. I'm trying to figure out why the class was programmed/named this way.

enter image description here

I would post all the code, but it's over 700 lines. It looks to me like a utility class that stores a bunch of functions to be called elsewhere in the app. If someone knows the design style of this class, what's it called? If you could also reference docs on this style of programming I'd appreciate it.

19

TL;DR

The code you are being asked to "document" follows a Service Layer pattern. Methods in this approach tend to be static void and act on an input. Another common name for it I've seen is indeed Util or Utility, as you mention in your question.

I wrote quite a lot below about what I believe a Trigger Handler should be. How does it relate to the task you've been handed down? Well, for one, it is the basis for my contention that you should not follow the pattern laid out by this class. My main problem with it is that combining the Handler and Service layers just leads to confusion in your mental model and test suite.

Normally, documenting the Trigger and Handler layers is nigh trivial. And in fact, if you are good at descriptive naming, it may be fairly straightforward to translate the Handler implementation into sensible documentation.

You should very rarely need to write a 700 line Apex Class. I would say never, but the Apex Wrapper Salesforce Metadata API* is one example which has made me soften my stance there and back off from absolutes.


Benefits of the Trigger Handler Pattern

Related reading: Trigger Frameworks and Apex Trigger Best Practices

While my preferred pattern differs slightly, the above article lays out many of the advantages. I personally find a handler implementation must-have because it:

  • facilitates logic-less triggers and One Trigger Per Object, which itself has many benefits
    • (including fine grained control over order of execution)
  • improves readability and Separation of Concerns
    • (this improved readability makes version control more fruitful as well)
  • optionally facilitates selective disablement

Separation of Concerns

The concerns can be simply separated into three basic questions:

  1. When (trigger layer) - When will records be acted on?
  2. What/Which (handler layer) - What actions will be taken? Which records will be acted on?
  3. How (service layer) - How will those actions be performed? How are those criteria defined?

Trigger

The trigger can simply worry about when:

trigger MyObject on MyObject__c (/*events*/)
{
    TriggerHandler handle = new TriggerHandler(trigger.new, trigger.oldMap);
    if (trigger.isBefore)
    {
        if (trigger.isInsert) handle.beforeInsert();
        if (trigger.isUpdate) handle.beforeUpdate();
    }
    if (trigger.isAfter)
    {
        if (trigger.isInsert) handle.afterInsert();
        if (trigger.isUpdate) handle.afterUpdate();
    }
}

One thing I really like about this pattern is that you can very quickly look at your trigger on the object and identify which events have logic on them. They also will be very stable in your code repository over time.

Handler

The handler can worry about what/which:

public with sharing class MyObjectTriggerHandler
{
    @TestVisible static Boolean bypassTrigger = false;

    final List<MyObject__c> newRecords;
    final Map<Id, MyObject__c> oldMap;
    public MyObjectTriggerHandler(List<MyObject__c> newRecords, Map<Id, MyObject__c> oldMap)
    {
        this.newRecords = newRecords;
        this.oldMap = oldMap;
    }

    public void beforeInsert()
    {
        if (bypassTrigger) return;
        MyObjectService.validate(
            MyObjectService.isInvalid().filter(newRecords)
        );
    }
    public void afterInsert()
    {
        if (bypassTrigger) return;
        MyObjectService.alterRelatedData(
            MyObjectService.shouldAlterRelatedData().filter(newRecords)
        );
    }

    public void beforeUpdate()
    {
        if (bypassTrigger) return;
        MyObjectService.transform(newRecords);
    }
    public void afterUpdate()
    {
        if (bypassTrigger) return;
        MyObjectService.alterRelatedData(
            MyObjectService.shouldAlterRelatedData().filter(newRecords, oldMap)
        );
    }
}

The primary advantages I see in the above are that it again becomes easy to quickly identify the effects of any given trigger event, and defer comprehension of the how (the trickiest question) to smaller code units. It also has a side benefit of making selective disablement much easier to implement. Usually I just make the entire trigger possible to bypass for unit testing purposes (about which more later).

Service

The service can then finally answer those pesky how questions:

public with sharing class MyObjectService
{
    public static Select.Filter shouldAlterRelatedData()
    {
        // some filter
    }
    public static Select.Filter isInvalid()
    {
        // some filter
    }
    public static void validate(List<MyObject__c> records)
    {
        for (MyObject__c record : records) record.addError('message');
    }
    public static void transform(List<MyObject__c> records)
    {
        // modify records
    }
    public static void alterRelatedData(List<MyObject__c> records)
    {
        // modify parent/sibling/child records
    }
}

The main advantage I see in this service pattern is that unit testing becomes much more atomic. The Selector library really helps keep this layer from growing too large, and also has a great explanation of the testing benefits in its documentation.

In testing the Service Layer, sometimes I need to insert records so I can test methods that need to be re-queried. In such instances, I can get a clearer picture about the behavior of the service by turning off the triggers, which may call the same methods when active.

* The MetadataService class has over 11K LOC

1

In a Salesforce context, a trigger handler is the starting point to 'handle' complex logic set into a trigger. Creating a class defined as MyObjectTriggerHandler can help to design a modular set of reusable objects which manage all the operations to be done by a trigger.

Also, there are some implications when developing triggers that should be taken into account as it's stated in this link:

The Force.com platform supports attaching any number of triggers to an object, but there is no guaranteed order of execution, and multiple trigger instances often query the same set of data, which can cause performance and governor headaches. To avoid these problems, and others, an accepted best practice is to delegate trigger handling to a second class, so that there is one trigger handler per object.

The main advantage of having a trigger handler is that you don't need to concentrate all heavy work in a single or multiple triggers, for example:

trigger MyBigFatTriggerForInserts on Account (before insert, after insert) {

    // Imagine the dirtiest 1000-line block of code in here to handle
}

trigger MyBigFatTriggerForUpdates on Account (before update, after update){
    // More complex (and maybe repeated) logic
}

This can be simplified and make a more readable and maintainable code:

trigger MySmarterTrigger on Account (before insert, before update, before delete, 
                                     after insert, after update, after delete, after undelete) {
    TheTriggerHandler handler = new TheTriggerHandler();
    handler.execute()
}

Handler:

public class TheTriggerHandler {
    // Leverage OOP, method overload, inheritance, etc, to implement a cleaner trigger logic
}

So basically, the code in your AccountTriggerHandler class is intended to divide all the trigger tasks in smaller pieces of code such as calculateTerritoryFieldsForDelete or setSalesTerritoryForUpdate. Again, it makes the code more readable and easier to maintain.

  • +1! We had a similar message, but your delivery is more succinct by a long shot! – Adrian Larson Sep 15 '16 at 1:36
  • 1
    Yeah, but I got to say, it's hard to answer this question with a short answer – Joca Sep 15 '16 at 2:06
0

https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices

Might be worth a quick read.

http://developer.force.com/cookbook/recipe/trigger-pattern-for-tidy-streamlined-bulkified-triggers

Trigger handlers (not sure if what code you posted you want to keep) "enforce a logical sequence to the trigger code and in turn help to keep code tidy and more maintainable. Keeping trigger logic for each object in a single place avoids problems where multiple triggers are in contention with each other and makes it easier to debug."

End goal is to have no code in the trigger itself, and to control the order of execution, and make maintaining the code easier.

The articles have better explanations.

0

The previous developer has compiled all of these methods that relate to processing of Account records into a single class.

There will be an Account trigger on the account object that calls these methods, likely in different 'before/after insert/update/delete' combinations or contexts. In each trigger context the trigger records are passed to one or more of the methods for processing.

This practice of keeping the logic out of the trigger is a good start.

I recommend you google Andrew Fawcetts published work on Enterprise Design Patterns to explore this style of programming further, particularly in the context of Salesforce.

  • 1
    the code posted above is absolutely not good to emulate in its current form. – Eric Sep 14 '16 at 22:37
  • Maybe Im not concise enough; the idea of separating the logic away from the trigger itself, and creating reusable methods I would argue is definitely a good move. As for the existing code sure its not great but the idea was there. The question was why the code was programmed that way, not whether its well written. – CloudHugger Sep 14 '16 at 22:41
  • 1
    one could argue that moving the code to a class like was done is no different than just keeping it all in the trigger – Eric Sep 14 '16 at 22:43
  • 1
    Lol - yep sure. The writer got step one right - keep logic out of trigger, but didnt split the logic out into reusable chucks of self documenting, domain specific, bulkified functions... So again more specifically - good to emulate keeping code out of trigger, good to break logic into reusable methods - so the sentiment was there , but should it be done the way this example is written ? No i agree. Edited response to avoid further wrist slapping or misinterpretation. – CloudHugger Sep 14 '16 at 22:50

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.