StratusOnMaestro Studio Ensemble

Inside createUiDefinition Expressions: How Maestro Studio ENSEMBLE's Expression Designer Works

Expressions are one of the gnarliest parts of a createUiDefinition.json when it comes to debugging and troubleshooting issues. There are no validation tools for UI expressions. You just have to build and test the whole file and hit the element on which you have the expression to make sure it's valid and working, or read the output parameters to make sure the output parameter's expression is not broken and does not have logic errors.

Because createUiDefinition (CUID) expressions are difficult to build and test manually due to lack of automated tools up till now, there are hundreds of Azure Application offers in the Azure Marketplace that have logic errors due to broken expressions. For the most part, the Azure Portal swallows those logic errors, so Azure Application developers/publishers have no idea that their offers do not behave deterministically. Most publishers only perform quick, high-level testing and don't detect most issues lurking in their JSON code.

This is about to change.

There are 100s of Azure Application offers in the Azure Marketplace that have logic errors due to broken expressions. The Azure Portal silently ignores most logic errors. Most publishers have no idea that their offers do not behave deterministically.

Maestro Studio ENSEMBLE sports a parser that generates an Abstract Syntax Tree and a JIT compiler that takes the AST to the next level, generating validation messages, warning and error locations, and just-in-time values of expression in design-time.

The image below summarizes what's it like to work with compex expressions manually, and how it becomes light years easier with Maestro Studio ENSEMBLE's Expression Designer. It takes the effort of debugging a complex expression from hours to seconds.

Let's make expressions human readable and maintainable. That's the goal we pursued with Maestro Studio ENSEMBLE's Expression Designer experience—turning what is an hours/days error-prone exercise into a seconds/minutes pleasant visual experience where you CANNOT make mistakes.

Maestro Studio ENSEMBLE turns an hours/days error-prone, frustrating exercise of parentheses counting and typo-fighting into a seconds/minutes pleasant visual experience where you CANNOT make a mistake.

A Real Example

The expression shown in the image above is taken from a real Azure Marketplace Managed Application offer. It sports 6 lambda functions and is used to filter a data set and prepare it to be used in a DropDown control in the UI definition of an offer.

The following is the full expression:

[map(filter(first(map(filter(first(map(filter(steps('resources').sql.apiSqlCapabilities.supportedServerVersions, (v) => equals(v.name, steps('resources').sql.serverVersion)), (vv) => vv.supportedEditions)), (e) => equals(e.name, steps('resources').sql.edition)), (ee) => ee.supportedServiceLevelObjectives)), (o) => contains(parse('["Default","Available"]'), o.status)), (item) => parse(concat('{"label":"', item.name, '","value":"', item.name, '","description":"', item.computeModel, ' ', string(item.performanceLevel.value), ' ', item.performanceLevel.unit,  '"}')))]

This is what the control using the expression looks like in Maestro Studio ENSEMBLE's design canvas:

This DropDown control looks like this at runtime when loaded in the Azure Portal's UI—in this example, we have no data (SQL Server instances) in the selected subscription, so an empty list of "allowed values" items is shown:

The Expression Designer

This is what the expression looks like in Maestro Studio ENSEMBLE's Expression Designer—no risk of typos, adding an extra parenthesis or having missing parentheses; it's just drag-and-drop and real-time validation:

This is just a partial view of the expression as it's rendered on the design canvas of the Expression Designer. The full visual representation is much larger.

The Toolbox

Notice the toolbox on the left-hand side of the image. You can drag a function from the toolbox and drop it on the design surface. The designer will only allow dropping a function in a location where it is legal per the grammar of createUiDefinition UI expressions. This ensures there is no way to introduce a broken or malformed expression.

In addition to the drag-and-drop capability, the Expression Designer allow adding functions or literals to the design canvas using a Quick Action menu that appears when you hover over a widget in the designer. The resulting menu will only offer the subset of all functions that is applicable to the widget selected. This helps avoid adding the wrong function in the wrong place and introducing runtime errors.

