Let’s start with why we need Composable Features in the first place. If you’ve been in product for a while, especially as a startup product leader, you’ll be familiar with seeing a roadmap filled with incremental but necessary projects. Ever felt like this quarter was just like the last but with slightly different variations on the same kind of project? Add a new column of data here, add a new data attribute there?
Part of the challenge is unavoidable as we lay the foundation of a solid product while working with scarce resources, mounting urgency, and the inherent uncertainty of building something new and innovative.
On the flip side, with the extra thought and consideration, we should strive to build meta-features that make the incremental effort of these Groundhog Day features almost trivial.
I certainly didn’t invent this kind of product thinking, but I wanted to put a label on it so we can point to it and say, “that applies here; let’s do that.” So I refer to this approach as building Composable Features.
I’ve advocated for this approach for many years and used the term since the beginning of 2020. Anyone I’ve worked with closely during this time can probably predict exactly when I’m going to say it during product discovery and planning.
Composable Features are built with the explicit goal of being expandable over time and reducing the amount of work required when doing that expansion.
Keep in mind that the goal here is to capture and label an approach that many of us use all the time. I didn’t invent or even perfect this approach. I’m just putting a label on it, so I (or we) can talk about it more effectively.
A fun aside: For those with an engineering bent, this might seem familiar to some of the magic of Ruby on Rails, where defining a model automatically generates your entire CRUD interface automagically.
Composability is a system design principle and essentially captures the same idea as building with Lego Bricks.
Composable entities must be modular and “stateless.”
Modular in that they plug together seamlessly and almost “cooperate” with one another.
Stateless can be applied to features as being somewhat self-managing and independent. I think this aspect captures the goal of significantly reducing the marginal effort of feature expansion.
I first came across the idea of “composability” in DevOps and Engineering Platform work. (In that context, it was that your architecture was composed of some arbitrary collection of Containers)
More recently, after I’d started using the term, composability has been heavily touted as a defining trait of web3. That use case captures the same philosophy but at a substantially more macro (typically protocol) level. Similarly, the common term “primitives” roughly translates to the earlier lego block idea but with far-reaching and infinitely creative applications.
When to build Composable Features
It’s a good idea to seriously consider a composable approach if you’re working on a feature that:
- You know will expand over time; and
- The nature of that expansion is well-understood upfront
Think of this as the Composable Feature Philosophy.
How can you scope your feature such that you’re not building every possible expansion upfront but building a flexible system that accounts for the expected angles of expansion?
For me, “we’re going to run out of space in the UI.” is a common trigger for considering composability.
At its simplest, a composable feature can be applied simply from a design perspective. For example, suppose you’re presenting data in a tabular format and know that you’re likely to continue to add new columns over time. In that case, you can expect to run out of space. Taking a composable approach would be to plan in advance for that outcome. Things like horizontal overflow and the ability to show/hide columns as needed are some UX patterns that could come in handy.
A composable approach shouldn’t be taken alone. To build a Composable Feature, you’ll need alignment and investment across the product trio (Product Manager, Product Designer, and Product Engineering Leader).
What you should I watch out for
The biggest risk when taking this approach is over-investing and over-engineering. Therefore, it’s vital you thoughtfully evaluate both the cost-benefit and short vs. long term benefit tradeoffs.
The scale and frequency of expansion will be the key drivers of cost-benefit. Suppose you’re regularly and significantly expanding the system. In that case, it’s more likely you’ll find the benefit of taking this approach outweighs the additional cost. On the other hand, suppose you don’t end up expanding the system. In that case, the additional cost of making the system composable will have been a complete waste.
A composable approach will take longer to deliver the first version than the typical approach. There’s an inherent cost to that time, and you’ll need to balance it against the long time savings (evaluated above). In many cases, this won’t change your decision. By way of example, though, if your users are demanding a particular feature or else they’ll churn, you’re probably going to be better off meeting their needs ASAP. You can always consider circling back to a composable approach later.
Examples of Composable Features
To help illustrate the approach, let’s dive into some examples. We’ll start with some composable features you’re probably familiar with. You might have even built one or two into your product already without thinking of them as composable:
- Keyboard Shortcuts
- Command Bar
Probably the most commonly composable feature. A highly composable navigation system might, after adding a new page, automatically:
- Add a link to the right place in your navigation
- Account for running out of space (such as with an overflow menu)
- Add the link to your sitemap for SEO purposes
- Notify Google to recrawl your site
- Add links to pages that specifically mention the exact title of the new page
The effort to build support for keyboard shortcuts (other than one or two) is generally non-trivial. Creating a system that makes it easy to add and manage new keyboard shortcuts is a prime example of a composable feature. Some products even expand the feature to incorporate listing the keyboard shortcuts in one convenient place.
This pattern has been around for a while but exploded in popularity after its impressive implementation in Superhuman. At this point, the command bar has become a design pattern. It’s even been turned into a SaaS product. Still, it is also a prime example of a composable feature. The command bar is summoned with a keyboard shortcut and shows a searchable list of actions all in one place. The composability comes from building a system where a new option can be created simply and efficiently, often without defining the UI.
The image above shows the implementation I worked on as a central part of our product experience. Providing a single place to take bulk actions on a set of items — a very common workflow in our product. An engineer can define the inputs and business logic of the action reading in a single file and write the item’s attributes. That single file then generates the UI, data validation, ability to undo the action, and even integrates with an auditable history log. All from a few lines of python code.
What about Design Systems?
One might look at this and say, “you’ve just reinvented design systems.” I know I’ve looked at the draft of this article and thought that myself…
I think composable features go hand-in-hand with a great design system and can also be a gateway to adopting a design system approach. I think of composable features as a full-stack design system plus a “generative” engineering layer. Rather than picking the appropriate design system components, the system does it for you as you configure the incremental expansion of your feature.
When are Composable Features the wrong choice?
The obvious time to use a different approach is when you’re not sure you’ll need to notably expand the feature over time. If you can lay out a clear phase 1 and phase 2 that are both realistic in scope, you’re probably better off just building it in two phases and designing (both UI/UX and your front-end) to meet the needs of phase two.
Similarly, I’d generally avoid this approach if you’re pre-product-market fit. If you don’t know the market wants what you’re building, it’s best to avoid over-engineering it. In a high-growth startup, you’ll have the opportunity to rebuild after you’ve found traction.
Likewise, you should be more confident that you’ve found a problem worth solving and solution worth building than when taking the standard approach. Invest the extra time in Discovery to be doubly sure the feature you’re building will add value and justify the expansion over time. Related: The two key types of product risk and how to manage them.
As you go through Discovery for your next significant feature, consider whether it’s likely to expand over time. Maybe it merits a more composable approach?