12 User interface and design system

This chapter covers:

  • Examining how a design system can help deliver a consistent experience to your users
  • Developing a design system and how it can affect the autonomy of the micro frontends teams
  • Technical challenges when building a pattern library that should be technology-agnostic
  • Distinguishing if a component should go into the central pattern library or stay under a product team’s control

In a micro frontend architecture, every team builds its part of the frontend. A team can plan, build, and ship new features without talking to its neighbors. But how do you deliver a consistent look and feel for the user? The different frontends should use the same color palette, typography, and grid layout. These measures ensure that the website does not look weird. But it typically doesn’t stop there. There’s also button styling, spacing rules, breakpoint definitions to support a variety of screen sizes, and a lot more.

Classical architecture discussions often dismiss these topics as unimportant. You hear sentences like, “We’ll find a way to make it pretty afterward.” However, in a distributed architecture like this, it’s essential to have a proper plan for managing your design from the start. Throughout the book, you’ve learned techniques to avoid sharing code and keep teams as decoupled as possible. When it comes to design, it’s not that easy. If you don’t want to alienate your users, you need a system to share your design building blocks with all teams. A design system enables them to build interfaces that have a similar look. However, a design system also introduces coupling because every team has to be compatible with it.

In the micro frontends projects I’ve worked on, planning and setting up a shared design system was always among the first and most important tasks. How to integrate a design system into the team’s code is a much-discussed topic. It has direct implications on how teams build their frontend features. Changing these architecture decisions afterward is expensive because all user-facing features rely upon it.

In this chapter, we’ll briefly introduce the concept of a design system, discuss how to organize effective development, and look at a variety of technical integration options and their trade-offs.

12.1 Why a design system?

Creating an overarching design that different teams can use is far from specific to micro frontends. The term design system has become popular in software development in recent years. It provides a way to systematically tackle design in an era of growing web applications that must work on a multitude of devices.

A design system contains design tokens (fonts, colors, icons ...), reusable interface components (buttons, form elements ...), more advanced patterns (tooltips, layers ...), and most importantly a well-explained set of rules on how to use these individual pieces together. Figure 12.1 shows some design system examples. 1

Figure 12.1 A lot of companies have published their design systems on the web. You can use them in your project or leverage them as a source of inspiration when creating your own.

Two other terms often also come up in this context: pattern library and (living) style guide. They mean the same thing: a way to modularize the complexity of the web with a component-based system. However, they have a slightly different focus.

The term pattern library describes a set of concrete building blocks developers can use. It is a library that contains tangible components like buttons and form inputs. It focuses more on the components than on the documentation aspect. You can say that a pattern library is a subset of a design system.

Style guide is a traditional term from the design world. Before the internet, a style guide in the form of a well-crafted stack of paper describing all design rules for a company’s corporate identity. The “living” prefix transferred this concept to the digital age, where the illustrated components use the real code. In this chapter, we’ll use the term design system when we talk about the broader concept and use pattern library when it comes to the technical integration with the team’s applications.

In this book, we won’t discuss how to build a design system. You can find a lot of excellent blog posts, 2 books, 3 and even hands-on checklists 4 to get deeper into this topic. Instead, we’ll focus on the design system aspects that are crucial to get right for running a successful micro frontends architecture.

12.1.1 Purpose and role

In a micro frontends project, all features the product teams create are directly targeted to the end user. These features make the user’s life more enjoyable and thus create value for the company. A centralized design system does not fit into this model.

No user signs up for Microsoft Office 365 because they think that Microsoft’s Fluent UI Design System is the best. But there’s no question that the existence of the design system makes Office a more usable product. People who are familiar with using Word have an easier time understanding PowerPoint or Excel because all teams use the same UI paradigms and components.

A design system has an indirect effect that manifests itself through the product teams. The goal of a design system team should never be to create the most beautiful, best documented, or most versatile design system on the market. The objective of a design system team should be supporting the product teams as best as possible. A design system is a product that serves other products.

12.1.2 Benefits

A sound design system can help product development by providing these benefits:

  • Consistency--Making user interfaces from different teams “feel familiar” to the user.

  • Shared language--A design system forces you to create a shared vocabulary that all involved parties understand. Proper naming is never easy, but having consistent names for your components and patterns improves communication across teams and avoids misunderstandings.

  • Development speed--Having clear guidance and the necessary UI components to build a new feature makes the developer’s life easier.

  • Scaling--The value of a design system increases by the number of teams using it. New teams have a solid foundation they can build upon. No redundant discussions on “if we should use a custom select box or not.” Hopefully, the authors of the design system have documented this decision before.

