3

I was watching some videos on apex best practises and I spotted some discrepancies in advice people give. I wonder how you people code your triggers.

The recommendation is to have one trigger per object that's rather obvious but:
1) Do you keep your logick in one handler class (maybe delegate it to services) passing the trigger context just like here @ around 18 min around 18 mins

2) or do you do it like here @ about 34 min . Keeping the context isolated but doing some preprocessing in the trigger.

I've seen the first pattern a few times and I wonder how bad practice it is (if any)

thanks for sharing your thoughts

1
  • also take a look at Andrew Fawcett's recently published book on Enterprise Design Patterns for SFDC (includes code on GitHub) that takes the trigger pattern and supercharges it to include oh so much more for a truly elegant architecture – cropredy Nov 23 '14 at 22:54
2

Someone will give you a much more detailed answers I an sure but:

The first example Controls the flow of all the processing done on all triggers throughout your org. This is useful in that you have one place to control the flow of your trigger processes. It is building on the second example.

The second example just take that processing out of the trigger and into a class. It is not reusable via other classes so all it is essentially doing is breaking up the code into two separate locations for easier reading / maintenance.

As far as a best practice, implementing the first example would be considered the best practice IMHO.

1

@user682217, I recommend that you keep the logic in a single utility class, although I wouldn't call it a "handler" class. I think "handlers" are more appropriate names for a factory method pattern that can be used to create trigger handlers for any object.

All methods in the utility class should be static. This promotes the creation of code that can be reused in other contexts, such as Visualforce controllers, Lightning controllers and Apex web services.

One more suggestion: Nest Trigger.isBefore and Trigger.isAfter control blocks inside control blocks for different DML operations (e.g., Trigger.isInsert). Programmatically the nesting order doesn't matter, but for troubleshooting purposes it's much easier to say, "Something went wrong with my insert. Let me see all of the processes executed for the insert operation in one place (or block)."

Below is a sample trigger, demonstrating the naming convention for a utility class and also the basic nesting order for

/*
 * Master trigger for all unmanaged, automated processes to be executed
 * for Case records during DML operations
 */
trigger CaseTrigger on Case (
    before insert, after insert,
    before update, after update,
    before delete, after delete
) {

    // Handle insert operations
    if (Trigger.isInsert) {

        // Execute appropriate processes in "before" and "after" contexts
        if (Trigger.isBefore) {
            CaseUtil.setAssistant(Trigger.new);
            CaseUtil.clearFlags(Trigger.new);
        }
        else if (Trigger.isAfter) {
            CaseUtil.notifySubscribedContacts(Trigger.new);
        }
    }

    // Handle update operations
    else if (Trigger.isUpdate) {

        // Execute appropriate processes in "before" and "after" contexts
        if (Trigger.isBefore) {
            ...
        }
        else if (Trigger.isAfter) {
            ...
        }
    }

    // Handle delete operations
    else if (Trigger.isDelete) {
        ...
    }
}
0

I'd have to agree with @Eric that the first option is better since it is reusable in other places, besides triggers.

So say, you want to do the same processing in a controller or whatever, you can reuse it there with no problems.

I personally tend to do a mix of the two.

public with sharing class HandlerExample
{
    public static void HandleInTrigger(Map<Id, Object> oldMap, List<sObject> newList)
    {
        //Filter out the records that you want using some method, like Filter...
        List<sObject> listToProcess = Filter(oldMap, newList);
        ProcessRecords(listToProcess);
    }

    public static void ProcessRecords(List<sObject> listToProcess)
    {
        //Execute Logic here...
    }
}

//In your trigger
HandlerExample.HandleInTrigger(Trigger.oldMap, Trigger.New);

//In a controller
HandlerExample.ProcessRecords(yourListToProcess);

I have some trigger specific logic simply to filter and pass it to the processing method. I can still use the ProcessRecords method anywhere else without issue if need be.

There is a slight problem (or big problem to me) with the example at 18 minutes. Using the ALEADY_RAN variable to true is great to protect against trigger recursion. However, if you use the dataloader on say, 400 records, how many records with the processAfterUpdate touch?

It will only touch 200 records... This is because the static variables are reset per transaction and updating the data in bulk, although it is doing it this 200 records at a time, it is still considered a SINGLE transaction. So you will need to toggle that flag accordingly for those scenarios. Figured I'd throw that out there since this bit me big time in my last project.

1
  • Thank you guys. The first pattern is also used in Dan Appleman's Advanced Apex book. I got confused when I saw that a session dedicated to Apex Patterns criticises it. @Programmable Medley I think the static variable is fine. It's defined in a helper class not the trigger. It will not be reset – user682217 Nov 23 '14 at 23:44

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.