Developing with design systems - workflow changes

How do development workflows change when using a standalone design system vs a self contained app?

Gav McKenzie
Author
Gav McKenzie
Published
Apr 29, 2024
Topics
Industry, Engineering, Design Systems

We had an interesting question come in from one of our clients about how development workflows change when using a standalone design system vs more classic workflows with a self contained app.

Tell me about the good old days

Traditionally, a site would have all the code for the front-end, back-end and UI all wrapped up in one place. Many years ago, designers would create designs in Photoshop showcasing all the pages that needed to be created. Once signed off, these would be handed over to the development team who would recreate the design as pixel-perfectly as possible.

Designs were usually fixed to a canvas that represented the average or minimum browser size of the users of the site.

960-grid.webp

Remember the classic 960px grid?

In the CSS, developers would create loose, unofficial, components that comprised groups of CSS arranged using a methodology like OOCSS or SMACSS. Because of the nature of the designs, the quest for pixel perfection and the page-centred workflow, we’d often end up with a bunch of page-specific CSS.

.hero {
background: #ff0000;
}
/* Green hero for the home page */
#home .hero {
background: #00ff00;
}

This method of design and development is very rapid at a small scale because designers can be free to create pages in a myriad of slightly tweaked styles and developers can easily recreate those by leaning on page-specific CSS when the designs don’t quite fit the base CSS classes.

This is fine for small sites, but as things get larger, it ends up in a maintenance pit of endlessly scaling CSS. The next move was towards component-focused development.

Lego bricks for the web

The classic metaphor is that components are Lego bricks to help you build websites.

Components are collections of HTML, CSS and JavaScript that combine to form reusable bits of UI that can be composed in different structures to build a whole website.

When we first moved to component-focused development, the design process remained fairly similar, with designers creating a suite of pages for a site that needed to be built.

The development team would then analyse the mockups, looking for similar bits of UI that could be grouped into components. These would be isolated so the dev team could see the differences between instances and identify the props required to drive the UI states.

Page-specific CSS, which caused many of the maintenance issues in the old workflow, went in the bin. Components are strictly isolated and require props to create the different variations.

.hero {
background: #ff0000;
}
/* Green variant */
.hero--green {
background #00ff00;
}

This new workflow required a mindset shift. When looking at a new design, we’d need to consider whether it could be built with the existing components and what changes would need to be made to them to support any new variations.

Component-focused development creates more scalable sites as components can be re-used again and again on many different pages. The initial process can take a little longer as we need to analyse what needs building and how to group elements and set up props, but from there, creating new pages and maintaining existing ones is much more efficient.

Let’s design systems

Component-based design is great, but the components are still housed and maintained in the codebase for a single app.

In a larger company (or even a small one sometimes!), there may be many apps and many development teams that all need to provide a unified feel across the UI ecosystem.

The next step in component-focused design is to create a standalone component library that can be used to power the UI across many apps.

With this method, the components we create are moved to a standalone repository, along with the design tokens.

Design tokens are the values for the smallest building blocks of UI, such as colours, typography and spacing.

/* Design tokens */
:root {
--color-blue-100: #0000ff;
--color-blue-90: #0000cc;
--color-blue-80: #0000aa;
--font-family: Helvetica, Arial, sans-serif;
--font-size-base: 16px;
--spacing-sm: 0.5rem;
--spacing-md: 1rem;
--spacing-lg: 2rem;
}

The first step to creating a consistent, multi-app, UI is to have all teams using the same set of design tokens. At the very least, this makes sure all teams are using the same fonts, colours and spacing across your whole UI, which is a massive step towards creating consistency.

Now the components are being used by multiple apps, there is an extra layer of consideration that needs to be taken for each component in the system. Different teams have different requirements and we need to make sure that each component can support those requirements, or is flexible enough to be adapted to support new requirements in the future whilst introducing minimal breaking changes.

Components introduced to the design system will rapidly be taken up by multiple teams and they need to be rock solid before being introduced. Bad components can quickly disseminate throughout different apps and need to be caught before they go into the system.

For each token, component or new prop, we need to ask a group of qualification questions:

  • Does this already exist in the design system?
    • If not, why do we need it in the system? What use case does it cover?
    • If it already exists, why is it different to what exists? Should we adapt the base, or add a new variation?
  • Would the design system benefit from this existing?
  • Would this component benefit multiple teams?
  • Has the component been tested in production?
  • Who do we need to collaborate with to ensure this fulfils all requirements?
  • Does this addition support different requirements, such as different text formatting, different actions or different words?

In a multi-app system, each change has to be carefully considered because it supports many teams of developers. The design system team, whether it is a dedicated team or a council of members from different squads, needs to police the system to make sure every addition is high quality and future-friendly.

Long term relationships

A good design system will last many years. We have been supporting some design systems for a decade at Etch, watching them move through different technologies and teams as the years progressed. This section describes some recommendations for processes to follow for long-term design system success.

Gather the council

A design system team should have members from different squads within the business. As well as different squads, there should be members with different roles, emphasising design, development, product ownership and management, and team members who are as close to the users as possible such as call centre staff.

Each of these member types can provide valuable feedback on component requirements, usage of the system and user’s frustrations with it.

Battle test

Components don’t have to be created in the design system first before being used in production. Teams should be free to build their components using the design tokens and to test them in production. The design system team should regularly review custom components used across different teams to look for common use cases or identify components that teams are particularly pleased with that could be uplifted to the central system.

Notice periods

Components and tokens will come and go over the lifetime of the system. A deprecation notice system should be established, and teams provided with enough notice about breaking changes, such as the removal of components, so that they can action them without having to break their immediate workflow. System-provided migration scripts, if possible, are ideal.

Get feedback

Gather as much feedback as possible about frustrations using the system. Regular surveys are great, but it can be easy for users to forget what was annoying them a week ago. If responses can be gathered at the time of frustration, that is ideal.

So what’s the difference?

The main difference between traditional development workflows and working with a standalone design system is a mindset shift. Use the system or improve the system.

  • Does this fit the system? If not, why not?
  • Should we use this to improve the system?

Design system-based development should be a constant evaluation of whether the design system is working for us and what we can do to improve it so it works better. Rather than isolated apps, we should be continuously iterating the UI layer of the whole ecosystem to drive it forward.