A journey towards Atomic Design on Android
As a French music streaming company evolving in an international, fast-paced environment, Deezer has quickly adapted to new opportunities over the past 10 years. The team has continuously grown in order to improve services, address very diverse and inspiring topics, develop new features and hardware integrations, etc.
This expansion has indeed brought new challenges, one of them being application design. How could we ensure consistency across platforms with more than 15 developers working on each, along with a very large number of UX/UI designers? How could we maintain a uniform design throughout our app while also allowing the design to evolve? How do we fill in the knowledge gaps between designers and developers, and ensure knowledge is shared effectively with newcomers? These were our main concerns to continue improving the app in an efficient way.
Atomic Design to the rescue
When addressing these issues, we first had to change the way we understand application design. It was important to stop seeing the apps as sets of pages, but instead as a design system. As a matter of fact, this idea is not new. Brad Frost developed a methodology to create and maintain robust design systems that he called Atomic Design (really worth a read). His idea was to break down pages into design components in an organized hierarchy.
What is an interface made of? What are our Lego bricks? What are our Subway sandwich pieces that we combine into millions of delicious combinations?
– Brad Frost, Atomic Design (chapter 1)
The main point was not to think top down (with pages coming first) but bottom up, i.e. to start with the tiniest component and see how it integrates in bigger components and so on. To explain it simply, he took his inspiration from chemistry — more precisely from the science of matter — and ended up with 5 stages: atoms, molecules, organisms, templates and pages:
- Atoms are the fundamental building blocks of our interfaces that cannot be broken down into smaller pieces. They consist of properties such as font or sizing of text, dimensions for a cover picture, etc.
- Molecules are simple combinations of elements (atoms) that, when combined, become a functional unit. Molecules should remain quite simple in order to be easily reusable.
- Organisms are more complex components, comprised of atoms, molecules and possibly other organisms. They generally represent entire sections of an interface.
For the last stages of the design process, Brad Frost refers back to a widely recognizable metaphor as seen in the publishing industry:
- Templates are blueprints of an interface organization, defining positions for each complex building block (typically organisms).
- Pages are actual instances of templates, with real data input, that show the result as the user will see it.
To sum up, molecules are made up of atoms, organisms are built from those molecules, which are then placed into templates to create pages. This hierarchal organization allows to:
- build a more consistent user experience throughout the application. A change on any component (e.g. an atom or molecule) is automatically applied to the entire app.
- speed up feature development, by leveraging the components’ reusability. Building a new page with already existing components becomes fast and easy. It frees up time for what matters, such as focusing on details at the atomic or molecular level, knowing it will be valuable for the whole application.
- support collaboration across disciplines. Developers and designers would work closely together to build all levels of components. But this also benefits other trades, from product to marketing, by establishing a vocabulary shared by all those contributing to the application.
By making a style guide a cornerstone of your workflow […], designers and developers are forced to think about how their decisions affect the broader design system.
– Brad Frost, Atomic Design (chapter 2)
Design system in practice
First, we needed a set of vocabulary that embraces these concepts and integrates them in a way that suits our organization. At Deezer, we rely on the LEGO metaphor as it conveys the idea of reusable building blocks used to construct bigger components until the final stage. This analogy is unsurprisingly quite common in the UX/UI communities, and is already put into practice at many companies.
Second, we established a UIKit, i.e. a pattern library (as called by Brad Frost) defining every brick that should be present in the app. The UIKit has both a design (built on Sketch and exported on Zeplin) and an Android implementation. On the development side, we created an external module implementing the bricks. This module also includes a playground, i.e. a small app serving as a showcase for the UIKit. This helps to quicken UI components’ development and testing as they can be checked all at once, and the playground is much faster to build than the actual application.
In order to implement the UIKit, we first specified the style guide (colors, textures, typography) that provides the design atmosphere of the app. Then came the atoms, which were built from Android base widgets with specific styles or custom views. Molecules were defined by two things, first a brick — which is a model embedding all data to display in the view, then the view itself, composed of widgets, custom views or other bricks. The view relies on databinding to display the actual data from the brick.
Organisms are also bricks, acting as wrappers, and taking a set of child bricks as input. For instance, the discography carousel is based on a horizontal carousel brick (using an horizontal RecyclerView) and takes a list of album card bricks.
The last part is the integration of bricks in pages (activity or fragment). To achieve this, we rely on RecyclerView. A LegoAdapter (implementation of RecyclerView.Adapter) takes a set of bricks (any bricks combined in any way) as argument to render in a RecyclerView. The LegoAdapter takes advantage of DiffUtil in order to update required views only. Therefore, building a page simply consists in retrieving the data, creating the brick set and passing it to the LegoAdapter. This process makes new feature development easier, faster and more reliable for it is easily testable.
We had (and still have) to adapt our organization in order to tackle a number of issues with this architecture, especially as android developers are split in different teams:
- Who approves and who implements component changes?
- Who handles and fixes bugs?
- How to release changes on components?
- What to do when a component does not exactly fit for a specific case? Should it be modified? Should a new component be created instead?
Another thing is that setting up a design system takes time, all the more for a long existing application like Deezer. Hence we have to proceed in stages, i.e. implement the Lego Brick architecture for new or revamped features first, and progressively extend it to the entire application. This implies maintaining a legacy and a new architecture for some time, which can appear cumbersome.
Anyway, these are some of the challenges we are currently taking up!
Our efforts are paying off though: we can already see the results and benefits when developing new features, making changes on components that impact the entire application, and coordinating with designers on major design changes. Establishing a design system clearly helped us optimize our design and development processes with better collaboration and a shared vocabulary, and build a more consistent application, thus improving the user experience.