Decomposition by Capability
Browse a product, add it to a cart, check out: a capability is something an actor can do, end to end, that you could demonstrate. Splitting a problem along capabilities gives every piece a test in the user's words and a natural order of work.
The situation, the reflex, and why it stalls
Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.
What is the unit a problem should be split into, so that finishing a unit means something to the person who asked for the system?
You have the store's requirements and a half-drawn tree, and you keep arguing with yourself about the children. Is "product images" its own piece? Is "the products table"? Is "the cart API"? Every candidate feels either too small to matter or too technical to test.
Split by noun. Products, Carts, Orders, Users — each becomes a module with a table, a model, an endpoint set and a page. It mirrors the schema, it is how most frameworks scaffold, and it produces a tidy folder per noun.
The nouns are finished one at a time, and none of them does anything alone. A Products module with a table and CRUD endpoints is not a catalog until someone can browse it; a Carts module is not a cart until an item from the catalog can go in it. The pieces are done and the product is not.
- The nouns are finished one at a time, and none of them does anything alone. A Products module with a table and CRUD endpoints is not a catalog until someone can browse it; a Carts module is not a cart until an item from the catalog can go in it. The pieces are done and the product is not.
- Behaviour that spans nouns — checkout touches cart, inventory, order and payment — has no home, so it lands in whichever module was written last, and that module quietly becomes the whole application.
- Each noun-module is tested by its own CRUD, which passes, while "a customer can buy a product" is tested by nobody until the demo.
The move
Precisely enough to apply it to a problem you have never seen — not a slogan.
- Split by verb-with-an-actor. A capability is a sentence: "a customer browses products", "a customer adds a product to the cart", "a customer checks out". The test is whether you could demonstrate it to the person who asked for the store, and they would nod.
- Let each capability own whatever it touches across all layers. "Add to cart" owns the button, the endpoint, the cart row and the stock check — whichever it needs — rather than borrowing them from noun-modules.
- Where two capabilities need the same noun, the noun is shared data, not a piece of the decomposition. Products are read by browse, by add-to-cart and by checkout; the Product entity belongs in the data model (Entities From Requirements), not in the tree.
- Order the capabilities by what the actor does first. Browse comes before add-to-cart comes before checkout — not because it is easier, but because the second cannot be demonstrated without the first.
Three capabilities, each end to end
The children below are the three the guide names — browse, add to cart, check out — decomposed one level, with the observation for each leaf written in the customer's words. Notice that every leaf, if built, would touch a page, an endpoint and storage; that is what makes it a capability and not a fragment.
- ├Browse products— first thing a customer does
- └See the listtestable The page shows the products that exist, with name and price.
- └Open onetestable Clicking a product shows its details; a missing id shows not-found.
- ├Add a product to the cart— the bridge from looking to buying
- └Add with a quantitytestable After adding quantity two, the cart shows that product with quantity two.
- └Reject impossible quantitiestestable Adding zero, a negative number, or more than stock is refused with a reason the customer can read.
- ├Check out— the capability that makes it a store
- └Turn the cart into an ordertestable After checkout, an order exists with the cart's lines and prices, and the cart is empty.
- └Pay for ittestable A test-mode payment marks the order paid; a declined one leaves it unpaid and tells the customer.
Products, Cart, Order and Payment appear as nouns inside the leaves; none of them is a child. They live in the data model.
The question that finds capabilities
"How should I split this?" is the vague form of the question. The ladder below shows the same need asked until the answer is a list of capabilities rather than a list of nouns.
why The best form yields pieces that are demonstrable and ordered by the actor's journey, which is what a decomposition is for; the middle form yields tables, which is what a schema is for; the vague form yields an argument.
Capability, noun, layer — side by side
The three ways of splitting are not interchangeable, and each has a legitimate use. The matrix says what each is good at, so the choice is deliberate.
| Split by | Children look like | Finishing one child means | Good for |
|---|---|---|---|
| Capability | "customer adds to cart" | Something demonstrable works end to end | Deciding what to build and in what order |
| Noun | Product, Cart, Order | A table and its CRUD exist | Designing the data model, after the capabilities are known |
| Layer | Frontend, Backend, Database | One layer of everything exists; nothing works | Assigning specialists, tuning one layer of a working system |
How to do it
Most important first.
- Write each candidate child as "<actor> <verb> <object>". If it does not fit that shape, it is probably a noun or a layer, not a capability.
- For each capability, name the layers it touches — page, endpoint, logic, storage — so you can see it is vertical. A capability that touches one layer is usually a fragment of a real one (Vertical Slices).
- Ask "could I demo this alone, with the other capabilities stubbed?" If not, find the smallest thing it needs and make that a capability too.
- Give each capability its own test in the actor's words: "after adding twice and removing once, the cart shows one" (A Slice Is Testable).
- Put shared nouns in the data model and shared machinery — auth, logging — beside the tree, not in it.
Worked on a concrete problem
The move has to produce something. This is what it produced.
- The customer's capabilities, in the order they happen: browse products; view a product; add a product to the cart; change a quantity; check out; see the resulting order. The admin's: create a product; change its price; change its stock. Nine sentences, each demonstrable, each touching every layer.
- "Add a product to the cart" owns: the button on the product page, an endpoint that receives product id and quantity, the rule that quantity must be positive and not exceed stock, and a cart line in storage. It does not own the Product entity; it reads it. That is the difference between a capability and a noun.
- Checkout, which had no home in the noun split, is simply the largest capability: it reads the cart, checks inventory, creates an order, asks Payments for a charge, and shows a confirmation. It will be decomposed again (Decomposing Checkout), but as a capability it already has a demo and a test.
How you know it worked
What now exists that did not before, and what question you can now ask.
- Every child of the root reads as a sentence with an actor and a verb, and you could act each one out in front of the founder.
- No child is named after a table, a layer or a folder.
- When a new requirement arrives — "customers can save a cart for later" — it is obvious which capability it extends or whether it is a new one.
The questions you can now ask
The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.
- ?Who does this, and what do they do — in one sentence with a verb?
- ?Could I demonstrate this piece alone, with everything else stubbed?
- ?Which layers does this capability touch, and does it own or merely read each thing it touches?
- ?Which nouns do several capabilities share, and have those gone into the data model rather than the tree?
What can go wrong
- Capabilities too fine: "click the add button" and "render the cart badge" as separate children. A capability is demonstrable to a stakeholder; a click handler is not. Merge until the demo is meaningful.
- Capabilities too coarse: "shopping" as a single child, which is just the root again with a different name. Split until each can be finished while the others are stubs.
- Forcing cross-cutting machinery into the tree: "Authentication" as a capability. Logging in is one; "authentication" is a mechanism several capabilities need. Keep mechanisms beside the tree, with the data model.
- Applying it to a problem with no actors — a batch pipeline, a compiler — and inventing fake ones. There the capabilities are the observable outputs: "produces a parse tree for valid input", "reports the line of the first error".
- Capability-owned code cuts across the layer folders a framework wants, so the folder structure and the decomposition disagree, and someone has to decide which wins (Decomposition by Folder in Design).
- Capabilities that share a noun have to agree about it, and that agreement is a coordination cost the noun split hid inside one module.
- "Capabilities are user stories, so this is just agile." The shape overlaps; the point differs. A capability here is a decomposition unit chosen because it is testable and vertical, whether or not anyone writes it on a card.
- "So never organise code by noun." Code organisation is a separate decision from problem decomposition. A module per entity can be a fine code layout; it is a poor way to decide what to build and when.
Where this applies
Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.
- GENERALSplitting by what an actor can observably do transfers to any system with observable behaviour; where there is no human actor, the observable outputs play the same role.
- TEAM-SPECIFICA solo builder can carry capability ownership in their head; a team of several needs it written down, because the temptation to split work by layer — "you do the API, I do the pages" — returns the moment there are two people.
- ILLUSTRATIVEThe nine capabilities and what each owns are invented for the running example; a store that sells services rather than goods would have a different list.
Where the depth lives
This domain asks the question and hands the answer off by name.