mikado-method

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Mikado Method Skill

Mikado Method 技能

A skill for guiding developers through the Mikado Method: a disciplined, graph-driven approach to safe, incremental refactoring that keeps the codebase in a working state at all times.

本技能用于引导开发者使用Mikado Method:这是一种严谨的、基于依赖图驱动的安全渐进式重构方法,可以让代码库在整个重构过程中始终保持可用状态。

What is the Mikado Method?

什么是Mikado Method?

Named after the Pickup Sticks game (Mikado), where you must remove the topmost sticks without disturbing the pile before reaching the high-value stick at the bottom. In software, your goal (the "Mikado") sits beneath a pile of dependencies. The method surfaces those dependencies visually so you can remove them one by one, safely.
Think of it as a "to-do list on steroids" — a living graph that is simultaneously your plan, your progress tracker, and your communication tool.

它得名于挑棍子(Mikado)游戏,游戏规则要求你必须先取走最上层的棍子,不能扰动整个棍子堆,才能拿到最底部的高分棍子。在软件开发场景中,你的目标(也就是“Mikado”)藏在一堆依赖的下方,这个方法会将这些依赖可视化呈现,让你可以逐个安全地移除它们。
你可以把它理解为“升级版待办清单”——它是一个动态的依赖图,同时充当你的规划方案、进度追踪器和沟通工具。

Core Definitions

核心定义

TermMeaning
GoalThe root node. What you ultimately want to achieve (e.g., "Encapsulate DB", "Extract Interface"). Circle it twice so it doesn't get lost.
PrerequisiteA dependency that must be resolved before its parent node can be done. Becomes a child bubble in the graph.
Leaf nodeA node with no further prerequisites. Safe to implement immediately without breaking anything.
Mikado Map / GraphThe full tree of goal + prerequisites. Your "save game" for the refactoring.
RevertUndoing all changes to return to a stable, compiling/passing state. The map survives; the broken code does not.

术语含义
Goal根节点,你最终想要达成的目标(例如“封装数据库”、“提取接口”),给它画两个圈避免遗漏。
Prerequisite必须在父节点完成前解决的依赖项,会成为依赖图中的子节点。
Leaf node没有更多前置依赖的节点,可以立即安全实现,不会破坏任何现有功能。
Mikado Map / Graph包含目标和所有前置依赖的完整树结构,是你重构过程的“存档”。
Revert撤销所有改动,回到代码可编译、测试全通过的稳定状态。依赖图会保留,破碎的开发代码不会保留。

The Core Loop

核心循环

Repeat this cycle until all leaves are resolved and the goal is reached:
1. SET GOAL        → Write the goal as the root node. Circle it twice.
2. BE NAIVE        → Attempt to implement the goal directly in the code.
3. OBSERVE BREAKS  → Compiler errors, failing tests, or broken behavior = prerequisites.
4. MAP             → Add each prerequisite as a child bubble connected to the current node.
5. REVERT          → Undo ALL changes immediately. Return to green/stable state.
6. PICK A LEAF     → Choose any leaf node (no children) and repeat the loop from step 2 on it.
7. COMMIT LEAF     → Once a leaf is implemented cleanly without breakage, commit it.
8. PRUNE THE GRAPH → Remove the committed leaf. Reveal new leaves. Continue upward.
⚠️ The revert step is non-negotiable. It feels counterintuitive to throw away "hard work," but the thought process IS the work — it produced the map. Never build on top of broken code.

重复以下流程直到所有叶节点都被解决,最终达成目标:
1. SET GOAL        → 写下目标作为根节点,给它画两个圈。
2. BE NAIVE        → 尝试直接在代码中实现目标。
3. OBSERVE BREAKS  → 编译器错误、测试失败、功能异常 = 前置依赖。
4. MAP             → 将每个前置依赖作为子节点添加到当前节点下。
5. REVERT          → 立即撤销所有改动,回到测试全过的稳定状态。
6. PICK A LEAF     → 选择任意一个叶节点(没有子节点),从步骤2开始针对这个节点重复循环。
7. COMMIT LEAF     → 当叶节点被干净实现、没有引入任何破坏时,提交代码。
8. PRUNE THE GRAPH → 移除已提交的叶节点,暴露新的叶节点,继续向上推进。
⚠️ 回滚步骤是不可妥协的。 扔掉“辛苦写的代码”看起来反直觉,但思考过程才是工作的核心——它产出了依赖图。永远不要在破碎的代码之上继续开发。

