Trigger Modularizaation
Overview
This guide demonstrates how to migrate from monolithic trigger handlers to a modular, metadata-driven trigger actions framework that enables small, focused, testable trigger logic units.
The Problem with Traditional Trigger Handlers
Most Salesforce implementations suffer from:
Monolithic trigger handlers with hundreds/thousands of lines
Mixed responsibilities in a single class
Poor testability - need to test entire handler
Merge conflicts when multiple developers work on same handler
No configuration - everything is hardcoded
Difficult debugging - hard to isolate issues
Typical Monolithic Pattern
// What we typically see - massive trigger handler classes
public class AccountTriggerHandler extends TriggerHandler {
public override void beforeInsert() {
// 50+ lines of validation logic
validateAccounts();
// 30+ lines of defaulting logic
setDefaultValues();
// 40+ lines of formatting logic
formatPhoneNumbers();
// 60+ lines of duplicate checking
checkForDuplicates();
}
public override void afterInsert() {
// 100+ lines creating related records
createDefaultContacts();
createTeamMembers();
createShares();
// 80+ lines of integration logic
sendToExternalSystem();
publishPlatformEvents();
// 40+ lines of notification logic
sendEmailAlerts();
}
public override void beforeUpdate() {
// 200+ lines of various business logic
validateStatusTransitions();
calculateScores();
updateDerivedFields();
enforceBusinessRules();
// ... and on and on
}
// Often 1000+ lines total in production handlers
}The Trigger Actions Solution
Core Concept
Instead of one large handler, create small, focused trigger action classes that each do ONE thing, configured through Custom Metadata.
Architecture Overview
Implementation Pattern
Step 1: Simple Trigger
Step 2: Individual Trigger Actions
Each action is a small, focused class:
Step 3: Configure Actions in Custom Metadata
Advanced Patterns
1. Conditional Trigger Actions
2. Stateful Trigger Actions
3. Async Trigger Actions
4. Trigger Action with Dependencies
Testing Trigger Actions
Individual Action Testing
Testing with Mocks
Migration Strategy
From Monolithic to Modular
Analyze Existing Handler
List all operations in current handler
Group related operations
Identify dependencies
Create Trigger Actions
One action per logical operation
Keep actions under 50 lines
Single responsibility principle
Configure Metadata
Create custom metadata records
Set appropriate sequence
Configure trigger contexts
Gradual Migration
Testing
Test each action individually
Integration test full flow
Performance test at scale
Benefits of Trigger Actions
Development Benefits
Focused Classes: Each action does one thing
Parallel Development: No merge conflicts
Easy Testing: Test individual actions
Reusability: Actions can be shared across objects
Operational Benefits
Configuration: Enable/disable without deployment
Sequencing: Control execution order via metadata
Debugging: Isolate issues to specific actions
Performance: Only run necessary actions
Maintenance Benefits
Clear Responsibilities: Easy to understand
Version Control: Better diff visibility
Code Reviews: Review small changes
Documentation: Self-documenting actions
Best Practices
1. Naming Conventions
2. Action Granularity
One business operation per action
Keep under 50 lines of code
Single trigger context per action
3. Metadata Organization
4. Error Handling
Common Patterns
Validation Actions
Field Update Actions
Integration Actions
Monitoring and Debugging
Custom Metadata Dashboard
Create reports/dashboards to visualize:
Active trigger actions per object
Execution sequence
Recently modified actions
Production Logging with Nebula Logger
Conclusion
The Trigger Actions pattern transforms unmaintainable monolithic handlers into:
Modular single-purpose actions
Configurable metadata-driven execution
Testable isolated units
Maintainable focused classes
This approach has proven successful in production systems with hundreds of trigger actions across dozens of objects, enabling teams to work in parallel without conflicts while maintaining code quality.
Last updated
Was this helpful?