Learn Process Automation and Logic (PD1) with Interactive Flashcards

Master key concepts in Process Automation and Logic through our interactive flashcard system. Click on each card to reveal detailed explanations and enhance your understanding.

Declarative Process Automation Features

Declarative Process Automation Features in Salesforce allow administrators and developers to automate business processes without writing code, using point-and-click tools. These are essential concepts for the Salesforce Certified Platform Developer I exam under the Process Automation and Logic domain.

**Flow Builder** is the most powerful declarative automation tool. It enables the creation of complex business logic using screen flows (user-facing), record-triggered flows (fired on DML events), scheduled flows, and autolaunched flows. Flows can create, update, delete records, call Apex, send emails, and make outbound calls.

**Approval Processes** allow organizations to automate the approval of records. They define the steps, assigned approvers, and actions taken upon approval or rejection. Entry criteria determine which records enter the process, and multiple steps can be configured with different approvers and conditions.

**Record-Triggered Flows** replace the legacy Workflow Rules and Process Builder. They fire before or after a record is created, updated, or deleted. Before-save flows are highly efficient as they don't require additional DML operations to update the triggering record. After-save flows can perform cross-object updates and other complex operations.

**Key Declarative Features include:**
- Assignment rules for leads and cases
- Escalation rules for cases
- Auto-response rules for email notifications
- Flow Orchestrator for multi-step, multi-user processes

**Order of Execution** is critical to understand. Declarative automations follow Salesforce's order of execution, where before-save flows run before validation rules (after system validation), and after-save flows run after record commitment alongside triggers.

**Best Practices:**
- Use before-save flows for field updates on the same record for optimal performance
- Bulkify flow logic to avoid governor limits
- Avoid recursive automations by using entry conditions wisely
- Consolidate multiple automations per object into a single flow when possible

Salesforce recommends migrating legacy Workflow Rules and Process Builder to Flow Builder, as these older tools are no longer actively enhanced. Understanding declarative automation is fundamental for the Platform Developer I certification.

Record-Triggered Flows

Record-Triggered Flows are a powerful automation tool in Salesforce that execute when a record is created, updated, or deleted. They are the modern replacement for Workflow Rules and Process Builder, offering greater flexibility and functionality within the Flow framework.

Record-Triggered Flows can be configured to run in three timing contexts:

1. **Before Save**: Executes before the record is committed to the database. This is ideal for updating fields on the triggering record without requiring an additional DML operation, making it highly efficient. No extra save is needed since the record hasn't been saved yet.

2. **After Save**: Executes after the record is saved to the database. This is used when you need to reference the record's ID (e.g., for newly created records), perform DML on related records, call subflows, or invoke actions like sending emails and posting to Chatter.

3. **Before Delete**: Executes before a record is deleted, allowing validation or related cleanup operations.

Key features include:
- **Entry Conditions**: Define criteria that filter which records trigger the flow.
- **Optimized for Bulk Operations**: They run efficiently in bulk, respecting governor limits.
- **Scheduled Paths**: Allow actions to be executed at a specific time after the triggering event (e.g., 3 days after a case is created).
- **Run Asynchronously**: After-save flows can include an asynchronous path to handle operations outside the main transaction, reducing governor limit concerns.

For the Platform Developer I exam, it's critical to understand that Before Save flows are more performant for field updates on the same record, as they don't consume additional DML operations. After Save flows should be used for cross-object updates or external callouts.

Record-Triggered Flows operate within the order of execution alongside Apex triggers, with before-save flows running before before-triggers and after-save flows running after after-triggers. Understanding this sequence is essential for developers to avoid conflicts and ensure predictable automation behavior.

Apex Language Basics and Data Types

Apex is a strongly-typed, object-oriented programming language developed by Salesforce that runs on the Force.com platform. Understanding its language basics and data types is fundamental for the Platform Developer I certification.

