Trailblazer Community Session - Patterns & Anti-Patterns_ The Good, The Bad, and The Ugly Code.pptx
mansoorahmad941764
15 views
29 slides
Oct 27, 2025
Slide 1 of 29
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
About This Presentation
A Lightweight Intro for Salesforce folks on Patterns & Anti-Patterns
Size: 40.7 MB
Language: en
Added: Oct 27, 2025
Slides: 29 pages
Slide Content
Patterns & Anti-Patterns: The Good, The Bad, and The Ugly Code A Lightweight Intro for Salesforce Folks 25th October 2025 Salesforce Architects Group, Sharjah, United Arab Emirates
Mansoor Ahmad 17x Certified Salesforce Application & System Architect AWS Certified Architect Sharjah Salesforce Architect Community Group Leader https://www.linkedin.com/in/ahmad-mansoor/
Todayβs Journey What are Patterns & Anti-Patterns? The Official Salesforce Framework Common Examples (Good vs Bad vs Ugly) Advanced Performance Concepts Your Action Plan & Resources Letβs begin!
Have you everβ¦? β’ Spent hours debugging simple code? β’ Seen governor limits at the worst time? β’ Wondered "what was this person thinking?" Congratulations, youβve encountered anti-patterns!
What even are Patterns & Anti-Patterns? And why talk about it?
What are Patterns & Anti-Patterns? Patterns = Proven Recipes Like your grandma's perfect chocolate chip cookie recipe Repeatable, reliable, proven to work Example : "Trigger Handler pattern" Anti-Patterns = Common Cooking Mistakes Like overcrowding the pan or burning the garlic Seem logical but cause more problems Example: "The 'God Trigger'"
The βUgly Codeβ // THE UGLY - Don't try this at home! trigger EverythingTrigger on Account ( before insert , after insert , before update , after update , before delete , after delete ) { if ( Trigger . isBefore && Trigger . isInsert ) { for ( Account a : Trigger . new ) { // SOQL in loop - dangerous! List < Contact > contacts = [ SELECT Id FROM Contact WHERE AccountId = : a . Id ]; } } // And 100 more lines of chaos... }
β Anti-pattern (SOQL/DML inside loops a.K.a β God Triggerβ) // OpportunityTrigger.apxt (ANTI-PATTERN) trigger OpportunityTrigger on Opportunity ( after update ) { if ( Trigger . isAfter && Trigger . isUpdate ) { for ( Opportunity opp : Trigger . new ) { Opportunity oldOpp = Trigger . oldMap . get ( opp . Id ); // β SOQL in loop Account acc = [ SELECT Id , Type FROM Account WHERE Id = : opp . AccountId LIMIT 1 ]; // Suppose business rule: when Opp becomes Closed Won β mark Account.Type = 'Customer' if ( oldOpp . StageName != 'Closed Won' && opp . StageName == 'Closed Won' ) { acc . Type = 'Customer' ; // β DML in loop update acc ; } } } }
Solution?
β Pattern (Bulkification + Separation of Concerns) // OpportunityTrigger.apxt (PATTERN) trigger OpportunityTrigger on Opportunity ( after update ) { if ( Trigger . isAfter && Trigger . isUpdate ) { OpportunityTriggerHandler . onAfterUpdate ( Trigger . new , Trigger . oldMap ); } } Thin trigger -> delegate to handler
β Pattern (Bulkification + Separation of Concerns) // OpportunityTriggerHandler.cls public class OpportunityTriggerHandler { public static void onAfterUpdate ( List < Opportunity > newList , Map < Id , Opportunity > oldMap ) { // Filter only those that transitioned to Closed Won and have an AccountId List < Opportunity > justClosedWon = new List < Opportunity >(); for ( Opportunity opp : newList ) { Opportunity oldOpp = oldMap . get ( opp . Id ); if ( opp . AccountId != null && oldOpp . StageName != 'Closed Won' && opp . StageName == 'Closed Won' ) { justClosedWon . add ( opp ); } } if ( ! justClosedWon . isEmpty ()) { OpportunityService . handleClosedWon ( justClosedWon ); } } } 2) Handler extracts intent and calls service
β Pattern (Bulkification + Separation of Concerns) // OpportunityService.cls public class OpportunityService { public static void handleClosedWon ( List < Opportunity > closedWonOpps ) { // Collect unique AccountIds Set < Id > accountIds = new Set < Id >(); for ( Opportunity o : closedWonOpps ) { if ( o . AccountId != null ) accountIds . add ( o . AccountId ); } if ( accountIds . isEmpty ()) return ; // β Single, selective query via selector Map < Id , Account > accountsById = AccountSelector . selectByIds ( accountIds ); // Apply business rule in-memory for ( Id accId : accountsById . keySet ()) { Account acc = accountsById . get ( accId ); acc . Type = 'Customer' ; // example: promote to Customer on first Closed Won } // β Single DML statement if ( ! accountsById . isEmpty ()) { update accountsById . values (); } } } 3) Service runs bulk logic (one SOQL, one DML)
β Pattern (Bulkification + Separation of Concerns) // AccountSelector.cls public class AccountSelector { public static Map < Id , Account > selectByIds ( Set < Id > ids ) { if ( ids == null || ids . isEmpty ()) return new Map < Id , Account >(); List < Account > rows = [ SELECT Id , Type FROM Account WHERE Id IN : ids ]; return new Map < Id , Account >( rows ); } } 4) Selector centralizes queries (DRY + testable)
Bigger Picture
How This Relates to Design Patterns & Apex Enterprise Patterns Design Patterns (Universal) Apex Enterprise Patterns (Code Architecture) Well-Architected Patterns & Anti-Patterns (Platform Architecture)
How This Relates to Design Patterns & Apex Enterprise Patterns Category Focus Example Audience Design Pattern Conceptual, universal Factory, Singleton All software engineers Apex Enterprise Pattern Implementation pattern for Apex Architecture Trigger Handler, Service, Domain, Selector Salesforce developers/ Architects Pattern / Anti-Pattern (Well-Architected Framework) Platform-wide architectural best practices Bulkification / SOQL-in-loop Salesforce architects, admins, consultants
Key Takeaways
Key Takeaways Start Simple - Use basic patterns like bulkification Consult the Framework - architect.salesforce.com is your guide Think Holistically - Consider trade-offs in your solutions Identify 1 anti-pattern in your org β find the pattern counterpart Build a team practice around reviewing patterns quarterly