task-decomposition
verified932fa134-7742-433b-817e-e40b8fc8ce3e
Decompose a feature or bug into an ordered list of small, independently testable subtasks before writing any code. Use when a task feels too big to start or keeps sprawling.
Metadata
Skill file
# Task Decomposition
Use when a task is too big to start in one go, keeps sprawling as you work, or you
need a defensible plan of attack for an "epic" or "feature" request.
The core idea: before writing code, turn the request into a flat, ordered list of
**leaf tasks** β each one small enough to be *verified by a single command*. A task
you cannot verify with one command is not yet a leaf; split it again.
## 1. The leaf-task rule
A leaf task is done when **one command** proves it is done. That command is a test
run, a script run, a `git diff`, or a single SQL/`curl` check. If verifying the
task requires "and then alsoβ¦", it is two or more leaves.
| Not a leaf (split again) | Leaf (one verify command) |
|---|---|
| "Implement user auth" | "Add `User` model + migration; verify `python manage.py makemigrations --check`" |
| "Add login endpoint" | "Add `POST /login` returning a JWT; verify `pytest tests/test_login.py`" |
| "Set up the database" | "Add `users` table DDL; verify `psql -f schema.sql -c '\\d users'`" |
Test the rule: for every leaf, write the exact verify command next to it. If you
cannot write one, the leaf is too coarse.
## 2. Ordering heuristics
Order the leaves as a **DAG, not a list**. Draw arrows for "B depends on A". Then
schedule with:
1. **Highest risk / highest uncertainty first.** Unknowns discovered early are cheap;
unknowns discovered at the end force rework.
2. **Dependencies before dependents.** A leaf is only scheduled after its parents.
3. **Foundations before polish.** Schema, interfaces, and contracts before UI and docs.
```
User auth decomposition (DAG order):
1. User model + migration (risk: low)
2. Password hashing util (risk: low)
3. Auth service (hash+verify) (risk: medium β unknown library choice)
4. POST /login endpoint (depends on 3)
5. Session/token issuance (depends on 3)
6. Middleware to protect routes (depends on 5)
7. Tests for each of the above (fan out after each leaf)
8. Migration + rollback script (depends on 1)
```
## 3. Writing a subtask spec (one line each)
Every leaf gets three fields β no more than one line each, or the decomposition is
itself over-engineered:
```
[objective] one verb-phrase sentence of WHAT, not HOW
[accept] the observable result that must hold
[verify] the exact command that proves [accept]
```
Example:
```
Objective: Hash a plaintext password with a salted KDF.
Accept: same input -> same stored hash; wrong input -> no match; never plaintext.
Verify: pytest tests/test_password.py -k hash
```
## 4. Worked example: "add user auth" -> 8 leaves
| # | Leaf | Verify command |
|---|---|---|
| 1 | `User` model + migration | `alembic upgrade head && alembic check` |
| 2 | `hash_password` / `verify_password` util | `pytest tests/test_password.py` |
| 3 | Auth service `authenticate(email, pw)` | `pytest tests/test_auth_service.py` |
| 4 | `POST /login` endpoint | `pytest tests/test_login.py` |
| 5 | Session/token issuance + expiry | `pytest tests/test_token.py` |
| 6 | Auth middleware protecting routes | `pytest tests/test_middleware.py` |
| 7 | Down migration + rollback test | `alembic downgrade -1 && pytest` |
| 8 | README/API doc update | `git diff --stat README.md` |
Note leaf 7 β the rollback/migration leaf β is the one everyone forgets.
## 5. When to stop splitting
- Stop when each leaf is a **single commit's worth** of work (roughly 1 file /
1β2 hours of focused change).
- Stop when further splitting produces **busywork** β leaves that are "write one
line and run the formatter".
- A good check: each leaf maps to roughly one commit message subject line.
## 6. Common decomposition patterns
Most tasks decompose into one of a few shapes; recognizing the shape speeds up the
work and tells you which leaves are usually forgotten.
| Pattern | Leaves look like | Commonly forgotten leaf |
|---|---|---|
| **CRUD feature** | model β schema/migration β create/read/update/delete β validation β tests | permission/authorization |
| **Pipeline / ETL** | source β transform stage 1..N β sink β error/retry β tests | retry/dead-letter |
| **Migration** | write DDL β backfill script β dual-write β cutover β rollback | rollback |
| **Bug fix** | repro test β root-cause isolate β minimal fix β regression test | the regression test |
| **Integration** | client wrapper β error mapping β config β end-to-end test | error/edge mapping |
Naming the pattern first tells you which leaves are usually missing.
## 7. When NOT to decompose
- **Trivial one-line changes** β decomposing "fix a typo" is ceremony, not planning.
- **Exploratory work** β if you do not yet know the shape of the solution, a spike
(see spike-prototype) is the right tool, not a decomposition.
- **You are the only consumer and it is under ~2 hours** β a short ordered list is
enough; a full leaf tree with verify commands is overhead.
Decomposition is a tool for tasks too big to hold in your head, not a ritual to
apply to everything.
## Guardrails
- Do **not** decompose so finely that the plan itself takes longer to write than the
work. Leaves of ~15β120 minutes of effort are the sweet spot.
- Do **not** mix unrelated concerns into one leaf ("add login AND fix the CSS on
the navbar") β they review and verify differently.
- Do **not** leave a leaf with no verify command. A leaf without a check is a hope.
- Always include **migration, rollback, and doc** leaves for schema/API changes.
- Re-split, don't stretch, when a leaf turns out to be bigger than estimated.
## Pitfalls
- **Decomposing too fine** β 40 leaves of "rename this variable" is a ceremony, not a plan.
- **Mixing concerns** β "add the endpoint and write the tests and update the README"
hides three separate risks in one line.
- **Forgetting the failure path** β decomposition that only covers the happy path
collapses the first time an error branch is needed.
- **Ordering by preference, not risk** β doing the easy/fun leaves first and the
hard/unknown ones last maximizes late rework.
- **Skipping rollback** β schema/API changes always need a "how do we undo this" leaf.
## Verify / Checklist
- [ ] Every leaf has a one-line objective, an acceptance result, and an exact verify command.
- [ ] No leaf requires "and then alsoβ¦" to confirm it is done.
- [ ] Dependencies are drawn as a DAG and highest-risk leaves are scheduled first.
- [ ] Migration/rollback and documentation leaves are present for schema/API work.
- [ ] Each leaf is roughly one commit's worth of work.
- [ ] The whole plan is written down (markdown file, task tracker, or commit message) before coding starts.
Attached files
No attached files.