This article is based on the ServiceNow documentation article. See the original article on the ServiceNow doc site: Business Rules Technical Best Practices Overview.
Quality Clouds automatically checks that all the best practices defined below are followed in any Business Rule which you create or modify on your ServiceNow instance. Below is a snapshot from the Quality Clouds Best Practice analysis dashboard which shows the issues detected in Business Rules on a ServiceNow instance.
Know when to run business rules
The When field on the business rule form indicates whether the business rule script runs before or after the current object is saved to the database. The most commonly used business rules are before and after rules.
You can use an async business rule in place of an after business rule. Async business rules are similar to after rules in that they run after the database commits a change. Unlike after rules, async rules run in the background simultaneously with other processes. Async business rules allow ServiceNow to return control to the user sooner but may take longer to update related objects.
Follow these guidelines to determine which value to choose for the When field.
|display||Use to provide client-side scripts access to server-side data.|
|before||Use to update information on the current object. For example, a business rule containing current.state=3; would set the State field on the current record to the state with a value of 3.|
|after||Use to update information on related objects that need to be displayed immediately, such as GlideRecord queries.|
|async||Use to update information on related objects that do not need to be displayed immediately, such as calculating metrics and SLAs.|
Use conditions in business rules
Since business rules are evaluated whenever an insert, update, delete or query action is made to a record, it is important to ensure you are using conditions. Conditions are evaluated before the rule is executed, if the condition is met, the script is evaluated and executed. If there is no condition, the system assumes that the business rule should be evaluated and executed for every action to a record on the specified table of the business rule. It is easier to debug business rules when you can see which one meet a particular condition and which do not.
→ In the business rule form, use the Filter Conditions field in the When to Run section to specify the condition.
→ In the advanced business rule form, use the Advanced section to specify the condition. Specify the condition using the Condition field.
Keep code in functions
By default, an advanced business rule will wrap your code in a function, and it is important that this guideline is followed. When code is not enclosed in a function, variables and other objects are available to all other server-side scripts. This availability can lead to unexpected consequences that are difficult to troubleshoot. Consider this example:
Because the gr object is not enclosed in a function, all server-side scripts, including script includes and other business rules, have access to it. Other scripts may also use the common GlideRecord variable name gr. The duplicate names can conflict and lead to unexpected results. These issues are very difficult to isolate and resolve because typical debugging methods identify the business rule giving erroneous results rather than the business rule containing global variables. To avoid this issue, keep the default function with the same code snippet:
This solution is safer because the scope of the variable grInc is limited to the Business Rule since it is wrapped in the default function. If every script was wrapped, it would not matter what the variables were called. But it is good defensive coding to minimize the possibility of collisions even further, and avoid using a variable called gr at all. This makes the possibility of namespace conflicts even more remote.
Prevent recursive business rules
Do not use
current.update() in a business rule script. The
update() method triggers business rules to run on the same table for insert and update operations, potentially leading to a business rule calling itself over and over. Changes made in before business rules are automatically saved when all before business rules are complete, and after business rules are best used for updating related, not current, objects. When a recursive business rule is detected, ServiceNow stops it and logs the error in the system log. However, this behavior may cause system performance issues and is never necessary.
You can prevent recursive business rules by using the
setWorkflow() method with the false parameter,
current.setWorkFlow(false). This will stop business rules and other related functions from running on this database access. The combination of the
setWorkflow() methods is only recommended in special circumstances where the normal before and after guidelines mentioned above do not meet your requirements.
Use business rules to double-check critical input
If you use a Client Script to validate data or a reference qualifier to present a filtered list, data may change between the time the user fills in the fields and the time the user submits the form. This mismatch can cause a conflict or error. business rules are an effective way to double-check critical input.
For example, a request allows users to reserve items. When users fill out the request form, they can only select currently available items. If two people fill out a business rule form at once and select the same item, the item appears to be available to both people because neither of them has submitted the form yet. If there is no business rule to double-check availability, ServiceNow assigns the same item to both requests. By using a business rule to re-verify item availability when the form is submitted, the second person receives a warning or other notification indicating the item has already been taken.
In this example, the Condition is: current.cmdb_ci.changes()
The script is:
Use script includes instead of global business rules
A global business rule is any business rule where the selected Table is Global. Any other script can call global business rules. Global business rules have no condition or table restrictions and load on every page in the system. Most functions defined in global business rules are fairly specific, such as an advanced reference qualifier on one field of one form. There is no benefit to loading this kind of script on every page.
Script includes only load when called. If you have already written a global business rule, move the function definition to a Script Include. The name of the Script Include must match the name of the function for the Script Include to work properly. There is no need to modify any calls to the named function.
Consider this global Business Rule:
This Script Include is a better alternative:
To call the function, use a script like this:
Use glideAggregate instead of glideRecord to count the records in a table
The GlideAggregate class is an extension of GlideRecord and allows database aggregation (COUNT, SUM, MIN, MAX, AVG) queries to be done. This is the most efficient way to obtain the total number of records on a table. Filters can also be added to the glideAggregate query, as is done with GlideRecord. Running a GlideRecord query (filtered or unfiltered) with the sole purpose of using the getRowCount property to count the number of returned rows is inefficient. Glide Aggregate should be used instead.