**Primitive Data Types:**
- **Integer**: 32-bit whole numbers (e.g., Integer count = 10;)
- **Long**: 64-bit whole numbers for larger values
- **Double**: 64-bit floating-point numbers for decimals
- **Decimal**: Numbers with decimal points, commonly used for currency calculations with precision
- **String**: Text values enclosed in single quotes (e.g., String name = 'Salesforce';)
- **Boolean**: True, false, or null values
- **Date**: Stores date without time
- **DateTime**: Stores both date and time
- **Time**: Stores time only
- **ID**: 18-character Salesforce record identifier
- **Blob**: Binary data type for attachments

**Collections:**
- **List**: Ordered collection of elements allowing duplicates (e.g., List<String> names = new List<String>();)
- **Set**: Unordered collection of unique elements
- **Map**: Key-value pairs where keys are unique (e.g., Map<Id, Account> accountMap)

**sObjects:**
These represent Salesforce objects like Account, Contact, or custom objects. Example: Account acc = new Account(Name='Test');

**Key Language Basics:**
- Variables must be declared with their data type before use
- Apex is case-insensitive
- Statements end with semicolons
- Null is a valid value for all data types
- Type casting can be implicit or explicit
- Constants are declared using the 'final' keyword
- Enums define a fixed set of constants

**Governor Limits Awareness:**
Apex runs in a multi-tenant environment, so understanding data types helps optimize SOQL queries, heap size, and CPU time. Using appropriate collections like Maps instead of nested loops is essential for writing efficient, bulkified code that respects platform limits.

Mastering these fundamentals is critical for building robust automation solutions on the Salesforce platform.

Apex Collections: List, Set, and Map

Apex Collections in Salesforce are powerful data structures used to store and manipulate groups of data. There are three primary types: List, Set, and Map.

**List:**
A List is an ordered collection of elements that allows duplicates. Elements are indexed starting from 0. Lists are commonly used when you need to maintain insertion order or access elements by their position.

Example:
```
List<String> names = new List<String>();
names.add('Alice');
names.add('Bob');
names.add('Alice'); // Duplicates allowed
String first = names[0]; // 'Alice'
```
Lists are heavily used in DML operations, SOQL query results, and batch processing.

**Set:**
A Set is an unordered collection of unique elements — duplicates are automatically excluded. Sets are ideal for ensuring data uniqueness and performing efficient lookups.

Example:
```
Set<Id> accountIds = new Set<Id>();
accountIds.add('001XXXXXXXXXXXX');
accountIds.add('001XXXXXXXXXXXX'); // Ignored, duplicate
```
Sets are frequently used to collect record IDs for filtering SOQL queries with the IN clause, improving bulkification in triggers.

**Map:**
A Map is a collection of key-value pairs where each key is unique. Maps provide fast lookups by key and are essential for correlating related data.

Example:
```
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Id, Name FROM Account]);
Account acc = accountMap.get('001XXXXXXXXXXXX');
```
Maps are critical in trigger patterns for accessing related records without additional SOQL queries, helping avoid governor limits.

**Key Considerations for the PD1 Exam:**
- All collections can be nested (e.g., Map<Id, List<Contact>>).
- Collections support iteration via for loops.
- Lists are returned by SOQL queries by default.
- Maps can be directly constructed from SOQL results using `new Map<Id, SObject>(query)`.
- Understanding bulkification patterns using Sets and Maps in triggers is essential.
- Collections help developers stay within Salesforce governor limits by reducing redundant queries and DML operations.

Mastering these collections is fundamental for writing efficient, scalable Apex code.

Apex Control Flow Statements

Apex Control Flow Statements are fundamental constructs in Salesforce's Apex programming language that allow developers to control the execution path of their code based on conditions, loops, and branching logic. These are essential for Process Automation and Logic in the Platform Developer I certification.

**Conditional Statements:**

1. **if-else:** Executes code blocks based on Boolean conditions. You can chain multiple conditions using else-if for complex decision-making.

2. **switch:** Introduced in later Apex versions, switch statements evaluate an expression against multiple possible values, providing cleaner syntax than multiple if-else chains. Switch supports sObject types, enums, Strings, Integers, and Longs.

