Skip to main content

AML Reusability Guide

AML provides several features to reuse code and logic across different objects, improving maintainability and efficiency in analytics development. Almost anything created in AML can be defined once and reused by any other AML object.

For example:

By reusing logic, you can avoid duplication, reduce errors, and make your code more modular and scalable. This page acts as a guide to provide an overview of the general steps needed to reuse logic in AML.

The Reusability Process

  • Step 1: Identify the logic to be reused and the resulting object that will reuse said logic.
  • Step 2: Extract reused logic to const or Partial for later reference.
  • Step 3: Refer to the reused logic in the resulting object.
  • Step 4 (optional): Extend the reused object to further customize it. This is useful when you want to mostly reuse the whole object, but with some additional small modifications.
  • Step 5 (optional): Parameterize logic with Func: for cases when you need to customize the reused logic with different parameters.

Step 1: Identify the logic to be reused

In order to reuse logic in AML, you should first identify the logic to be reused, and the resulting object that reuse said logic. Examples of reused logic include:

Step 2: Extract the reused logic to const or Partial

Top level objects in AML with explicit types (e.g. DataModel, Dataset, Dashboard, etc.) are already AML constants and ready to be reused, thus no further extraction is needed. An object's properties (Dashboard's blocks, Model's dimensions, etc.) are also ready to be reused individually (see step 3 for details).

There are 3 cases when extracting reused logic is necessary:

  • For reusing primitive values such as numbers, strings, etc.
  • For reusing non-top level objects in AML such as VizBlock, you can extract them to a const object.
  • For reusing parts of an object, you can extract them to a Partial object.

Primitive values can be extracted to const objects. For example:

Extracting primitive values to const
const my_const = 123
const my_string = "Hello, World!"

Non-top level objects are sub-objects that are part of another object, such as a VizBlock or PageTheme in a Dashboard. Non-top level objects with explicit types can be extracted to a const object.

Extracting a dashboard block to const
// Equivalent: const my_block = VizBlock {...}
VizBlock my_block {
// details omitted...
}

Multiple properties of objects (such as dataset's metrics, data model's fields) can be extracted together, at once, to a Partial object. Note that any subset of an object's properties can be put in a partial.

Extracting a group of dataset metrics to a PartialDataset
PartialDataset my_dataset {
description: "This is a dataset that contains metrics a and b"
metric a {
// details omitted...
}
metric b {
// details omitted...
}
}
Extracting a group of model dimensions to a PartialModel
PartialModel my_model {
dimension a {
// details omitted...
}

dimension b {
// details omitted...
}
}

To reuse Partial objects, you can use extend function. Please refer to step 4 for details.

Use AML Module to group extracted objects

Extracted objects can quickly clutter your project files, making it difficult to navigate your work. To improve organization, consider grouping extracted AML objects and functions into an AML module. An AML module is essentially a directory that serves as a container for these related items, helping you maintain a cleaner and more structured project.

Step 3: Refer to the reused object or its properties

For primitive values, you can refer to them directly by their name, or use string interpolation feature.

Refer to a const value
const my_const = 123
const color_blue = "#0000FF"

PageTheme my_theme {
background_color: color_blue
}
Refer to a const value with string interpolation
const today = @sql current_date() ;;

Model today_sales {
description: "Sales data for today"
query: @sql select * from sales where date = ${today} ;;
// other details omitted...
}

For full object with explicit names, you can refer to them directly just with the name itself.

For individual properties of objects, you can refer to them by using the object's name followed by a dot and the property name. For examples:

Refer to another model's dimension
Model original_model {
dimension my_dimension {
// details omitted...
}
}

Model another_model {
dimension another_dimension: original_model.dimension.my_dimension
}
Refer to another dataset's metric
Dataset original_dataset {
metric a {
// details omitted...
}
}

Dataset another_dataset {
metric b: original_dataset.metric.a
}
Refer to another dashboard's block
Dashboard original_dashboard {
block my_block {
// details omitted...
}
}

Dashboard another_dashboard {
block another_block: original_dashboard.block.my_block
}

Step 4 (optional): Extend an existing object

Refering to the reused object directly is useful when you want to reuse the whole object. In order to reuse an existing object with some additional modifications, you can use the extend function. This function can be applied on an analytics object to produce a new object that takes on the original properties, while merging in the additional properties.

Extend an existing object
Model base_model {
dimension a {
// details omitted...
}
}

Model another_model = base_model.extend({
dimension b {
// details omitted...
}
})

Another use case is to reuse a Partial object. You can use extend function to combine the Partial object with another object.

Extend an existing object with Partial
PartialModel my_partial_model {
dimension a {
// details omitted...
}
}

Model base_model {
// details omitted...
}

Model another_model = base_model.extend(my_partial_model)

More details about extend function can be found in the AML Extend page.

Step 5 (optional): Parameterize logic with Func

When you need to customize the reused logic with different parameters, you can use Func to parameterize the logic. Func is a reusable block of code designed to perform a specific task. It can take parameters and return a value.

Parameterize logic with Func
Func sum(x: Number, y: Number) {
x + y
}

Func double(x: Number) {
const multiple = 2
x * multiple
}

Func myvizBlockWithDataset(dataset: String) { // auto infer return type = VizBlock
VizBlock {
label: 'A pie chart'
viz: PieChart {
dataset: dataset // use the dataset parameter here instead of hard-coding
legend: ref('public_users', 'role')
series {
field {
ref: ref('public_users', 'id')
aggregation: 'sum'
}
}
}
}
}
Using Func in an object
Dashboard my_dashboard {
// details omitted...
block my_block: myvizBlockWithDataset('ecommerce')
}

More details about Func can be found in the AML Func page.

Conclusion

By following the steps above, you can effectively reuse logic in AML, making your analytics development process more efficient and maintainable. For more details on AML's reusability features, please refer to the AML Reusability Overview.


Let us know what you think about this document :)