Separation of Concerns

Keeping the logic (or model) of a component separate from the markup template (or view) is usually a good practice. There are several ways to achieve that, however the recommended one is to use Sling Models for the logic and the HTML Template Language (HTL) for the markup, like the Core Components also do.

Sling Models are a set of Java annotations to easily access needed variables from POJOs, and therefore offer a simple, powerful, and efficient way to implement Java logic for components.

HTL has been designed to be a secure and simple template language that is tailored for AEM. It can call many forms of logic, which makes it very flexible.

Reusable Component Patterns

The guidelines in this section can be used as well for any kind of component, but they make most sense for components that are intended to be reused across sites or projects, like the Core Components for instance. These guidelines can therefore be ignored for components that are only used on a single site or project.

Pre-Configurable Capabilities

In addition to the edit dialog that is used by page authors, components can also have a design dialog for template authors to pre-configure them. The Template Editor allows to setup all these pre-configurations, which are called “Policies”.

To make components as reusable as possible, they should be provided with meaningful options to pre-configure. This will allow to enable or to disable features of the components to match the specific needs of different sites.

Proxy Component Pattern

As each content resource has a sling:resourceType property that references the component to render it, it is usually good practice to have these properties pointing to site-specific components, instead of pointing to components that are shared by multiple sites. This will offer more flexibility and avoid content refactoring if one site needs a different behavior for a component, because this customization can then be achieved on the site-specific component and won’t affect the other sites.

However, for the project-specific components not to duplicate any code, they should each refer to the shared parent component with the sling:resourceSuperType property. These project-specific components that mostly just refer to parent components are called “proxy components”. Proxy components can be entirely empty if they fully inherit the functionality, or they can redefine some aspects of the component.

TIP
See the Using Core Components for details on how to create proxy components.

Component Versioning

Components should be kept fully compatible over time, yet sometimes changes that cannot be kept compatible are necessary. One solution to these opposing needs is to introduce component versioning by adding a number in their resource type path, and in the fully qualified Java class names of their implementations. This version number represents a major version as defined by semantic versioning guidelines, which is incremented only for changes that are not backward-compatible.

Incompatible changes to the following aspects of components will result in a new version of them:

  • Sling Models (following semantic versioning guidelines)
  • HTL Scripts and Templates
  • HTML Markup and CSS Selectors
  • JSON Representation
  • Dialogs

For further details, see the Versioning Policies document in GitHub.

Component versioning creates a form of contract that is important for upgrades as it clarifies when something might need to be refactored. See also the section Upgrade Compatibility of Customizations, which explains what considerations different forms of customizations require for an upgrade.

To avoid painful content migrations, it is important to never directly point to versioned components from content resources. As rule of thumb, a sling:resourceType of the content must never have a version number in it, or upgrading components will require the content to be refactored too. The best way to avoid this is to follow the Proxy Component Pattern described above.