**Loop Statements:**

1. **for loop (Traditional):** Iterates using an initializer, condition, and increment expression — for(Integer i=0; i<10; i++).

2. **for loop (Collection):** Iterates over lists or sets — for(Account a : accountList). This is heavily used in trigger handlers to process bulk records efficiently.

3. **SOQL for loop:** Iterates over query results in batches of 200 records, helping avoid heap size limits — for(Account a : [SELECT Id FROM Account]).

4. **while loop:** Repeats execution as long as a condition remains true.

5. **do-while loop:** Similar to while but guarantees at least one execution before checking the condition.

**Branching Statements:**

1. **break:** Exits the current loop immediately.
2. **continue:** Skips the remaining code in the current loop iteration and moves to the next iteration.
3. **return:** Exits the current method, optionally returning a value.

**Exception Handling:**

- **try-catch-finally:** Controls flow when exceptions occur. The try block contains code that might throw exceptions, catch handles specific exceptions, and finally executes regardless of whether an exception occurred.

Understanding these control flow statements is critical for writing efficient, bulkified Apex code that respects governor limits — a key focus area for the Platform Developer I exam.

Apex Classes and Methods

Apex Classes and Methods are fundamental building blocks of business logic in Salesforce development. Apex is a strongly-typed, object-oriented programming language that runs on the Salesforce platform, and understanding classes and methods is essential for the Platform Developer I certification.

**Apex Classes** are blueprints or templates that define the properties (variables) and behaviors (methods) of objects. They encapsulate related logic and data together. Classes can include access modifiers such as `public`, `private`, `global`, and `virtual` to control visibility and inheritance. A class can implement interfaces, extend other classes, and contain inner classes.

Example:
```
public class AccountHandler {
private String accountName;

public AccountHandler(String name) {
this.accountName = name;
}
}
```

**Methods** are functions defined within a class that perform specific operations. They can accept parameters, return values, and be declared as `static` (called on the class itself) or instance-based (called on an object). Methods also support access modifiers to control their accessibility.

Key method types include:
- **Static methods**: Invoked without instantiating the class (e.g., `AccountHandler.getAccounts()`)
- **Instance methods**: Require object creation before invocation
- **Constructors**: Special methods called during object instantiation

**Important Concepts for the Exam:**
1. **Governor Limits**: Apex operates under strict execution limits (e.g., SOQL queries, DML statements) to ensure shared resource efficiency.
2. **Bulk Processing**: Methods should handle collections of records rather than single records to optimize performance.
3. **Trigger Context**: Apex classes are commonly invoked from triggers to separate business logic from trigger definitions (best practice).
4. **Test Classes**: Every Apex class requires at least 75% code coverage through test methods annotated with `@isTest`.
5. **Sharing Rules**: Classes can be declared with `with sharing` or `without sharing` to enforce or bypass record-level security.

Mastering Apex classes and methods is critical for building scalable, maintainable automation solutions on the Salesforce platform.

Apex Interfaces and Inheritance

Apex Interfaces and Inheritance are fundamental object-oriented programming concepts essential for the Salesforce Certified Platform Developer I exam, particularly in Process Automation and Logic.

**Inheritance** allows an Apex class to extend another class using the 'extends' keyword, inheriting its methods and properties. The child class (subclass) can reuse, override, or extend the behavior of the parent class (superclass). Apex supports single inheritance, meaning a class can only extend one parent class. The 'virtual' keyword allows a class or method to be overridden, while 'override' is used in the child class to redefine the method. The 'super' keyword references the parent class's methods or constructors.

Example:
virtual class Animal { virtual String speak() { return 'sound'; } }
class Dog extends Animal { override String speak() { return 'Bark'; } }

**Interfaces** define a contract of methods that implementing classes must fulfill. They are declared using the 'interface' keyword and contain method signatures without implementations. A class implements an interface using the 'implements' keyword and must provide concrete implementations for all defined methods. Unlike inheritance, a class can implement multiple interfaces, enabling a form of polymorphism.