The benefits of a design system are mid- and long-term. Creating a robust system will take a considerable amount of time. However, if your project is of a particular size, these efforts will pay off quickly. It will also save you a lot of unsatisfactory design consolidations and eliminate chaotic redesign projects.

12.2 Central design system versus autonomous teams

Now you know the basics of a design system and its benefits. Let’s look at some aspects that are important in a micro frontends architecture. One question that’s frequently asked is if it’s indispensable to build your own design system.

12.2.1 Do I need my own design system?

Creating a design system is not an easy or cheap task. If you are building an internal product where branding is not an important aspect, it’s perfectly fine to go with an off-the-shelf solution. Projects like Twitter Bootstrap, 5 Google’s Material Design, 6 Semantic UI, 7 or Blueprint 8 are great candidates. They all bring a set of generic components developers can adapt for their use case.

But you shouldn’t choose a library by its appearance alone. They have different technical architectures that introduce constraints into your project. Some integrate solely via CSS classes (Bootstrap, Semantic UI), dictate a specific frontend framework (Blueprint), or provide a set of framework options (Material Design). Later in this chapter, we’ll dive deeper into the possible integrations and their pros and cons.

If your product should convey a unique style and must be in line with your companies branding, it’s a good idea to develop your own design system from scratch. Such a system also enables you to incorporate components that are unique to your business domain. In e-commerce, you want to have a price component that defines how reductions, sales, or the base price should render. When you are building a messaging application, you will want to include primitives like user avatars or chat bubbles.

12.2.2 Process, not project

Having your own design system has some real benefits. We, as developers, like to focus on its technical aspects. Creating a set of usable components for all teams sounds like a worthwhile project. But in an otherwise distributed organizational structure, a design system also introduces an important social aspect. A former co-worker of mine likes to describe the design system as...

... the campfire around which people from different teams and with different professions gather regularly.

Dennis Reimann

This quote highlights the fact that a design system is never a finished product. It’s better to think of it as a process. A design system should be a living and evolving piece of infrastructure. The usable components and formalized design rules are the result of discussions between user experience (UX) and design experts as well as developers and product owners from the teams. It should be the single source of truth when it comes to design questions. Figure 12.2 illustrates this.

Figure 12.2 A good design system is a place where all key design decisions get documented. It’s constantly refined to best meet the needs of its users.

12.2.3 Ensure sustained budget and responsibility

It’s important to set appropriate expectations in management. The bulk of the design system work will be in the first few months, but the work doesn’t stop then. New use cases arise, and teams develop new and more sophisticated features. You need free space to adjust and grow the design system accordingly. It’s crucial to have a sustainable budget dedicated to doing this work:

  • Extending components

  • Questioning existing patterns

  • Refactoring areas

  • Refining the documentation

  • Fixing inconsistencies

I’ve seen projects with thoroughly crafted design systems that worked pretty well in the beginning. But when there is nobody who feels responsible or can maintain and evolve the system, it starts getting out of date. Teams work around existing patterns. They modify components with custom override styles to adjust them to their needs. Some components get extended several times and grow in complexity. Documentation becomes out of date.

From this point, it usually gets worse pretty quickly. That’s what the community calls a zombie style guide. 9 Don’t let your design system join the zombie army. Rebuilding and replacing a design system is expensive. The micro frontends architecture optimizes for feature development speed inside team boundaries (vertical). Introducing substantial changes across teams (horizontal) requires a lot of coordination, creates friction, and can impair development for a considerable time.

Make sure to establish proper conditions in the first place. Having a dedicated budget and strong responsibility is vital.

12.2.4 Get buy-in from the teams

Getting the green light from management is an essential precondition, but it’s even more important to have a healthy relationship with the product teams. They are the users of your design system. They are your customers. Take time to explain the design system and its concepts to them.

The first sprints

Learn about their development roadmap and discuss wireframes to identify the components that are required first. A transparent development process helps the product teams to know when needed parts are ready. Publishing documentation, examples, and changelogs supports this.

In the early stages of a new project, the design system team is usually the bottleneck. There’s a lot of technical setup to do. The team needs to build essential components for typography and interactions. Giving the design system team a head-start of a couple weeks is something we’ve had good experiences with. This way, the product teams can use the pattern library from the start. Nobody needs to wait or use temporary solutions that cause trouble later on.

Acceptance