Building the Mikado Graph

构建Mikado依赖图

Starting a new graph

新建依赖图

When the user presents a refactoring goal, help them:
  1. Name the goal precisely — vague goals produce vague maps. Bad: "clean up the DB layer". Good: "Replace
    FileDatabase
    with a
    DatabaseInterface
    ".
  2. Draw the root node — on paper, whiteboard, or a tool like Mermaid or Excalidraw.
  3. Attempt the change naively in a throwaway branch or with
    git stash
    ready.
  4. List every error/breakage — each one becomes a child bubble.
  5. Revert immediately
    git checkout .
    or
    git stash drop
    .
当用户提出重构目标时,帮助他们完成以下步骤:
  1. 精准定义目标——模糊的目标会生成模糊的依赖图。反例:“清理数据库层”;正例:“将
    FileDatabase
    替换为
    DatabaseInterface
    ”。
  2. 绘制根节点——可以画在纸上、白板上,或是用Mermaid、Excalidraw这类工具绘制。
  3. 进行初步尝试改动——在临时分支上操作,或者提前准备好
    git stash
  4. 列出所有错误/功能破损——每个问题都对应一个子节点。
  5. 立即回滚——执行
    git checkout .
    git stash drop

Populating prerequisites

填充前置依赖

For each prerequisite node, apply the same loop recursively. A prerequisite may itself have prerequisites. The graph grows depth-first until you reach nodes that:
  • Can be implemented without touching anything else (leaves), OR
  • Map to a single atomic refactoring from Fowler's catalog.
对每个前置依赖节点,递归应用相同的循环。一个前置依赖本身也可能有自己的前置依赖,依赖图会深度优先扩展,直到你找到符合以下条件的节点:
  • 不需要改动其他代码就可以实现(叶节点),或者
  • 对应福勒重构目录中的单个原子重构操作。

What makes a good leaf?

合格叶节点的标准

A leaf node is ready to implement when:
  • It compiles/passes tests after the change with NO other modifications needed.
  • It can be expressed as one atomic commit (a single refactoring gesture: rename, extract method, move class, add parameter, etc.).
  • It does not change observable behavior (internal structure only).

符合以下条件的叶节点才可以开始实现:
  • 改动完成后不需要其他修改就可以编译通过、测试全过。
  • 可以通过单个原子提交完成(对应单个重构操作:重命名、提取方法、移动类、添加参数等)。
  • 不会修改可观测的外部行为(仅调整内部结构)。

Execution Strategy

执行策略

Order of work

工作顺序

Always implement leaves first, work upward toward the goal. Never attempt a parent node until all its children are committed and pruned from the graph.
Example graph execution order:

Goal: Replace FileDatabase with DatabaseInterface
  ├── Extract DatabaseInterface              ← implement 3rd
  │   ├── Move FileDatabase to impl/         ← implement 1st ✓
  │   └── Update all import paths            ← implement 2nd ✓
  └── Add constructor injection              ← implement 4th
      └── Rename constructor param           ← implement 1st ✓
永远优先实现叶节点,从下往上向目标推进。在父节点的所有子节点都被提交、从依赖图中移除之前,永远不要尝试实现父节点。
依赖图执行顺序示例:

目标:将FileDatabase替换为DatabaseInterface
  ├── 提取DatabaseInterface              ← 第3个实现
  │   ├── 将FileDatabase移动到impl/目录下 ← 第1个实现 ✓
  │   └── 更新所有导入路径                ← 第2个实现 ✓
  └── 添加构造函数注入                    ← 第4个实现
      └── 重命名构造函数参数              ← 第1个实现 ✓

Committing

提交规范

  • One commit per leaf node.
  • Commit message should name the atomic refactoring:
    "Extract: DatabaseInterface from FileDatabase"
    .
  • Commits go directly to main/trunk — no refactoring branches needed.
  • Never commit a node that leaves the build broken or tests failing.

  • 每个叶节点对应一次提交。
  • 提交信息应该写明原子重构操作:
    "Extract: DatabaseInterface from FileDatabase"
  • 提交直接推送到主干分支——不需要专门的重构分支。
  • 永远不要提交导致构建失败、测试不通过的节点代码。

