Optimize APL Template Design

APL provides a variety of UI components that help you structure your APL documents and layouts more efficiently and there are concepts you can follow to make resource-efficient use of the components during runtime. You can assess on a template’s design efficiency in two ways:

  • Efficiency of APL template code, which is best for optimizing towards greater maintainability.
  • Efficiency of inflated APL documents at runtime, which is best for optimizing towards better performance.

While it would seem that both efficiency goals would always go hand in hand, that’s not always the case. You need to be aware of what inflated APL documents can look like as a result of your chosen APL template design.

Increase reusability with modular template design

The efficiency you gain when you build and structure APL template code that supports better readability and maintainability of your APL documents often goes along with eliminating redundant APL code and creating a modular template structure; for example, by using APL layouts and style definitions. When you take this approach, you usually reduce the file size of a template. You also gain a potential performance benefit because less bytes need to be downloaded and parsed by the APL runtime on a device when it inflates the APL document.

In general, you should make it a goal to increase reusability of APL components in your templates to establish modularity and reduce redundancy as much as possible. APL provides a variety of options to achieve modular template design:

  • Use APL layoutsLayouts in APL are a great way to extract repeating visual UI components. You can make layouts reusable by adding input parameters that enable you to customize content and behavior of the layout dynamically. As you can have nested layouts as well, you can optimize even further by breaking up and nest your layouts if they happen to contain repeated structures. For details, see APL layouts.
  • Use APL stylesStyle definitions in APL enable you to reuse a set of styled properties across multiple APL components. If you see a pattern of APL components sharing the same style properties in one or across multiple templates, this is a good opportunity to outsource these properties into a centralized APL style definition. Learn more about APL styles.
  • Use APL resources — If you see static resources like strings, numbers, color codes, dimensional values, easing functions etc. repeatedly being used in your template, consider defining them globally as a resource in your template. Learn more about resources in APL.
  • Use APL style extensions —You can make even more efficient use of APL styles by extending them. If you see two or more of your custom style definitions that use a similar set of styled properties, consider sourcing out the shared set of property values so they are defined in their own base style definition. Learn more about APL style extensions.
  • Use user-defined APL commands — APL command groups tend to repeat themselves as well if there is shared UI behavior across APL components and their event handler properties. If you discover a set of similar APL command blocks in your templates, consider putting them into a user-defined APL command. Also keep in mind that your Alexa skill code might need to duplicate an entire command sequence from an APL template to replicate the effect a UI event such as a button press would have when the same action is requested by the user using voice. By keeping UI event handler commands reusable as user-defined commands, the skill can request to execute this command in the same way the APL document does in response to a corresponding UI event, such as a button press. Learn more about user-defined commands.
  • Use custom APL packages — Custom packages are reusable APL documents that you can import into other APL documents. The ability to import APL documents as packages is a great way to share reusable APL artifacts, such as layouts, resources, user-defined commands, styles etc. across several of your APL document templates. Learn more about APL packages.

Reusability also ensures design consistency across your templates. For instance, a change made to a style property value or a layout component automatically applies to all dependent visual components that reference the respective style or layout. This can easily be missed if related APL components and properties are replicated across your templates.

Whenever you decide to merge similar APL components into one centralized layout, style, resource, etc., keep in mind that you implicitly equalize these components. This removes some of your flexibility to customize individual APL components later on. Ask yourself if it makes sense for similar APL components to have a shared base or if this would likely change in the future.

Make template design more frugal

Design frugality refers to achieving your APL design goals while minimizing the use of APL components in your template. Establishing a modular design to support better reusability is a great way for you to reduce the number of APL components and the size of a template itself. However, it doesn’t guarantee an efficient use at runtime. Design frugality also optimizes towards performance by reducing the number of APL components that are unnecessarily being inflated or contained in your APL documents after they are processed by the APL runtime on a screen device.

Examples

Always prefer to use the when property to discard an APL component from the inflated APL document instead of using a component's display property to hide it. Be aware that the when property is only evaluated one time during inflation of the document and there is no option to display the component after the document is rendered.

Instead of doing this:

{
    "type": "Container",
    "display": "${@viewportProfileGroup == @tv ? 'normal' : 'none'}",
    "items": [
        ...
    ]
}

Better do this:

{
    "when": "${@viewportProfileGroup == @tv}",
    "type": "Container",
    "items": [
        ...
    ]
}

Avoid toggling display between similar looking APL components.

Instead of doing this:

{
    "type": "Text",
    "display": "${isOn ? 'normal' : 'none'}",
    "text": "On"
},
{
    "type": "Text",
    "display": "${isOn ? 'none' : 'normal'}",
    "text": "Off"
}

Better do it like this:

{
    "type": "Text",
    "text": "${isOn ? 'On' : 'Off'}"
}

Avoid unnecessary use of structural APL components, such as Container, Frame, and layouts if there is an opportunity to resolve them. Flat component trees are better to read as well.

Instead of:

{
    "type": "Container",
    "width": "50vw",
    "items": {
        "type": "Frame",
        "backgroundColor": "red",
        "item": { ... }
    }
}

Better do this:

{
    "type": "Frame",
    "width": "50vw",
    "backgroundColor": "red",
    "item": { ... }
}

Use data array inflation on multi-child components, such as Container, GridSequence, or Sequence to resolve repetitive component structures, such as enumerations and lists.

Instead of:

{
    "type": "Container",
    "items": [
      {
        "type": "Text",
        "text": "1) Apples"
      },
      {
        "type": "Text",
        "text": "2) Bananas"
      }
    ]
}

Better do it like this:

{
    "type": "Container",
    "data": [ "Apples", "Bananas" ],
    "items": [
      {
        "type": "Text",
        "text": "${index+1}) ${data}"
      }
    ]
}

Avoid making excessive use of the Text component if there is an opportunity to merge. Markup tag support for the Text component is useful.

If possible, don't do this:

{
    "type": "Container",
    "items": [
      {
        "type": "Text",
        "color": "red",
        "text": "Red,"
      },
      {
        "type": "Text",
        "color": "yellow",
        "text": "Yellow"
      }
    ]
}

Better do this:

{
    "type": "Text",
    "text": "<span color='red'>Red</span><br><span color='yellow'>Yellow</span>"
}

Where possible, use relatively or absolutely sized Text components in particular for dynamic text if high frequency updates to the text property itself are expected. Calculating Text component dimensions is a rather costly operation for an APL runtime.