Even though all teams know about the benefits of the design system, it’s often tempting to work around it. Imagine Team Decide wants to ship a new product review feature. To build it, they need a new rating-star icon and a new, smaller heading style. The team is already under pressure because the lead developer broke their arm in a sporting accident a week ago. To keep the schedule, it would save time to add the icon directly to Team Decide’s application code. They could take the standard heading and just overwrite it with a smaller font size. Yes, other teams wouldn’t be able to use these components in their features. “But that’s not important right now.” These moves would save Team Decide time. Bringing the change into the central pattern library requires more work than building it locally.

The main benefit of micro frontends is to empower teams to move fast by eliminating dependencies and waiting for other people. A central design system will get in the way. Having discussions around reusability and consistency doesn’t help the product team’s primary mission. Make sure everyone understands this conflict of interest and recognizes the importance of the design system. Find a way to spot technical debt, and don’t let it build up.

Communication

Establishing proper communication channels between the design system and the product teams is a crucial factor for success. There are a lot of ways to do this. It doesn’t have to be regular in-person meetings. Being creative and coming up with lightweight solutions makes the process leaner and can build up acceptance.

We’ve experimented with a concept called opening hours. The design team offers dedicated time slots. Product teams can come in and discuss wireframes for upcoming features. They don’t need to schedule a meeting. The goal is to identify changes for the design system in an early phase.

However, the method we found most effective is to directly involve people from all teams in the development process itself. Next up, we’ll see how this can work.

12.2.5 Development process: Central versus federated

There’s no single way to organize the development of a design system. Up until now, we implicitly talked about an organizational form that’s called the central model. We have a dedicated team that plans and builds the design system and distributes it to the product teams to use. But there’s another approach that’s gaining popularity and fits well into our autonomous-teams architecture: the federated model. 10 Figure 12.3 shows both models side by side.

The central model

In the central model, we have a clear division of labor. A group of developers, designers, and UX specialists plan and build the design system. To know what they should build, they talk to the product teams. The design team has a pretty good overview of the complete system, can spot inconsistencies quickly, and works efficiently.

The product teams are only users of the pattern library. They make requests to the design system team and wait until their components are ready. The central team has the potential to become a bottleneck. When product teams request more changes than the design team can implement, it gets ugly. Teams have to delay their schedule or start working around the design system.

Figure 12.3 Two approaches for organizing the development of a design system. In the central model, a dedicated design team develops the system, and the teams use it. The federated model blurs the line between the design system and the product team. The members of the product teams contribute to the system and drive development.

The federated model

The federated model changes this. Designers and UX specialists move into the product teams. There’s no real central team anymore. Yes, we still need someone who stewards the design system and has an eye on quality and consistency. However, the product teams now drive the development of the design system themselves. When a product team needs a new component, they design it, build it, and publish it to the design system for everyone to use.

This model gives the team a lot more freedom and autonomy. But since the design system is a shared project, it’s crucial to properly communicate changes to others. Running this model requires some skill and experience. Its most significant benefit is that UX experts and designers now work in the product teams. They bring new perspectives to the development team and can help to improve the product directly. This quote from Nathan Curtis 11 brings it to the point:

We need our best designers on our most important products to work out what the system is and spread it out to everyone else. Without quitting their day jobs on product teams.

Nathan Curtis

12.2.6 Development phases

You might ask yourself what’s the best model for your project. It’s hard to give a general answer to this question. But I’ll share what worked for us.

First of all, the two models aren’t mutually exclusive. They blend very well. You don’t have to pick one of the extremes. Running a design system with a strong central team does not mean that you can’t take contributions from a product team. Figure 12.4 shows the Central-to-Federated Continuum.

Figure 12.4 Central vs. federated is not a binary decision. The models work well together. The scale at the bottom shows the spectrum. You can run the central model with some federated aspects (left side). It’s also possible to run the federated model in combination with some central planning and development (right side).

In our projects, I could observe two phases of design system development: the ramp-up phase (phase 1) and the production phase (phase 2). Figure 12.5 shows how these phases vary in focus.

Figure 12.5 What model fits best can depend on the development phase your project is in.

When starting a new project, we’ve had good experiences with the central model. It’s an efficient way to get a new design system off the ground. In this ramp-up phase, there’s a lot of work to do--setting up pipelines and tools, making initial decisions, and creating the first set of standard components. Having a dedicated team that has no other responsibilities is valuable in this phase.

When the dust has settled, and teams start to get productive, we slowly move toward the federated model. This way, we ensure that the real use cases drive the development. We encourage frontend developers from the product teams to learn about the design system and contribute. Developers and designers from the design system team move toward the product teams. In this transition phase, it’s common for people to divide their time between two teams. A designer might spend 50% of their time on the design system and 50% on the product team. These percentages make planning easier. They can gradually shift over time.

