Follow Business Process design guidelines
The article contains the best practices to follow while writing code for any Business Process (BP).
Introduction
To launch a demo BP, create the Invoice_storage Data Store from the attached CSV file. After that, open the BP, check the No Data option on the Data tab, and launch the BP.
required business process data
- BP package:
BP_best_practices_package.zip - Data Store to start a demo BP:
Invoice_storage.csv
Naming conventions
Business Processes components
- Name the BP and Bot Tasks with proper naming conventions. Avoid using the default name for a BP like "Business Process 05/13/2019 06:21:52".
- Keep consistency in naming Data Stores. Preferably use the lowercase with an underscore between words.
Data Store naming convention:
<!-- inconsistent datastore naming -->
<insert-datastore datastore-name="AbSomething_ds"
json-value-map="${jsonValueMap}" create="true" />
<!-- devise a naming convention and stick to it -->
<insert-datastore datastore-name="api_result" create="true"
json-value-map="${jsonValueMap}" />
Bot code
- Input parameters and WebHarvest-defined variables are usually the lower case with underscore-separated words.
- Keep consistency in naming the variables. Use camelCase for methods and variable names.
Business Process design guidelines
There are three main approaches to the BP design and execution:
- The process is executed on a scheduled basis with specific input (Schedule Tasks and BPs).
- The process is executed through the API. For more details, refer to API Documentation.
- Continuous monitoring of the input source is performed.
Common mistakes found in Business Process code
Do not use
thread.sleepfor any retry (asynchronous calls). Try using the retry-attempts and retry-delay option in the http-extended plugin. Another option is to use the release plugin.Avoid chained method invocations, split the chain into variables, and handle exceptions to help proper debugging.
Chained invocation:
try{ Transaction processedTransaction = AppExample.init(binding).get().processTransaction(TransactionEncryptionProcessor.class, transactionId); }catch(Exception ex){} //instead do as below try{ App app = AppExample.init(binding).get(); Transaction processedTransaction = app.processTransaction(TransactionEncryptionProcessor.class, transactionId); }catch(Exception ex){ logger.error(ex.getMessage()); }Add proper exception handling with try-catch, avoid empty catch block, and log the exception message to help to debug.
Exception handling:
try{ App app = AppExample.init(binding).get(); Transaction processedTransaction = app.processTransaction(TransactionEncryptionProcessor.class, transactionId); }catch(Exception ex){} //avoid exception swallowing //instead do as below try{ App app = AppExample.init(binding).get(); Transaction processedTransaction = app.processTransaction(TransactionEncryptionProcessor.class, transactionId); }catch(Exception ex){ logger.error(ex.getMessage()); }Avoid duplicate queries to the same Data Store in multiple Bot Tasks. Instead, query once and export the object to subsequent steps.
Use Secrets Vault for sensitive data. For more details, see the Secrets Vault plugin.
Avoid procedural coding style. Instead, group functionality into methods.
Create classes for related properties, create methods to manipulate instances, and share classes between steps using the include-config plugin.
Give meaningful names to non-primitive variables.
sys.defineVariableshould not be inside any conditional or method. Avoid overwriting inside blocks. Instead, use local properties and define variables outside the block. Refer to Bot Task context | Object sys.Using
sys.defineVariable://bad practice if(resultStatus.equals("SUCCESS")) { sys.defineVariable("requestId", result.taskRequestId); sys.defineVariable("accNumber", result.accNumber); } else { sys.defineVariable("requestId", defaultTaskRequestId); sys.defineVariable("accNumber", defaultAccNumber); } //instead do as below String requestId= defaultTaskRequestId; String accNumber= defaultAccNumber; if(resultStatus.equals("SUCCESS")) { requestId= result.taskRequestId; accNumber= result.accNumber; } sys.defineVariable("requestId", defaultTaskRequestId); sys.defineVariable("accNumber", defaultAccNumber);Use explicit types for variable declaration, and avoid the def keyword for variable declaration.
Explicit type declaration:
long salary = getSalary(); //instead of salary = getSalary(); //avoid def for variable declarations. always give explicit data types. def accountNumber = 1l;Use
sys.isVariableDefinedto ensure the variableexists.sysobject. Do null checks before comparisons.
Logging
- Logging helps in debugging issues in a BP. Follow proper formatting of log messages and log only useful information.
- Never log sensitive information.
- Add as much logging as possible. Make sure to use the log level as debug to avoid unnecessary logging. For more information, see the log plugin.
Common performance-related guidelines
Configuring multiple threads for your bot steps without checking whether the server has enough cores and memory leads to performance degradation.
Keep bot steps stateless. Stateless execution will boost overall performance.
Avoid unnecessary calls to Data Stores or restful APIs. If a single call can suffice for the entire BP, you can export that single call's result to later bot steps.
Use SQL joins. It is a good approach to join over multiple tables instead of calling each datastore separately and then doing joins with Groovy or Java.
Use the export plugin judiciously.
Export plugin misuse:
<!-- avoid this --> <export include-original-data="true"></export> <!-- use this --> <export include-original-data="false" export-columns="invoice_number,urn"></export>Avoid unnecessary use of the multi-column plugin. It will help in running the bots stateless.
Avoid unnecessary split joins. The split data rules are not supported in stateless execution.
Use WorkFusion tools and techniques for analyzing the instance performance.