Apptitude Developer Best Practices

by Christina Moore Updated May 04, 2020

Onit Apptitude provides you with many different tools and methods to solve business problems. When you are faced with a specific use case, our platform may present you with literally dozens of different ways to solve the same problem. Inevitably though, some solutions will be better than others, and usually there is one single solution that trumps them all.

When building a new Onit App or workflow, you should always aim for a solution that is performant, user friendly, safe, readable by others, and testable. Of course, designing a solution that checks all of these boxes can be challenging.

In this tutorial we’ll cover commonly accepted best practices used by Level 4 certified Apptitude Developers. While following these best practices won’t 100% guarantee success, it will put you on the right path.

Always Require Comments

Always require comments from your Apptitude Developers (including yourself). Requiring comments for changes will make troubleshooting and tracking changes to your App much easier. For example when making changes to your environment you find a broken Action. If all App builders left comments when they changed configuration it would be easy to go back and change what had been broken.

To require comments in an environment:

  1. Navigate to your environment’s Administration page.
  2. Under the Edit Corporation tab check the Require Comments on App Changes

Enable Test Mode

Note: Environments with gold-ab (e.g., www.onit.gold-ab.com) in the URL cannot send external emails by default.

Turn on Test Mode to avoid spamming users with emails while developing a solution. For example, let’s say that you’re building a new workflow that involves a Send Notification Action. You would like to test this notification before you send it to system users. Enabling Test Mode allows you to be sure that you will not notify users when testing your new Send Notification Action.

There are three different levels where Test Mode can be enabled: at the environment level, at the App level, and at the Action level.

To turn on Test Mode in the whole environment navigate to the Administration page then the Edit Corporation Tab and choose Notification Tab Mode. Enabling test mode at the environment level will prevent any notifications from being sent by the entire environment.

Test mode can also be enabled at the App level. Enabling test mode at the App level will prevent an entire App from sending any notifications. To enable test mode at the App level, navigate to the Advanced Designer and choose the Settings node. At the bottom of the page choose Notification Test Mode.

The most granular way to enable test mode is at the Action level. Choose Test Mode on the appropriate Action configuration page. Test mode can be enabled on the Send Comment Notification, Send External Notification, Send Notification, and Send Report Actions.

Watch Out for Expensive Liquid

Some Liquid expressions are very memory intensive and should be avoided whenever possible. This includes Liquid for loops, and list lookups, as well as calling .size, .first, and .last.

Additionally, calculated Fields can be expensive. When using calculated Fields in your App turn off calculated Fields at the environment level and specify when Onit should recalculate them using the Recalc Single Transaction Action. The Recalc Single Transaction Action should be utilized in Business Rules to run calculated Fields only when necessary (e.g., on a Record update).

For example, your App has a calculated Field named total. Total should update only when a user enters different amounts and prices in the Record. However, because total is a calculated Field Onit will recalculate total every time the Record is loaded. To prevent the unnecessary recalculation, you can turn off calculated Fields at the App level and create a Recalc Single Transaction Action to update total only when a Transaction Updated Business Rule fires. Recalculating total in this way prevents expensive Liquid calculations on Record load.

For a more detailed explanation of Record Recalculations see this section.

Avoid Excess Configuration

Remember that every Field, button, App panel, and widget that you add to your App will impact page load time. Every time a Launch or View Screen is loaded, Onit must individually load each item on the page, including hidden Fields. The more fields in an App, the slower its Records will load.

This doesn’t mean that you shouldn’t create enough configuration in your App to satisfy the business problems at hand. Instead, it means that you should be careful not to create configuration elements that aren’t really needed.

Do Not Make REST Calls into Onit

Onit’s API should not be called from within the Onit application. The REST Request Action makes it possible to perform API calls from within Onit. This Action might be used to call an external API to update a business Record. However, making API calls to Onit, from Onit is expensive and can cause locking errors. For example you might want to make a REST call from Onit to Onit to retrieve multiple Records from an App that meet certain criteria. 

Background Conditional Compound Actions (CCAs) When Appropriate

Backgrounding a Conditional Compound Action (CCA) allows Onit to run the CCA while the user is performing other tasks. This helps speed up perceived performance because the user can navigate away from the page while the Action is being processed. You might want to background a CCA that changes phases on a related Record, adds participants, or creates a child Record.

That said, backgrounding a CCA is not always the appropriate course of Action. For example, if a backgrounded CCA fails the user may never see the error or know of the failure, if they’ve browsed away from Onit before the Action has completed processing.

Do not background a CCA that must work synchronously with other Actions. For example, a Change Phase Action should happen after a backgrounded CCA completes. However, the CCA silently failed and the Change Phase Action never happens. The end-user would not see any errors and the Record would be in an incorrect phase.

