Send your request Join Sii

Clear and understandable architecture is one of the key success factors in software development[1]. Both architects and developers are making dozens of architectural decisions every day. In a complicated environment where multiple technologies are mixed, the cognitive load of every decision drains out mental resources. Adobe Experience Manager, without any doubt, goes under this category.

In this article, I introduce the concept of modules and the boundaries between them so delivering a tailored system of components within AEM is less stressful and easier to change from a broader perspective.

Our hive-mind Sii experience delivering tailored content management systems based on Adobe Experience Manager taught us to think of the software created as a set of moving parts that can connect to each other and construct a system that has a unique value on its own. I will show you these moving parts below, revealing the mysticism of designing good architecture without too much cognitive load.

This blog post is not meant solely for AEM specialists but also for people who design larger solutions in which AEM plays a part – solution and enterprise architects.

Adobe Experience Manager briefly

AEM is the top CMS solution in the market. It is a large piece of software that is currently delivered as a cloud service. Historically, Adobe provided AEM as software on-premises. Still, a few years later, customers were more interested in a hybrid solution – Adobe Managed Services – where Adobe hosted the application in its cloud.

One would think these dramatic changes of deployment methods were severely affecting the actual AEM internal architecture. They were not – seems like that was Adobe’s goal. Thanks to that, we can talk about AEM architecture for all these deployment methods and versions. This blog post mentions elements that have existed for a long time, so you do not have to check which version you work with now.

AEM for specialists