Practical Guidance by Situation

不同场景的实践指南

Legacy code with no tests

没有测试的遗留代码

Use the Mikado + Test Data Builder combination:
  1. Make "add a test around this bug/feature" a node in the graph.
  2. Each prerequisite for that test (instantiating a tangled class) becomes a Test Data Builder node — a reusable builder other developers can leverage.
  3. Each completed builder increases system-wide testability virally.
  4. Avoid mocks for data setup — they duplicate real behavior and create rigidity.
使用 Mikado + Test Data Builder 组合方案:
  1. 将“为这个Bug/功能添加测试”作为依赖图中的一个节点。
  2. 这个测试的每个前置依赖(实例化耦合度高的类)都对应一个Test Data Builder节点——这是其他开发者也可以复用的构建器。
  3. 每完成一个构建器都会全局提升系统的可测试性。
  4. 避免在数据准备阶段使用Mock——它们会重复真实逻辑,导致代码僵化。

Circular dependencies

循环依赖

A classic Mikado target. Typical leaf sequence:
  1. Identify the cycle (compiler/linter output).
  2. Leaves: move classes, add interfaces, update imports.
  3. Work inward until the cycle is broken.
这是典型的Mikado适用场景,标准叶节点处理顺序:
  1. 识别循环(通过编译器/ linter输出)。
  2. 叶节点操作:移动类、添加接口、更新导入。
  3. 向内推进直到循环被打破。

Very large / multi-week refactorings

超大规模/跨数周的重构

  • Keep the graph on a physical whiteboard visible to the whole team.
  • Long-running graphs (weeks or months) are normal — the map tracks progress.
  • Team members can pick up any current leaf node independently.
  • The graph is also a negotiation tool: show stakeholders the dependency tree to make scope/cost trade-offs visible (e.g., "removing this node saves 3 months").
  • 将依赖图画在整个团队都可见的实体白板上。
  • 长期运行的依赖图(数周或数月)是正常的——依赖图会记录进度。
  • 团队成员可以独立认领任意当前可用的叶节点。
  • 依赖图也是协商工具:向干系人展示依赖树,可以让范围/成本权衡可视化(例如“移除这个节点可以节省3个月时间”)。

Solo / informal use

个人/非正式使用

For small tasks, the method can be done mentally. For anything touching more than ~3 files or taking more than a day, always externalize the map (paper is fine).

对于小型任务,可以在脑中执行这个方法。如果改动涉及超过3个文件或者耗时超过1天,一定要把依赖图画出来(用纸就可以)。

Enforcing Good Refactoring Hygiene

良好重构习惯的执行规则

When reviewing or generating refactoring code, enforce these rules:
  1. No behavior changes in a refactoring commit. Renaming a variable ✓. Renaming a public API endpoint ✗ (that is a breaking change).
  2. One type of change per commit. Mixed commits (rename + extract + move) make the graph untrustworthy and rollback dangerous.
  3. Always return to green before picking the next leaf. If the build is red, revert — do not patch forward.
  4. No "just one more thing" creep. If a new prerequisite is discovered mid-leaf implementation, stop, add it to the map, and revert. Do not chain fixes.
  5. Prefer TDD. Fast test feedback makes error discovery immediate, shrinking the identify-prerequisites step dramatically.

在评审或生成重构代码时,强制执行以下规则:
  1. 重构提交中不能包含行为改动。 重命名变量 ✓;重命名公共API端点 ✗(这是破坏性改动)。
  2. 每次提交只包含一种类型的改动。 混合提交(重命名+提取方法+移动类)会让依赖图不可信,回滚风险很高。
  3. 选择下一个叶节点前必须回到稳定状态。 如果构建失败,回滚——不要在当前基础上打补丁。
  4. 不要出现“就多改一点”的范围蔓延。 如果在叶节点实现过程中发现了新的前置依赖,停止开发,把它添加到依赖图中然后回滚,不要链式修复问题。
  5. 优先使用TDD。 快速的测试反馈可以即时发现错误,大幅缩短识别前置依赖的步骤耗时。

Output Format

输出格式

