Good Practices
Overview & General Rules
To ensure effective implementation of Breezz in a Salesforce application, follow these guidelines:
- Class Structure: For solutions implemented in Apex, every method invoked within Apex Triggers requires a dedicated class extending the
forvendi.Stepabstract class. - Trigger Context Guidelines:
- Before Triggers: Should solely modify records from the trigger context. Asynchronous calls in before triggers are non-optimal and should be avoided.
- After Triggers: Should solely modify records other than the trigger context.
Breezz Step Methods Guide
void Initialize()
Override this method when step-level initialization is required before processing records.
Boolean initRecordProcessing(Object record, Object optionalOldRecord)
Used to modify record fields when all necessary data is available upfront.
- Restrictions: Neither DML, SOQL, nor SOSL are allowed in this method.
- Modifying Related Records: Use
ModificationContextviagetContext(). - Querying Data: Use
DataStoreviagetStore()to request data asynchronously for subsequent processing. - Return Value (
Boolean):- Return
falseif all record processing is completed using data already available in the trigger (no additional queries needed). - Return
trueif additional data was requested usingDataStore. This signals Breezz to proceed tofinishRecordProcessing.
- Return
DataStoreUsage: Without custom Loaders,DataStoreloads flatSObjectrecords by ID usingrequestToLoad(List<Id> ids, Set<String> fields). Subqueries are also supported:getStore().requestToLoad( accountRecord.Id, new Set<String>{ 'Id', 'OwnerId', '(SELECT Id FROM Public_Accounts__r)' } );For complex queries with distinct clauses, define a custom loader in the Breezz configuration and pass the
storeKeyparameter torequestToLoad.
ModificationContextUsage Warning:
addToUpdate(SObject record): Adds the given record to the update list. Replaces the whole record.addModificationToUpdate(SObject record, SObjectField objectField, Object value): Appends a single field modification to the record. Use this when applying multiple sequential changes to avoid overwriting existing fields.
void finishRecordProcessing(Object record, Object optionalOldRecord)
Executed only for records where initRecordProcessing returned true.
- Restrictions: Direct DML and SOQL/SOSL queries are not allowed.
- Data Access: Data requested in
initRecordProcessingis loaded between execution phases and can now be retrieved viagetStore().getFromStore(recordId)(returnsSObjectorMapdepending on loader usage). - Modifications: Record fields and related records can be updated or created via
ModificationContext.
void finishSyncProcess(List records, List optionalOldRecords)
Finalizes the synchronous process.
- Accesses records added via
addToSyncFinishduring previous steps. - Note: Runs automatically, even if no records were explicitly added to the sync context.
void executeAsyncProcess(Map<String, forvendi.AsyncJobInfo> asyncJobsByRecordKey)
Executes for records queued via addAsyncJob() (called in initRecordProcessing, finishRecordProcessing, or finishSyncProcess).
Advanced Concepts & Key Utilities
Flow Interviews
Flow Interviews can be skipped in Apex Steps and replaced with Flow Steps configured directly in Breezz, provided the target flow requires no input parameters originating from Apex logic.
Key ModificationContext Methods
- Emails: Use
getContext().addToSend(Messaging.SingleEmailMessage record). - Async Manipulations:
addToAsyncInsert,addToAsyncUpdate,addToAsyncRemove. - Platform Events: Publish events using
addEventToPublish. - Lead Conversion: Convert leads using
addToConvert. - Inspect Context: Use getter methods (
getRecordsToUpdate,getEventToPublish,getRecordsToConvert) to inspect queued records.
Breezz Logger
Use forvendi.BreezzApi.LOGGER.logError() to record warnings, catch errors, and gather execution metrics across your steps.
💡 Writing Custom Steps? For specific guidelines on writing clean, modular Apex Step classes, check out our dedicated Step Development Best Practices.