A fellow solution architect should treat AEM as a web server. Overall, it provides a UI for creating content that the server provides as HTML/JSON/XML/*.

A fellow architect or developer should think about it as a set of components capable of forming into pieces of expected format, keeping in mind these vital facts about components:

  • Content editors or other parties, like external systems, fill components with data – so we can consider components as a type and components as the content of a specific type.
  • Components can have other components inside, can nest themselves, or other types.
  • A component interacts with the non-component context of the universe. Bear with me – this part will be explained below.
Komponenty zagnieżdżone w celu renderowania strony
Fig. 1 Components nested to render a page

Structured of sample page

The diagram above shows how the sample page is structured. This is naturally very simplified; however, it is an important view of the entire architecture used in AEM. Nesting in components can be forced (so the component inside is “given” by the parent) or relaxed (the content author decides to nest this or another component).

This is how pages and content are generally represented. The default servlet asks the top component to render, and it runs its rendering, additionally calling nested ones if necessary.

To verify this understanding, let’s try to break things down. If you create the component A that nests B, and B nests back A, it will end up in the infinite loop. Do not worry, though – implementation has a maximum number of components called within a request, but this is an interesting thought experiment that will confirm your understanding of this mechanism.

Sposób wprowadzenia pętli nieskończonej za pomocą metody zagnieżdżania komponentów
Fig. 2 Way of introducing endless loop using the component nesting method

Components

This knowledge is key to a closer look in the next section, where we will disassemble the component based on its technological dependencies.

So, if you would try to imagine your first hello world page designed using components – that’s probably a main page component that will render necessary HTML tags and the text one that displays text.

Correct?

Well, to some extent – that’s the key value of AEM – because Adobe Experience Manager comes with a really solid set of ready-to-use components called Core Components[2]. In my career, customers covered static content with these ready-to-use components, with just extra tailoring and CSS styling. It is not a challenge for architects or developers.

The real fun begins when we must provide a piece of unique behavior on the page – like context-wise content, processing the data created by content authors, changing in time, or using other data sources outside of AEM.

Let’s take a look at The Concept, disassembling components into pieces that we can understand, splitting them between teams, and, more importantly, designing upfront without getting into the expensive development phase, at least for now.

The Concept

Module types map in Adobe Experience Manager
Fig. 3 Module types map in Adobe Experience Manager

Java, JavaScript, and AEM Worlds

This diagram may look too complicated, but let’s break it down piece by piece, starting with worlds:

  • Java World – holds any piece of software that is programmed via Java programming language. This is the place where we used to have the back-end developer role.
  • JavaScript World – the same as Java, just using JavaScript. However, this can be both running server-side and browser-side. People dealing with this world are usually called front-end developers.
  • AEM World – unoccupied zone, specific to AEM. It usually consists of a set of components or dialogs (which are components, too!) that can be handled as XML configurations, HTL files, and the basic deployment unit – a package. In principle, these are dealt with by both back-end and front-end developers, depending on the task.

This separation helps an architect understand the split of work between engineers who specialize in different fields. It is very uncommon for one engineer to master all three worlds together.

Communication between worlds

Presented worlds are talking to each other using:

  • Exposed Java Use or JS Use in scripts – this is how we can access Java/JavaScript World from AEM World. A script can call methods or functions to obtain information that affects rendering.
  • Including client library (AEM World to JavaScript World) into a script to incorporate a link to CSS or JS resource for a browser.
  • Calling OSGi Service from JavaScript Use – JavaScript World to Java World.

In other words, worlds communicate with obtained objects via identifiers in another world and call functions on them.

A side note: there are other ways of communicating between worlds (like accessing data through the Session or ResourceResolver objects and storing them); however, they are not part of the regular rendering, hence not recommended or used under normal conditions.

AEM Component

Now, let’s take a look at the first-class citizen, AEM component, and what this consists of:

  • Nesting. The component can nest another component.
  • Scripting. The component can determine what kind of script renders the output (usually HTML). There are other script options, like JSP; they are not generally recommended to use as obsolete.
  • Configuring. The component has its dialog that allows content authors to input data (like text or other information that affects the component’s rendering.

I mentioned in the paragraphs above how important the concept of components is. Meanwhile, if we consider a component a root of another tree of components, we get a tree structure that plays well with HTML and similar data structures. Nesting, however, is a function completely controlled by the component itself. There is an extra vocabulary extension: “parsys” (paragraph system), but generally, an architect should know there is a way to point out a place where other components can be dropped in.

One can design a component as a standalone, not allowing any nesting – that is fine. Another can make a component that has extra fixed components within. That is also OK. We should not judge the component’s structure and interactions by static facts (as we do when analyzing all potential connections here) but verify this against the usability standards of the customer’s domain.

I cannot imagine a gallery component without internal, or even better, out-of-the-box components to manipulate inside so that the gallery is only a container that can control images currently displayed and handle all the logic of changing them while visiting the page. On the other hand, a text component should not have other component nested, as long as we want to keep this function solidly maintained over time.

AEM Packages

Packages are ZIP files that contain JCR-ish data, but from our architectural perspective, they carry a set of components that can be entangled in one specific deployment unit. Packages have their version and name, which allows straightforward updating of the package during deployment, i.e., replacing the same components with their other versions.

In our case, a package can provide components to the AEM environment.

Script

A script is usually HTL (rarely JSP) code that transforms into an HTML response. Execution of a script is request-based, meaning it can have conditions specific to the context. Look at this example:

<sly data-sly-use.related="com.sii.RelatedPages">
${properties.name}
    <ul data-sly-list.page="${related.list}">
        <li><a href="${related.path}">${page.name}</a></li>
    </ul>
</sly>

It looks like a regular HTML snippet, with that sly tag and extra data-sly-* attributes. They are processed with the backend and do some extra actions on HTML as text. In the example above, we get a Sling Model or Java Use (at this point, we don’t know that), and we get from it a list using a method list and display each page link with its name within the unordered list. Properties object is the information that content author inputs directly in the component instance.

This is the core use of scripts concept within AEM – interact with other worlds, define conditions for rendering, and run it.

Sling Model / Java Use / JavaScript Use

These three hold different technologies but have the same use case. They are meant to interact within scripts. The main problem an architect must solve is whether the system’s design should rely on logic kept in these cross-world interactors or more generic places like JS modules or generic Java classes.

Usually, systems use the fact they can implement most of the data processing functions in these objects, and they are tangled with the components they are using. But, if you have a good reason to do so, your Sling Models, Java Use classes, and JS Use modules can be shared across multiple components, as long as it makes sense, and can be only just proxies to more complicated code bases written in less-AEM wise Java or JavaScript. This can work for a domain-driven codebase, which can be reused among different frameworks as a framework-agnostic core library.

Sling Models and Java Use classes are the same concept, with Java Use classes being an older implementation. Nowadays, developers create more Sling Models. However, you will certainly find ancient Java Use classes in long-maintained systems and consider them within your architecture.

The other core functionality from our architectural perspective is these objects can communicate with OSGi services that have no direct relation to any component. This is the point where architects can pivot the responsibility and, more importantly, interactions with systems outside of AEM’s component-oriented architecture.

OSGi Service

Concisely, OSGi is a framework method for running separated class loaders within the Java Runtime Environment[3]. AEM, and its core framework – Sling- uses it, but OSGi itself is a standalone solution; it is used in other software systems based on JVM, like Eclipse IDE. Architects find OSGi interesting, especially for extra isolation between running bundles – units that can have different classes, even though they share the same qualified name.

Describing OSGi functionalities is, in principle, a subject for another blog post, if not an entire book. Hence, I recommend visiting the official documentation[4] if you need to know more.

From our architectural perspective, OSGi bundles are like AEM packages – they are a set of Java classes that can be installed in a specific version of the AEM instance. These deployment units allow us to control what kind of other dependencies are used within our code. Strategically, it does contribute to overall maintainability – the bundle can narrow down usage of other bundles (i.e., a set of Java class paths) that our code communicates with.

Apart from the isolation method, OSGi delivers a way to run class instances – Java objects – and manage their lifecycle. Such objects are called components. They can be instantiated based on configurable conditions, torn down, and run extra activation code. For example, if we need an object that writes a message to standard output once the bundle is up, we can configure a class to become an OSGi component that activates the method containing this action.

It would be a tricky situation if components were not capable of communicating with each other. OSGi introduces a concept of OSGi service, which can declare the interface used to be provided to other components. The provisioning happens either dynamically or during component instantiation. In other words, components can aggregate OSGi services and call their methods if necessary.

But what if we want to run some web action outside of AEM components?

Servlets and Filters

Architects work within limited environments, frameworks, constraints, and concepts. Sometimes, we are forced to depart from the existing approach and add something to the proposed concept.

Consider a scenario in which we must introduce a JSON endpoint to feed a stock component with dynamically obtained data from another, usually internal, source. We saw the part where components are representatives of generated HTML snippets. Today, architects should design intensively visited HTML pages as static ones, cached as close to the end user as possible using a Content Delivery Network (CDN).

So far, the AEM modularity approach does not give this opportunity unless we can have an extra extension for the same component and render it. Sometimes, given that we can play with longer paths, this is off the table, and we must take a step back and use a popular web server mechanism in the Java world, which is a Servlet.

If you are rooted in this technology, you know this is always entangled with another concept – Filter. If this sound unfamiliar, I recommend reading documentation and play with these outside of AEM first[5].

The difference between regular Servlet and AEM’s ones is all of them are OSGi Services – they can communicate with other services, effectively with the rest of AEM system. An architect should use that fact while designing concise solutions to avoid repeating the same functionality implementation in Servlets and Sling Models, introducing either shared Java classes or OSGi services.

At the end of the day, even with so many isolation layers, the system is a system of added-value direct and indirect relations between the parts, not the parts themselves.

Client Library

Websites are not only HTML files or JSON data communicated to the end user. The look and feel of the page are as important as the content; in the literature, look and feel are the content[6]. The architect cannot miss this part in planning the design of the website and its components.

Think about the stylesheets for now – are they coupled with components? In other words, can certain stylesheets be as reusable as components? Given their reusability, components should keep a modifiable look and feel. Stylesheets are more part of the page (a template, which we did not bring up in this blog post) than the component.

What about front-end scripts? The behavior of components (especially those that dynamically change or can be interacted with without page load) seems to be much closer to components than how they look.

Given that discrepancy, we should consider behavior and appearance to be optionally related to each other. At the end of the day, some are connected to each other and cannot be torn apart.

Client Library's structure
Fig. 4 Client Library’s structure

AEM introduces a mechanism for aggregation and dependency management of CSS and JS files. It is identified by a string identifier called category name. Excluding shadow DOM, a browser loads all those files in the same context as the page, so an architect should reuse the existing pattern of loading client libraries only in a page component.

Client libraries can define other categories to be dependent on or embedded into. This ends up in a powerful capability of defining required libraries for your JS or CSS to be loaded without putting a burden on users of your client libraries. Additionally, you don’t have to change anything on the page if some dependencies become obsolete for your client library.

Surprisingly, one can name multiple libraries with the same category name, and all of them will be loaded into the page. This feature can be useful for architects, leveraging the capability to add some extra CSS or JS for a specific category without changing the page content and template. You can consider it as an aspect programming pattern for client libraries.

There are no codified rules for structuring or designing client libraries. However, the logical solution seems to be keeping one kind of them to handle the vital behavior of components and another one for a page’s appearance.

Summary

These basic concepts are the foundation of any decent, tailored system developed within the AEM environment. Do not be deceived, though – this is just the beginning of your journey through the functions AEM has. Nevertheless, this different approach was the original reason AEM is now the most innovative CMS in the market – it makes the architecture much closer to content than the template-based approach. Oh, you cannot imagine your website without templates? Do not worry; there are templates, too, but they are not first-class citizens.

Adobe Experience Manager is a large CMS. In this blog post, I did not tackle the functionalities available in the system out-of-the-box – my point was to introduce the tooling I use to plan work for creating components that are not there or simply cannot be, given that the solutions we implement are unique for the business a customer runs.

Now, Go Practice!

Using solely this overview, you should be able to build architecture suitable for interesting cases. If you currently don’t have any, I will give you some ideas:

  • A library website, where every book is a page, can add extra aggregation pages by categories that are natural and static (like genres) or temporary and dynamic (like “recommended for you”).
  • A scientific institute that publishes tons of pages weekly, where you need to implement components that external AI sets relations between (plan using ChatGPT API for it).
  • A financial business, where you need to introduce a component based on the rest of the page, gives hints about the potential investment options (AI or BI engine-driven).

Designing architecture for AEM-based solutions is fun, but you need the right tools and practice a lot. Now that you have the tools, enjoy the practice part!


[1] N. Nan i S. Kumar, “Joint Effect of Team Structure and Software Architecture in Open Source Software Development“, w: IEEE Transactions on Engineering Management, tom 60, nr 3, s. 592-603, sierpień 2013 r.

[2] https://www.aemcomponents.dev/

[3] https://en.wikipedia.org/wiki/OSGi

[4] https://docs.osgi.org/specification/osgi.core/8.0.0/toc.html

[5] https://www.baeldung.com/intro-to-servlets

[6] Barker, Deane. Zarządzanie treścią internetową: systemy, funkcje i najlepsze praktyki. “O’Reilly Media, Inc.”, 2016.

***

If you’re interested in Adobe’s solutions, be sure to also take a look at other articles by our experts.

5/5 ( vote: 1)
Rating:
5/5 ( vote: 1)
Author
Avatar
Dawid Pura

Software engineer specialized in delivering and maintaining CMS systems based on Adobe Experience Manager. In his career, he revolutionized some projects he worked on, but he definitely had an impact on all of them. Working in the industry for 10 years, he has no doubt that creating software is still undiscovered, organic, and uniquely interesting. When possible, he wears a philosopher of programming hat

Leave a comment

Your email address will not be published. Required fields are marked *

You might also like

More articles

Don't miss out

Subscribe to our blog and receive information about the latest posts.

Get an offer

If you have any questions or would like to learn more about our offer, feel free to contact us.

Send your request Send your request

Natalia Competency Center Director

Get an offer

Join Sii

Find the job that's right for you. Check out open positions and apply.

Apply Apply

Paweł Process Owner

Join Sii

SUBMIT

Ta treść jest dostępna tylko w jednej wersji językowej.
Nastąpi przekierowanie do strony głównej.

Czy chcesz opuścić tę stronę?