practice

Mikado Method

also called Mikado Graph, Prerequisite Graph Refactoring

Probing a large change to discover its prerequisites then reverting and landing the leaves one at a time on trunk - so the work arrives as small reversible commits instead of a branch nobody merges.

refactoringtrunk-based-developmentincremental changebranch lifetimeplanning

Replacing a home-grown money type with a decimal-backed one breaks 180 call sites across 11 modules the moment you try it. The team's last attempt lived on a branch for five weeks and was abandoned when the rebase cost more than the remaining work.

The Mikado Method, named and written up by Ellnestam and Brolund (Manning, 2014), inverts the order of operations. Make the change, do not fix anything, write down every break as a prerequisite, and revert to green. The output of the attempt is not code; it is a graph of what must be true first. Then work the leaves - prerequisites with nothing underneath them - one at a time, on trunk, each as a commit that stands alone.

180 compile errors are not 180 units of work. They usually collapse into about 12 of 180 distinct causes, and most of those leaves are changes a reviewer can read in one sitting.

Why it matters

The dominant failure in large refactoring is not difficulty; it is that the work is invisible until it is finished. A branch is the default container for an unknown-sized change, and a branch's cost grows with its lifetime: divergence, rebases, review fatigue and the organisational fact that a four-week branch has to survive a reprioritisation.

The graph converts an unknown into a bounded list before any of that is risked. It also makes the estimate arguable: a graph that converges to twelve leaves is a two-week plan, and a graph that keeps widening is evidence that the change is a rewrite - which is a different conversation with different approvals.

Implementation patterns

  • The probe is for information. Attempt, record, revert. The revert is the step teams skip, and skipping it is what produces the long branch.
  • Write prerequisites as outcomes, not tasks. "Reporting no longer reads the integer cents field", not "fix reporting".
  • Work leaves only. A leaf has no prerequisites of its own, so it can land today without the goal being reached.
  • One leaf per commit, on trunk, with its own tests. Each is independently releasable and revertible.
  • Pair it with branch by abstraction for the switch itself: old and new coexist behind a conversion seam, modules migrate one at a time, the old implementation is deleted last.
  • Keep the graph where the team can see it - a whiteboard photo or a markdown file in the repository. Its second job is handover: anyone can take the next leaf.
  • Re-probe after a few leaves. The graph is a hypothesis, and it shrinks as often as it grows.

Industry example

The canonical use is a type or dependency replacement in a long-lived codebase: a money or date type, a logging facade, an ORM version, a currency rounding rule. A platform team replacing a logging call at a few thousand sites hits the same structure, and the method is used in practice for exactly these changes because the alternative - a codemod that cannot compile until every prerequisite is met - produces a branch nobody can review.

The method is a published technique rather than one company's practice, which is its strength here: it assumes nothing about scale, tooling or language. The planning number worth carrying is the collapse ratio - expect roughly 1 in 10 of the breaks to be a distinct prerequisite, and re-probe once a few leaves have landed.

Failure scenarios

  • Keeping the probe. The half-finished attempt becomes the branch, with the graph as decoration.
  • Working a non-leaf, which pulls three other changes into the commit and recreates the big-bang diff.
  • Mistaking a behaviour change for a structural one. A money type replacement changes rounding, and no compiler notices; without a parallel run the divergence appears weeks later as a reconciliation that is 0.01 out across tens of thousands of rows.
  • A graph that never converges, worked anyway, until the team has spent a quarter and has neither the old structure nor the new one.
  • Deleting the old implementation too early, which removes the only cheap rollback.

Trade-offs

What it buys: a bounded plan before the branch, commits that survive reprioritisation, a reviewable unit every day, and a rollback at every step.

What it costs: more total commits and more review events for the same change, a probe that produces no shippable code, and a period where two representations coexist in the codebase and both must be understood. The graph also makes the true size visible, which is occasionally unwelcome - some changes get cancelled once their shape is known, and that is the method working.

When not to use it

When the change fits one sitting. 180 sites of pure mechanical rename with no behaviour change: write the codemod, land it in one commit, spend the saved time on the test that proves nothing moved.

When the prerequisites are already known from a previous attempt or a well-understood codebase. Go straight to the leaves.

When the graph will not converge. Past roughly three or four levels of depth and still widening, stop: cut the scope to one module and keep the conversion seam permanently, or fund a rewrite with a parallel-run plan. Continuing to probe converts an estimate into a sunk cost.

Interview question

Q: You need to remove a deprecated internal library used in 400 places across 14 modules owned by six teams, and a previous attempt died on a branch. Describe how you would sequence it, what you would put in front of the teams, and how you would know when to stop.

What a strong answer covers: the probe-record-revert loop and why the revert is non-negotiable · the graph as both plan and handover artefact, with prerequisites written as outcomes · landing leaves on trunk as independently releasable commits rather than accumulating a branch · a conversion seam so old and new coexist while modules migrate · the behaviour-change risk and a parallel comparison where results could differ · the stop rule when the graph keeps widening · and the organisational step of giving each module's leaf a named owner on the owning team, because 400 sites across six teams is a coordination problem before it is a refactoring problem.

Quick check

Quiz: What do you do with the first attempt at a change that breaks 180 call sites, and why? — Record every break as a prerequisite and revert to green. The attempt's product is the graph; keeping the half-finished state is how the previous try became a five-week branch.

Flashcard: What is a leaf in a prerequisite graph and why does it matter? — A prerequisite with nothing underneath it, so it can be made alone, tested, reviewed and merged today without the overall goal being reached - which is what keeps the change on trunk.