Adaptable Solutions (learning paths)

Introduction

Notes about the Mendix learning paths covering Adaptable Solutions:

  1. Become an Adaptable Solution Developer
  2. Implement and Upgrade an Adaptable Solution
  3. Create an Adaptable Solution
  4. Secure Your Adaptable Solution
  5. Manage Your Adaptable Solution Lifecycle
  6. Design the UX/UI of Your Adaptable Solution
  7. Brand Your Adaptable Solution

Development of Adaptable Solutions is available from Mendix 10.0 and up (enable it in app settings > solution tab).

Key takeaways

Adaptable Solutions sits between off-the-shelf (COTS) software and bespoke applications specifically tailor-made for a client. Solution development requires a different approach to application development.

It offers additional possibilities to protect your IP, create a generic core, allow customization and still have a (relatively) easy path for further development & upgrades.

  • Solution development requires a different approach and mindset.
  • Create a solid core and Implement customizations on the extension points and implementation modules.
  • Shift of responsibilities: Upgrades, Maintenance, License compatibility (checks), Marketplace content support go via the solution.
  • Project and modules will be structured differently:
    • Elements can be hidden (mainly in design time: only source code is hidden in Studio Pro, runtime remains unchanged), more layering/interfacing and separation of concerns
    • Module types can be set to: App, Add-on and Solution, and Export level can be set (on documents) to Usable or Hidden
    • Module Security is permission-based
    • Standard components and customizations need to be separated

Quirks

Some quirks and things to consider when developing Adaptable Solutions:

  • Solution and Implementation require Mendix Git (private git not supported).
  • Implementation needs to be on the same Mendix version to be able to import or update the solution.
  • ISV will be responsible for supporting the community marketplace content within the solution.
  • Imported components need to be checked for compatible licenses.
  • Upgrades (Mendix & Marketplace modules) go via the solution.
  • Use PostgreSQL or Microsoft SQL Server database for local development to see the Data Synchronization Commands (and prevent accidental data loss).
  • Keep Check Security turned on for the core roles.
  • Pages in a solutions module cannot be called directly, make sure a microflow or nanoflow is present that calls that page.
  • Snippets should always be placed in an implementation module if they should be freely usable by the consuming side.
  • Entities, attributes and associations will only be hidden design-time. In Runtime these are visible (e.g. Mx Model Reflection, Database).
  • Java and JavaScript implementations in a protected module will remain visible when the mxmodule file is unzipped. If you want to protect the code you wrote, you can respectively add the code to a compiled/obfuscated jar or a minified npm package.

1. Become an Adaptable Solution Developer

An Adaptable Solution

  • Ideally: 80% is Immutable Core (IP Protected), remaining 20% is customer adaption (Adaptable Core + Customer Specific Extensions)
  • Scenarios for adaptability: UI/UX, Data, Logic, Integrations

The Mendix Solutions Kit

Module 522 The Mendix Solutions Kit

  • Protected Modules
    • Manage risk of loss of intellectual property (IP)
    • Lock down editability of parts to ensure no changes are made by others
  • Solution Lifecycle Management
    • Upgrade adapted solution implementations through visual merge mode
  • Adaptation Insights
    • Provide insight into the extent of implementation’s adaptations
    • Dry-run upgrades to get insight in maintenance and upgrade effort

Building a Solution

Module 630 Building a Solution (with the Mendix Solutions Kit)

Key inputs and architectural considerations:

  • Adaptability - To what extent will you make your solution adaptable (if at all)
  • Configurability - What can be configured in the client (at runtime, like templates) vs in Studio Pro (design time, like validations, pages, workflow)
  • Scalability - Designing a solution that can support multiple implementations customers regarding both scope and performance
    • Scope Scalability (handle many use cases)
    • Performance Scalability (efficient use of resources)
  • Security - Ensure security by design
  • Maintainability - Taking into account release cadence, branching, versioning, deployment, etc.
    • Proper customization points

2. Implement and Upgrade an Adaptable Solution

Set up the Adaptable Solution

Module 610: Set up the Adaptable Solution

Concepts of an Adaptable Solution:

  • Each implementation gets an instance of the solution based on a common core.
  • Not a fork (which can no longer be upgraded)
  • Not a Software-as-a-Service (only runtime configurable)
  • Receive upgrades over time and still retain design time customizations

Importing a solution (.mxsolution) needs to happen on the same Mendix version, at this moment you cant import a 9.24.1 mxsolution into 9.24.22

It appears that adaptable solution implementations (and probably the solution itself) can only be stored on Mendix git servers and not a private git server. I assume this is due to Adaptation Insights…?

Changes are made on the Implementation modules, such as extension entities and microflows.

Upgrade the Solution

Module 611: Upgrade the Solution

Upgrading a solution (.mxsolution) requires all changes to be committed first

Update solution, “push version to the ‘solution-releases’ branch”, why the branch? I assume it’s to be able to merge the changes into the current branch? And then it gets deleted…

Resolve Conflicts

Module 612: Resolve Conflicts

Conflicts are resolved the regular way (interactive merge). Once conflicts are resolved you don’t have to fix them again in the next upgrade.