When helping a user apply the Mikado Method, always produce:
当帮助用户应用Mikado Method时,始终输出以下内容:

1. The Mikado Map (Mermaid diagram)

1. Mikado依赖图(Mermaid图表)

mermaid
graph TD
    G(["🎯 GOAL: <goal name>"]) --> P1["Prerequisite A"]
    G --> P2["Prerequisite B"]
    P1 --> L1["🟢 Leaf: step 1"]
    P1 --> L2["🟢 Leaf: step 2"]
    P2 --> L3["🟢 Leaf: step 3"]
Use 🟢 for current leaf nodes (safe to implement), ⬜ for prerequisites not yet reachable, ✅ for completed nodes.
mermaid
graph TD
    G(["🎯 GOAL: <goal name>"]) --> P1["Prerequisite A"]
    G --> P2["Prerequisite B"]
    P1 --> L1["🟢 Leaf: step 1"]
    P1 --> L2["🟢 Leaf: step 2"]
    P2 --> L3["🟢 Leaf: step 3"]
🟢 表示当前可用的叶节点(可以安全实现),⬜ 表示暂不可达的前置依赖,✅ 表示已完成的节点。

2. Ordered implementation plan

2. 有序实现计划

A numbered list of leaf-first steps, each with:
  • The atomic refactoring gesture (from Fowler's catalog if applicable)
  • A one-line test to verify it didn't break behavior
  • The suggested commit message
按叶节点优先的顺序排列的步骤列表,每个步骤包含:
  • 原子重构操作(如果适用,对应福勒重构目录中的操作)
  • 一行验证代码,确认改动没有破坏原有行为
  • 建议的提交信息

3. Revert reminder

3. 回滚提醒

After any naive attempt, explicitly remind the user: "Revert now —
git checkout .
— your map is saved, the broken code is not needed."

在任何初步尝试之后,明确提醒用户:“现在回滚 —— 执行
git checkout .
—— 你的依赖图已经保存,破碎的代码不需要保留。”

Common Mistakes to Correct

需要纠正的常见错误

MistakeCorrection
Fixing errors in place instead of reverting"Revert now. Add these errors as prerequisite nodes instead."
Building on top of broken code"This violates the core rule. Revert to green before continuing."
One giant commit with multiple changes"Split into one commit per leaf node."
Skipping the graph for "small" refactors"Start with even a 3-node graph. It prevents scope creep."
Using mocks to avoid test data setup pain"This creates Mock Hell. Use Test Data Builders as Mikado leaf nodes instead."
Long-lived refactoring branches"Work on main. Only commit leaves that don't break anything."

错误行为纠正方式
原地修复错误而不是回滚“现在回滚,把这些错误作为前置依赖节点添加到依赖图中。”
在破碎的代码之上继续开发“这违反了核心规则,继续前先回滚到稳定状态。”
包含多个改动的巨型提交“拆分为每个叶节点对应一次提交。”
认为“小型”重构不需要画依赖图“哪怕只有3个节点的依赖图也可以避免范围蔓延,先画出来。”
用Mock规避测试数据准备的麻烦“这会导致Mock地狱,用Test Data Builder作为Mikado叶节点替代。”
长期维护重构分支“在主干分支上开发,只提交不会破坏任何功能的叶节点代码。”

Quick Reference Card

快速参考卡

MIKADO LOOP
───────────
① Write goal (root) → circle it twice
② Attempt naively in code
③ Every error = a prerequisite bubble
④ REVERT (always, immediately)
⑤ Pick a leaf → repeat from ②
⑥ Leaf passes cleanly → commit → prune
⑦ Repeat until goal is reached

RULES
─────
• Never build on broken code
• One atomic change per commit
• No behavior changes in refactoring commits
• Leaves only touch one concern
• The map is the work — protect it
MIKADO LOOP
───────────
① Write goal (root) → circle it twice
② Attempt naively in code
③ Every error = a prerequisite bubble
④ REVERT (always, immediately)
⑤ Pick a leaf → repeat from ②
⑥ Leaf passes cleanly → commit → prune
⑦ Repeat until goal is reached

RULES
─────
• Never build on broken code
• One atomic change per commit
• No behavior changes in refactoring commits
• Leaves only touch one concern
• The map is the work — protect it