Build the Domain Layer
By the end of this lesson, you'll be able to:
- Write a domain/trigger handler class for Milestone__c following Module 43's pattern exactly
- Decide which trigger events this object actually needs to handle
- Keep the domain layer focused purely on dispatch, not business logic
Prerequisites: "Design the Architecture"
The handler, following Module 43's exact shape
public with sharing class MilestoneTriggerHandler {
public void beforeUpdate(List<Milestone__c> newMilestones, Map<Id, Milestone__c> oldMap) {
MilestoneStatusService.validateStatusTransition(newMilestones, oldMap);
}
public void afterUpdate(List<Milestone__c> newMilestones, Map<Id, Milestone__c> oldMap) {
MilestoneStatusService.recalculateProjectHealth(newMilestones, oldMap);
}
}
public with sharing class MilestoneTriggerHandler {— one class, every event for this object.public void beforeUpdate(List<Milestone__c> newMilestones, Map<Id, Milestone__c> oldMap) {— one clearly named method per event.MilestoneStatusService.validateStatusTransition(newMilestones, oldMap);— delegates entirely; zero logic here.}— closesbeforeUpdate.- (blank line)
public void afterUpdate(List<Milestone__c> newMilestones, Map<Id, Milestone__c> oldMap) {— the second event's method.MilestoneStatusService.recalculateProjectHealth(newMilestones, oldMap);— delegates entirely again.}— closesafterUpdate.}— closes the class.
trigger MilestoneTrigger on Milestone__c (before update, after update) {
MilestoneTriggerHandler handler = new MilestoneTriggerHandler();
if (Trigger.isBefore && Trigger.isUpdate) handler.beforeUpdate(Trigger.new, Trigger.oldMap);
if (Trigger.isAfter && Trigger.isUpdate) handler.afterUpdate(Trigger.new, Trigger.oldMap);
}
trigger MilestoneTrigger on Milestone__c (before update, after update) {— one trigger file, both events.MilestoneTriggerHandler handler = new MilestoneTriggerHandler();— one handler instance.if (Trigger.isBefore && Trigger.isUpdate) handler.beforeUpdate(Trigger.new, Trigger.oldMap);— routes the before-update event.if (Trigger.isAfter && Trigger.isUpdate) handler.afterUpdate(Trigger.new, Trigger.oldMap);— routes the after-update event.}— closes the trigger.
Identical structure to Module 43\'s TransactionTriggerHandler — the handler only routes; MilestoneStatusService (built in Lesson 5) holds the actual business logic.
Deciding which events actually matter
Milestone__c only needs before update (to validate a status transition, like preventing a jump straight from "Not Started" to "Complete") and after update (to recalculate the parent Project\'s health once a milestone changes) — no insert-time logic is needed yet, since a newly created Milestone starts in a default state requiring no special handling. Deciding this deliberately, rather than handling every possible event out of habit, keeps the handler focused.
Exercise
As a comment, explain why MilestoneTriggerHandler has no logic of its own beyond calling MilestoneStatusService methods.
Show hint
Think back to Module 43's separation of concerns between trigger mechanics and business logic.
Build the Domain Layer Quiz
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
The domain layer for Milestone__c reuses Module 43's exact trigger-handler shape — a thin dispatcher that routes each trigger event to the appropriate service method, with zero business logic living in the handler itself.