Rethinking Component Libraries
This is the first of three articles discussing aspects of shared component libraries, whether in a design system context or otherwise. Specifically, we’ll look at how we define value, understanding cost, and how to build for the future. This article will focus on how we think about the value of a shared component library. I find the value of shared components is often misunderstood and misrepresented, and it deserves a bit of redefinition before we can talk about the other aspects.
When folks describe the value of a shared component library, they often talk about a few common attributes: UI consistency, development speed, efficient prototyping, etc. Those are certainly valid outputs of a well-built component library, but they are also a bit short-sighted. Why? Because while reducing the cost of initial implementation is an important aspect of development, it only represents a fraction of the lifecycle of any successful product UI. If we were building static interfaces or the lifespan of a product was relatively short, initial speed and consistency would be the absolute measure of a component library’s value. But active product UIs are dynamic environments that change continuously as teams respond to user feedback, test out new features, and deprecate old ones.
Because of this dynamic environment, I prefer to focus on a different metric to assess the effectiveness of a component library: resilience, or “How well does the library allow teams to adapt to change over time?” Resilience is a common metric for evaluating the success of a system. The human body is a successful system because of how well it adapts to different environments over time. Conversely, transportation systems are often (rightly) criticized for their inability to adapt to population growth and rate of deterioration.
All that to say: The initial gains from time and effort saved during implementation are quickly lost if the library becomes a stumbling block for building the next iteration. While product teams need to focus on their current iteration, a shared library team’s job is to help them build the next.
This is where most component libraries fall short. It’s a tremendously challenging problem. How can we build components for UI that doesn’t yet exist? How can we support the future of multiple products, all of which have their own needs and trajectories? How can we design our library in a way that reduces the cost of change over time?
It would be useful to know the future state for any given product with enough lead time to stay ahead, but that is often a (laughable) impossibility. Instead it’s helpful to think about how product UIs change over time. While client-side applications are in a constant state of change, they do not change at the same rate. The application-level business logic (authentication, authorization, data fetching, et al) usually remains fairly intact over time. The UI logic layer (checkout flow steps, modal logic, etc) will change more frequently as features evolve or are deprecated. But the most frequent changes happen at the markup structure and styling level.
Optimizing for adaptability means we need to think differently about how we build components. We will talk more about particular ways to optimize components to be adaptable in the third article. But first we need to understand the costs, which will be the focus of Part Two.
Thanks for Reading!
Redefining the value of a shared component library in this way has been a useful heuristic for how I think about what to prioritize and where to grow. I hope this was helpful for you as well. This series is not yet complete, and I’m writing these posts as I have time and headspace, so I’m not sure when I’ll finish the last post. But if you have questions or just want to say thank you, you can find me on Twitter.