Skip to main content

Trusted Advisor

OutSystems

Code Analysis Patterns

Trusted Advisor an internal tool designed to support Success Plans therefore with limited availability.

To know more check this FAQ.

Up to date list of code patterns analyzed by current version of Trusted Advisor.

Check Release Notes to know when patterns have been included and/or changed.

Additional information on some patterns can be found in Best Practices.

Architecture

  1. Lack of module classification

    Module not placed in one of the Canvas layers in Discovery

    Impact

    Not classifying a module prevents the discovery of architecture patterns

    How to Fix

    Classify every module according to its nature matching the Canvas layers. If a module has more than one nature - e.g. provides end user functionality and also contains reusable business services - it should always be classified at the top layer. In this example, it would be an End User module.

  2. Orchestration module providing services

    Orchestration module providing services

    Impact

    An Orchestration module is not supposed to provide services - any reference to it normally reveals the existence of misplaced reusable code. Furthermore, being in the top layer, any reference to an Orchestration module will inherit the entire hierarchy of modules beneath it.

    How to Fix

    Check Discovery for which elements are being consumed. Extract those elements and move them to Core/Library modules, according to the concepts. Check the Forge component Refactor for more support on this operation.

  3. End User module providing services

    End User module providing services to non-Orchestration modules

    Impact

    An End User module is not supposed to provide services - any reference to it normally reveals the existence of misplaced reusable code. References to an End User compromise life cycle independence between applications and typically pull a lot of indirect unwanted references.

    How to Fix

    Check Discovery for which elements are being consumed. Extract those elements and move them to Core/Library modules, according to the concepts. Check the Forge component Refactor for more support on this operation.

  4. Core module consumed by Libraries

    Core module providing services to Library modules

    Impact

    Library modules are not supposed to consume services from a core module. They need to be fully isolated with no business logic or reference to a business module, otherwise consuming a library might bring unexpected impacts.

    How to Fix

    Check Discovery for consumed elements. Either they should be moved to a Library module, if they don't have a business nature, or you need to question if the logic in the Library modules that are consuming the core elements is not misplaced.

  5. Cyclic references between modules

    Cyclic references between two Library or two Core modules

    Impact

    Cycles between modules usually mean a wrong service abstraction and bring unwanted impacts in both development and runtime

    How to Fix

    Understand the conceptual relation between modules involved in a cycle, to decide which module is not supposed to consume the other. Check Discovery for the wrongly consumed elements and decide whether moving them to the module that is supposed to be consumed makes sense in terms of conceptual abstraction, or if there is a need to move them to a composition module on top of the two.

  6. Orchestration application providing services

    Orchestration application providing services

    Impact

    An Orchestration application must be fully isolated, not providing services - any reference to it normally reveals the existence of misplaced reusable code. Furthermore, being in the top layer, any reference to an Orchestration application may inherit the entire hierarchy of modules beneath it.

    How to Fix

    Check Discovery for which modules are being consumed and move them to Core/Library applications, according to the concepts

  7. End User application providing services

    End User application providing services to non-Orchestration applications

    Impact

    An End User application is not supposed to provide reusable modules for other applications. References to an End User compromise life cycle independence between applications and typically pull a lot of indirect unwanted references.

    How to Fix

    Check Discovery for which modules are being consumed and move them to Core/Library applications, according to the concepts. Check the Forge component Refactor for more support on this operation.

  8. Core application consumed by Libraries

    Core application with modules consumed by Library applications

    Impact

    Library applications are not expected to consume modules from a Core application, since they should not rely on business related services

    How to Fix

    Check Discovery for consumed modules. If they are Libraries, they should be moved to a Library application. If they are Core modules, you need to question if the logic in the Library modules that is consuming those modules is not misplaced.

  9. Cyclic references between applications

    Cyclic references between two Library or two Core applications

    Impact

    Cycles between Core or Library applications usually mean a wrong isolation of reusable modules that leads to consumers being unnecessarily impacted when requiring only one of the applications

    How to Fix

    Understand the conceptual relation between applications involved in a cycle, to decide which application is not supposed to be consumed by the other. Check Discovery for the wrongly consumed modules and decide whether moving them to the application that is supposed to be consumed makes sense in terms of conceptual abstraction.

  10. Client and Server side entities not isolated (Mobile only)

    Both client and server side entities and logic implemented in the same module

    Impact

    Supplying client-side logic and entities together with reusable server-side definitions does not promote the optimized design of mobile functionality. While server-side logic can be extended to support several applications, generalizing client-side logic for the same purpose tends to generate redundant information and useless sync logic for each specific mobile App.

    How to Fix

    Client-side logic should be catered to the use cases of each mobile application. The normal pattern is to have a generic server-side module around a concept, e.g. Accounts, and a specialization for each mobile app that handles Accounts. For instance, if you have a Mobile Banking (MB) application for end users and a Mobile Agent (MA) application for agents, on top of the server-side core service Account_CS module, you should create the MB_Account_CS and the MA_Account_CS modules with the specialized client-side DB and logic for each each mobile app.

  11. Monolithic mobile UI module (Mobile only)

    All mobile UI content is being kept in the same module

    Impact

    Due to technical requirements for Native Build generation, all screens of a mobile application, including the exception flow and the menu must be placed in the same eSpace. Hence, the UI screens module can become a monolithic eSpace that keeps growing. This will make different lifecycles for different processes hard to maintain.

    How to Fix

    Keep module with all the Screen Flows but keep screens only as layout containers. Supply UI content in webblocks from different Core widgets modules, organised per functional area to allow different lifecycles per such functional area.

  12. Public entities not read only

    Public entities should be exposed as read only

    Impact

    When public entities are not exposed as read only, their respective entity actions for creating, updating and deleting records are available to be referenced by any consumer. These entity actions directly affect records in the entity, allowing any consumer to perform inconsistent and potentially destructive changes without considering the complete semantic and validation of the operation.

    How to Fix

    Enable "Expose Read Only" in public entities and create your own public actions for creating, updating and deleting records of those entities, abstracting all validations, business rules or other side effects such as audit trailing or notifying changes to another system.

