Blog

Make It Easy for Your Developers to Use Your Pattern Library

By Ryan Killeen on January 14, 2019

Pattern libraries are a valuable tool for organizations large and small. In this article, we’ll explain how we’re making pattern libraries even easier to use and maintain.

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?

Wireframe of old pattern library

In the old setup, you can’t pull any changes in version 3 without pulling all the changes. Product Team A might not be ready for some of those changes!

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!

Wireframe of new pattern library

The new, flexible deployment allows teams to pick what they need, and make granular updates as they become available!

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.