Logicless APEX Triggers: A Straightforward And Neat Structure.

Emphasize logic-free triggers.” This is a common piece of advice you’ve likely encountered frequently while researching how to create your initial triggers online. To accomplish this, you must implement a “framework,” which essentially involves structuring your code in a manner that prioritizes simplicity. Upon reviewing numerous articles and tutorials, I’ve discovered that this straightforward trigger framework is my preferred approach for clarity and understanding.

What is your definition of a trigger without logic?

What I’m suggesting is that your trigger should solely invoke methods created in a separate handler class. It should be structured in such a way that you can readily anticipate the actions that will occur whenever your trigger is activated. For example:

trigger ContactTrigger on Contact (before update, after update, before insert, after insert) {

    if(Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)){
        if (checkRecursive.runOnce()){
            ContactHandler.isBeforeInsertAndUpdate(Trigger.new);
        }
   
    }
}

In this illustration, rather than incorporating all the operations (i.e., the actions we want it to perform, along with all its commands and steps) directly into the trigger, we utilize a “contact handler” class to invoke the necessary methods for each scenario.

This structure allows for effortless management of when actions occur, and practically eliminates the need to modify your trigger file when adjusting specific behaviors. Instead, you simply interact with your handler class and/or helper methods.

The structural framework

The typical structure of the framework I employ is as follows:

  • Trigger (.trigger file)
  • Handler Class
  • Helper Class

The trigger file specifies the conditions under which the trigger should execute a specific sequence of actions. These sequences are managed by the Handler Class.

Within the Handler Class, we define the sequences that need to be executed each time. Employing descriptive names for its methods assists us in determining when to implement each sequence. For example:

Public with sharing class ContactHandler {
   
    public static void isBeforeInsertAndUpdate(List<Contact> newContacts){
   
            developmentValidator.updateDevelopmentId(newContacts);
    }
}

Having “routines” that execute identical methods can benefit from having a Helper Class that consolidates them. This Helper Class may not always be necessary if your trigger is limited to a few distinct scenarios. However, if you anticipate your trigger expanding and utilizing the same methods repeatedly, it’s worth considering the inclusion of a Helper Class.

Alternatively, you can include all the methods within the Handler Class and call them locally. Nevertheless, integrating a Helper Class can enhance the cleanliness of your code.


A comprehensive illustration of a trigger framework The trigger file

This method ultimately results in a trigger code that lacks logic, allowing us precise control over when our trigger activates.

An extensive demonstration of a trigger framework

The trigger component

Through this method, we achieve a trigger code that is free from logic, enabling us to precisely determine when our trigger will activate.

trigger saleCaseUnitTrigger on Sale_case_unit__c (after insert, before insert, after update, before update, after delete, before delete) {

	if(Trigger.isInsert && Trigger.isAfter){
		saleCaseUnitHandler.isAfterInsert();
	}

	if(Trigger.isUpdate && Trigger.isBefore){
		if (checkRecursive.runOnce()){
			saleCaseUnitHandler.isBeforeUpdate();
		}	
	}
	
	if(Trigger.isDelete && Trigger.isAfter){
		saleCaseUnitHandler.isAfterDelete();
	}
	
}

The Handler component

On occasion, if your trigger isn’t overly complex, you might consolidate all your logic within this class. However, there’s a likelihood that certain methods will be repeated across multiple scenarios.

The purpose of this handler class is to delineate the actions that the trigger must initiate in each specific scenario without any ambiguity.

public with sharing  class saleCaseUnitHandler {
    public static void isAfterInsert(){
      SaleCaseUnitHandlerHelper.checkIfListingIsAvailable();
    }
    public static void isBeforeUpdate(){
      SaleCaseUnitHandlerHelper.checkIfListingIsInAnotherSaleCase(Trigger.new);
    }

    public static void isAfterDelete(){
      saleCaseUnitHandlerHelper.changeListingStatusWhenSCUDeleted(Trigger.old);
    }
}

The Auxiliary Class

In this class, we write all the methods that will be invoked by the handler in each scenario.

public with sharing class SaleCaseUnitHandlerHelper {

    public static void checkIfListingIsAvailable(){
       // Your actions...
    }

    public static void checkIfListingIsInAnotherSaleCase(List<Sale_Case_Unit__c> updatedSCUs)    {
       // Your actions...
     
}

    public static void changeListingStatusWhenSCUDeleted(List<Sale_Case_Unit__c> deletedSCUs)       {
     // Your actions...
    }


}


If you’re aware of other beginner-friendly trigger frameworks that are easy to understand, please share your comments and suggestions below.

Peace and Happy Coding