---
schema_version: "1"
id: 10d999d3f21c255cf87508b3249a4274763e81148159b52a29bdf2ed22712369
title: Operational Excellence - Automation Patterns
collection: architect
version: next
locale: en-us
portal_url: https://docs.salesforce.com/architect/next/en-us/well-architected/guides/operational-excellence-automation-patterns.md
canonical_url: https://staging.architect.salesforce.com/docs/architect/well-architected/guide/operational-excellence-automation-patterns.html
source_site: staging.architect.salesforce.com
content_type: documentation
content_hash: 1fd92c98763f47200e537e920013955aa6e305be5a5d3606c9908c41c5abe98c
products:
  - Well-Architected Framework
  - Architect Site Content Repo
---
# Operational Excellence - Automation Patterns

<br>

Learn more about Well-Architected [Operational Excellence](/docs/architect/well-architected/guide/operational-excellence.html) → [Automation and Efficiency](/docs/architect/well-architected/guide/operational-excellence.html#automation-and-efficiency)

## KPIs and Metrics

**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  |

## Declarative Automation

**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) |

## Programmatic Automation

**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                                                             |

## Platform Events

**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) |

## Apex Development Standards

**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                                              |

## Error Handling

**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  |