Upgrade Marketplace in Mendix

Module 613 Upgrade Marketplace in Mendix

Marketplace modules with data in the database included in the solution should never be upgraded in the customer implementation, but always through a solution release upgrade. Otherwise, this may lead to loss of data.

Never upgrade a solution implementation to a higher minor or major version on its own (for example, 9.18 to 9.20, or 9 to 10, respectively) when the solution has not yet been upgraded.

Process for upgrading a solution implementation to a higher minor or major version:

  1. Upgrade the solution implementation to the targeted Mendix version and commit. If this causes errors, commit with the errors.
  2. Upgrade the implementation with the new version of the solution (all errors in the part of the application model that came from the solution template should be gone).
  3. Apply the needed changes to make the adapted part of the model compatible with the new version of the platform.

3. Create an Adaptable Solution

Solution Modules

Module 532: An Adaptable Solution

  • Adaptable flow – A microflow or nanoflow with a default implementation created in an implementation module, but called from a protected microflow or nanoflow in order to enable additional logic created by the consuming side.
  • Add-on module – A Mendix module with protected options enabled. This module does not allow for cross-module hidden associations.
  • App module – A Mendix module as you have known it for years. One without any possibility of IP protection.
  • Consumer mode – The mode of viewing a Solution in which hidden documents, entities, attributes and associations can’t be seen and usable items can be used, without showing the actual implementation.
  • Documents – Anything you can see in the project explorer of Studio Pro (e.g. microflow or page).
  • Export level – The visibility level of an item while exporting the module or application as a solution or add-on module or project. The export level can be set to Hidden or Usable. Hidden will hide the item. Usable will show the existence, but not the implementation of the item.
  • Extension entity – An entity created for the consumer of a Protected application to extend the protected entity with new attributes and associations.
  • Extension flow – An empty microflow or nanoflow created in an implementation module, but called from a protected microflow or nanoflow in order to enable additional logic created by the consuming side.
  • Implementation hiding – Supports Protecting the intellectual property of an application by hiding the implementation of the application.
  • IP – Intellectual property.
  • Separation of concerns – A general concept in programming languages where every piece of code is responsible for one concern and only handles that concern. By applying separation of concerns properly in your application, the application will become very modular.
  • Solution module – A Mendix module with protected options enabled. This module does allow for cross-module hidden associations and document references (e.g., microflow calls).
  • Source mode – The mode of viewing a Solution in which the full source code is exposed and editable to the user.

Use of Solution Modules in Solutions

Module 533 Use of Solution Modules in Solutions

Module types

  • App module: default module, no protection abilities, used for implementation modules (use _Impl suffix)
  • Solution module: can be protected, contents immutable, depending on export level the domain model can be viewed (or not)
  • Add-on module: can be protected (same way as solution module), stand-alone, no or very few dependencies

Export levels

  • Usable: everything in this module is visible and usable (not mutable) by the consuming side (similar to the Mendix System module). Logic in Microflows and Nanoflows will not be visible (only input and output).
  • Hidden: default option for a protected module, all contents of the module will be hidden.

Hidden documents

  • Pages in a solutions module cannot be called directly, make sure a microflow or nanoflow is present that calls that page.
  • Snippets should always be placed in an implementation module if they should be freely usable by the consuming side.
  • Entities, attributes and associations will only be hidden design-time. In Runtime these are visible (e.g. Mx Model Reflection, Database).
  • Java and JavaScript implementations in a protected module will remain visible when the mxmodule file is unzipped. If you want to protect the code you wrote, you can respectively add the code to a compiled/obfuscated jar or a minified npm package.

Hiding certain implementations can aid the Solution developer:

  • Hide complexity for the consuming developer
  • Restricts the amount of customizable elements (more predictable)
  • Upgrade effort reduced due to limited customization options

If in doubt whether to open something or not, it’s probably easier to hide it (at first). It is always possible to open something in a new release, but hiding it, as mentioned above, can be challenging.

Implement and Upgrade

Exporting

  • Solution Package: export with protection enabled, add-on and solution modules will be transformed into .mxmodule format.
  • Source Package: unprotected, nothing will be hidden.

Importing

  • Customers should import Solution Package (.mxsolution) and upload it to their own Team Server respository (to allow customer access and prevent IP exposure)
  • Use PostgreSQL or Microsoft SQL Server database for local development to see the Data Synchronization Commands (and prevent accidental data loss)
  • Big changes and new features: update solution version number (and update all modules to same number), small changes and fixes): update module version number

Adapt and Extend

Extension entity

Add an entity in the Implementation module, two options:

  • Inherit from the entity (generalization) in the Solution module:
    • Downsides: Hard to convert/migrate, database performance impact, create logic complexity.
    • Advantages: Overwrite entity access of the core entity.
  • Use an association (1-1 or 1-n, the core entity should always be owner) between core and extension entity
    • Downsides: Additional logic to ensure data consistency (creates, deletes).
    • Advantages: Faster, attributes are easily usable.

Extending logic

