Advanced 30 min read

Domain Layer and Trigger Handlers Revisited

By the end of this lesson, you'll be able to:

  • Write a trigger handler class that centralizes an object's trigger dispatch logic
  • Route Module 42's two separate Transaction__c triggers through a single handler
  • Explain why a single handler per object is easier to reason about than several separate trigger files

Prerequisites: "Selector Layer"

The problem with two separate triggers on one object

Module 42 had both TransactionTrigger (after insert, balance updates) and TransactionValidation (before insert, validation) on the same Transaction__c object. This worked, but as an object accumulates more trigger logic over time, having several independent trigger files for the same object makes it hard to see, at a glance, everything that happens when a Transaction__c is inserted.

One handler, one entry point per event

public with sharing class TransactionTriggerHandler {
    public void beforeInsert(List<Transaction__c> newTransactions) {
        Set<Id> accountIds = new Set<Id>();
        for (Transaction__c t : newTransactions) accountIds.add(t.Bank_Account__c);

        Map<Id, Bank_Account__c> accounts = new BankAccountSelector().selectByIdAsMap(accountIds);
        TransactionValidationService.validate(newTransactions, accounts);
    }

    public void afterInsert(List<Transaction__c> newTransactions) {
        TransactionBalanceService.applyDeltas(newTransactions);
    }
}
trigger TransactionTrigger on Transaction__c (before insert, after insert) {
    TransactionTriggerHandler handler = new TransactionTriggerHandler();
    if (Trigger.isBefore && Trigger.isInsert) handler.beforeInsert(Trigger.new);
    if (Trigger.isAfter && Trigger.isInsert) handler.afterInsert(Trigger.new);
}

Now there is exactly one trigger file for Transaction__c, and exactly one handler class where every trigger event for that object is visible together — Lesson 3's TransactionValidationService and a new TransactionBalanceService (the balance-update logic from Module 42, similarly extracted) are both called from here.

Why one handler beats several independent trigger files

A developer asking "what happens when a Transaction__c is inserted?" now has exactly one file to open (TransactionTriggerHandler) rather than needing to know that logic is split across two separately-named trigger files that happen to both target the same object — a real cost that only shows up as an object accumulates more automation over time.

Exercise

As a comment, explain why the trigger itself (TransactionTrigger) contains almost no logic, delegating immediately to TransactionTriggerHandler.

Show hint

Think back to Lesson 2's separation-of-concerns framing of trigger mechanics as their own concern.

APEX

Domain Layer and Trigger Handlers Revisited Quiz

1. What is the main benefit of a single trigger handler class per object, compared to Module 42's two separate trigger files on Transaction__c?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

A domain (trigger handler) class centralizes an object's trigger dispatch logic into one place — one class per object, with each trigger event routed to a clearly named method, rather than Module 42's two entirely separate trigger files for the same object.