12.3 Runtime versus build-time integration

You’ve learned a lot about the organizational aspects. Let’s see how we can technically integrate a pattern library with the team’s applications. First, we’ll talk about different strategies for rolling out changes.

Imagine you’ve changed the color of your button component in the central pattern library. What needs to happen so that the user can see it?

You can find two deployment approaches that people use: runtime integration and distribution as versioned packages. Figure 12.6 shows both of them side by side.

Figure 12.6 In the Bootstrap model (left), the pattern library deploys its artifacts (JS, CSS, and possibly images) directly to production. Changes are instantly visible and distributed across teams. With versioned packages (right), the pattern library offers the components as a package (for example, NPM) that teams can pull into their application. Teams control when to update to the latest version.

12.3.1 Runtime integration

Twitter Bootstrap is the most famous example of a runtime integration. The concept is simple. Teams embed a link to a global CSS file that’s maintained by the design system team. They can style their page by applying CSS classes to the markup. The same goes for the micro frontends embedded on that page. The CSS classes are globally available. Here’s a code sample that shows how to embed and use global styles.

Listing 12.1 /team-decide/product/porsche.html

<link rel="stylesheet" href="/shared/pattern-library.css">       
 
<button class="btn btn-call-to-action">Buy a tractor</button>    

Integrating the pattern library styles

Using the styles via CSS classes

The runtime model is not exclusive to pure styling. If you use client-side rendering, it’s also possible to provide components that encapsulate styling and internal markup. Here’s an example of doing it via Web Components.

Listing 12.2 /team-decide/product/porsche.html

<script src="/shared/pattern-library.js"></script>     
 
<tractor-store-price reduction="10%" value="$66">      

Integrating the pattern library script which contains Web Component definitions

Using the price component as markup. It renders the appropriate styled markup inside its ShadowDOM.

Setting up a pattern library using a runtime integration is pretty straightforward. It’s simple to develop and easy to use. Another benefit is that the design system team can roll out changes instantly.

However, this model has some considerable coupling and autonomy disadvantages:

  • Testing in isolation--Micro frontends should be self-contained. With runtime integration, a team’s user interface doesn’t work in isolation. For it to function, it’s necessary to include the pattern library’s styles and scripts. Since the design system team can change these assets at any time, a product team can’t ensure that its user-interface looks right and is working correctly. They would have to run their automated test-suite on every pattern library change.

  • Single point of failure--With runtime integration, the pattern library becomes a mission-critical part of the system. An error that slips through can bring down the complete project, since all teams rely on it.

  • No tree shaking or deprecations--Since the design system team cannot know which components a specific page uses, it’s common practice to include the styling code for all of them in one big CSS file. This file tends to only grow in size because there’s no safe way to ensure that an old component is unused. When you go for the JavaScript components option, you can at least use on-demand loading strategies to avoid loading unneeded script code.

  • Breaking changes--There’s no structured way to handle breaking changes. If the team wants to refactor the button component in a significant way, they need to create a new one (for example, .btn_v2) and delete the old one when everyone has updated their markup.

  • Versioning and scoping--It’s hard to establish proper versioning in this model. There’s also no easy way to prevent leaking styles between different micro frontends.

The lack of versioning is particularly critical. It means that all teams must use the latest version of the pattern library. You can’t restructure or upgrade the pattern library in a meaningful way. It would require close coordination and simultaneous deployments from all teams. The fear of introducing friction incentivizes the design system team to shy away from making the necessary steps forward. Let’s look at a more flexible model to distribute a pattern library.

12.3.2 Versioned package

In the versioned model, the pattern library is not a runtime system. Instead, the design team distributes it as a package that contains all components. The LEGOTM metaphor works well here. You can think of it as a big box of bricks. The product teams can grab one of these boxes and take the required bricks out of it. Together with their own special bricks, they can build features for the customer.

Listing 12.3 /team-decide/static/product.jsx

import { Price, Button } from "@the-tractor-store/pattern-library";   
 
function ProductPage() {
  return <div>
    <Price reduction="10%" value="$66" />                             
    <Button type="call-to-action">Buy a tractor</Button>              
    ...
  </div>;
}

Importing the required components from the pattern library package

Using the components to build the product page

Independent upgrades

The design system team can iterate on the pattern library. They produce new revisions of the LEGOTM box regularly. An updated revision might include new kinds of bricks or an updated surface finish. But teams don’t have to upgrade instantly. They can upgrade at their own pace. An older revision might not look as sweet as the new one, but it still works fine.