Extension flows and adaptation flows

  • Extension flow:
    • Placeholder microflow/nanoflow in the implementation is called from the core module.
    • Additional logic on top of protected flows.
    • Don’t change the input and output of extension flows to avoid merge conflicts and/or errors.
    • Identify extension points early on.
  • Adaptation flow:
    • Facilitate or predefine some logic that can be changed.
    • Should not contain critical logic (can be changed or deleted in the implementation).

Use EXT_ as a prefix for both, so that they are recognizable

Expand

  • Adapting: within the solution, contains the protected core modules and adapted module(s)
  • Extending: within the solution, contains the protected core modules and adapted module(s) and extension module(s)
  • Expanding: solution interacts with other (Mendix) apps & solutions through APIs, connectors, Data hub etc.

4. Secure your Commercial-Solution

Identify Module Roles

Module 518: Identify Module Roles

Module roles in an Adaptable Solution are created as if they are permissions, types:

  • Core roles: to access core functionality and data. (e.g. TicketEditAll, TicketEditCreated, TicketEditGroup, TicketEditMy)
  • Add-on roles: dealing with additional logic (e.g. _AR_TicketApprover) indicated with prefix eg. _AddOn_ or _AR_.

Combining multiple module roles on a project role can have a performance impact as the SQL queries become more complex (CASE WHEN).

Complex Module Security can be a sign that the module should be split.

Implementation

Only use the add-on roles solution when it meets the following conditions:

  • It is a core module that is not expected to be modified. If there are modifications, you lose the ability to update and you might as well modify the module roles.
  • There is a high probability that you need to modify permissions depending on the customer.

Best practices and workarounds for Add-on Application Roles

  • Keep Check Security turned on for the core roles.
  • Use conditional visibility on pages and grids where you make assumptions on data access if those pages are accessible from the navigation. This will prevent the security checking feature from generating errors on those pages.
  • Use non-persistable entities for additional attribute access.
  • Take care of failure scenarios (add-on user roles don’t function stand-alone)
  • Be careful modeling create permissions as add-on roles (editability during the creation phase is needed and tricky)

5. Manage Your Commercial Solution Lifecycle

Feedback Process

Module 506: Feedback Process

  • Build: Turn industry knowledge into reusable adaptable solution templates

  • Implement: Adapt template into customer-specific solutions, provide Mendix skills and maintenance & operations

  • Consume: Use solution

  • Feedback: all three parties play a role in the feedback cycle

  • Developing and Implementing the solution are two distinct responsibilities (and teams)

  • Feedback: not all feedback needs to be implemented in the solution (decide) it can also be solved by the implementation team.

Technology Life Cycle Management

Module 507: Technology Life Cycle Management

Build your application on a Long Term Stable (LTS) or Medium Term Stable (MTS) release.

Check licenses (and support) for Marketplace content in your solutions, to see if it is compatible with desired usage. As well as for external dependencies and vulnerabilities, as ISV or enterprise you become responsible for community-supported content (possibly supported by the creator)

Be prescriptive about the version the customers should use (rolling release schema).

Adopt an MTS / LTS strategy as well (consider backporting of critical fixes)

6. Design the UX/UI of Your Adaptable Solution

Design for Selling and Extending

Don’t alter the default Atlas behavior.

Use standard components and design properties, and avoid custom classes.

Understand customer workflow and use (user journey) mapping to see how it fits the core.

Entanglement of Data

Separate data and pages, do not let the page layout determine the domain model.

Separate actions, e.g. edit parent object and adding/editing/removing child objects on separate pages and not embedded in a single page.

7. Brand Your Adaptable Solution

Different Theming Modules

Module 514: Different Theming Modules

Theme folder:

  • Applied last, and overwrites themesource folder
  • Has a copy of the Atlas custom-variables file

Add a theme module:

  • Link the custom-variables file in the theme folder to link to the app_specific module
  • Multiple modules: set the priority in project settings > theme (highest priority has to be the last one in the list).

Atlas_core:

  • Uses !default for all variables (and should have this defined on all variables). Default means use own value if there is no other value claimed for that variable.
  • Has a fallback for its variables in main.scss file. The fallback will overrule the ‘!default’ before your project loads the theme/web/custom_variables file, and will thus interfere with the variables order you defined. Change the order of imports.

Structuring SASS

Mendix based the SASS folder structure on their own adoption of the SASS architecture guideline and contains:

  • Abstracts: files that can be used for more than one components (animations, support classes like borders, specific widths or heights)
  • Components: all widgets within Mendix (buttons, datagrids, inputs, alerts, headers, tab container, etc.)
  • Core: main behaviour of your app (typography, html-tag, body-tag, scroll behaviour, etc,)
  • Layout: changes in the layout pages
  • Pages: page-specific styling
  • Vendors: files that are needed to include styling from a third-party (iconfont)

Files

  • have an _ (underscore) to exclude them from being compiled to their own css file when Mendix starts compiling the sass files.
  • main.scss file is the one and only file that needs to be compiled to a css file and thus has no underscore in front of its name.
  • main imports _all.scss in every folder
  • _all.scss needs to import other files in those folders.
  • no need to include the _ (underscore) when importing files, SASS will pick them up anyway.
  • create a file for every component or widget to keep the maintainable