Performance

  1. Unlimited records in aggregate

    Number of records fetched from DB is not set in aggregate

    Impact

    More records are fetched from the database than are used by the application, resulting in useless I/O and memory consumption

    How to Fix

    Set the Max. Records parameter of the aggregate to the required usage

  2. Unlimited records in SQL query

    Number of records fetched from DB is not set in SQL query

    Impact

    More records are fetched from the database than are used by the application, resulting in useless I/O and memory consumption

    How to Fix

    Use ROWNUM (for Oracle) or TOP (for MS SQL Server) in the SQL query to limit the number of records according to required usage. Be aware that in SQL queries the Max. Records parameter only limits the amount of records displayed, not the number of records fetched from the database.

  3. Query data in Viewstate (Web only)

    Screen actions are using query data obtained in preparation

    Impact

    Page size affects usability since it will increase the time to submit a form. If you use screen preparation data on screen action, that data will be saved in the page's viewstate. Since the viewstate is a part of the page, it is sent to the client with every requested page. The viewstate is also sent back to the server on a post, postback and AJAX request.

    How to Fix

    Avoid using data from screen preparation in screen actions. For instance, instead of using the TableRecords record data, send the Id of the row as a parameter of the screen action and fetch the data from the database again as needed. If you need the full list of records, simply refresh the query - it is better to rerun the query server side than to send the data back and forth through the viewstate.

  4. Large variable in Viewstate (Web only)

    Screen local variable with large type is being used in a screen action

    Impact

    When local variables defined at screen level are used in screen actions, their data is saved on the screen viewstate. Viewstate is included in the response of all requests made to the screen (both first load and AJAX requests). Additional data in viewstate, especially with large data types, increases response size and loading time in the browser.

    How to Fix

    Avoid using screen local variables in screen actions

  5. Timeout in Server Calls (Mobile only)

    Long timeout in server action call

    Impact

    Default timeout for server action calls is too long or an explicit timeout in a server call is too long (more than 5 seconds). In a mobile application, a server call should be efficient. 5 seconds is all it takes for a device to go to sleep mode or lose network.

    How to Fix

    Prepare and cache data in advance in the server side to be promptly available when required. The timeout should also be reduced to fail quickly (with a "retry later" message), except on explicit operations, because it's acceptable for those to take a little bit longer.

  6. Inline JavaScript

    Inline JavaScript defined in an unescaped expression

    Impact

    Javascript defined at the screen/web block level is optimized by OutSystems. For example, if you have the same web block in your screen twice, it’s only included once. It also improves maintenance.

    How to Fix

    Define JavaScript at the screen/web block level instead of in inline expressions

  7. Inline CSS style

    CSS style being defined as an extended property of a screen element

    Impact

    CSS and HTML should be kept separated. Inline styles are inefficient, harder to maintain and make your HTML bigger.

    How to Fix

    CSS should be centrally managed in the application style guide to avoid loading a proliferation of CSS files. If the CSS is too specific for one screen or one webblock, define your CSS at the screen/web block level instead of doing it in extended properties.

  8. Dynamic inline parameter

    Dynamic expression used in an expanded inline parameter of a SQL Query

    Impact

    Inline parameters that change too often don't allow the database to optimize execution plans, since it keeps generating different queries

    How to Fix

    Change query to remove the frequently changing inline parameters. Consider selecting specialized queries depending on the parameter or using sub-queries or temporary tables.

  9. Site property update

    Site property being updated in the application logic

    Impact

    When a site property is updated it invalidates the cache of the eSpace. This causes subsequent accesses to cached data to have to be fetched from database or recalculated in the application logic, which may result in a performance hit.

    How to Fix

    Avoid changing site property values programmatically by using alternatives such as storing the value in the database

  10. Inefficient empty list test

    Using the Count property of an aggregate or SQL query to check if results were returned

    Impact

    For performance purposes, OutSystems query optimizer assures that output of aggregates and advanced queries returns only necessary data to feed screen. So, Count property needs to execute an additional query to get the total number of registries.

    How to Fix

    Use List.Empty property to test for lack of results instead of List.Count

  11. Inefficient query count

    Counting query results using an inefficient query

    Impact

    SQL queries are usually designed for retrieving data and may perform joins and fetch extra data, needed for processing but that are not required to count the query results. When using the Count property of a query, the same query is executed to count the results, which is inefficient since it will use the same query definition.

    How to Fix

    Use a simplified SQL query just to count the results in a more efficient way, removing unneeded extra data and joins

  12. Inadequate data preparation

    Query is being executed inside a loop

    Impact

    Each run of the query may be fast enough, but when inside a loop, the total amount of DB effort may be considerable.

    How to Fix

    Often executing only one complex query to obtain the required information is better than executing a simple aggregate in a for-each loop. Also check if the entity model copes with your needs - when the data base model is inadequate, getting the required information proves to be too complex to be fetched by a single query.

  13. Large session variable

    Session variable with large or complex data type

    Impact

    On all screen requests, the current session's data is loaded from the database. This data is a binary including all session variables content. If large or complex variables are used, each request will take longer to process the session data (include serializing and deserializing it) increasing response times and causing contention in all concurrent requests.

    How to Fix

    Store this data in your own entities using the session identifier as primary key and fetch it only when needed. Keep the session limited to context information that is useful in every request.

  14. Large image or resource

    Large images or resources included in module

    Impact

    Large images and resources have different kinds of impact in an application. If large images are being included in a screen to be displayed to the user, they need to be fetched from the server, increasing bandwith usage and request processing time in the browser (even if they have their width/height set to lower values). On the development side, a module with large images and/or resources takes more time to be saved and published, consuming additional bandwidth when being uploaded/downloaded from the server.

    How to Fix

    Reduce the size of images to the minimum needed to be correctly displayed to the user. Avoid including big resources in modules.

  15. Avoid Server Calls (Mobile only)

    Server actions being called in client events

    Impact

    Server calls should be avoided on client events (On Initialize, On Ready, On Render, On After Fetch). These events are serialized in the request and server calls may tremendously impact the wait time to render the screen.

    How to Fix

    A mobile app should rely on local storage for performance and offline. Server side calls should be limited to synchronization calls (typically performed on business events fired in screen actions, session start or online events) and online transactions (typically performed in screen actions)

  16. Non Optimized Local Data Fetch (Mobile only)

    Local data fetch performed in client events

    Impact

    Local data fetch should be avoided on client events (On Initialize, On Ready, On Render). These events are fully serialized, not taking advantage of the parallel fetch of data while the screen is being already rendered.

    How to Fix

    Retrieving data should occur inside data fetch calls to enable the parallelization of several data fetches and the screen render. If a data fetch depends on a previous fetch, use the On After Fetch event.

