Skip to main content

Change Propagation Tutorial

What is Change Propagation?

Change Propagation is a mechanism in Txture which allows you to infer data and store it in asset properties. It is similar to:

  • Formulas in Excel and other spreadsheet applications
  • Database Triggers in relational databases
  • Calculated Properties in business intelligence software

Just like those technologies, Change Propagation has a wide variety of uses and is a very powerful tool for customizing your Txture instance precisely to your needs. Its main purpose is to define rules in the shape "if X changes, Y needs to change as well". Those X and Y placeholders are very flexible in Txture, and we are going to cover examples in this tutorial, starting with some very basic usages and moving to more advanced cases while exploring the benefits and pitfalls.

Basic Example: Total User Count

Assume that we want to track how many users any given Application asset has in Txture. We want to differentiate between External Users and Internal Users for reporting purposes. To accomplish this, we define three custom Properties in the Structure Editor and link them to the Application Asset Type:

  • External Users: integer, single-valued
  • Internal Users: integer, single-valued
  • Total Users: integer, single-valued

Now imagine that we ask a user to enter a value for External Users and Internal Users (for example, via a Survey). It would be very hard to manually ensure that Total Users is always the sum of External Users and Internal Users.

In Excel, you would solve this by using a formula for the Total Users column (something along the lines of =A1+B1). In Txture, we use a Propagation Rule for that purpose:

return asset.props.externalUsers + asset.props.internalUsers
What is the language we're using here?

Change Propagation Rules in Txture are written in type-safe Groovy. Generally speaking, Groovy is a convenient superset of Java. If you're familiar with Java, you can use plain Java to formulate the rules as well.

Please note that some of the more dynamic features of Groovy are not supported, only the type-safe subset of Groovy is allowed.

Open the Txture Admin panel, and navigate to the Propagation Rules section. Add a new rule for Application Instance, and select Total Users as the output.

Tip: Use CTRL+Space

In the Propagation Rule Script editor, you can use the key combination CTRL+Space (or Option+Space on macOS) to bring up a code completion window. It contains many useful pre-made snippets that help in reducing the "guesswork".

Here's what the corresponding rule would look like in Txture:

This screen gives us quite a lot of information, let's break it down:

  1. The name of the Asset Type to which the rule belongs.
  2. The Property which will receive the rule result (the "Output Property")
  3. The rule definition (in type-safe groovy code)
  4. Shows which Links are used as input by the rule definition (in this case none; we will see an example for this later)
  5. Shows which Properties are used as input by the rule definition (in this case, Internal Users and External Users)

If we save this rule (and the entire ruleset) then Txture will ensure that:

  • For any Application Instance...
  • ... the property Total Users...
  • ... will always be set to Internal Users + External Users

There are some details here which are important:

  • The rule applies to any Application Instance. This means that no matter if the user is currently manually creating a new Application Instance, or if the Application Instance was produced by an importer, or if a Survey participant created it, the rule will always be applied.

  • The rule will always be applied. So it doesn't matter if Internal Users has been changed manually or through an automated process (such as an importer), the Total Users property will be updated accordingly. Furthermore, upon saving the rule, it will be evaluated on all currently existing Application Instance assets in the repository. This has a noteworthy side effect: if a user attempts to manually update the value of Total Users, the rule will be applied when the asset is saved, and the changes made by the user will be reverted to match the rule result. This may be surprising for end users, which is why they're presented with a visual warning that they're seeing a property which is targeted by a Change Propagation Rule:

Important

Change Propagation rules always overwrite all other changes, including manual changes.

This is a great difference from a spreadsheet like Excel. If the user enters a value manually into a cell, that value is always accepted (even if the cell previously contained a formula). In Txture, the formula "wins" the conflict over the manual edit.

This may seem like a downside in the beginning, but when applied correctly, it is a valuable tool for ensuring data quality and enforcing invariants.

Debugging Propagation Rules

Writing a good Propagation Rule script which behaves correctly under all circumstances can be challenging. To make the process of testing a rule easier, Txture provides tools to debug your rule scripts inside the rule editor.

The first important tool is the Test Rule on Asset functionality. You can pick any asset from the repository, click on "Run Test" and inspect the outcome of the script. This is the new property value produced by the rule which will be assigned to the Asset. Please note that performing test runs like this does not apply any changes to the repository, so feel free to experiment.

When inspecting the overall rule outcome is not enough, you can use log statements inside a rule. They produce textual output which will be shown in the Debug Logs section of the panel. These logs can be very useful to inspect intermediate results or check the control flow within the script. There's two different functions which can be used for this purpose:

log.debug("I'm a debug log. Debug logs only appear in this window")

With log.debug you're producing a log which only appears when testing the script in the rule editor panel, nowhere else. The function not only accepts strings; you can pass in any object and it will be added to the log (although some objects may not have a clean textual representation). In most cases, you should prefer log.debug over the log.info function we discuss next.

log.info("I'm an info log. Info logs appear in Propagation Rule logs.")

log.info behaves similarly as log.debug, with one important difference: log.info also contributes to the Change Propagation logs which can be downloaded in the Propagation Rules admin page. Please note that Propagation Rules are potentially being called very often, and every call leads to log.info producing more log lines, which will increase the size of the logs very quickly and can have a negative impact on performance. Unless you have a concrete need to see your rule logs when they're being executed on the entire repository, prefer log.debug.

Cascading: Computing Business Relevance

Based on the previous example, let's assume that we want to infer the Business Relevance of an Application Instance based on the Total Users using the following mapping table:

Total UsersBusiness Relevance
< 1000Low
1000..10000Medium
> 10000High

