Agent Engineering
Module 06 · Shipping/Lesson 6.3/3 min

Decomposing into phases

How to cut a feature so that every cut point is a place you could stop.

Given a spec, the question is where to cut. The principle: each phase should end somewhere the codebase is coherent, the checks are green, and you could genuinely stop.

The default cut: vertical, thin, end to end

Cutting by layer — all the database work, then all the API, then all the UI — is the intuitive decomposition and usually the wrong one. Nothing is verifiable until the last phase, so every assumption made in phase one is tested in phase four.

Cut vertically instead. The narrowest path that works end to end, then widen.

Horizontal (avoid)Vertical (prefer)
1. All tables and migrations1. One schedule type, hard-coded daily, no UI, prove the pipeline end to end
2. All API endpoints2. Add weekly and monthly
3. All UI3. Add the CRUD UI
4. Wire together, discover problems4. Add retries and failure notification

Vertical cuts mean phase one already answered the risky question — does the queue deliver, does the email attach, does streaming work — and later phases are elaboration rather than discovery.

Front-load the risk

Order phases by uncertainty, not by dependency alone. The phase most likely to invalidate the plan goes first, even if it is not the most natural starting point. Discovering in phase four that exports cannot stream through your email provider is a rewrite; discovering it in phase one is a design change.

A worked decomposition

specs/scheduled-exports/plan.md
Phase 1  Pipeline spike (riskiest)
  T1 schedules table + migration
  T2 hard-coded daily scheduler -> enqueue -> export -> email
  -> stop point: one account, one schedule, works end to end

Phase 2  Real scheduling
  T3 findDueSchedules with timezone + DST handling
  T4 weekly and monthly rules
  -> stop point: correct scheduling, still no UI

Phase 3  Management UI
  T5 CRUD API
  T6 settings screen
  -> stop point: shippable to a friendly customer

Phase 4  Robustness
  T7 retries + admin notification
  T8 size limit + link fallback (blocked on open question)

Note that phase 3 is the first phase a user could see, and phase 4 is where the open question lives — deliberately last, so it does not block the work that does not depend on it.

Keep the plan file honest

The plan is a living artifact. After each session, mark what is done and note anything the session learned that changes later tickets. That file, plus the spec, is the entire memory of the project — and unlike a session, it does not degrade.

Watch out

Do not write all the tickets up front in detail. Write the next two or three. Later tickets will be wrong because earlier sessions will change what is true, and detailed wrong tickets are worse than sketched ones — they look authoritative.

Try it

Decompose your spec into phases. For each, write the stop point in one sentence. If a phase has no meaningful stop point, it is not a phase — merge or re-cut it.

Takeaways

  • Cut vertically: thin end-to-end slices, not layer by layer.
  • Order by risk — put the phase that could invalidate the plan first.
  • Every phase ends at a coherent, green, stoppable state.
  • Detail only the next two or three tickets.
Why is layer-by-layer decomposition tempting but usually wrong?

Because it matches how the codebase is organised, so it feels tidy. But nothing is verifiable until the final layer, which means every assumption from the first layer stays untested for the whole project — and when one is wrong, the correction is a rewrite rather than an adjustment.

← Tickets Handoffs →

A course by Pieter Zandbergen