Business Rules, Flow Designer, and Script Includes
Key Takeaways
- Business Rule timing is an exam-favorite decision point: before changes the current record before commit, after reacts to committed data, async runs through the scheduler queue off the user's transaction, and display populates g_scratchpad for form load.
- Flow Designer is best for readable process automation; flows own a trigger, subflows package reusable logic without their own trigger, and actions are reusable steps that collect inputs and produce outputs.
- Script Includes centralize reusable server logic; mark one Client Callable and extend AbstractAjaxProcessor so a form can reach it through GlideAjax instead of querying the database from the browser.
- Use GlideRecord for trusted server work, but prefer GlideRecordSecure when returning user-context data so Access Control Lists are enforced automatically.
- A strong CAD answer chooses configuration first, then script only for precise validation, reusable logic, or a requirement Flow Designer cannot express cleanly.
Business Rules, Flow Designer, and Script Includes
Quick Answer: Use Business Rules for trusted server-side logic tied directly to database activity, Flow Designer for readable process automation, and Script Includes for reusable server logic. If a client script needs server data, call a Client Callable Script Include with GlideAjax; if a script returns records in user context, use GlideRecordSecure so Access Control Lists are respected.
The Automating Applications domain is 20% of the 60-question Certified Application Developer (CAD) exam, and almost every item is a tool-selection scenario rather than a syntax recall. Read each requirement for three clues: when the logic must run, who must maintain it, and whether the result must be protected by server-side security. Pick the artifact that satisfies the requirement with the least risk and the most readability.
Business Rule Timing
A Business Rule is server-side JavaScript that reacts to record operations such as insert, update, delete, query, or display. Timing changes both behavior and performance, so memorize the four when values and what runs against the record at each point.
| Timing | Runs | Object available | Best use | CAD trap |
|---|---|---|---|---|
| before | Before the database commit | current (writable) | Set or validate fields on current; abort with current.setAbortAction(true) | Calling current.update() triggers recursion and extra writes; just set the field. |
| after | After commit, in the same transaction | current (committed) | Create or update related records | Do not edit the same record you could have set in a before rule. |
| async | Later, via the scheduler queue | current snapshot | Heavy calculations, metrics, outbound integrations | It may not finish before the user sees the saved form. |
| display | When the form loads, before HTML is sent | current plus g_scratchpad | Push server values to g_scratchpad for client scripts | It is form-load support, not post-save processing. |
Always add a condition so the rule only fires when needed. A rule with order 100 runs before one with order 200, which matters when two before rules both touch the same field. A broad rule that runs on every update is slower and far more likely to create side effects than a narrowly scoped one.
A Worked Timing Example
Requirement: when an expense record is saved, reject amounts over the policy cap, then stamp an approval-needed flag, then notify finance. The cap check belongs in a before rule (if (current.amount > 5000) { current.setAbortAction(true); gs.addErrorMessage('Over cap'); }) so the bad save never commits. The notify-finance step belongs in an after rule, because it depends on a committed record and you do not want to send mail for a save that was aborted. If the finance message involves a slow external API, move it to async so the user is not blocked.
Flow, Subflow, and Action
Flow Designer is the low-code automation layer. A flow owns a trigger such as Created, Updated, a schedule, or an inbound REST call. A subflow has no standalone trigger; a flow, action, or script calls it, which makes it ideal for reusable logic like a standard manager-approval path. An action is a reusable step with defined inputs and outputs, such as Create Record, Ask for Approval, Send Notification, or a custom script step.
- Choose Flow Designer when the process should be visible to admins and process owners: approvals, task routing, notifications, catalog fulfillment, multi-step orchestration.
- Choose a Business Rule when the logic is tightly coupled to record commit behavior, especially validation that must block a save.
- Choose a subflow when several flows reuse the same steps; choose an action when several flows reuse a single step.
Script Includes, GlideAjax, and Secure Queries
A Script Include stores reusable server-side functions or classes and keeps shared logic out of multiple Business Rules, UI Actions, and flows. To call it from the browser, set Client Callable to true and extend AbstractAjaxProcessor; the client then uses GlideAjax, passing sysparm_name to choose the method and reading getXMLAnswer(). Return only the value the form needs, never a broad record dump.
GlideRecord is the standard server-side table API. Write it carefully: filter your addQuery() precisely, avoid sweeping updateMultiple() calls, and use getValue() or getDisplayValue() instead of pulling whole reference objects when a string suffices. GlideRecordSecure performs the same table work but enforces ACLs row-by-row, so it is the safer choice whenever user-facing logic requests records through a client-callable path.
Exam Decision Checklist
- Need to stop an invalid save? Use a before Business Rule with
setAbortAction(true). - Need a readable approval or fulfillment path? Start with Flow Designer.
- Need reusable server logic? Create a Script Include.
- Need form code to ask the server for a value? Use GlideAjax into a Client Callable Script Include.
- Need returned records to honor the user's ACLs? Prefer GlideRecordSecure over plain GlideRecord.
Order, Recursion, and Common Mistakes
When two before rules write the same field, the lower order wins the final value, so set order intentionally rather than relying on the default of 100. A classic recursion bug is a before rule that runs on update and calls current.update(); the update fires the same rule again. The fix is simply to set the field on current and let the platform persist it once at commit. Another frequent error is using a display rule to do work that belongs after save, or putting database queries in a Client Script instead of routing through GlideAjax.
Finally, prefer declarative tools before scripting. If a UI Policy, Data Policy, or Flow Designer action can satisfy the requirement, choose it over a script: it is easier for the next developer to read, it survives upgrades better, and the CAD exam consistently rewards the lowest-code answer that still meets the requirement. Reserve scripting for precise validation, reusable cross-component logic, or behavior the declarative layer cannot express.
A scoped expense app must reject saves when the amount exceeds a hard limit, route approved records through a manager approval path, and reuse a currency-formatting helper from several scripts. Which design is strongest?
A form must show a server-calculated discount when it loads, before the user edits anything. Where should the value be prepared?