AEM Proxy Component Pattern and Component Versioning



Most organization want to keep content and user experience flexible so that they can innovate and deliver new experiences/features faster. Flexibility allows organizations to reuse what has been built already and keep adding new features and functionalities on top of it. One of the key characteristics of flexibility is backward compatibility and non-breaking changes.

This flexibility comes with a clear definition of a strategy for content creation and user experience.

In this article we are going to look at 2 very simple but powerful component development strategies that organization (specifically technical teams) can adopt to win the flexibility game and stay ahead in competition of delivering rich user experience.

 

Let’s start with a scenario/problem statement. 

Assume that a large banking organization has business in multiple countries. The organization is using AEM and MSM (Multi Site Manager) to manage regional sites. The bank started using a video component (custom developed) few years ago. The video component is integrated with Google analytics. The bank is starting business in few new countries and has decided to use Adobe analytics on new websites for video tracking.

The common considerations to implement such scenario:

  • We need to ensure that existing component’s functionality (Google analytics) is not impacted
  • We need to just update the tracking behaviour of component (ideally this can be achieved using a well-defined DataLayer and Tag management implementation, we’ll ignore DataLayer for now)
  • Maintain both functionalities side-by-side but independently 

To make the problem more complex, assume that we have 500K pages where existing video component is being used today and we don’t want to impact existing pages.

How is the bank going to achieve this? The bank needs to ensure that existing functionality (Google analytic tracking) is not impacted. Let’s look at some of the options first, we’ll discuss solution later.

Table

Description automatically generated

 As you can see both approaches can impose additional risk and demands time. This translates to additional expense.

 

Is there better way to handle this? 

Yes, this is where Proxy Component and Component Versioning can help.

 

What is Proxy Component?

AEM relies on “sling:resourceType” property to identify which component is responsible for rendering. The rendering component can further extend from another parent component using “sling:resourceSuperType” property. This concept is similar to Object Oriented programming (a class can extend from another class). But where is the proxy component? 

Proxy component is a component that is just a placeholder component whose “sling:resourceSuperType” property points to an actual rendering component. Instead of using actual component while creating pages/content, we refer to this proxy component. Think of this proxy component as an interface (in Object Orient programming). Implementation behind interface can change without asking consumers of interface to change anything forcefully. Similar, if we are using proxy component, we can point to a different component in future (by updating the sling:resourceSuperType property of proxy component). We don’t need to update the “sling:resourceType” property in content tree.

This is typically useful when a component is already used and we don’t want to find all the references and replace them one by one. We can simply change the pointer (sling:resourceSuperType property) of proxy component to point to new implementation/version of component. We’ll see versioning next.

 

What is component versioning?

As name suggests, component versioning allows us to create different version of same component. If we were to compare this with object-oriented programming, think of component versions as various implementation of a base component (or interface or abstract class). Each version of component inherits the functionality from base component and then we can add/update new features. Proxy component allows us to switch the implementation from one version to another. We’ll look at an example later in this article.

 

We can use above capabilities to address scenarios like what we have one (banking video component scenario that we assumed above in this article). The company could use proxy component and component versioning to reduce the risk.

Let’s talk about an example solution. Let’s see how we can structure our video component using proxy component pattern and leverage component versioning which will allow us to switch from one implementation to another easily.

//The page (cq:Page) in "united-states" site where video component is being used
{
  "/content/my-bank/united-states/home/jcr:content/video":'',
      "jcr:primaryType": "nt:unstructured",
      // Pointing to proxy component (see below)
      "sling:resourceType": "my-bank/components/video" 
}

// This is PROXY video component pointing to (v1) of video component
{
  "/apps/my-bank/components/video":'',
      "jcr:primaryType": "cq:Component",
      // Pointing to v1 of Video component
      "sling:resourceSuperType": "my-bank/core-component-lib/video/v1/video" 
}

// v1 Component: GOOGLE Analytics tracking implementation
{
  "/apps/my-bank/core-component-lib/video/v1/video":'',
      "jcr:primaryType": "cq:Component",
      "video.html": "",
          // This is based Model interface
          "data-sly-use.model": "com.suryakand.demo.model.Video" 
}

// Model interface (implemented by both V1 and V2 version of Video component)
package com.suryakand.demo.model;
public interface Video {

}

// Model implementation (for version v1) of Video component
package com.suryakand.demo.model.impl.v1; // Note the package name (v1)
@Model(
  adaptables = SlingHttpServletRequest.class, 
  adapters = { Video.class}, 
  // Note the (v1) in resource path
  resourceType = "my-bank/core-component-lib/video/v1/video" 
)
public class VideoImpl implements Video {
  
}

// v2 Component: ADOBE Analytics tracking implementation
{
  "/apps/my-bank/core-component-lib/video/v2/video":'',
      "jcr:primaryType": "cq:Component",
      "video.html": "",
          // This is based Model interface
          "data-sly-use.model": "com.suryakand.demo.model.Video" 
}

// Model implementation (for version v2) of Video component
package com.suryakand.demo.model.impl.v2; // Note the package name (v2)
@Model(
  adaptables = SlingHttpServletRequest.class, 
  adapters = { Video.class}, 
  // Note the (v2) in resource path
  resourceType = "my-bank/core-component-lib/video/v2/video" 
)
public class VideoImpl implements Video {
  
}

Comments

Popular posts from this blog

AEM as a Cloud Service (AEMaaCS) – Architecture Overview

AEM 6.3 - Bundle Whitelisting - Deprecation of administrative authentication

AEM - Query list of components and templates

Custom synchronisation or rollout action for blueprint ?