Example:
interface Loggable { void log(String message); }
class ConsoleLogger implements Loggable { public void log(String message) { System.debug(message); } }

**Key Differences:**
- Inheritance shares behavior; interfaces enforce a contract.
- A class can extend only one class but implement multiple interfaces.
- Interfaces support loose coupling and are heavily used in Salesforce patterns like Trigger Handlers and Batch Apex (Database.Batchable).

**Relevance to Process Automation:**
Salesforce leverages interfaces extensively. For instance, Database.Batchable, Schedulable, and Queueable are standard interfaces used in asynchronous processing. Implementing these interfaces enables developers to build scalable automation solutions. Understanding inheritance and interfaces is critical for writing maintainable, extensible Apex code and is a core topic on the Platform Developer I certification exam.

Apex Triggers and Context Variables

Apex Triggers are specialized pieces of Apex code that execute before or after specific Data Manipulation Language (DML) events occur on Salesforce records, such as insert, update, delete, merge, upsert, and undelete operations. They allow developers to perform custom actions and implement complex business logic that cannot be achieved through declarative tools alone.

There are two types of triggers: **Before Triggers** are used to validate or modify field values before records are saved to the database, while **After Triggers** are used to access system-set field values (like record IDs) and perform operations on related records after the record has been committed.

Triggers are defined using the syntax: `trigger TriggerName on ObjectName (trigger_events) { // code }`

**Context Variables** are system-defined variables available within the trigger context that provide critical information about the runtime environment:

- **Trigger.new**: Returns a list of the new versions of records (available in insert, update, and undelete triggers).
- **Trigger.old**: Returns a list of the old versions of records (available in update and delete triggers).
- **Trigger.newMap**: A map of IDs to new versions of records (available in before update, after insert, after update, and after undelete).
- **Trigger.oldMap**: A map of IDs to old versions of records (available in update and delete triggers).
- **Trigger.isBefore / Trigger.isAfter**: Boolean values indicating whether the trigger fired before or after the record was saved.
- **Trigger.isInsert / Trigger.isUpdate / Trigger.isDelete / Trigger.isUndelete**: Booleans indicating the DML operation that fired the trigger.
- **Trigger.size**: The total number of records in the trigger invocation.
- **Trigger.operationType**: Returns a System.TriggerOperation enum value corresponding to the current operation.

Best practices include writing bulkified triggers, using one trigger per object, and delegating logic to handler classes to maintain clean, maintainable code and avoid governor limit issues.

Trigger Bulkification and Best Practices

Trigger Bulkification and Best Practices is a critical concept in Salesforce development that ensures triggers handle multiple records efficiently rather than processing one record at a time. Since Salesforce operations can involve up to 200 records in a single DML transaction, triggers must be designed to handle bulk data gracefully.

**What is Bulkification?**
Bulkification means writing code that efficiently processes collections of records rather than individual records. Instead of performing SOQL queries or DML operations inside loops, bulkified triggers operate on lists, sets, and maps to minimize resource consumption and avoid governor limits.

**Key Best Practices:**

1. **Never use SOQL/DML inside loops:** Queries and DML statements inside for-loops quickly hit governor limits (100 SOQL queries, 150 DML statements per transaction). Instead, collect data first, query once, and perform DML outside the loop.

2. **Use Collections:** Leverage Lists, Sets, and Maps to aggregate records and process them in bulk. For example, collect all related IDs in a Set, perform a single query, and store results in a Map for efficient lookup.

3. **One Trigger Per Object:** Maintain a single trigger per object to control execution order and avoid unpredictable behavior. Use trigger handler classes or frameworks to organize logic.

4. **Separate Logic from Triggers:** Move business logic into handler classes following the separation of concerns principle. This improves testability, maintainability, and reusability.

