Business logic in triggers
Why is this an issue?
Embedding business logic directly inside a trigger leads to several problems:
Untestable in isolation: Trigger code can only be exercised by performing DML operations, making unit testing difficult.
Not reusable: The same logic may be needed in other contexts but cannot be invoked independently.
Difficult to maintain: As triggers grow in complexity, they become harder to read, understand, and modify.
Poor separation of concerns: Mixing trigger plumbing with business rules violates clean architecture principles.
Examples
Example of incorrect code:
trigger AccountTrigger on Account (before insert) {
for (Account acc : Trigger.new) {
// Business logic directly in trigger
if (acc.Industry == 'Technology') {
acc.Priority__c = 'High';
acc.Segment__c = 'Enterprise';
}
// More complex logic...
}
}
Example of correct code:
// Trigger delegates to handler
trigger AccountTrigger on Account (before insert) {
AccountTriggerHandler.handleBeforeInsert(Trigger.new);
}
// Handler class contains logic
public class AccountTriggerHandler {
public static void handleBeforeInsert(List<Account> accounts) {
AccountService.setDefaults(accounts);
}
}
// Service class is testable and reusable
public class AccountService {
public static void setDefaults(List<Account> accounts) {
for (Account acc : accounts) {
if (acc.Industry == 'Technology') {
acc.Priority__c = 'High';
}
}
}
}
How can I fix violations?
Create a trigger handler class: Move all logic out of the trigger and into a dedicated handler class.
Create service classes: Extract business logic into reusable service classes that can be tested and called independently.
Keep triggers minimal: Triggers should only delegate to handler methods without containing any logic themselves.
When should I disable this rule?
You may dismiss specific violations for very simple triggers that contain only trivial logic (e.g., setting a single default value).
Resources
