Components Creation Rules - reggie7/aem-tools GitHub Wiki

I will try to gather information on what I consider to be good practices regarding creating AEM components in the text below. This will not include strict Java development issues for the components, only AEM part itself.

Keep properties close

Try to make all the labels, texts, images, etc. configurable inside the dialog(s) of the component. What the end user can see should live under /content as close as possible to the resource being rendered. As much as possible of the content should be a part of the resource itself.

Imagine you are about to create a navigation menu. It will gather some internal pages of the site. You can create e.g. a simple parsys based component that will contain references to those pages just like here. Each item in the list can have its own resource type. In case you need a nested list of links that will pop up on mouse hover - just add a new component type (with a nested parsys for the second level links) that will allow you to do that.

I've seen an ugly approach where in the main navi each link entry came from a separate dedicated proxy page. Each link_i page contained a redirect property that later had to be used in order to render the link. There was a lot of indirection just to hold one property. In order to configure this small part of the app authors had to visit a couple of pages. And those had to be defined under a specific path - making the content editor obligated to know this setup.

Pros

  • direct access to the desired properties,
  • easier to copy/package/activate content - everything is stored in the local context of the resource,
  • avoids additional artificial components serving just as technical brigdes between the source content and target component.

Cons

  • when the resource structure grows bigger it might get hard to maintain, but then zoom mode come at handy.

Store content in /content

Cloud Services are maintained by one group of users. I18N is maintained by a different group of users. Authors that create content usually do not have access to those other parts of the app/etc management. CCs and i18n might sometimes seem like a time-saving solution, but in general it is not, their purposes are different. Use inherited properties for shared content instead. Labels, images, texts usually belong to underneath /content, not /apps (where i18n is stored) or /etc (where CCs are located).

Avoid using Cloud Services and i18n for content that the end user will see. I've seen AEM apps implementations where this rule was not obeyed. It just didn't seem right in the first place. It was simply wrong actually and was a result of lazy, convenience seeking approach. Some shared labels would end up in various cloud configs, others would be defined inside i18n and basically the whole thing becomes a mess.

A label for Search does not belong to CCs. You can e.g. create a search component and force a resource named search inside jcr:content of the language/home page. Inside of other pages you will simply render the same resource by providing an absolute path.

Labels for button texts OK, Continue, Cancel do not belong in i18n. I've seen a project full of it and it was a pain in the code-developing-fingers. You can simply allow the common labels to be defined inside the root page and then use the inherited page properties.

Rules

  • Use i18n for whatever an author will see, but the end user will not. i18n is the AEM application, not the customer website.
  • Use CCs for whatever neither the author nor the end user will see directly. This is configuration, not content, for services that are external somehow. They are not content holders.

Pros

  • more direct access to the desired properties,
  • authors define content and do not have to escalate such trivial things as label typo,
  • CCs and i18n are used for what they were designed for.

Cons

  • you will need to develop proper ways to access common properties, which will take a little more time (but I've done it for you here already).

For me it's yet another example of thinking out of the box that's gone wrong. There are interpretations that say i18n is allowed for simple labels. It's an indication that bad and ugly code is about to be developed... Run, just run.

Aggregation over inheritance

Try to favor content aggregation over inheritance. This rule works just as in classes within object oriented programming. We'd rather favor dividing resource data into subresources over creating attributes that need a lot of prefixes making their names very long to be meaningful. Don't be afraid of subresources. You will be able to e.g. use them later more uniformly throughout the whole application. E.g. to use one model to adapt to from different resources.

Imagine you have a contact form component. What it does is the following:

  • defines parameters of an email that the user will send to us, the company (recipients, template, subject,...),
  • defines the parameters of an email that we will send as the confirmation of receiving user's e-mail (sender, template, subject).

We could try to add the values directly on the contact resource, e.g.:

  • inquiryRecipients
  • inquiryTemplate
  • inquirySubject
  • autorespondSender
  • autorespondTemplate
  • autorespondSubject

Then Java HTL model for sending those e-mails needs fields for that exactly as they are named above. But if instead we used:

  • inquiry/recipients
  • inquiry/template
  • inquiry/subject
  • autorespond/sender
  • autorespond/template
  • autorespond/subject

then we can simply work on two resources: inquiry and autorespond which can be adapted to the same model now. They can then also be displayed (e.g. for the author) in a uniform manner.

Another example is when you allow an image inside your component - it's safer to make it a separate resource. Why? E.g. width property is used by the image rendering code and in case you want to add such property on the main resource - you simply can't.

Generally - standardization is very powerful for avoiding additional work later...

Pros

  • you can create a tool for one part of content and then be able to reuse it for another,
  • the new content structure is easier to read once you get used to the old one,
  • you can reuse the same scripts to render a subresource.

Use the existing content

Don't force the author to duplicate information that already exists somewhere else. You can simply use the default values derived from there, but maybe add an option to override them if actually needed. When creating a link to a page we can display it's internal labels (navigation title, page title, jcr:title, subtitle, name) instead of using additional text. But an override option should be supplied in case author needs that.

I've seen projects that were using a couple of sources within content repository where a value for X was defined. Why not use just one? Every time we had to configure components that relied on X - we were not sure which place they should come from. There should have been just one point of entry. Why would content editors be forced to change the same value multiple times? Some more teams coordination was needed...

Pros

  • less work and more data consistency for the author,
  • less copy/paste for the author,
  • less confusion - one source works better than multiple ones.

Remember context

Remember context and use uniform naming. Use accurate names within the given context - not too short, not too long. Don't duplicate the context as it adds no useful information, just complexity in naming. The sling:resourceType tells you where you are, you don't need to remind it everywhere. In case you are developing a component mycomponent there is no need to name its properties with additional prefix mycomponent. Why use mycomponentHeight if you can simply name it height? Your context is mycomponent already, you know it. On the other hand - h would be too short.

The rule above applies in the same manner to JCR content as to class properties in a programming language or column names in a relational database. Another examples would be:

  • teaseritems, galleryitems - bad names, use items simply as the context tells you where you are - inside a teaser or inside a gallery,
  • linksparsys, buttonsparsys - bad, use links/buttons instead as the sling:resourceType tells you already these are paragraph systems,
  • color - good inside a font related resource, bad for text component where it should probably be either backgroundColor or foregroundColor,
  • linkreference, linktitle, linktext - bad inside a link component where the context is known - use reference, title, text.

Pros

  • going through items every time it is needed is much simpler than always conforming to a non-standard name,
  • copy/paste of code is less error-prone,
  • less is more.

Cons

  • you will need to remember the context, but you are the smartest person I know - you can do it!