Composition
“Favor composition over inheritance.” — Gang of Four, Design Patterns
Understand This First
- Abstraction – composition works best when parts hide their internals.
Context
Systems are built from parts. Composition is the act of combining smaller, simpler parts into something larger and more capable. It operates at the architectural scale. Instead of building one big thing, you build small things that snap together.
Composition appears everywhere: functions calling functions, components wiring together, services coordinating through APIs, and AI agent workflows chaining tool calls into multi-step plans. Wherever small pieces combine to produce behavior that none could produce alone, composition is at work.
Problem
How do you build complex behavior without creating complex parts?
Forces
- Complex requirements demand complex results, but complex implementations are hard to understand and maintain.
- Building everything from scratch is wasteful. Many problems have already been solved.
- Combining parts requires compatible interfaces. Parts that can’t communicate can’t compose.
- Deeply nested compositions can become hard to follow, even if each piece is simple.
Solution
Build small, focused parts that each do one thing well. Give each part a clear interface. Then combine them to produce the behavior you need. The combination itself should be simple: ideally, just wiring outputs to inputs.
Effective composition requires parts that are:
- Self-contained — each part works without knowing how it will be combined.
- Composable — parts accept standard inputs and produce standard outputs.
- Substitutable — you can swap one part for another that has the same interface.
Unix pipes are a classic example: cat file.txt | grep "error" | sort | uniq -c. Each tool does one thing. The pipe operator composes them into something none of them could do alone.
In agentic coding, composition is how agents accomplish complex tasks. An agent doesn’t solve a big problem in one step. It decomposes the goal into sub-tasks, uses tools to complete each one, and composes the results. The quality of the available tools (their clarity, their contracts, their composability) directly determines how effectively the agent can work.
How It Plays Out
A data processing system needs to ingest CSV files, validate records, enrich them with data from an API, and write the results to a database. Instead of building one monolithic script, the team builds four stages: parse, validate, enrich, and store. Each stage reads from a queue and writes to the next. When the enrichment API changes, only the enrich stage changes. When a new output format is needed, a new store stage is added alongside the existing one.
An AI agent is asked to prepare a code review. It composes several tool calls: first search_code to find the changed files, then read_file on each one, then run_tests to check for regressions, then it synthesizes a review. Each tool is simple. The agent’s plan — the composition — is where the intelligence lives. If the tools are well-designed and composable, the agent’s plan works. If they produce inconsistent formats or have surprising side effects, the composition falls apart.
“Build the data pipeline as four composable stages: parse, validate, enrich, and store. Each stage should read from an input queue and write to the next. I want to be able to replace or add stages without rewriting the others.”
Consequences
Composition keeps individual parts simple while enabling complex outcomes. It supports reuse: the same parts can appear in different compositions. It supports evolution: you can replace or add parts without rewriting the whole.
The cost is coordination. Composed parts must agree on data formats, error handling, and sequencing. When a composed system fails, debugging can be harder because the bug might be in any part or in the wiring between them. Good logging, clear contracts, and predictable error propagation are essential complements to compositional design.
Related Patterns
- Uses: Interface, Contract — parts compose through compatible interfaces.
- Produces: Component — a composition of parts often becomes a new component.
- Depends on: Abstraction — composition works best when parts hide their internals.
- Contrasts with: Monolith — a monolith resists composition by entangling concerns.
- Related to: Decomposition — decomposition breaks things apart; composition puts them together.
- Requires: Dependency management — composed parts depend on each other.