Security

  1. Disabled button

    Disabled actionable button, that is still visible

    Impact

    Doesn't prevent an experienced user from performing an unauthorised action

    How to Fix

    Use the Visible property instead of the Enabled property.

Maintainability

  1. Missing description on public element

    Required description on public elements

    Impact

    Meaningful descriptions in public elements, entities and attributes make their purpose and expected behavior more clear. It’s crucial when consuming closed modules, as you cannot look at the implemented logic.

    How to Fix

    Add a description to all public elements and to their parameters (or attributes in the case of Entities or Structures). If parameter/attribute names already follow well established naming conventions, you can choose not to add a description (e.g. Id, Name, Label, Description, CreatedBy, UpdatedBy, CreatedOn, UpdatedOn).

  2. Unidentified public action managing transaction

    Public action not describing that it manages the DB transaction

    Impact

    Explicit CommitTransaction or AbortTransaction operations may affect your application as they may commit/rollback data in unexpected places. Since the content of public reusable actions may not be acessible, it is extremely important to explicitly describe when transaction is being handled inside it, in order to avoid unwanted runtime behaviors.

    How to Fix

    Clearly identify in the description of the public action that the transaction is being managed and in which cases is it being committed or aborted.

  3. Avoid hard-coded literals

    Avoid hard-coded literal values

    Impact

    The maintenance and natural application evolution is compromised each time a hard-coded literal is used. Since there is not an easy way to find an hard-coded literal spread into the logic, each time it needs to change, the maintenance effort, the risk and unpredictable behavior are severely increased.

    How to Fix

    Keep these values in configurable entities, static entities or site properties

  • Was this article helpful?