5. **Use Trigger Context Variables:** Leverage Trigger.new, Trigger.old, Trigger.newMap, and Trigger.oldMap appropriately based on the trigger event (before/after insert/update/delete).

6. **Avoid Recursive Triggers:** Implement static boolean variables or recursion handlers to prevent triggers from firing infinitely.

7. **Write Comprehensive Tests:** Test with bulk data (at least 200 records) to verify the trigger handles bulk operations without exceeding governor limits.

By following these practices, developers ensure scalable, efficient, and maintainable automation that performs well within Salesforce's multi-tenant architecture and governor limit constraints.

Save Order of Execution

The Save Order of Execution in Salesforce defines the precise sequence of operations that occur when a record is saved (inserted, updated, or upserted). Understanding this order is critical for Platform Developer I certification, as it impacts how triggers, workflows, validation rules, and other automation interact.

Here is the order of execution:

1. **Load Original Record** – The original record is loaded from the database (for updates) or initialized with default values (for inserts).

2. **Override Values** – New field values from the request overwrite the old values.

3. **System Validation** – Salesforce runs system-level validations such as required fields, field formats, and field lengths.

4. **Before Triggers** – All before triggers execute. These allow modification of field values before the record is committed.

5. **Custom Validation Rules** – Salesforce evaluates custom validation rules, including any validations added via the Validation Rule setup.

6. **Duplicate Rules** – Duplicate rules are evaluated to identify and handle potential duplicate records.

7. **Record Saved (Not Committed)** – The record is saved to the database but not yet committed. The record now has an ID (for inserts).

8. **After Triggers** – All after triggers execute. The record is read-only at this point, but related records can be modified.

9. **Assignment Rules** – Auto-assignment rules (e.g., Lead or Case assignment) execute.

10. **Auto-Response Rules** – Auto-response rules are evaluated.

11. **Workflow Rules** – Workflow rules fire. If field updates exist, before and after triggers may re-fire.

12. **Process Builder & Flows** – Processes and record-triggered flows execute.

13. **Escalation Rules** – Escalation rules are evaluated.

14. **Roll-Up Summary Fields** – Parent roll-up summary fields are calculated, potentially triggering parent record save logic.

15. **Cross-Object Workflow** – Cross-object formula updates execute.

16. **Criteria-Based Sharing** – Sharing rules are recalculated.

17. **DML Committed** – All changes are committed to the database.

18. **Post-Commit Logic** – Emails, async operations, and enqueued actions execute.

Understanding this order helps developers avoid recursive triggers, unexpected behaviors, and logic conflicts in automation.

Trigger Recursion and Cascading

Trigger Recursion and Cascading are critical concepts in Salesforce development that every Platform Developer I candidate must understand.

**Trigger Recursion** occurs when a trigger's execution causes the same trigger to fire again, creating a loop. For example, if an after-update trigger on the Account object updates the same Account record, the trigger fires again, potentially creating an infinite loop. Salesforce enforces governor limits to prevent truly infinite recursion, but uncontrolled recursion can quickly exhaust DML statements, SOQL queries, and CPU time limits, causing runtime exceptions.

To prevent recursion, developers commonly use a **static Boolean variable** in a helper class. The trigger checks this variable before executing its logic. Once the trigger runs the first time, the static variable is set to true, preventing subsequent executions. For example:

public class TriggerHelper {
public static Boolean hasRun = false;
}

