# Operational Excellence - Automation Patterns | Patterns Source: https://architect.salesforce.com/docs/architect/well-architected/guide/operational-excellence-automation-patterns.html > Patterns and anti-patterns for automation design, data integrity, error handling, and operational efficiency in Salesforce solutions. # Operational Excellence - Automation Patterns Learn more about Well-Architected [Operational Excellence](https://architect.salesforce.com/docs/architect/well-architected/guide/operational-excellence.html) → [Automation and Efficiency](https://architect.salesforce.com/docs/architect/well-architected/guide/operational-excellence.html#automation-and-efficiency) **Patterns** Where to look What good looks like Platform | Dashboards ✅ All metrics related to KPIs are included in at least one dashboard Platform | Documentation ✅ Outputs for every automation are measurable and timebound Platform | Documentation ✅ Accountable stakeholders are listed for each KPI **Anti-Patterns** Where to look What bad looks like Platform | Dashboards ⚠️ KPI reporting does not exist or dashboards are missing metrics related to some KPIs Platform | Documentation ⚠️ KPIs exist without accountable stakeholders Platform | Documentation ⚠️ KPIs do not exist for automations or have unclear time frames for measurements **Patterns** Where to look What good looks like Platform | Flow ✅ Flow Builder is used for record-triggered automation (replacing Process Builder and Workflow Rules) Platform | Flow ✅ Record-triggered flows with before-save execution are used for field population before record creation Platform | Flow ✅ Flows handle decision logic, loops, API callouts, DML operations, and complex multi-step orchestration Platform | Flow ✅ Flow transaction control is used for committing intermediate changes when needed Platform | Flow ✅ Fault handling is implemented for graceful error recovery in flows Platform | Flow ✅ Reactive screen flows provide dynamic user experiences Platform | Flow ✅ Declarative automation is chosen when business users or administrators need to modify logic without developer involvement Platform | Flow ✅ Variables do not refer to hard-coded values (for record types, users, etc.) Platform | Flow ✅ Flows hand logic off to Apex in large data volume contexts Platform | Flow ✅ Subflows are used for sections of processes that need to be reused across the business Platform | Flow ✅ All autolaunched flows use decision and/or pause elements to evaluate entry criteria and prevent infinite loops or executions against large data volumes Platform | Flow ✅ Users are only asked to provide data when existing system data can’t be used Platform | Flow ✅ Flows are organized in a hierarchical structure consisting of a main flow and supporting subflows Platform | Flow ✅ All user inputs have a clear purpose within the flow Platform | Flow ✅ Each flow serves a single, specific purpose Platform | Flow ✅ Each step performs a specific, granular task Platform | Flow ✅ All flows launched in user context abstract system context transactions to subflows, consistently placed after Pause element to create new transaction Platform | Flow ✅ All record-triggered flows have trigger order values populated Platform | Flow ✅ Flows involving external system callouts or long-running processes use asynchronous paths Platform | Flow ✅ Complex sequences of related data operations are created with Orchestrator (instead of invoking multiple subflows within monolithic flow) Platform | Validation ✅ Data integrity is enforced at platform level using validation rules, duplicate rules, and required fields Platform | Validation ✅ Validation rules prevent invalid data entry before save (more efficient than trigger validation) Platform | Approval Processes ✅ Multi-step approval routing handles parallel and sequential approval paths with delegated approvers Platform | Approval Processes ✅ Approval architecture accounts for exception scenarios (all approvers on vacation, urgent business requirement bypassing normal approval) **Anti-Patterns** Where to look What bad looks like Platform | Flow ⚠️ Process Builder and Workflow Rules used for new automation (Flow Builder is the strategic direction) Platform | Flow ⚠️ Programmatic automation used when business users or administrators need to modify logic without developer involvement Platform | Flow ⚠️ Flows lack fault handling resulting in poor error recovery Platform | Flow ⚠️ Variables have hard-coded values Platform | Flow ⚠️ Flows must be manually deactivated prior to bulk data loads Platform | Flow ⚠️ Portions of a flow are repeated across flows rather than using subflows Platform | Flow ⚠️ Flows trigger “unhandled exception” notices Platform | Flow ⚠️ Even simple flows regularly cause errors related to governor limits Platform | Flow ⚠️ Flows require additional inputs to provide context Platform | Flow ⚠️ Flows serve multiple purposes Platform | Flow ⚠️ Groups of related steps contain functionality that overlaps with groups of steps in other flows Platform | Flow ⚠️ Flows ask for user inputs when stored data can be used instead Platform | Flow ⚠️ Flows require inputs whose data is not used Platform | Flow ⚠️ Performing DML using collection that is output from screen component (leveraging “Use the IDs and all field values from a record or record collection” setting on create, update or delete element when collection is output from screen component) Platform | Flow ⚠️ Record-triggered flows do not use trigger order attributes at all or do not use trigger order values consistently Platform | Flow ⚠️ Asynchronous paths not used consistently or at all Platform | Flow ⚠️ Large, monolithic flows attempt to coordinate complex sequences of related data operations (with or without subflows) Platform | Approval Processes ⚠️ Approval architecture does not account for exception scenarios (all approvers on vacation, urgent business requirements) Platform | Validation ⚠️ Data integrity enforced only in triggers instead of validation rules (trigger validation less efficient and more complex) **Patterns** Where to look What good looks like Platform | Apex ✅ Trigger handler framework enforces single-trigger-per-object, bulkification, separation of concerns, and recursive execution prevention Platform | Apex ✅ Trigger handlers delegate to service classes for business logic, maintaining clear separation of concerns Platform | Apex ✅ Triggers use recursion protection using static flags or dedicated recursion control class Platform | Apex ✅ Future Apex is used sparingly, for callouts or system object DML Platform | Apex ✅ Async Apex invocations use Queueable to ‘chain’ complex DML across transactions Platform | Apex ✅ Batch Apex is used for large data volumes (processes large amounts of data with dedicated governor limits per chunk) Platform | Apex ✅ Batch jobs have error handling that logs failed records without stopping entire batch execution Platform | Apex ✅ Bulk API is used only when large amounts of data must be processed (native SOAP and REST APIs leveraged for smaller amounts of data) Platform | Apex ✅ Queueable Apex is used for complex workflow orchestration, external callouts with retry logic, and processing benefiting from async limits Platform | Apex ✅ Scheduled Apex executes processing on fixed schedules for nightly maintenance, daily reporting, periodic integration sync, and time-based business rules Platform | Design Standards ✅ Use cases for synchronous and asynchronous operations within automations are outlined clearly as part of design standards Platform | Documentation ✅ Planned and potential execution paths for automations are outlined clearly **Anti-Patterns** Where to look What bad looks like Platform | Apex ⚠️ Multiple triggers on one object with unpredictable execution order and overlapping logic Platform | Apex ⚠️ Business logic embedded directly in trigger files making testing difficult Platform | Apex ⚠️ No trigger handler framework or inconsistent trigger patterns across objects Platform | Apex ⚠️ Batch Apex jobs have very small scope size (e.g., scope size = 1) Platform | Apex ⚠️ Batch Apex used for external callouts (large volumes of Salesforce data pushed to external system using Batch Apex) Platform | Apex ⚠️ Async Apex features used arbitrarily (Future Methods and Queueable Apex used inconsistently or interchangeably) Platform | Apex ⚠️ Async Apex rarely used Platform | Apex ⚠️ Database operations do not have clear, consistent logic for passing execution to Batch Apex when needed Platform | Design Standards ⚠️ Use cases for synchronous and asynchronous operations are not addressed Platform | Documentation ⚠️ Automation invocation is not documented **Patterns** Where to look What good looks like Platform | Platform Events ✅ Platform Events are used for event-driven automation that decouples publishers from subscribers Platform | Platform Events ✅ Publishers are unaware of subscribers and publish fire-and-forget Platform | Platform Events ✅ Multiple subscribers react independently to events through platform event-triggered flows, Apex triggers, or external integrations Platform | Platform Events ✅ Replay IDs are used to replay missed events from any point in the 72-hour retention window Platform | Platform Events ✅ Platform Events enable cross-org communication, external system notification, and internal workflow orchestration **Anti-Patterns** Where to look What bad looks like Platform | Platform Events ⚠️ Direct coupling between publishers and subscribers preventing composable automation Platform | Platform Events ⚠️ Account tier upgrade directly calls opportunity update, account team notification, and data warehouse sync in one transaction (tight coupling requires changes to account logic every time new downstream processing is needed) Platform | Apex ⚠️ Publish Immediately Platform Events used adhoc (real-time events used instead of Publish After Commit regardless of publish order requirements or record-locking risks) **Patterns** Where to look What good looks like Platform | Apex ✅ SOQL statements use positive logic comparison operators (`INCLUDES`, `IN`) as primary or only logic Platform | Apex ✅ SOQL avoids `= NULL`, `!= NULL` or uses them sparingly after positive comparison operators Platform | Apex ✅ SOQL does not use `LIMIT 1` statements Platform | Apex ✅ SOQL does not use `ALL ROWS` keyword Platform | Apex ✅ SOQL does not appear within loops Platform | Apex ✅ Wildcard criteria appear in SOSL (not SOQL) Platform | Apex ✅ SOQL statements avoid `LIKE` comparisons or partial text comparisons Platform | Apex ✅ SOQL is wrapped in `try-catch` blocks Platform | Apex ✅ Variables do not refer to hard-coded values (for record types, users, etc.) Platform | Apex ✅ Each class serves a single, specific purpose Platform | Apex ✅ Each method performs a specific, granular task Platform | Apex ✅ All input variables have a clear purpose within the class Platform | Apex ✅ Code execution requires a minimal number of resources **Anti-Patterns** Where to look What bad looks like Platform | Apex ⚠️ SOQL statements use `NOT`, `NOT IN` criteria as primary or only comparison operator (non-selective) Platform | Apex ⚠️ SOQL statements use `ALL ROWS` keyword (non-selective) Platform | Apex ⚠️ SOQL statements use `= NULL`, `!= NULL` criteria as primary or only comparison operator (non-selective) Platform | Apex ⚠️ Variables have hard-coded values Platform | Apex ⚠️ SOQL appears within loops Platform | Apex ⚠️ SOQL statements use `LIKE` and wildcard filter criteria frequently (non-selective) Platform | Apex ⚠️ SOQL not wrapped in `try-catch` blocks Platform | Apex ⚠️ SOQL statements use `LIMIT 1` (non-selective) Platform | Apex ⚠️ SOSL rarely or not consistently used for wildcard selection criteria Platform | Apex ⚠️ Classes serve multiple purposes Platform | Apex ⚠️ Methods perform multiple tasks or methods perform tasks that don’t align to the stated purpose of the class they’re part of Platform | Apex ⚠️ Input variables aren’t actually used in methods Platform | Apex ⚠️ Methods unnecessarily retrieve data from the database or from external systems **Patterns** Where to look What good looks like Platform | Apex ✅ Custom exceptions are used to create advanced error messaging and logic Platform | Apex ✅ Code wraps all DML, SOQL, callouts, and other critical process steps in `try-catch` blocks Platform | Apex ✅ Database class methods may be used exclusively for all data operations (instead of DML) Platform | Apex ✅ In async and bulk contexts, Database class methods are used instead of DML Platform | Aura ✅ JavaScript wraps all data operations and critical process steps in `try-catch` blocks Platform | Aura ✅ Within `try-catch` blocks, native JavaScript `Error` is used in throw statements (no usage of `$A.error()`) Platform | Aura ✅ All recoverable error logic appears within `catch` statements, and provides clear user messages Platform | Flow ✅ Flows with data operations, callouts, and other critical processing logic have fault paths for all key actions Platform | Flow ✅ Screen flows consistently use fault connectors to show errors to users Platform | Flow ✅ Custom error messages are configured for errors that will appear on screen Platform | Lightning Web Components (LWC) ✅ JavaScript wraps all data operations and critical process steps in `if ()`/`else if ()` blocks Platform | Lightning Web Components (LWC) ✅ All `@wire` functions use `data` and `error` properties provided by the API Platform | Lightning Web Components (LWC) ✅ All `if (error)`/`else if (error)` statements contain logic to process errors and provide informative messages **Anti-Patterns** Where to look What bad looks like Platform | Apex ⚠️ DML, SOQL, callouts, or other critical process steps not consistently wrapped in try-catch blocks Platform | Apex ⚠️ No Database class methods are used Platform | Apex ⚠️ Data operations done exclusively with DML Platform | Apex ⚠️ `System.debug` statements appear in production code (and are not commented out) Platform | Aura ⚠️ JavaScript does not consistently wrap data operations and critical process steps in `try-catch` blocks Platform | Aura ⚠️ Components use `$A.error()` Platform | Aura ⚠️ Recoverable error logic does not consistently appear within `catch` statements, and error messages to users are not clear Platform | Flow ⚠️ Flows do not use fault paths consistently or at all Platform | Flow ⚠️ Custom error messages not used, so users see default “An unhandled fault has occurred in this flow” message Platform | Lightning Web Components (LWC) ⚠️ `@wire` functions do not use `data` and `error` properties provided by the API (or do not use them consistently) Platform | Lightning Web Components (LWC) ⚠️ If used at all, `if (error)`/`else if (error)` statements do not actually contain logic to process errors and provide useful error messages Platform | Lightning Web Components (LWC) ⚠️ JavaScript does not consistently use `if ()`/`else if ()` blocks with data operations or critical process steps