In the Structure editor, add a Property named "Business Relevance" of type Enumeration (single-valued), add the literals "Low", "Medium" and "High". Link the property to the Application Instance.

Then, create a new Change Propagation Rule for Application Instance, targeting the new Business Relevance property.

By applying what we've learned so far, we can come up with the following Change Propagation Rule:

if(asset.props.totalUsers < 1000){
return "Low"
} else if(asset.props.totalUsers <= 10000){
return "Medium"
} else {
return "High"
}

Save the rule. Immediately, it will be applied on all Application Instances in our repository.

Let's hold on for a moment and consider the following question: What happens if the Internal Users property changes on an asset?

  • We already have a rule that says: if Internal Users changes, update Total Users.
  • Now we have a rule that says: if Total Users changes, update Business Relevance.

This showcases a very important characteristic of Change Propagation Rules: they cascade. This means that:

  • One rule may use the output of another rule as input. Just like the output of our Total Users rule is used as input by our Business Relevance rule.
  • If a change occurs to any input property of a rule, it is re-evaluated. This may cause recursive re-evaluations of rules, until no rule produces any further changes.

With this setup, consider the following example configuration of an Application Instance asset:

Let's assume that our application gains popularity with external users and increases to 12000 external users. Nothing else changes. If we update only the External Users property, here's what the asset will look like after the changes have been saved:

Note the following:

  • The External Users property has been set to 12000, as described.
  • Automatically, Total Users was updated to 12200 because of our Total Users rule.
  • Also automatically, since Total Users has changed, the Business Relevance has been updated to High, since we now surpass the user count threshold for high relevance.
Limitations of Change Propagation Rules

Since Change Propagation Rules are applied repeatedly until no further changes are produced, this means that the rules must be deterministic and pure functions. In particular, your rule definitions...

  • .... must not depend on "outside information" such as:
    • network calls
    • database contents
    • files on disk
    • current system time
    • randomness
  • ... must not alter the system state in any way except for returning a new value for the target property
    • In particular, using global variables is not allowed.
    • Also, Change Propagation Rules can not create or delete assets or links. They may only provide a value for the target property.
  • ... must not form cyclic dependencies among each other
  • ... must be quick to compute
    • each rule invocation has a configurable timeout

Propagation across assets: Computing Business Relevance of Organizational Units

Based on the previous example, let's assume that we're faced with another business requirement. We have to calculate the Relevance of a Business Unit depending on the Business Relevance of the Applications it operates. The business requirement states that a score should be calculated for each Business Unit:

Application Instance Business RelevanceScore
Low1
Medium2
High3

The points for all Application Instances should be summed up per Business Unit. Every Business Unit should receive a Business Relevance rating based on the outcome:

Sum of ScoresOrganizational Unit Business Relevance
0..5Low
6..8Medium
9+High

Let's start by opening the Structure Editor. Take the existing Business Relevance property you've created earlier and link it to the Organizational Unit. Then, create a new Propagation Rule for Organizational Unit, targeting the Business Relevance property.

This time, it is not sufficient to only look at the asset's own properties. To satisfy this requirement, we need to look at our neighbor assets as well. Change Propagation Rules allow us to do that by depending on the incoming and/or outgoing Links of an asset:

def totalScore = 0
// sum up the business relevance of the applications we own
for(appBusinessRelevance : asset.links.out.owns.props.businessRelevance){
if(appBusinessRelevance == "Low"){
totalScore += 1
} else if(appBusinessRelevance == "Medium"){
totalScore += 2
} else if(appBusinessRelevance == "High"){
totalScore += 3
}
}

// based on the sum of scores, decide the relevance of the organizational unit
if(totalScore <= 5){
return "Low"
} else if(totalScore <= 8){
return "Medium"
} else {
return "High"
}

In the rule editor, it will look like this:

Note that this time, we see an entry in the Based on Links section: we're making use of the "owns" Link between the Organizational Unit and the Application Instance in our rule script.

The Txture scripting API allows us to easily access the businessRelevance of all Application Instances owned by the Organizational Unit at once. However, since the "owns" Link is multi-valued, the expression asset.links.out.owns.props.businessRelevance now produces a list of relevances, even though the property Business Relevance is single-valued. That is because "owns" can point to more than one application. Txture will gather the Business Relevance property values for all owned Application Instances for us here. This allows us to inspect them one by one using a regular for loop.

Neighbors only

In Change Propagation Rule scripts, you may access the properties of your current asset and all neighbor assets (i.e. all assets reachable by navigating across one link).

Navigating to other assets (e.g. the neighbor of the neighbor) is not supported. This restriction is important because it allows Txture to efficiently determine which rules have to be executed when a property changes on an asset.

Here's an example of an asset setup to which this rule applies:

In this particular case, the calculation for the Organizational Unit Development works as follows:

  • It gets 3 points for the "High" relevance Application Instance Website
  • It gets 2 points for the "Medium" relevance Application Instance Online Shop
  • It gets 2 points for the "Medium" relevance Application Instance CRM System

... so the total is 7 points. This places Development in the "Medium" range for its own Business Relevance.

If there's any change in the amounts of users on any of the applications, or if an application is added to / removed from Development, the calculation will be repeated and the output properties will be updated automatically.

Summary

In this tutorial, we've seen Change Propagation Rules in action. They offer a powerful set of tools for customizing Txture to the business requirements of your company and serve a similar role as Triggers in databases or Formulas in spreadsheets. Change Propagation Rules may use the properties of the current asset or its neighbors as input and compute an output value for a target property. This process cascades, so the outcome of one rule may trigger the execution of another rule. Change Propagation Rules are always executed, regardless of the source of the change, and overwrite any other changes (including manual changes). They can be used to establish invariants and can help to improve data quality in the repository.