Don’t ship unused code

With this approach, each team generates its own CSS file. A bundler like Webpack includes only the pattern library components that a team uses. So if the pattern library still includes an old component, but no team requires it, the browser won’t have to download its code. This mechanism leads to quite small CSS files.

Self-contained

You can instruct your bundler to prefix all CSS classes automatically. This way, it’s possible to achieve proper scoping, and a page can contain micro frontends that use different versions of the pattern library.

Let’s look at an example. Imagine Team Decide owns the product page, which displays a price and a button. It also includes a micro frontend from Team Inspire, which also shows a button:

  1. Team Decide uses pattern library version 4 in their applications.

  2. The design system team releases a new iteration (v5) in which the buttons have a new and rounder style.

  3. Team Inspire immediately upgrades to this version and deploys its application.

  4. Team Decide has other work to do. They’ll update tomorrow.

Here is what the generated production code might look like.

Listing 12.4 /team-decide/dist/product.css

/* based on pattern library v4 */
.decide_price {...}
.decide_button { border-radius: 2px; }     
.decide_[...] {}

The old button styling from pattern library v4

Listing 12.5 /team-inspire/dist/reco.css

/* based on pattern library v5 */
.inspire_button { border-radius: 10px; }      
.inspire_[...] {}

The new more rounded button styling from pattern library v5

Listing 12.6 h ttps://the-tractor.store/product/porsche

<div>
  <span class="decide_price">only $66 (10% off)</span>
  <button class="decide_button">Buy a tractor</button>              
  <aside>
    <button class="inspire_button">Show recommendations</button>    
  </aside>
</div>

Team Decide’s button references its own CSS class.

Team Inspire’s button also references its own CSS class.

The two buttons on the page have different appearances. Team Inspire’s button is already on the new rounder style, whereas Team Decide’s button is still on the old style. Being able to use different versions side by side is an essential step for independent deployments. With this approach, a micro frontend is fully self-contained and doesn’t rely on styles from other teams. The product teams are in control of upgrading their pattern library and testing the changes before they deploy them.

The drawbacks

This approach has a lot of advantages compared to the runtime integration. But it also has some drawbacks:

  • Redundancy --When teams use the same component, the user has to download the associated code multiple times. You can see this in the preceding example. We have two versions of the button styling. This redundancy is typically not a big problem. Since the bundler only includes components that are in use, and no team uses all components at once, the total CSS file size is usually much smaller compared to the global Bootstrap model.

  • Slower rollouts--Changes in the pattern library take longer to be visible in production. The design system team cannot push new updates. They can provide a new version and inform all the teams. The changes are only visible when all teams have updated and deployed their application. It might be necessary to encourage teams to deploy faster to rollout a critical design system bugfix quickly.

  • Eventual consistency --Most graphic designers are not comfortable with the idea that a page can contain different versions of the same component. However, when teams update on a regular schedule, this is not a pressing issue. Pro tip: In my last project, we created a dashboard that shows which team is using which version of the pattern library. Merely showing this information in an aggregated view leads to faster upgrades by the teams. On another note: Take a look at figure 12.7. It shows different generations of Amazon’s buttons. These were all active at the same time in different areas of the site. The fact that Amazon does it should not be an excuse to discard consistency, but having temporal inconsistencies can be perfectly fine.

Figure 12.7 Screenshot of different Amazon button styles from different parts of the site

12.4 Pattern library artifacts: Generic versus specific

Now let’s take a closer look at the technology of the pattern library. Its output has to be compatible with the technology stack of the teams. There’s no gold standard for shipping reusable components. Different options exist, and they all have their benefits and drawbacks. Some don’t support server-side rendering, some require a specific JavaScript framework, and others support styling but not templating.

12.4.1 Choose your component format

User interface components consist of three parts:

  1. Styling in the form of CSS code.

  2. Templating to generate the components' internal HTML markup based on the provided inputs. You can execute the templates on the server and/or client, depending on its format.

  3. Behavior (optional) for components the user can interact with, like tooltips or modals. They require client-side JavaScript to work.

Let’s explore our options. Look at figure 12.8 and take some time to get an overview. The diagram shows different formats a pattern library can produce.

Figure 12.8 Different artifacts a pattern library can produce. Some output formats have technical implications for the team. When the pattern library only exports Vue.js components, all teams need to use Vue.js to be compatible.

We’ll go through the diagram line by line.

Pure CSS

