• Micro Design Systems — Breaking the Monolith
  • Paul Van Oijen
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: Charlo – O
  • Proofread by: Wangalan30

It’s time to refine our design system and prepare for the future.

Designers like to talk about a single source of fact. A unique and universal solution that forms the foundation of everything we do. A ubiquitous, all-encompassing system.

A design system.

But is this centralized, unified approach to organizing and documenting the design of everything the best way? I don’t believe it.

Of course, structuring the design system as a one-stop repository sounds great. It may work at first, but our team will continue to grow. As our product grows, so does the number of designers. Soon there were a dozen — or dozens — of designers working on the same system.

At this point, the system as a whole will begin to break, with the continuous expansion of the system and gradually collapse. As each use case is added, or the design pattern is documented, its glamorous look begins to fade.

Microservices for designers

In recent years, microservices have gained tremendous momentum. It was once seen by the likes of Uber, Netflix, and Amazon as the best way to address the architectural complexities of scaling systems, and it’s easy to see where its popularity came from.

For those unfamiliar with the term, Amazon describes microservices as:

Microservices are an architectural and organizational approach to developing software that consists of small independent services that communicate through well-defined apis. These services are managed by small independent teams.

[…]. Microservices architectures make applications easier to scale and faster to develop, accelerating innovation and shortening time-to-market for new features.

AWS – What are microservices?

Microservices allow engineering teams to break up services into small, self-executing functional modules. Companies used to build a single system architecture, but now they are increasingly building self-contained services. This reduction in dependency allows them to build systems faster, scale functional modules more easily, and maintain a steady pace of progress in innovation.

Our development peers are increasingly adopting the idea of microservices. And when they throw away their single system, our designers still believe in a single “from start to finish” design system.

With this in mind, I suggest that we model our design system to form a set of separate, goal-driven services. We can mimic the concept of microservices and build a system on top of each other, gradually increasing the speed of building. Again, it will reduce our dependence on a single point of failure.

Break our system

When we modularize systems, turning each part into a separate cog in a larger machine, it is helpful to categorize these services according to their purpose, source, and dependence on other services. With a clear definition of what constitutes a particular service type, it is easier to determine when to extract a service. It eliminates the difficult process of extracting and building.

We can define three service types from the outset. These are likely to continue to emerge as our design systems evolve.

  • The core of * *. ** The basis of each design system.
  • * * extensions. ** These services extend specific elements or sets of elements within the core service. They embed additional attributes and are usually used for a few specific use cases.
  • * * framework. ** frameworks are purposeful services that can be reused in our products. They consist of several interrelated parts.

That still sounds pretty vague at this stage. Let’s walk through each of the different service types. Along the way, I’ll illustrate the elements they can contain and the relationships between services.

A strong core

At the center of every design system is a core. We all started with this core, drawing use cases, defining their patterns, and laying the foundation for our products.

This is a service that every designer on the team will contribute to, borrow from, and iterate on. Our core contains basic elements such as color, ICONS, spacing, and typography. In addition, we can define components here that span the entire product. Components that each designer will use. Elements such as input, check boxes, buttons, or drop-down menus may appear in every part of the product.

Because every designer borrows from the core, it is important to establish and maintain quality standards. After all, any changes made to these parts of our design system can affect every area of our product.

Note that the core is not an explicit naming convention. Whether it’s the core, the foundation, the blueprint, do what you and your team like. Just make sure they form the basic, important foundation layer of our product.

The core extensions

Extension is borrowing a component or elements from our core and extending the services it uses. By embedding additional properties, they enable us to leverage these components to handle different kinds of use cases. These often require dealing with complex problems in a specific context.

In the example above, we see a table that consists of a table header and multiple cells. This simple table shows us a small number of data points at the same level. Its purpose is to realize the visualization of data classification selection.

But what happens when we want to introduce more layers of complexity? What if we want to group different data points, or add more attributes to the cell, such as thumbnails? We need to extend the original title to show different levels. Similarly, cells should expand to include operations that expand or collapse data, as well as rows that indicate depth.

Probably not every table in our product needs to display such a complex level of data. Therefore, if we were to insert every variation of a cell or table header into an existing core, we would quickly inflate the design system. In fact, these components are not essential to our system.

Instead, we can extract these extension elements into separate services. This allows us to iterate over existing elements and build additional attributes to meet specific service requirements. At the same time, keep a basic minimum functional unit.

A purpose-driven framework

The framework does not rely on or extend existing base elements. Instead, they contain a series of elements that have a common purpose. Their main goal is to simplify the design process and speed up design iterations.