The Tree Navigation View

Underneath the toolbox, inside the explorer tab, lies the tree view of the expression. In technical terms, both the expression loaded on the design canvas and the tree view are representations on the Abstract Systax Tree created during the parsing and lexical analysis of the expression. Clicking on a node in the tree allows locating the corresponding visual representation on the design canvas so that the function or argument can be edited directly.

The Just-in-Time (JIT) Evaluation View

The power of ENSEMBLE's expression designer lies in its ability to provide a just-in-time (JIT) value of the expression whenever possible. If there are values that can only be discovered at runtime, the JIT evaluation view will display a placeholder indication where the runtime values will reside. This helps get a grasp, during design-time, of what the result of the expression will look like at runtime. It also helps avoid countless round trips to get the expression right. For most practical scenarios, you will be able to design your expression in the Expression Designer before you got test it live.

In our example of the "6 lambdas" expression, the JIT evaluation returned an empty array since the JIT evaluation of the design-time state found empty data sets.

In the following example of an expression involving the concatention of functions whose values can only be determined at runtime (like Azure subscription id and Azure location), the JIT evaluation shows useful placeholders:

The Abstract Syntax Tree (AST)

The AST is our internal representation of the expression, generated after parsing and lexcial analysis of the expression before JIT compilation. It is used to hydrate the Expression Designer view as well as the Tree View, as mentioned above.

In certain cases, specifically when importing expressions as part of an imported Azure Managed App or Solution Template into ENSEMBLE, there might be malformed or otherwise broken expressions that cannot be loaded into the designer because their AST could not be fully generated. In such cases, some customers have requested access to the AST to help them troubleshoot and debug such cases. To help with that, we added a feature flag that can be turned ON for ENSEMBLE customers that request the feature. When turned on, ENSEMBLE will pretty-print the AST of each expression in ENSEMBLE's Monitor log. Here's what the AST looks like for the 6 lambdas examples discussed in this post:

This is a simplified view that can help power users debug their expressions. The AST data structure holds a lot more information that we use for validation and JIT compilation.

Don't Make Parentheses Counting your Forte

Many DevOps engineers who build ARM or Bicep templates (even some who do AWS CloudFormation) still like to hand-craft their expressions. createUiDefinition.json expression language is similar to all those mentioned—it just has a much smaller grammar; a smaller set of functions and less rules. But the pain and the error-prone nature of manual editing is the same. The worst part about it is that most of the time, when a nasty logic error is introduced, it remains dormant, unnoticed for a long time until it is accidentally detected.

Compilation helps detect those issues early on before they cause issues and loss of revenue. Just like most people use pre-compilation in most languages today, DevOps engineers need to reduce the risk by leveraging automation tools. No one wants to be known as the parentheses counter, let alone the parentheses counter who missed a parenthesis.

Just like most people use pre-compilation in most languages today, DevOps engineers need to reduce the risk by leveraging automation tools. No one wants to be known as the parentheses counter, let alone the parentheses counter who missed a parenthesis.

Conclusion

This was just a simple overview of the Expresson Designer feature and a brief overview of the parsing and compilation process that helps drive all the UI goodness you see in the designer. It is not meant to be a technical overview of the JIT compilation implementation and our custom-built lexer and JIT compiler. We wanted to keep the content light and easy to follow given that the technical details can make this presentation unnecessarily confusing and distract from the core concepts and benefits that the Expression Designer feature offers.

If you want to learn more about a certain ENSEMBLE feature and can't find enough details in the embedded help or on our blog, do reach out to us.

The Expresson Designer feature mentioned in this article is available in the Free Trial of Maestro Studio ENSEMBLE, which allows you to kick the tires, so to speak, and get a first-hand experience of the product and the value it can bring and benefits it can add to your publishing process so you don't have to deal with the mundane details and focus on your own product.

We hope you find this feature useful. Please provide us with feedback using our Contact form. You can also send us feedback from within the product using our Megaphone feature.

Comments are closed