The pattern library provides its component styling via CSS classes. Twitter Bootstrap is the role model in this category. Teams need to craft the components markup according to the pattern library’s documentation:

  • Benefits

    • Easy to implement.

    • Works server- and client-side.

    • Compatible with all tech stacks that can generate HTML.

  • Drawbacks

    • Styling only.

    • Teams need to know the internal markup.

    • Changing the component markup is hard.

Framework-specific components

The pattern library uses the component format of one specific framework. An open-source example is Vuetify, 12 a component library designed for Vue.js. This model requires all teams to use the chosen JavaScript framework. The component formats of the popular frameworks have been pretty stable--even across major versions. This format stability means that teams have to use the same framework but aren’t required to run the same version:

  • Benefits

    • Easy to implement.

    • Works server- and client-side.

    • Components integrate seamlessly with the team’s code.

    • Components can use the full feature-set of the framework.

  • Drawbacks

    • All teams must use the same framework.

Framework-agnostic components

Web Components integrate well with all modern frameworks. 13 You can also use them on plain old HTML pages. Have a look at the Duet Design System 14 as a useful reference. The developers built it using Stencil. 15 In contrast to the “pure CSS” approach, Web Components also encapsulate templating and behavior:

  • Benefits

    • Supported by all browsers

    • Future-proof (web standard)

    • Compatible with plain HTML and frameworks

  • Drawbacks

    • Only works client-side16

    • JavaScript required (makes progressive enhancement hard)

Multiple framework components

The model is related to framework-specific components. But instead of supporting one framework, the pattern library exports its components in different formats. Providing more than one format requires extra work because you will need to implement the framework-specific parts multiple times. However, the concepts, component list, and the CSS styling stay the same.

Google’s Material Design is a large-scale example of this. The design system itself defines styling, markup documentation, and scripts. Projects like Material UI (React) or Angular Material take the “generic” design system and transform it into a framework-specific format:

  • Benefits

    • Works server- and client-side.

    • Components integrate seamlessly with the team’s code.

    • Components can use the full feature set of the framework.

  • Drawbacks

    • More work required.

Common templating language (e.g. JSX)

It doesn’t have to be a specific component format. You can also ship HTML templates and styling (for example, via CSS Modules). Many JavaScript libraries and frameworks support the JSX templating format. This way, it’s possible to write the HTML template once and use it in a Hyperapp, Inferno, Preact, or React application.

The lifecycle methods and event handling in these frameworks are not the same. This difference means that you can’t include behavior. Components have to be stateless. But if your design system mainly includes essential UI components, this is not an issue.

Have a look at X-DASH 17 from The Financial Times to see a real world example of this method. We are using the JSX approach in newer projects and are happy with its trade-offs:

  • Benefits

    • Works server- and client-side.

    • Supports all frameworks compatible with the templating language.

  • Drawbacks

    • You can’t include behavior.

    • Implementations might vary and speak different “dialects.”

NOTE You can use this model with any templating language. But be aware that implementations aren’t always 100% compatible with each other. For example, we had significant issues with using handlebar templates across languages like Scala, Python, and JavaScript. Be confident that your model works and its limitations are well understood. Create technical spikes to verify it before you roll it out company-wide.

12.4.2 There will be change

As I said before, there’s no clear winner. The right choice for your project or company depends on your needs.

However, if you’ve made a choice, you should communicate the contract between the pattern library and the teams. Does your integration rely on a framework component format, is it based on a specific DOM structure that’s documented somewhere, or do teams need to support a dedicated templating language?

This decision impacts the team’s autonomy long-term. Switching to another model later is costly and cumbersome.

Be open for change

A good option for being open to future trends and technologies is to have the “multiple framework components” model in mind from the beginning, even if you decide to start with Vue.js components. If your concepts are stable and you architect your CSS in a reusable way, it will be easier to add new output formats like Web Components, Angular, or Snowcone.js 18 later on.

Keep it simple

Another tip is to keep the central components as dumb as possible. Try to keep the behavioral aspects to a minimum.

Let’s take a navigational tree component as an example. It’s a vertical list of links you can expand to see its nested links. The pattern library could provide a fully-fledged component which includes functions like expand/collapse and text search, and has hooks for lazy loading subtrees. But getting all of these aspects right and fulfilling every team’s needs is challenging.

You could also go the other route and let the pattern library only provide the building blocks and states this tree component can have: expanded/collapsed items, active state, and position of a search box. With this approach, the teams have more work to do because they need to build the mechanics (toggle, search, ...) themselves, but they also have much more flexibility. They could decide to pick an open-source tree library that fits their needs and feed it with the styled building blocks from the pattern library. Focusing on the visual aspects makes your pattern library more flexible and reduces feedback loops with the teams.