The above example demonstrates a sidebar framework. The sidebar in our example contains some of the components used to construct it. General-purpose headings that represent a page or product area, subheadings for grouping content, and different navigation components.

The different elements of the framework are bound together for a common purpose. They don’t mean much by themselves. Nor can they convey their intent without relying on the overall framework. That’s how they differ from the basic elements in our core. Our components, such as buttons, can communicate specific functions independently. You don’t have to rely on the help of other parts of the system to determine their purpose.

The benefit of extracting frameworks is to keep the core light and agile. Building these different elements makes it easier for any designer on our team to understand what an element’s intended function is. This avoids the need for complex naming conventions.

Although the extension borrows existing elements and inserts complex additional layers, the framework builds a more complete and interrelated package from the start. Therefore, moving it to a separate service causes the number of moving parts in the core to plummet.

More and more services

With the development of our products, our design system continues to expand in size and scope. A single approach would quickly become unwieldy. With this in mind, we should be proactive in extracting different elements for purposeful services.

In a perfect world, the number of different services would increase as we develop our products. Elements will float up and down periodically between our base core and standalone services. So we either extract them every time they grow big enough to undermine the foundation, or we do it deliberately from the start.

We moved the elements into separate modules, leaving more room for experimentation. The core maintains the highest standards due to its universality, while the predefined scope of smaller, other services makes it possible to explore differences.

Broaden the scope of

Sometimes we come across various elements of the design system that are not suitable for either extension or framework. That’s good. The beauty of those planned architectures is that there is room for expansion. This means that if we see a special need for them, we can add additional service types.

One type of service we might encounter is patterns. We have defined extensions that build on existing components and add to their functionality. Similarly, frameworks have a common purpose. But the schema does not show these two properties.

In the example above, there is an instance of the card pattern. It consists of several elements that do not fit into any of the service types we defined earlier.

Cards are essentially containers for other elements. As shown in the three examples above, they can contain a large number of different components with few mandatory elements. The actual bare card — a combination of background, border, and spacing — is likely to be an essential element.

The content itself is not bound together by a single shared purpose. Illustrations, photos, videos and buttons can all appear in multiple different locations across our products. They can appear in different Settings, whether or not they use cards as containers. Therefore, patterns are neither extensions nor frameworks.

Rather, they serve as building blocks or guidelines. Their purpose is to provide a frame of reference for how to lay out, compose, and piece together an interface of different parts. They are templates that use functionality as a starting point, not end-to-end solutions.

Therefore, it is easy to see that as we extend our design system further, we will encounter use cases that are not categorized by the type of service we started using. That’s the point.

Our system is no longer rigid, monolithic. Instead, they consist of different services from the product development process. Different organizations and companies need different types and classifications. We had to start questioning our own classification and hierarchy when defining service types that went beyond our initial setup.

disadvantages

Like any approach, this approach has its drawbacks. The same problems that plague microservices arise when building these microdesign systems.

The biggest disadvantage of microservices architecture is that it is much more complex than a single application. For microservices-based applications, the complexity is directly related to the number of services.

Phil Wittmer, Tiempo Development

Complexity is also a major drawback of our system. The growing number of different services means that responsibility for maintaining them is dispersed, not centralized. Furthermore, it forced us to make a decision to consciously extract existing elements from the core services. This means that we need to allocate dedicated resources for it.

This is certainly a disadvantage, but it also brings some benefits. Spreading responsibility for maintaining different services means less work for individuals. At the same time, it enables us to maintain a high level of core operational quality while maintaining a degree of independence in extracting services. This independence allows us to develop these extracts at a much faster rate. Therefore, we can innovate and develop with characteristics.

Fortunately for us designers, the recent development of design tools has enabled us to implement this approach in a fairly efficient way. Tools like Abstract support an out-of-the-box model, allowing users to plug and play different libraries in each project. As a result, we can easily assign different extensions and frameworks to our projects as needed.

Finally, microdesign systems are not really microservices. Microservices enable complete autonomy, yet our design system still relies on a degree of interconnection. Extensions still borrow core services, and our functionality still depends on several degrees of connectivity. These connections will be there for some time to come. The nature of the design effort — secondary front-end development — is essentially constrained by this.

In contrast, these relationships between elements also enhance visual consistency to varying degrees. Any given interface program may consist of several elements that borrow from different services. This makes the services visually different and immediately clear.


Since many of our design systems are still in their infancy, it’s time for our work to mature. By modeling, classifying, and extracting the different services in the system, we force ourselves to face questions about the nature of the different components, set quality standards for their foundations, and prepare for the future.

Our tools have paved the way for a change in the way we think about work. Build a shared language based on this to make our design systems better.

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.