In the trigger, you check: if(!TriggerHelper.hasRun) { TriggerHelper.hasRun = true; // execute logic }

More sophisticated approaches use static Sets to track processed record IDs, allowing the trigger to skip only already-processed records rather than blocking all subsequent executions.

**Trigger Cascading** happens when a trigger on one object causes a trigger on another object to fire. For instance, an after-insert trigger on Opportunity might update the parent Account, which then fires an after-update trigger on Account. This cascading chain can become complex and difficult to debug, especially when multiple objects and triggers are involved.

Cascading is not inherently bad but must be carefully managed. Developers should document trigger execution order, maintain a single trigger per object pattern, and use handler classes to centralize logic. Understanding the **order of execution** in Salesforce — including validation rules, before triggers, after triggers, workflow rules, and process builders — is essential to predicting cascading behavior.

Both recursion and cascading can lead to governor limit violations and unexpected side effects, making proper design patterns and thorough testing indispensable for robust Salesforce development.

SOQL Queries in Apex

SOQL (Salesforce Object Query Language) queries in Apex are used to retrieve data from Salesforce objects (similar to SQL SELECT statements in traditional databases). They are fundamental to Salesforce development and are essential knowledge for the Platform Developer I certification.

**Basic Syntax:**
SOQL queries in Apex can be written inline using square brackets:
`List<Account> accounts = [SELECT Id, Name FROM Account WHERE Industry = 'Technology'];`

**Key Features:**

1. **Static vs Dynamic SOQL:** Static SOQL is written directly in code using square brackets, while Dynamic SOQL uses `Database.query()` with a string parameter, allowing runtime query construction.

2. **Bind Variables:** Apex variables can be referenced in static SOQL using a colon prefix: `[SELECT Id FROM Contact WHERE AccountId = :accId]`. This prevents SOQL injection and improves readability.

3. **Relationship Queries:** SOQL supports parent-to-child (subqueries) and child-to-parent traversals. For example: `[SELECT Name, (SELECT LastName FROM Contacts) FROM Account]` retrieves accounts with their related contacts.

4. **Governor Limits:** Apex enforces a limit of 100 SOQL queries per synchronous transaction and 200 per asynchronous transaction. Each query can return up to 50,000 records. Developers must write bulkified code to avoid hitting these limits.

5. **Aggregate Functions:** SOQL supports COUNT(), SUM(), AVG(), MIN(), MAX(), and GROUP BY clauses for data aggregation.

6. **Return Types:** Queries can return `List<sObject>`, a single sObject, or `Integer` (for COUNT queries).

**Best Practices:**
- Never place SOQL queries inside loops (bulkification)
- Always use selective filters with WHERE clauses
- Query only the fields you need
- Use LIMIT to control result set size
- Leverage relationship queries to minimize query count
- Use bind variables instead of string concatenation

Understanding SOQL queries is critical for building efficient, scalable Apex solutions that respect Salesforce governor limits and follow platform best practices.

SOSL Queries

SOSL (Salesforce Object Search Language) is a powerful search language in Salesforce that allows developers to perform text-based searches across multiple objects simultaneously. Unlike SOQL, which queries specific objects and fields, SOSL searches the entire search index, making it ideal for finding records across various objects when you don't know exactly where the data resides.

**Syntax Structure:**
A basic SOSL query follows this format:
`FIND {searchTerm} IN searchGroup RETURNING ObjectType(fields)`

For example:
`FIND {Acme} IN ALL FIELDS RETURNING Account(Name, Phone), Contact(FirstName, LastName)`

**Key Components:**
- **FIND:** Specifies the search term, enclosed in curly braces. Supports wildcards (* and ?) for partial matching.
- **IN:** Defines the search scope — ALL FIELDS, NAME FIELDS, EMAIL FIELDS, PHONE FIELDS, or SIDEBAR FIELDS.
- **RETURNING:** Specifies which objects and fields to return in results.
- **WITH:** Adds filters like WITH DATA CATEGORY or WITH NETWORK.
- **LIMIT:** Restricts the number of results returned.

**Important Considerations for Developers:**
1. SOSL returns a list of lists `(List<List<SObject>>)`, where each inner list corresponds to an object type specified in the RETURNING clause.
2. SOSL queries in Apex use `Search.query()` method or can be written inline with square brackets.
3. Governor limits allow up to 20 SOSL queries per transaction.
4. SOSL searches require at least two characters in the search term.
5. SOSL leverages Salesforce's search index, which may have a slight delay in indexing newly created or updated records.

**When to Use SOSL vs SOQL:**
- Use SOSL when searching across multiple objects or when performing text-based searches.
- Use SOQL when you know which object contains the data and need precise field-level filtering with WHERE clauses.

SOSL is particularly valuable in building global search functionality, custom search pages, and scenarios where users need to find records matching a keyword across the entire org efficiently.

DML Statements and Database Methods

DML (Data Manipulation Language) Statements and Database Methods are two approaches in Apex for performing database operations in Salesforce, including inserting, updating, deleting, upserting, undeleting, and merging records.

**DML Statements** are straightforward commands like `insert`, `update`, `delete`, `upsert`, `undelete`, and `merge`. They operate directly on sObject records or lists of records. When a DML statement encounters an error, it throws a `DmlException` that must be handled using try-catch blocks. DML statements follow an all-or-nothing approach by default — if one record in a batch fails, the entire operation is rolled back.

Example:
```
try {
Account acc = new Account(Name='Test');
insert acc;
} catch(DmlException e) {
System.debug(e.getMessage());
}
```

**Database Methods** (e.g., `Database.insert()`, `Database.update()`, `Database.delete()`, `Database.upsert()`) provide more flexibility. They accept an optional `allOrNone` parameter — when set to `false`, partial processing is allowed, meaning successful records are committed while failed records are returned with error details. These methods return result objects (`Database.SaveResult`, `Database.UpsertResult`, `Database.DeleteResult`) that contain success/failure information for each record.

Example:
```
Database.SaveResult[] results = Database.insert(accounts, false);
for(Database.SaveResult sr : results) {
if(!sr.isSuccess()) {
for(Database.Error err : sr.getErrors()) {
System.debug(err.getMessage());
}
}
}
```

**Key Differences:**
1. DML statements are simpler but less flexible; Database methods offer granular error handling.
2. Database methods support partial success with `allOrNone=false`.
3. DML statements throw exceptions on failure; Database methods return result objects.

**Governor Limits:** Both approaches share the same limit of 150 DML statements per transaction. Developers should bulkify operations by performing DML on collections rather than individual records inside loops.

Choosing between the two depends on the use case — use DML statements for simplicity and Database methods when partial processing and detailed error handling are required.

Governor Limits and Apex Transactions

Governor Limits and Apex Transactions are fundamental concepts in Salesforce development that every Platform Developer I must understand.

**Apex Transactions:**
An Apex transaction represents a set of operations executed as a single unit of work. A transaction begins when a trigger, web service call, Visualforce page request, or anonymous block is initiated. All DML operations, SOQL queries, and processing within that execution context are part of the same transaction. If any operation fails, the entire transaction is rolled back, ensuring data integrity. Transactions follow an all-or-nothing principle unless savepoints are used for partial rollbacks.

**Governor Limits:**
Salesforce operates on a multi-tenant architecture where resources are shared among all organizations. Governor Limits are runtime restrictions enforced by the platform to prevent any single tenant from monopolizing shared resources. These limits are applied per transaction and ensure fair usage.

**Key Governor Limits include:**
- **SOQL Queries:** 100 per synchronous transaction, 200 per asynchronous
- **DML Statements:** 150 per transaction
- **DML Rows:** 10,000 per transaction
- **SOQL Query Rows Retrieved:** 50,000 per transaction
- **Heap Size:** 6 MB (synchronous), 12 MB (asynchronous)
- **CPU Time:** 10,000 ms (synchronous), 60,000 ms (asynchronous)
- **Callouts:** 100 per transaction
- **Future Methods:** 50 per transaction

**Best Practices to Avoid Hitting Limits:**
1. **Bulkify code** — Never write SOQL or DML inside loops
2. Use **collections** (Lists, Maps, Sets) to process records efficiently
3. Use **SOQL FOR loops** for large data sets
4. Leverage **asynchronous processing** (Batch Apex, Queueable, Future methods) for heavy operations
5. Use **Limits class** methods like `Limits.getQueries()` to monitor consumption at runtime

Violating governor limits throws a runtime `LimitException` that cannot be caught, causing the entire transaction to fail. Understanding these limits is critical for writing scalable, efficient Apex code on the Salesforce platform.

Exception Handling in Apex

Exception Handling in Apex is a critical mechanism for managing runtime errors gracefully in Salesforce development. Apex uses a try-catch-finally block structure, similar to Java, to handle exceptions and prevent unhandled errors from disrupting business processes.

**Try-Catch-Finally Structure:**
- **Try Block:** Contains the code that might throw an exception.
- **Catch Block:** Catches and handles specific exception types. Multiple catch blocks can handle different exception types.
- **Finally Block:** Executes regardless of whether an exception occurred, typically used for cleanup operations.

**Common Exception Types:**
- **DmlException:** Occurs during DML operations (insert, update, delete) such as validation rule failures or required field violations.
- **QueryException:** Thrown when a SOQL query returns unexpected results, like assigning multiple rows to a single sObject.
- **NullPointerException:** Triggered when referencing a null object.
- **ListException:** Occurs when accessing an invalid list index.
- **LimitException:** Thrown when governor limits are exceeded (cannot be caught).
- **CustomException:** User-defined exceptions extending the base Exception class.

**Key Methods on Exception Objects:**
- `getMessage()` – Returns the error message.
- `getCause()` – Returns the cause of the exception.
- `getLineNumber()` – Returns the line number where the exception occurred.
- `getStackTraceString()` – Returns the full stack trace.

**Custom Exceptions:**
Developers can create custom exception classes by extending the Exception class: `public class MyCustomException extends Exception {}`

These can be thrown using: `throw new MyCustomException('Custom error message');`

**Best Practices:**
1. Catch specific exceptions before generic ones.
2. Never use empty catch blocks—always log or handle errors appropriately.
3. Use Database methods (Database.insert) with allOrNone=false for partial processing instead of relying solely on try-catch for DML.
4. Remember that LimitException and some system exceptions cannot be caught.

Proper exception handling ensures robust automation, improves debugging, and delivers meaningful error messages to users in triggers, batch classes, and other Apex contexts.

Invocable Methods and Flow Integration

Invocable Methods and Flow Integration are essential concepts in Salesforce Platform Development that bridge the gap between declarative automation (Flows) and programmatic logic (Apex).

**Invocable Methods** are Apex methods annotated with `@InvocableMethod`, allowing them to be called directly from Salesforce Flows, Process Builder, and REST API. They serve as a powerful mechanism to extend declarative tools with custom Apex logic when out-of-the-box Flow elements are insufficient.

**Key Characteristics:**
- Only one `@InvocableMethod` is allowed per Apex class.
- The method must be `public static` and can accept a `List<>` of input parameters.
- Use `@InvocableVariable` to define input and output variables within wrapper classes, enabling structured data exchange with Flows.
- They support bulkification since inputs and outputs are list-based.

**Example Use Cases:**
- Performing complex calculations or callouts that Flows cannot handle natively.
- Executing DML operations with advanced error handling.
- Integrating with external systems via HTTP callouts.

**Flow Integration:**
Flows can invoke these methods through the **Action** element. When building a Flow, developers select the Apex Action, which surfaces all available invocable methods. Input variables from the Flow are mapped to `@InvocableVariable` inputs, and output variables are returned back to the Flow for further processing.

**Best Practices:**
1. Always design invocable methods to handle bulk data (List inputs) to avoid governor limit issues.
2. Use descriptive labels and descriptions in annotations for Flow builders to easily understand the method's purpose.
3. Keep the method signature simple — use inner classes with `@InvocableVariable` for complex inputs/outputs.
4. Handle exceptions gracefully to prevent Flow failures.
5. Write comprehensive test classes covering various scenarios.

This integration pattern empowers organizations to leverage the simplicity of Flows for business logic orchestration while utilizing Apex for complex operations, creating a balanced approach between declarative and programmatic development that is both maintainable and scalable.

More Process Automation and Logic questions
850 questions (total)