Design system maintenance — sharing markup between applications

Discussing the problems we have to keep applications in sync with our design system. Changes in CSS and JavaScript is one thing, refactoring that require changes to shared component markup much more difficult.

A little over 2 years ago we decided to switch to a modular UI design methodology and a style guide driven development process.

In the beginning we spent a lot of time discussing how we should build our design system, what components it should include, what CSS architecture to use and how to create a template layer with the vision to achieve the holy grail design system.

Now, we are in a state where our component library, processes and the template framework are relatively stable. Instead, one of the more time consuming tasks has been to keep the markup of each application in sync with the markup in our component library.

The markup is distributed between many different applications, all with separate code bases.

The medium post, Chasing the holy grail, discusses different techniques on how you can distribute and link up different versions of a design system’s resources (CSS, JavaScript, Icons etc.) to different applications.

Modifying a component’s CSS and JavaScript is rather straightforward, but when refactoring require changes in markup it suddenly gets more complicated.

As Brad Frost writes in his book Atomic Design:

Sharing CSS and JavaScript is all well and good, but where things get tricky is when you want to share markup between environments.
Atomic Design: the Book, chapter 5

Our ecosystem of applications

Our applications are distributed between a few big external and internal web portals. This means that in a production environment, over 50 applications (with separate code bases) share the same version of our design system’s minified CSS and JavaScript.

Since so many applications are running on the same web site our situation doesn’t really allow us to use versioning as an effective tool to manage updates. I believe that this situation might differ from what many others are dealing with.

To explain our situation, compare the following two ecosystems of applications distributed between different web sites.

The first image shows an ecosystem with many sites (on perhaps many different platforms) where each is home to a small number of applications. This means that there are fewer applications that need to be bumped up to the next version of the design system at the same time.

Ecosystem 1— Many sites (on different platforms) that hosts a small number of applications each.

The second image shows an ecosystem much like ours, where you have a few large websites/portals that is home to many different applications, each with their own code base. All applications within a website/portal share the same design system resources.

Ecosystem 2— Few sites that hosts a large number of applications each

Even in our situation, it is of course possible to link up a different version of the design system to our different portals but this still means that we have about 50 applications for each site that require a simultaneous update and deployment.

Templates — to relieve some of the pain

In the beginning of this post, I mentioned our template layer which adds an abstraction layer on top of our component templates. This template layer is a great help. It means that refactoring of HTML markup can be done at template level — in a single place.

All applications (including the component library in the style guide) share the same templates so a change in HTML markup in the template is automatically reflected in all our applications the next time we deploy the component framework templates.

The problem, for us, arise when we need to update the template XML, which we have been forced to do more often than we would have liked (and perhaps expected).

It can be larger refactoring of the components content model but also small things like streamlining the naming of content elements in a template, e.g. we want to change name=”title” to name=”header” in the template for the component “message”.

/* Application code for displaying a message using the message-template. Written in our XML template language. */
<gbg:message>
<gbg:element name=”title”>Of Dominion After Land</gbg:element>
<gbg:element name=”content”>
So Saw second every fifth likeness.
</gbg:element>
</gbg:message>

Possible solutions

We have discussed different alternatives to facilitate the process of updating markup. And frankly, we are not really satisfied with any of them but let’s look at three of the options we have discussed.

Introducing a versioning number per component

One possible solution we have discussed would be to include a version-numbering on each component, like <gbg:message version=”1.2"> and temporarily duplicate the components CSS, JavaScript and template to accommodate multiple versions. This would make it possible to update the shared design system’s resources for the environment and then one by one move specific applications up to the latest version.

Although this is a possible solution, it adds a complexity to the system that’s otherwise not necessary. And also, if you’re not careful you might soon have another maintenance issue on your hands.

Linking up different versions of the design system per page

Another solution that could work in theory is to let each page decide which version of the design system resources to load. This also mean that we need to be able to use different versions of the template framework on different pages.

One obvious downside is that a user, during a visit, might have to download several versions of the resources. It is also problematic if two different applications on a single page needs different versions.

So, for many reasons, this approach does not seem like a way forward.

Updating applications one component at the time

The approach we are using now is to batch update all applications that uses a specific component and then simultaneously deploy these to production together with the latest design system resources and component framework templates.

The downside is that we, over a short period of time, might have to do several deploys of a single application if there are markup for several components that need refactoring (since we update only one component at the time).

To update markup for more than one component at the same time increases the the number of applications that we need to update simultaneously, e.g. all applications that uses either component A, B or C.

Summary

Regardless of whether you use a template language or plain HTML in your applications it is still a difficult task (or at least time consuming) to keep markup distributed over many different applications in sync with a central design system.

If you have many of those applications running on the same website it adds to the complexity.

Are you maintaining a design system and have you experienced similar problems. We’d love to here about it!


This was part 7 in the publication: Our Story: Building a component library