Finding the right balance between centralized and distributed is not always easy. In the next section, we’ll dig a little deeper into this question.

12.5 What goes into the central pattern library?

Having all user interface elements visible and documented in the central pattern library is valuable. The central documentation makes it easy to get an overview. But sharing a component comes with costs.

12.5.1 The costs of sharing components

Changing a component in a team’s application code is much easier than changing a component in the central pattern library because central components

  • Live in another project. You have to publish a new version to see the change in the team’s code.

  • Might be used by other teams. You need to think about the possible consequences of these teams.

  • Must conform to higher quality standards. You want to ensure that even people from outside your team understand a component’s capability and the reasoning behind it.

  • Might require code review. Depending on your design system development process, you might instantiate a dual control principle to guarantee a high standard.

These aspects make changing a component in the central pattern library much harder than directly changing it in your own code. Putting all components into the pattern library would slow down the development. That’s why you need to consciously decide what goes into the central pattern library and what should better be local to a team.

12.5.2 Central or local?

In a lot of cases, the decision whether a component should be central for all or local for one team is easy to make:

  • The definition of the sale color should, of course, be global. The same goes for an icon set or the styling of an input field.

  • Advanced patterns like a payment options box or the concrete layout of the product page should be controlled by the respective teams.

But there’s a middle-ground where these decisions are not that clear. Is the filter navigation or a product tile a central component? Let’s look at some vectors that help you make your decisions.

Component complexity

The atomic design methodology 19 is quite popular. It uses the chemistry metaphor of atoms, molecules, and organisms to sort components by their complexity. This metaphor also highlights the fact that larger components are a composition of smaller ones. Figure 12.9 shows the atomic design categories from lowest complexity (design tokens) to highest complexity (features and pages).

Figure 12.9 The atomic design methodology organizes the design system by complexity. The central pattern library should include the basic building blocks (tokens, atoms, molecules). More sophisticated components (organisms, features, entire pages) should be under a team’s control. The middle ground around molecules and organisms is fuzzy.

This scale maps well to our central vs. local question. A good rule of thumb is to share simple components and put complex ones under team control.

But this model is fuzzy in the middle of the scale. Developers like to argue about whether a particular component is a molecule or an organism, but these discussions are almost always theoretical and fruitless. Comparing code complexity is not the only important factor.

Reuse value

The reusability of a component is a reliable indicator. Components that different teams need might go into the central pattern library, even if they are not simple. Patterns like accordions or carousels are good examples here.

However, you should be careful with this rule. The focus of larger components might change over time. Here is an example:

Team Inspire uses the product tile component for their recommendations. Team Decide has built a wishlist feature. They use the same product tile on their wishlist page. The central component worked great at the start, but over time both teams come up with conflicting requirements. Team Inspire wants the component to be more compact to fit more tiles in a recommendation slot. Team Decide needs to add more functions and product details to it. Moving the component out of the central pattern library and letting each team work on their own version of it might be an option. Another alternative can be to reduce the product tile component to its essence. The new component could provide dedicated slots where teams can add functionality if they need to.

These conflicts are natural because nobody can foresee the future. It’s essential to reevaluate your decisions regularly and be open to revising them.

Domain specific

Domain-specific components are good candidates to be team-owned. To identify this, you can ask the question: “Which team has the interest in changing this component, and why?” When there’s a team that frequently updates a component to improve its business, it’s a reliable indicator that this component should be local to that team.

A filter navigation is a good example here. At first sight, a list of filters looks pretty simple. However, when you have a product team with the mission to “make finding products easier,” this team will want to change this component frequently. They want to test different variants, collect feedback, and improve the component. Making this team jump through hoops by centralizing the component will slow them down and block innovation.

Trust in teams

These three properties (complexity, reusability, and being domain-specific) can give you a good idea of where a component should live. Don’t be afraid to give up central control and let teams own and evolve specific components.

But it’s not just about control. If a component is not part of the global pattern library, it’s hard for designers to keep an overview. Next up, we’ll look at the concept of local pattern libraries to mitigate this.

12.5.3 Central and local pattern libraries

It’s not a hard rule that you must have a single design system. There’s the concept of tiered design systems 20 that perfectly fits into our micro frontend architecture. The idea is to have a central pattern library that defines the basics, and other pattern libraries that build on it and add their use case-specific components. In our case, each team can have its own local pattern library. Figure 12.10 illustrates this.

Figure 12.10 A two-tiered pattern library approach. Each micro frontend team has its own local pattern library where it develops its domain-specific components.

