Design System: spreading a good word
Every product company at some point realizes that it is better to create single design system than create every visual component over and over again for each screen separately, and it’s time to create a single design system. HeadHunter is not an exception. In this article we will share our experience in design system development, which is common for two platforms — Android and iOS.
We’ll talk about balance between chaos and structure, reuse and duplication; discuss relationships between designers and developers; find out whether frontend is only about the color of buttons or not.
If you prefer to watch a video instead of reading, check our video on design-system on our “HHella cool stories” channel.
Why did we start developing our own design system in the first place?
All products start from design. First designers create mockups, then developers turn them into reality. We had lived without design system for a long time: designers and managers worked separately, some components were duplicated, others written from scratch. It caused discrepancies in mockups, projects, and the process in general.
So we decided to systemize our work and started from updating a huge part of the app — CV creation. While studying it, we realized that the section needed to be rewritten in order to provide the necessary flexibility. It was a turning point for us, as we made a decision not just to change the code, but to revise our approach to the description and development of UI-components. Thus, the key prerequisites for design system were:
- code reuse
- a strive for elaborate and conceptual sequence of all mockups
Drawing inspiration from others, we couldn’t just copy what already existed, because we had our own unique components and design.
The key principles of HH design system
It’s important to understand that a design system is not about components in Figma/Sketch/Zeplin/ etc, and it’s not about views in code. It’s about agreements and rules that your developers and designers follow to collaborate. They may agree on components code conventions, what points everyone should pay attention to, choose one source of truth, and if they really stick to these rules, it will be a design system.
Our design system is based on the following principles:
- Each Figma component has the same naming and work logics as code component;
- The system appears gradually: in case a new component arises, when we’re drawing a new screen — we implement it;
- All new mockups are drawn only with the design system components, we don’t use custom elements;
- We think twice before implementing a new component.
All these principles make the communication between designers and developers constructive and effective and enable them to create universal components for both platforms.
When a new component appears, we don’t redo the old screens right away, because it’s expensive and time-consuming. If your product is updating fast, the new component is likely to be on all screens in a year anyway.
How we live with synchronized platform design
About three years ago Android and iOS design was very different: it had different flows, navigation, components.
That’s what our Android app looked like: no bottom navigation, NavigationDrawer with numerous sections:
And that was iOS app:
The time of change has come. First we updated navigation — now it’s similar everywhere, then the main app flows and so on. Mockups became almost identical: buttons, inputs, list items — all are universal.
April 2022, the app for searching jobs looks identically on both platforms: bottom navigation is present everywhere. As for vacancy cards, search bar, and writing CV — they all look alike.
So it’s become possible to draw one mockup with minimal differences. Among them are icons, headers on Android, progress bars. It saves time for designers as well as the team. Thanks to design system, everybody is aware of the components used and how they function. One more advantage — when discussing mockups, it’s become possible to focus on usage scenarios, rather than visual discrepancies of the two platforms.
What about drawbacks? Well, there were cases when components travelled from one platform to the other, to our developerssurprise. Once our designer drew a component, showed it to the iOS team, and it turned out to be an input-component from Android.
It’s a common tendency among platforms, as they become more similar and constantly borrow successful solutions from each other.
Design system in Android apps
For Android apps, the design system is a single Gradle module that we connect to the necessary feature modules that require certain components of the design system.
This module contains a lot of XML-files — the colour palette, our styles, icons, and XML-layout of components. We do not break the components into separate modules. This way it is much easier to understand which of them have already been implemented and which are on the way. Plus, it becomes easier to connect the components.
We also made a special application module with a gallery app to show designers and developers how to work with some particular components.
Yeah, we took the design from material-components-android. Such app is convenient both for demonstrating the components’ functionality and for experiments with new tech — Hilt, Navigation Component, Jetpack Compose.
Design system in iOS apps
Speaking of the design system structure, there is also one module (one Framework), which, if necessary, connects to other modules. The framework contains atoms — colors, text styles, types of shadows. There are also coded components that can be nested into each other with the help of special containers. Thus, they’re easy to combine, and we get like a declarative style when describing the UI.
Like on Android, the module contains everything required for working with UI.
We also use Fugen, a special tool for generating part of the code for resources from Figma (Figma has API through which you can do this). The development and implementation of this tool was not very expensive, more time was spent on communication: how to deal with automation, how should designers prepare their own Figma files. Now we are generating style text colors and indents from Figma: we run the script and get the code ready for use. Fugen is not available on Android yet.
Did the development of such a tool pay off? It’s hard to say, as the atoms were changed rarely. However, we’re confident that Fugen will come in handy when we decide to implement the dark theme.
Is the design system ready for Swift UI / Jetpack Compose?
Do we have modern declarative frameworks implementation in mind? Clearly, yes. However, the situation varies depending on the platform.
iOS team has developed declarative DSL for the components of design system, they describe all UI in code. That’s why we don’t see any obstacles in switching to Swift UI. Maybe half a year later the team will be able to rewrite the app.
As for Android, all UI is coded in XML, we never switched to any existing declarative frameworks. That’s why switching to Jetpack Compose will be harder: we’ll have to rewrite the system of components, code them again. So we’re preparing for a huge amount of work by reading articles, studying codelabs, trying to write design system components with Compose, starring the issues.
Duplicate or reuse?
All right, we’ve mentioned the general principles of working with components, but what should you do if a common component is not suitable in a particular situation? Should you waste your time on patching it up?
Here designers come to the rescue. They’re closer to business department, which means they can predict how mockups will behave. Plus, they know, which parts are going to be used. It means that designers can prepare developers for future changes, so that the necessary flexibility for component creation is provided.
Developers value the dialogue with designers. Before making updates, it’s necessary to discuss the details: what component is drawn, should it be common or custom. Thus, the work becomes even more effective.
Nothing good comes easy. Each component adds up to the complexity of the design system. Of course, some difficulties are justified, when you copy the elements of another platforms and try to make API more convenient. But chasing the common grounds, you may accidentally create inextensible monsters with tons of generics.
To reduce the complexity, we follow the principle of option limit. If there are too many options for using one and the same component, the work will take infinite time.
In some cases, a programming language can help in reducing the complexity of the code. For example, in order to achieve the greatest reuse of components, the iOS team created components embedded in each other. You take container components, where you embed other components, then others, etc. Due to this, generics grow exponentially, and it becomes inconvenient to use the components directly. The remedy? Short aliases, which serve to maintain the limited options.
Who should drive a design system?
Design system is a product of synergy between developers and designers. If a designer does everything well, and developers mess it up in code, the work will have no sense. It works vice versa.
The first step to creating and developing a design system is made by a designer. It provides the basis that allow you to grow correctly in the future. In addition, most often it’s the designer, who takes the initiative in building the structure of the components.
Developers succeed in improving existing components. They know how to make a component more convenient for coding, and sometimes they notice things that designers don’t.
Teamwork is essential in this process. Without realizing the bigger picture, without mutual agreements, it is difficult to do the work efficiently. Our team is aware of that, and everybody is up for long calls and discussions on components synchronization on both platforms.
Systematic or creative thinking?
What is more important for a designer — systematic approach or boundless imagination? Just like everywhere, balance is key. On one hand, product designer is required to have some knowledge about structure. On the other, get too much busy with system — and you forget about ordinary people, who are the potential buyers of the product. Aesthetics matters too, so striving for creativity together with composition is good.
Developers operate in similar conditions. It’s important to release the component correctly, so that it looks and works right. At the same time, remember that the component in development is also a product for other developers. Pay attention to API and make it more convenient.
Team (dis)agreements
It’s important for a designer to be open to developers and their struggles. Designers are responsible for the quality of markets, which influence the quality of work and the result in general.
Communication problems appear when there is lack of clarity from both sides. A designer created a component, but forgot to notify the developers? Trouble. A developer released handy component extension, but never told the designer? More trouble.
Such problems are gradually solved, and the goal of design system is to fix the majority of them. For example, missing deadlines. Thanks to design system, creators and developers now see which mockups are fast and cheap, and which demand too much money and time.
As for “friendship” between platforms, there are specific patterns suitable for only one system. However, there are also patterns that work in both systems. Kotlin, Swift are pretty similar. So when one platform goes far ahead, you can always study its implementation and copy something.
Is there anything else apart from components?
Various design systems are built differently: some include only general colors, some — UI Kit. We added haptic feedback to our system. It’s a feature that improves interaction with UI-components. Frankly speaking, it’s more relevant for iOS-platforms, Android is struggling with vibrations. The thing is that iOS vibration is soft, pleasant, and familiar to the user, all because hardware is made by the same manufacturer. Android has so many devices, that its rough touch response will send you to the Moon!
First the designer described the set of possible reactions from vibration buttons
Then he started adding these effects when drawing mockups:
We also keep accessibility in mind. When designing the buttons, we worked on the low vision mode, so that the buttons function correctly and pronounce the text.
Is Frontend only about painting buttons?
There are two challenges regarding frontend development. The first is about implementation accuracy: your task is to develop a component that looks properly. The second — the implementation convenience. It’s a truly difficult part: you need to find common ground with your team, develop prototypes, conduct demo versions, factor in the opinions of others. While doing it, you come to realize that frontend is not just about the right button colors. It’s about communication, the ability to foresee the result and their practical convenience. Very often you get a feeling that at this point it’s impossible to make something handier, because t’s not clear how other developers see it. Sometimes a component should lie a bit in the code, spread in the code database, before you actually realize how it should have been implemented.
But what should be done with “incorrect” component implementation? Fix them. Not at once, but gradually, making tasks in backlog, so that the development process is not slowed down.
Design system is an ability of turning chaos into consistent experience.
Is it expensive to create a design system?
I have bad news — you can’t just take a couple of months to focus on design system development. It should be done gradually, starting from the basic things: ask a designer to systemize the color palette, fonts, basic styles. Agree on basic components that will be used in new features.
Besides, it’s important to decide how to work with legacy code. You can use our approach — don’t touch the old screens when adding new components, — or you can start from scratch right away (but it’s more expensive).
Design system doesn’t intervene in feature development, it is gradually built in the process. It’s essential to follow the agreements, spread information in the team, warn about changes in time.
What’s next?
HeadHunter continues to work on components addition and their synchronization between platforms.
Additional technical tasks include the following: improved automation of routine actions, declarative frameworks adaptation, and, most likely, dark theme release. The team is growing, so we need to keep thinking not only about writing a new code, but also about preserving the quality of the old one.
As for designers, they have an intriguing task on design system extension so that it includes the whole company.