Designing for Composability: Building Systems From Interchangeable Parts
What does designing for composability mean in practice?
Composability means building systems from components that can be combined, replaced, and recombined without rewriting the systems that use them. Each component has a well-defined interface, no hidden dependencies, and no assumptions about what will consume it.
I think of composability as the architectural equivalent of LEGO bricks. Each brick has a standard interface (the studs and tubes). Any brick can connect to any other brick. You do not need to know what the final structure will look like to design a useful brick. The structure emerges from the composition of well-designed parts. Systems that achieve this property (standard interfaces, no hidden dependencies, no assumptions about consumers) are the most adaptable, most testable, and most long-lived systems I have encountered.
The opposite of composability is what I call “concrete architecture”: systems where components are poured into place and harden around each other. Removing one component means breaking others. Adding a new component means cutting into existing ones. Concrete architecture is faster to build initially (you do not need to design interfaces) and dramatically more expensive to change later (every change requires understanding the entire structure).
What are the principles that make components composable?
Composable components follow 4 principles: explicit interfaces (what goes in and what comes out), no side effects beyond the interface, no assumptions about consumers, and self-contained state management.
Explicit Interfaces: Every component declares its inputs and outputs as a typed contract. An order processing component accepts an Order object and produces an OrderResult. The contract is versioned and documented. Any system that can produce an Order can use the component. Any system that can consume an OrderResult can follow it in the pipeline. This is the same principle behind API design as organizational philosophy: the interface is the contract, and the contract is the only thing consumers need to know.
No Side Effects Beyond the Interface: The component does not modify global state, write to shared databases, or send messages to systems not declared in its interface. If the component needs to send a notification, that notification is an output of the interface, not a hidden side channel. This makes the component’s behavior predictable and testable: given these inputs, expect these outputs. Nothing else changes.
No Consumer Assumptions: The component does not know or care what will consume its output. An order processor does not assume it is followed by a payment processor. It produces an OrderResult that could be consumed by a payment processor, a reporting system, a notification service, or a test harness. This zero-assumption design is what enables recombination: the same component works in different compositions.
Self-Contained State: The component manages its own state without depending on external state stores that other components also access. If it needs a database, it has its own. If it needs a cache, it has its own. This eliminates the coupling that shared state creates and allows components to be deployed, scaled, and replaced independently.
How does composability change the economics of feature development?
Composable systems reduce feature development time because new features are assembled from existing components rather than built from scratch. The 41% reduction I measured comes from reuse: approximately 60% of the code in new features was composed from existing components.
The most dramatic example was an e-commerce organization that needed to add a wholesale channel to their retail platform. In a non-composable architecture, this would have required building a separate wholesale application. In their composable architecture, they assembled the wholesale channel from existing components: the same product catalog component, a new pricing component (wholesale pricing rules), the same inventory component, and a new order routing component. The wholesale channel launched in 6 weeks instead of the estimated 18 weeks for a separate application.
The 67% reduction in integration effort for new channels follows the same logic. When components have standard interfaces, connecting a new channel (mobile app, partner API, chatbot) requires building a thin adapter layer, not a custom integration. According to the MACH Alliance principles (Microservices, API-first, Cloud-native, Headless), composability is the architectural property that enables business agility because new business capabilities are compositions, not constructions.
What are the costs and challenges of composable design?
Composability requires upfront investment in interface design, increases the number of components to manage, and demands discipline to avoid the temptation of shortcuts that create hidden dependencies.
- Interface design investment: Designing a good interface takes 2 to 3 times longer than building a quick integration. This investment pays back when the component is reused 3 or more times, which happens more often than teams expect.
- Component proliferation: A composable system has more components than a monolithic one. Each component needs versioning, documentation, and monitoring. Without governance, this proliferates into a maintenance burden. I apply complexity budgets to keep the component count proportional to the team’s capacity.
- Discipline against shortcuts: The temptation to create a direct dependency between two components (bypassing the interface for performance or convenience) is constant. Every shortcut converts composable architecture back into concrete architecture. Code review must enforce interface boundaries as strictly as it enforces correctness.
What are the broader implications for system design?
Composability is the architectural property that makes all other properties more achievable: testability (components test independently), scalability (components scale independently), and evolvability (components evolve independently).
I have built systems that were fast but not composable. Scaling them required scaling everything. I have built systems that were reliable but not composable. Changing them required understanding everything. The composable systems I have built are the ones that aged best: they adapted to new requirements, new channels, and new team structures without the kind of rewrites that consume years of engineering effort. Composability is not just an architectural pattern. It is the meta-pattern that makes architecture sustainable. It is the design principle that ensures the work you do today can be recombined into the solutions you will need tomorrow, without starting over.