A team can only use the components from its own local pattern library. But all teams can browse the component catalog of the other teams. This visibility is a good starting point for spotting cross-team inconsistencies. It’s also a solid basis to start a “central vs. local” discussion.

The central and local pattern libraries could also use the same tool to develop and generate the design system documentation site. Popular tools for this are Storybook, 21 Pattern Lab, 22 and UIengine. 23 Using the same tool has the advantage that moving a component from the central to the local pattern library (or the other way around) is as easy as moving a component folder.

Now you’ve learned a lot of aspects that can help you when implementing a design system in a micro frontends project. In the next chapter, we’ll broaden our view and look at other organizational implications this architecture introduces to your company.

Summary

  • Every micro frontend team develops its own user interface. A central design system that all teams can use helps to deliver a consistent user experience across all micro frontends.

  • A shared design system introduces coupling between the teams. All teams must work with the system and be compatible with its technology.

  • All visible features the product teams produce rely on the design system. Changing the technical architecture of the design system afterward is cumbersome and costly.

  • The design system exists to help the product teams ship features and be more consistent. It does not create value on its own.

  • Developing a design system is a continuous process. Ensure that it’s maintained properly and doesn’t get out of date. Don’t let it become a zombie design system.

  • The design system can become a bottleneck when teams request more changes than the central team can handle. Product teams might need to wait and delay features.

  • You can develop the design system in a federated way. Developers and designers from each team contribute to the system. A small core team ensures quality and has an eye on consistency. This model can scale and works well with the micro frontend principles.

  • The central and federated development models are not mutually exclusive. You can move between them.

  • There are two ways to integrate the pattern library into your project: runtime integration and via versioned packages.

  • With runtime integration, the design system team deploys directly to production, and all product teams must use the latest version. This model has considerable drawbacks for team autonomy, since teams cannot ensure that their software is always working correctly.

  • Distribution via versioned packages enables the product teams to upgrade the pattern library at their own pace. A team’s micro frontend can be self-contained because it doesn’t rely on external dependencies at runtime.

  • There are different formats (CSS only, framework-specific ...) a pattern library can publish their components in. The format has technical implications for the team. Some don’t work server-side; others require all teams to use the same JavaScript framework.

  • Frontend tools and libraries change over time. Try to build your design system in a way that makes adapting to changes easy.

  • Sharing components across teams is not free of cost because they require a higher-quality standard. The central pattern library should include basic building blocks. More complex and domain-specific components should be local to the team that needs it.

  • A product team can have its own local pattern library. It presents all the components this team owns. This is a good way for designers and developers to get an overview, spot inconsistencies, and start discussions.


1.See https://designsystemsrepo.com/design-systems/.

2.See Vitaly Friedman, “Taking The Pattern Library To The Next Level,” Smashing Magazine, http://mng.bz/wB7W.

3.See Design Systems, by Alla Kholmatova, http://mng.bz/qM7E.

4.See https://designsystemchecklist.com.

5.See https://getbootstrap.com.

6.See https://material.io/develop/web/.

7.See https://semantic-ui.com.

8.See https://blueprintjs.com.

9.Tweet by @jina: “zombie style guides -- style guides that aren’t maintained and part of your process. they die and rot. they eat your brains,” https://twitter.com/jina/status/638850299172667392.

10.See Nathan Curtis, “Team Models for Scaling a Design System,” Medium, http://mng.bz/7XBg.

11.A series of blog posts on design systems. It’s a goldmine. You should read them all. :) https://medium.com/@nathanacurtis.

12.See https://vuetifyjs.com/.

13.See https://custom-elements-everywhere.com/.

14.See https://www.duetds.com/.

15.Stencil is a toolchain for building reusable, scalable Design Systems. See https://stenciljs.com/.

16.Yes, there are ways to render them on the server. But there’s no standardized templating in the current web components spec (https://github.com/whatwg/html/issues/2254). That’s why all current solutions require a lot of hacking and fiddling.

17.See https://financial-times.github.io/x-dash/.

18.This might be the hot new thing in a couple of years. You never know :)

19.See Brad Frost, “Extending Atomic Design,” Brad Frost, https://bradfrost.com/blog/post/extending-atomic-design/.

20.See Nathan Curtis, “Design System Tiers,” Medium, https://medium.com/eightshapes-llc/design-system-tiers-2c827b67eae1.

21.See https://storybook.js.org.

22.See https://patternlab.io.

23.See https://uiengine.uix.space. (This is the tool we are using in most projects.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.115.195