Know When to Create a Child App

If an App collects a variable amount of data from end-users then think about creating a child App to collect this data. Trying to collect this data from one launch form may become unwieldy for end-users.

For example, you are building an App that needs to collect documents from end-users. You might be tempted to create 10 different Attachment Fields to accommodate a variable number of uploads. However, this will make the launch form clunky for users. Instead you should aim to create a new child App that will collect as many documents as the user needs to upload in an organized manner.

Always Aim for a DRY Solution

When configuring your App always aim for a DRY solution. The acronym DRY stands for Don’t Repeat Yourself. For example, you are building an App and have five different Change Phase Actions to accommodate different workflows in your App, one for each phase that could be encountered in the workflow. However, by adhering to DRY you can condense all of your Change Phase Actions using Liquid to variablize the phase.

Don't Hardcode

When building make your Actions and Business Rules as flexible as possible (e.g., don’t hardcode names or email addresses when you can use a list lookup). Additionally, use list combos or transaction list providers instead of plain combo Fields wherever possible to avoid hardcoded values.

For example, when building a new workflow, it might be tempting to enter the Financial Supervisor’s email address into the Approver role, after all the Financial Supervisor will always be the same, right? Well in the event the Financial Supervisor changes you have now signed yourself up for a lot of App changes. Instead you should abstract users from their Roles in Apps. One way to do this is to use a global_roles list. The global_roles list is a list of every position in your company and the employee’s corresponding email. This way if any employee changes you can edit the list and the new email will be reflected across the whole environment.

Use Roles Appropriately

When building use Roles appropriately in your App. For example, only use an Approver role for a user who will need to click the approve or reject buttons on a Record. When assigning a user to an Approver role there are reporting and UI implications associated to the Role.

Think of Security Design Early Not Late

Before starting your project spend time thinking about the security of your environment. There are some security requirements possible in other platforms that are not possible in Onit, for example read-only security. Often security will fall by the way side and a very brittle ad-hoc security system will develop over time. For example, Company A decides that simply restricting Record access to participants will be enough security to keep their Records safe. However, when an employee leaves Company A they now have a participant who should no longer have access to sensitive Records. The old user will need to be manually removed from hundreds of Records and replaced with another user. Counteract this by planning your security strategy beforehand. A good place to start is our Crash Course on Security tutorial.

Avoid Giving End-Users Unnecessary Access

End users should not be given access to the development environment. The development environment is meant for building configurations and is not production ready. In our experience, giving end-users access to a development environment can confuse them with partially built solutions and may even lead to loss of confidence in App builders. As a general rule, end users should only have access to UAT and Production environments. Additionally, avoid granting end-users a System Admin role. Instead compromise with an App Admin, List Admin, or App Creator Role instead.

Alert Onit to Any Infinite Loops

If you accidentally create an infinite loop in your environment, alert Onit right away. Onit tries to detect and kill all infinite loops, however they can still happen. A hallmark of an unintentional infinite loop is an App running much slower than it usually does or large amounts of unexpected data being created. If you are not sure that you have created an infinite loop contact Onit just in case. Infinite loops are easy to accidentally create. For example, you have created a loop to run a couple of Actions for every user in your environment; however, when specifying the stop condition you accidentally used a greater than sign when you should have used a less than sign, so the loop never terminates. 

If you suspect an infinite loop in your environment run debugger/logger. To access the debugger/logger tool navigate to the better advanced designer page in your environment, then click Debugger/Logger.

Think About Your End-User Experience

When building think about the UX of your App. For example, think about the ordering of Fields on your launch page or using empty text (i.e., placeholder text) in Fields to help end-users understand what should be entered in Fields. Additionally, you should think about using validators in Fields, auto-populating Fields when appropriate, strategically ordering Fields in launch forms, and not cluttering launch forms with too many Fields.

Make Your Configuration Reader Friendly

When configuring your App make it as reader friendly as possible. Include comments in your Liquid script, and name your Business Rules, Actions, and conditions appropriately. Keeping your configuration clean will not only help you but also Onit understand your configuration. For example, a new App builder is trying to learn your configuration, but when they access the environment they see twenty Change Phase Actions named “Change Phase”. How are they supposed to know what’s going on? The Change Phase Actions should each have descriptive names like “Change Phase from Discovery to Planning”. This way the configuration can easily be followed.

 Below are some quick tips for keeping your configuration reader friendly:

  • When many Actions work together to solve a business problem insert something similar in all of their names. For example, you have a couple Actions handling phase changes and notifications when a user rejects a Record, so you name all of the Actions “Rejection – Action name”.
  • When you have disabled a Business Rule add “Disabled” to the beginning of its name. This way other App builders can tell if the Business Rule has been disabled at a glance.
  • Create a stand-alone document and ERDs that outline how the configuration has been built and how it works together. For example, this is an ERD of our ELM product:

Prevent Users from Accessing the /apps Page

Always prevent end-users from accessing the /app page. End-users should navigate around your environment through the navigation items in a dashboard.

  1. To prevent users from accessing the /apps page navigate to your environment's Administration page.
  2. In the Edit Corporation node click the Security tab.
  3. Scroll to the bottom of the page and check the Restrict to System Admin and App Creators box.

Button Best Practices

When configuring your environment be mindful of how many buttons you create and what business problem they solve. Creating too many buttons could be a sign of a brittle workflow configuration. For example, you create six buttons to move through each Phase in your App when you could create just one button that moves the Record to the next phase. Additionally, make sure to delete any testing or troubleshooting buttons you create during development. 

You should also make use of hide/show conditions to display buttons only when appropriate. This will not only keep page clutter down to a minimum, it will also prevent users from clicking the wrong button. To further organize pages use secondary buttons that will only show when expanded. 

Don't Assume You Know How Configuration Works

If you inherit a large amount of pre-existing configuration, don't assume you know how the configuration works. When in doubt consult other App builders and read our documentation!

Optimizing Calculated Fields

Heads up: The information below assumes you know how calculated Fields work in general. For a detailed explanation on configuring calculated Fields see our tutorials on Liquid calculations and Numeric calculations.

When it comes to recalculating Records, a certain amount of judgment is required to determine the best configuration for your environment. If you simply mark a Field as “calculated” in an App’s wizard and do nothing else, Onit will take on the responsibility of determining when and how many times to recalculate the Field whenever a Record is created or changed. This approach is simple to set up and works well, up and until you notice a drop in the App’s performance (e.g., Records take a long time to create and update). This commonly occurs if you have many calculated Fields in an App and/or the Field calculation logic is complex and expensive. When this happens, it is often advisable to switch take an alternate configuration approach, which relies on firing the Recalculate Single Transaction Action to recalculate Records.

So, what’s the difference between the default recalculation approach and the approach that relies on the Recalculate Single Transaction Action?

When you rely on the default recalculation approach, a calculated Field automatically recalculates whenever a Record is updated, even if the update that was made by a user has nothing to do with the value being recalculated. In addition, using this approach, when a Record is created or updated, on the backend Onit tells each of the App’s calculated Fields to re-run their calculations multiple times. In other words, if you have five calculated Fields in App, when a Record is updated, each calculated Field doesn’t just re-calculate once each. Rather, to ensure that each Field has up-to-date data, Onit recalculates each Field multiple times, just in case one of the calculated Fields relies on the completed calculation of another calculated Field. For these reasons, performance can be affected.

Alternatively, moving away from the default approach and instead using the Recalculate Single Transaction Action approach gives you much more control to specify exactly when, and how many times, a Record should re-run Field calculations.

Tip: There is no one-size-fits-all number in terms of how many calculated Fields you must have in an App before you should change your configuration approach. This threshold differs depending on various factors, most importantly the type of calculations being performed. As a general rule, if your App’s performance seems poor when it comes to creating and updating Records, this is one area to investigate from a performance tuning standpoint.

For example, a Budget Record contains a calculated Field that displays the total dollar amount on the Record. If you change the name of the Budget Record, under the default approach, the calculated Field will also recalculate, even though this field isn’t at all affected by the name change. Alternatively, if you use the Recalculate Single Transaction Action (and you disable the default Field calculation approach in the App), you can specify exactly when the Record should recalculate and how often. So, if the Record should only recalculate once when a relevant Field is updated, you can create a Business Rule that checks which Field has been updated and then recalculate the Record accordingly.

The steps below explain how to take the alternative calculation approach via the Recalculate Single Transaction Action.

  1. Navigate to the App’s Advanced Designer Page.
  2. Under the Actions node, click Add and choose Recalculate Single Transaction.
  1. Provide a name for your Action.
  1. Click Ok to save your configuration.
  2. Create a Business Rule to fire your Recalculate Single Transaction Action. The Business Rule that you select depends on when you want this Action to fire. Often times you’ll create two Business Rules: Transaction Created and Transaction Updated.

Only performing the steps above is not sufficient. While your Fields will indeed recalculate every time that the Recalculate Single Transaction Action fires, because the App in question still has the default method of calculating Fields enabled, the App will continue to recalculate the Fields using the default, less performant approach.

In order to prevent this from happening you must also disable the default method of calculating Fields in your App. To do so, follow the steps below:

  1. Navigate to your Apps' Settings page.
  2. Uncheck the Evaluate Calculated Fields checkbox.
  1. Click Save to save your changes.

