EXAMPLE: Microflow typologies
This example demonstrates the implementation of a small user story through the application of microflow typologies.
While a developer experienced with Menditect's Testability Framework would instinctively create a well-structured microflow hierarchy from the outset, we will instead introduce Jasmira, a junior developer for the purpose of this illustration.
Jasmira initially modeled the required functionality without incorporating typologies, only to then be instructed to refactor the microflows to align with these standards. The entirety of this example is dedicated to showcasing this restructuring process step by step.
1. Context
Let's assume that we have a simple application that registers orders from a website.

The website sells two product types:
- physical products that are sold 'per piece'
- service products that are 'sold for a given time period'
The difference between both products is that for the physical product the customer can enter a number to specify the ordered quantity. Service products on the other hand have a start and end date and the application is calculating the ordered quantity by calculating the period between start and end date and divide that by 365 days.
There are some calculated attributes:
- Order.TotalAmount: which is the sum of all OrderLine.Amount
- OrderLine.Amount: which is the multiplication of the Orderline.Quantity * Ordeline.Price
- OrderLine.Quantity: which is only calculated for the service product.
For this example we assume that an order has been created already and a customer wants to add an orderline to the order.
2. The initial result of Jasmira
Jasmira has been following her line of thought and created the microflow below.

- The depicted microflows on this page only show the necessary steps to illustrate the difference between the typologies and omits a lot of things you normally add to microflows like error handling etc.
- In our standard we use unique 4-letter codes to identify the entities in the app. Like OLNE for OrderLine and ORDR for Order.
After this initial commit she was instructed to decompose this structure into touchpoint, orchestration and unit microflows.
2. Split off touchpoint logic.
Jasmira is instructed to identify all touchpoint logic first and put that in the touchpoint microflow ACT_olne_newedit_save. All other logic is put in an orchestration microflow ORC_olne_save. The touchpoint ACT microflow is responsible for:
- checking if the input is ok via validity preconditions.
- calling the underlying microflow logic.
- executing conditional navigational logic.
After identifying the touchpoint logic elements, the resulting ACT microflow now looks like the picture below. Jasmira stored the ACT microflow in the same folder as the page OLNE_newedit.

3. Split off unit logic from the orchestration
The resulting orchestration microflow still is a mixture of several microflow actions that can be separated in the following units:
- Operations (
OPR) to change objects - Retrieves (
GET)to get objects - Functions (
FTN) to calculate values - Validations (
VAL) to check if all objects apply to the rules
Jasmira is now instructed to mark all units in the orchestration microflow and put them in separate units.
3.1. Splitting off functions into FTN microflows
Jasmira identifies two calculations in the orchestration and puts each of them in a separate function microflow:
FTN_date_calculate_yearfraction: a calculation that determines how many decimal years are between the given start and end date. This decimal year is called ‘fraction’.FTN_decimal_multiply: a multiplication of the quantity and the price resulting in the amount.
Grouping calculations
In this example we work out the microflow FTN_date_calculate_yearfraction. The calculation takes two steps:
- counting the days between start and end of the OrderLine using the Mendix function ‘daysBetween’
- divide the number of days by the total number of days in a year (365 for the ease of the example).
When a function consists of complex sub-tasks that could be reusable, it is recommended to split this ‘main’ function in ‘sub’ functions. Because the ‘daysBetween’ is a straightforward Mendix function we don’t do that in this example.
Adding preconditions
Grouping the calculating actions into FTN is not enough. The original microflow is checking the availability of the start and end-date and is checking if the start date is before or on the end-date. These checks must be implemented as preconditions because otherwise the function will result in unhandled exceptions or strange behavior.
This is one of the main tasks while creating units, to detect which preconditions are necessary to make the unit robust and reusable.
Notice in the microflow below that the preconditions are implemented without the validation feedback. Reason for that is, that a function is never responsible for user feedback. That is the responsibility of the ACT microflow (early warning to the user) or should be part of the unit validation microflows (business rule checking).
If it is necessary to prevent illegal implementation of a function microflow, throw an exception instead. But be aware that if such a function is called by a page trigger, it will cause an unwanted ‘internal server error’.
In this case, we choose ‘silent ignore' to avoid an 'internal server error' to deal with the scenario where the user has not entered a start or end date yet.
The result
The resulting microflow FTN_date_calculate_yearfraction looks like this:

Optional other function
The orchestration microflow also contains an action that takes a sum of attribute 'OrderLine._Amount’ to calculate the total order amount.
There are two viable ways to implement this:
- As a
FTNmicroflow: This function takes a list of orderlines as input parameter and executes the Mendix ‘Aggregate List' action in order to sum all orderline amounts. - As a
GETmicroflow: This 'getter' takes the Order as input parameter, retrieves the OrderLines by the order and executes the Mendix ‘Aggregate List’ action.
An aggregation action executed in a GET microflow that retrieves objects from database has the advantage that the aggregate action could be optimized by Mendix when aggregation is executed directly after a database retrieve.
3.2. Putting retrieves into GET microflows
Next step is to separate retrieve actions into GET microflows. The orchestration has the following retrieve actions that can be put in separate GET microflows:
GET_M_ordr_by_olne: retrieve the Order by the Orderline via the association. This retrieve is necessary because the Order.Amount is changedGET_M_olnes_sum_amount_by_ordr: retrieve all Orderlines by the Order via association and aggregate the orderline amount. The microflow returns a decimal order amount.
Here the example of the microflow GET_M_olnes_by_ordr that returns the aggrated orderline amount:

In the Menditect Testability Framework each GET microflow get a precondition in order to prevent unnecessary retrieve actions. The GET_M microflows retrieve objects by association (memory) while GET_D microflows retrieve objects from database.
While it seems that splitting retrieves into GET microflows is ‘overkill’, it has actually some benefits:
- if an association in a domain model changes, this change only have impact on the
GETmicroflows and not on other microflows. This reduces the impact of a change. - there is an overview of all retrieval implementations of a certain object in the
GETmicroflow folder, which also stimulates reuse. - XPath constraints are only implemented once, which prevents implementation variety, errors and enhances testability.
3.3. Splitting off operations into OPR microflows
Jasmira then notices that three object changes could be split off into unit microflows:
OPR_olne_set_quantity: to set the calculated quantity on the OrderLine of an ordered serviceOPR_olne_set_amount: to set the calculated amount on the OrderLineOPR_olne_set_totalamount: to set the calculated total amount on the order
Let’s work out the first microflow OPR_olne_set_quantity. Special care should be given to the implementation of preconditions:
- Check if the OrderLine is not empty, because setting a value on an empty object will result in a null-pointer exception
- Check the product type, because the quantity is only allowed to be set by the software in case of a ‘service’ product.

3.4. Splitting off Validations into VAL Microflows
In this example we focus on the validation messages to find business rules. The implemented business rules are not ‘invariant’ because they are part of an orchestration instead of being called by the CMT microflow. Jasmira deals with that later. She detected the following invariant business rules:
VAL_olne_mandatory_attributesmandatory attributes ‘quantity’, ‘price’, ‘amount’ must have a valueVAL_olne_mandatory_attributes_start_end‘start’ and ‘end’ attributes must have a value if the ordered product is a ‘service product’. Observe that these two attributes cannot be part of the generic mandatory attributes because of this extra precondition and the ‘rule of thumb’ is that validations can only be part of the same microflow as long as all the preconditions in the microflow apply to all validations.VAL_olne_mandatory_associationsan OrderLine must be associated to an order and to a product.VAL_olne_start_before_end: start date must on or before end dateVAL_ordr_mandatory_attributeswhich checks if the mandatory attributes ‘amount’ and ‘orderstatus’ have a value.
Here the resulting microflow VAL_olne_start_before_end. Observe that the preconditions on ‘start’ and ‘end’ do not result in validation feedback. The reason is that validating if ‘start’ and ‘end’ have a value should be part of another validation microflow: VAL_olne_mandatory_attributes_start_end.

The pattern of the validation microflow is more advanced than shown in this example. Have a look at the section ‘Ensuring data quality’ where the more advanced pattern is shown. For now, the boolean return value is used to determine if a validation is ok.
4. Improve the orchestration
After the splitting units from the orchestration microflow ORC_olne_newedit_save the result is better but still contains actions that should be aggregated.
The intermediate result is shown below where the following improvements are marked:
- red: some of the unit microflows should be grouped together in an orchestration microflow because they are tightly bound. For instance the calculation of a value and the setting of a value.
- green: the validations could be grouped into rule families
- orange: the commit and rollback behavior should be grouped together in a
CMTmicroflow, this microflow must also call the validations

4.1. Grouping Into Orchestrations
There are two groups of units that are tightly bound. One is about manipulating the OrderLine and one is about manipulating the Order. Jasmira splits these into two separate orchestrations:

ORC_ordr_set_amount: this orchestration is setting the order amount (Notice the dependency which will be improved in the app architecture example).ORC_olne_set_quantity_and_amount: this orchestration is setting the amount on the OrderLine. One of it’s sub-tasks is setting the quantity. Jasmira chooses to put that functionality in the same microflow.
Changing the OrderLine amount must trigger the Order amount to be updated as well. Therefore Jasmira add the call to the ORC_ordr_set_amount at the end of the microflow.

The resulting orchestration hierarchy now looks like:

4.2. Grouping Validations in Rule Families
Group validations in ‘rule families’ when the number of validation microflows is growing. For instance, the validations on the orderline can be grouped in the microflow VAL_ORC_olne_save. The picture below shows the grouped validations in the microflow: VAL_ORC_olne_save.

The expression at the end of the microflow checks if all validations result in true.
4.3. Separating the Commit Behavior
Finally, Jasmira centralized the validations, commits and rollbacks in the CMT microflow. It is important to note that the design ensures that if a validation fails, the OLNE object (the user's input) is not rolled back, allowing the user to correct the data without losing the information entered on the page

4.4. More Improvements
There is more to say about the resulting microflow hierarchy. Jasmira rationalized that the organization of the hierarchy should follow the order of the changes, but is that the case? Another thing ignored by Jasmira is the fact that most OPR microflows cannot be independently called anymore because they depend on the the execution of FTN microflows. These issues will be addressed in the app architecture example.
5. The testable result
Restructuring the microflow hierarchy enables unit testing of each independent unit, allowing all edge cases to be tested separately. The decision which unit should be tested depends on its risk factor, complexity, and number of preconditions.
It is also possible to execute component tests. This is particularly useful for the orchestration microflows that calculate and set the OrderLine quantity and amount, and determine the overall Order amount.
Finally, an integration test can verify that each unit is called in the correct sequence. Interestingly, this test is independent of the orchestration's internal structure. Even if the OrderLine quantity and amount calculations are moved to separate microflows, the calling order of the units remains unchanged, and the test result is therefore consistent.