How to View a Diagnostic Report of Your Application Composer Changes

The Configuration Analysis report provides a diagnostic analysis of all your custom application changes that were made in Application Composer. The report lists any non-recommended Groovy-related patterns that can impact the runtime scalability of your application. It also lists high-level corrective actions for the same.

You can download the report in an HTML format for a maximum of 5 objects.

To generate the report:

  1. Make sure that you're in an active sandbox session.

  2. In Application Composer, select Metadata Manager in the Common Setup pane.

  3. In the Configuration Analyzer section, click Generate Configuration Analysis Report.

  4. On the Generate Configuration Analysis Report dialog, select the objects for which you want to generate the diagnostics report.

  5. Click Generate Report.

The following is a sample report:

This image is an example of a Configuration Analysis Report.

The following table lists the Groovy-related patterns that can impact the scalability of your application.

Pattern

Details

More than 10 object triggers per object

For better performance, minimize the number of triggers to 10 per object.

The report lists the objects with more than 10 object triggers, along with the count and corresponding object trigger names.

Object functions with special characters in their names

Avoid object functions with special characters (like " , ' , ( , ) , * , / , \ , # , @ , +, or ! ) in their names. Some characters are already blocked by the application, but some aren't and may be allowed during object function creation or while renaming existing object function names. The report lists any such object functions with special characters.

Web services registered in Application Composer and invoked from triggers and object functions

The Web Services UI in Application Composer is used to support external web services for integration purposes. Don't register and use internally available web services.

The report lists any web services that are internally deployed on the same host.

Validation exceptions thrown from triggers instead of directly using validation rules

Triggers are generally used for standard processing logic, such as record creation, updates, and deletions, or to assign programmatic default values to fields. Don't use triggers to perform validations. Instead, use field-level or object-level validation rules.

The report lists all the field-level and object-level triggers that throw validation exceptions.

Complex formula fields

Use formula fields for simple computation logic only, since they're evaluated whenever referenced. If you use complex logic, it may have a performance impact due to additional evaluation overheads. For example, using executeQuery() in formula fields impacts performance and using certain APIs like setAttribute() can cause record lock issues.

The report lists all the formula fields where you've used executeQuery() or setAttribute().

Number of field types per object

The performance guidelines recommend that you limit the number of long text attributes for an object to 4 to optimize performance. It also recommends that you limit the number of dynamic choice list fields to 15.

The report lists any object where the number of long text and dynamic choice list fields exceed their recommended limit of 4 and 15, respectively.

newView() API inside a loop

While implementing business logic, make sure that you keep the number of queries minimal. Avoid invoking the newView() function inside loops as this could cause extra queries.

The report lists any occurrences where you've used the newView() API inside any loop.

Long text fields on landing pages Restrict long text fields to Create and Detail pages, as appropriate.

Using long text fields can impact performance. So, avoid adding long text fields to landing pages. Querying a long text field for multiple records on a summary page can impact performance.

Number of custom subtabs per details page layout Limit the number of custom subtabs per details page layout for optimal performance. Don't exceed 10 custom subtabs per layout.

Custom sub tabs and custom layouts are essential features that make a page dynamic. You create a custom layout when you want to display a different set of fields/tabs based on roles, record type fields, or conditions (implemented as Groovy expressions). However, you want to be sure to use custom sub tabs and custom layouts only when they're used to support a business use case. A custom layout puts a lot of information in metadata, so many layouts can degrade the performance of the runtime flow because the MDS loading time is higher.

Actions and buttons with the setAttribute() exposed on pages Avoid using the setAttribute() API inside a Groovy function used for actions, buttons and links.

Groovy expressions written for actions, buttons and links can execute multiple times during the page life cycle. So, make sure the Groovy logic is safe to run multiple times. Don't write any custom business logic to update object records, because repeated execution of such scripts can lead to errors.

Number of object workflows per object Limit the number of active workflows per object to fewer than 10 and use a light-weight expression for the Groovy evaluation.

Even though the execution of an object workflow is asynchronous, during the triggering action (Insert/Update), it evaluates conditions and publishes the events. As a result, complex Groovy logic or a large number of object workflows can impact the runtime performance of the application. Hence, it's important to restrict the number of active object workflows per object.

Object workflows with a field update action Avoid field update actions for optimal performance.

You can instead incorporate the action inside a trigger and handle it as a synchronous action.

Use field update object workflows only if you need an execution schedule or if the business use case demands an asynchronous execution of the field update.

Validation rules with the setAttribute() API For optimal performance, don't implement any business logic other than validations inside an object or a field validation rule Groovy script.

You should only use validation scripts for validation. For example, you shouldn't use setAttribute() values in a validation script.

Number of layouts per object
For optimal performance, follow these guidelines when working with custom layouts:
  • Minimize the number of custom layouts to 20 or less.
  • Avoid creating layouts frequently and making them inactive later. Marking a layout as "Inactive" only hides it from the UI.
  • Avoid the usage of Groovy expressions to differentiate layouts. Always, consider other options such as Roles and Record Type fields.
Web service invocations from Before Insert and Before Update triggers

Try to implement business logic without relying on web services, if possible.

Consider whether the same logic can be executed in an asynchronous way. If you can execute the Groovy logic asynchronously, then the parent transaction (object record creation) will not wait for the completion of this Groovy. Instead, the Groovy logic is executed in the background, without impacting the UI performance.

However, if your business requirement absolutely requires it, note the following:
  • Ensure that the web service call is executed at the right time, ideally as late as possible in a commit life cycle to ensure the validations in the current transactions are passed. Otherwise, it may lead to data inconsistency, because the web service call will commit automatically. Also, consider the After Commit, After Delete, and After Change Posted to DB triggers for logic involving Web Services.
  • Avoid using web services to manipulate a business object which is directly accessible from Groovy.
  • A before update trigger to call an external web service to sync data is a time-consuming process. The entire commit has to wait for the web service response, impacting the total runtime performance. Instead of doing this with triggers, you can write an object workflow that calls a Groovy expression on the update of a record and syncs to the external system. This asynchronous method of syncing data with the external system reduces the UI overhead.
Web service invocations inside a loop Avoid the use of web service calls inside a loop. Consider if it's absolutely necessary and if it can be done asynchronously as an ESS job or as a straightforward Groovy update.
Object workflows calling sendNotification()

Avoid using the adf.util.sendNotification() API from the context of an object workflow.

ExecuteQuery API inside a loop Avoid using executeQuery() inside loops, wherever possible and consider if it's absolutely necessary. If yes, it should be done as per Groovy Scripting guidelines, by using bind variables to achieve better performance.
ExecuteQuery before getEstimatedRowCount

Avoid executeQuery() if you're using the getEstimatedRowCount() API.

If the requirement is to get the row Count, simply use the getEstimatedRowCount() API. It will return the row count from the database. You don't need a separate executeQuery() execution.

ExecuteQuery called from dynamic layout advanced expression

Avoid the usage of complex Groovy expressions with executeQuery() in dynamic layout advanced expressions.

Always consider other options, such as Roles and Record Type fields.

ExecuteQuery called without any selected attributes

When performing a business object query, it's important to indicate which fields your code will access from the results. This includes fields your logic plans to update as well.

By doing this proactively, your application gains two advantages:
  • You retrieve only the data you need from the database.
  • You avoid an additional system-initiated query to "fault-in" missing data on first reference.
This can be achieved using the selectAttributesBeforeQuery API. Ensuring this will improve the performance of the Groovy scripts.

For more details, see "Explicitly Select Only the Attributes You Need" of the Groovy Scripting guide.

Number of searchable fields per object

Keep the number of searchable fields restricted to 100 or less.

You can reduce the performance impact on a list page by reducing the number of searchable fields. The recommended practice is to determine which fields your user will most often need to perform searches for the object. Then, when you create a new custom field, clear the Searchable option, unless it's a necessary search field. This will reduce the performance impact of needing to populate the searchable attributes list whenever Advanced Search is used.

Field updatable expressions calling the SetAttribute API

Follow the below guidelines when using field updatable expressions:

  • Don't set any object attribute values inside an updatable Groovy expression.

  • Avoid using object functions in an updatable Groovy expression.

  • If the use case requirement is that an attribute's required or updatable property changes at runtime, then consider using simple expressions in the condition.

  • If the use case requirement is to make an attribute read only in a single page, you can use the layout level UI properties.

  • If the updatable property for an attribute can have single value on different functional flows, and this value is True or False, then you shouldn't use expressions. Instead, use the absolute values for the Required or Updatable property.

Global functions in updatable and required field level expressions
Follow the below guidelines when using updatable or required field expressions:
  • Avoid using global function invocations as much as possible in required or updatable Groovy expressions
  • If the use case requirement is that an attribute's required or updatable property changes at runtime, then consider using simple expressions in the condition.