Use Initial Values Instead of Calculated Fields for Simple Field Populations

Did you know that you can use a Field’s initial value to preform simple Liquid calculations? In certain situations, this approach can be more performant than marking as a Field as being “calculated.”

In many cases, you’ll want to programmatically assign a static identifier to a Record. For example, a Matter Number or a Contract Number. Since this number should never change, it would be a bad idea to set this value by making the Field in question as “calculated.” If you did so, you’d be asking Onit to recalculate and repopulate this Field every time that the Record was modified, which would add needless processing time to your App (since the calculated value would always remain the same). Instead of making this Field “calculated,” you should set the value of this Field once (and only once) by inserting Liquid into the Field’s Initial Value property (in the App’s Wizard).

In the screenshot example below, a Matter Number field is set by concatenating together the following values: the four-digit year when the created was created, a hardcoded dash, and the Record’s Onit Atom Number.

Use Numeric Calculation When Appropriate

When performing math calculations across related Records, Numeric calculations are very often the better choice, over Liquid calculations.

For example, let’s say that you have an App named Matter that is the parent of an App named Invoices. In Matter, you want to create a field that shows the total of all child Invoices (all summed up in a grand total for that parent Matter). While you could technically construct a Liquid calculation that would perform this math, that would be a bad idea, for two reasons:

  1. As compared to using a Numeric calculation, using Liquid in this situation would be vastly less performant.
  2. The Field in the parent App would be much more likely to get stale as child records were created and updated. One major advantage with Numeric calculated Fields is that, without you having to add in any extra configuration, Onit will perform the necessary recalculations to re-run Numeric calculations whenever one is needed. This is not true for Liquid calculations, which will only re-run when a Record is modified or when a recalculation-related Action (that you must create) runs.

Numeric Field calculations allow you to calculate the sum, average, minimum, or maximum from a Currency, Integer or Decimal Field across related Records. Additionally, Numeric calculations offer a filter that Liquid calculations do not, letting you to perform calculations on Records that match specified parameters.

For more information on Numeric calculations see our tutorial on this topic.

Always assign an initial value to Checkbox Fields

Checkbox Fields that do not have an initial value and are not interacted with by the user have a value of Null, not false. To avoid throwing off reporting or configuration, always give Checkbox Fields an initial value of true or false.

Background Actions in Email Received Business Rules

Any action tied to an Email Received Business Rule should always be placed in a Conditional Compound Action (CCA) and backgrounded so it can run asynchronously.

The email service that Onit uses to facilitate receiving emails expects all of the Actions fired by Email Received to be short-running (i.e., to collectively start and end relatively quickly). If you do not fire an async action off of an Email Received Business Rules, you may run into unintended and unexpected behavior if your Actions take a long time to complete. For example, Onit may abandon your Actions before they complete, and start the process over again.

To background a Conditional Compound Action, check the Run in Background box while configuring the Action.

Questions to ask if you are experiencing poor performance

  • Are Fields being calculated in the settings?
  • Are there any un-used phases causing extra phase change rules to fire? (E.g., Auto Open MV on Create in VATM.)
  • Is the Pending phase used or can it be removed?
  • Can any notifications be backgrounded?
  • Can any Conditional Compound Actions be backgrounded?
  • Can any set-related actions (update related, set related phases, etc.) be backgrounded or avoided?
  • Can any find/create Actions be changed to relate-to-transaction?
  • Are there any unnecessary Update Transactions running? Can we combine any? (E.g. set Legal Entity BelongsTo)
  • Are there any Update Related Transactions that can be changed into Run Action on Transactions?
  • Are there any duplicate loops (especially endorsements) that can be combined or set as a Field?
  • Are there any list lookups on Field calculations that we can set with a UI action?
  • Are there any list lookups that we can optimize using list_lookup_atom?
  • Are there any for loops in field calculations that we can optimize or remove?
  • Is MM being replaced on initial create (in Matter)? We can prevent this with a flag Field.
  • Are there any manual sums in Update Transaction Actions that we can get with a numeric calc?
  • Are there any conditions with loops in their logic?
  • Are there any buttons with conditions that have loops in their logic?
  • Can we set conditions to prevent unnecessary actions from running?
Previous Article Creating a Shared Dashboard
Next Article Crash Course on Security

© 2020 Onit, Inc.

docs.onit.com contains proprietary and confidential information owned by Onit, Inc. that is subject to copyright. Onit presents it exclusively to you for your sole use in conjunction with using Onit products. No portion of the materials contained herein may be used for any other purpose. No portion of the materials contained herein may be shared with third parties or reproduced in any form.