Make it easy for your developers to use your pattern library
At Think Company, we know that pattern libraries (also referred to as component libraries, UI libraries, or code kits) are excellent tools for enforcing consistency across an organization’s products. They’re a central source of truth for design and code, and they reduce repeated work.
If you’ve read Greg’s post on the benefits of using pattern libraries, then you know a pattern library benefits many different folks in an organization. One of those is of course the developer, who oversees the implementation and upkeep of the team’s design system.
For the last few years, we’ve partnered with a financial services product company to help them integrate a pattern library we created for them. We’ve seen how different teams use patterns, how they evolve, and how we can remove many common pain points. Here’s some of what we’ve learned.
Historical Challenges
In the past, we included a Build Kit’s assets wholesale, and developers would copy and paste the patterns they wanted to use. We noticed across many teams that this didn’t scale well at all. Updates were cumbersome and manual, if possible at all, and the burden to make changes was often too great to expect those changes to happen. To answer these challenges, we began deploying the pattern library as a single package—making it possible to pull a version of the library down and use any and all of the elements desired.
New solutions often come with new challenges. Being embedded with the teams using the library allowed us to identify opportunities to make everyone’s life a little bit easier. We identified a few challenges with updates and maintenance:
Pattern Updates: All or Nothing
Every change to a pattern meant an updated version of the entire pattern library. This meant that a product’s development team had some work ahead of them. They had to assess all the changes made since the last update, and weigh whether they could bring down the whole new library without issue. Compounding the problem, if multiple product teams depending on that shared library couldn’t agree, then no team could make efficient use of the update.
For instance, say Meghan’s team is working full steam ahead on a product overhaul. As part of the update, they’ve designed a more accessible, versatile pattern for the navigation. As the product owner, Meghan has worked with the design team to refine the navigation design and functionality. The design team has kept other product teams informed to assure the design will meet their needs in the future.
Meanwhile, Keith’s product team is working on a bug fix for some of the form patterns. The fix is ready to test, and they’re looking forward to moving the fix into production.
Meghan’s team is ready to install the navigation, but there’s a problem. If they introduce the new navigation (v2) to the pattern library before Keith’s bug fixes, then Keith’s team is forced to accept v2 of the navigation as well. They’re not ready for the extra work workload just yet. What’s the organization to do?
Unused Code
It was unlikely that any given product was using every pattern in the library. This meant that if a dev included the entire library wholesale out of convenience, a lot of unused HTML, CSS, and JavaScript made its way to the user’s browser, increasing load time. Why make users wait for something they’ll never see?
Implicit Dependencies
Many patterns in the library are built of other foundational patterns. In code, it’s better to have explicit dependencies: when you know what you need, it’s clearer when it’s missing. If your navigation component includes a search bar component, it might appear broken if you haven’t included the search bar on your own.
Meaningless Versioning
When releasing a new version of the pattern library, Pattern Library v1.2.3 meant nothing. It wasn’t clear what had changed, or the extent of those changes, from the version number alone. This meant there was more work for teams to determine what updates they were pulling in to their project.
In reality, we’ve found manual ways to circumvent some of these issues. But they introduce extra cognitive work and code complexity. What if there was a better way?
Break It Down
We want both Meghan’s and Keith’s teams to be happy and productive! My colleague Amanda knew there had to be a way to make the pattern library easier to manage and consume. So, we set out to solve some of these pain points. At Think Company, we design components as isolated and reusable, and we develop them the same way. Why not deploy them in the same manner? Publishing patterns as a self-sufficient package seemed to address many of our concerns, and we leveraged a library called Lerna.js to help us do just that.
Use Only What You Need
With the new structure, the pattern library is like shopping: pick right off the shelf, and use only what you need. Don’t need a footer? No need to install it! Need the latest version of the modal, but don’t have time to update anything else? Go right ahead!
Update Without Disruption. Version Numbers With Meaning
Patterns now receive regular updates and major changes as needed.
We use versioning conventions (Semver) to show whether a change is small, large, or potentially breaking. This helps teams reason through updating the components that they’re using.
No More Code Bloat
Using only what you need means less code, and less code means a better user experience. Dependencies shared between components are only installed once, avoiding duplication.
Explicit Dependencies
When you install a component, it automatically installs the foundational components it relies on. Now when you install your navigation, the search bar is listed as a dependency! All the logic and style required is installed alongside the navigation. No more worrying about what might be missing!
In the past few years, large JavaScript library maintainers have started to move in the direction of small, isolated packages. Only very recently has this paradigm been applied towards UI Pattern Libraries. We’ve drawn inspiration from the likes of GovAU in leveraging new tool sets to make small packages easy to manage.
Conclusion
There’s no doubt that Meghan’s and Keith’s products will continue to grow in complexity as user needs change. We develop pattern libraries to manage complexity. We must future-proof our code and systems so that Meghan and Keith are free to focus on the things they care about: their users and the product.