mikado-method
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMikado 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
核心定义
| Term | Meaning |
|---|---|
| Goal | The root node. What you ultimately want to achieve (e.g., "Encapsulate DB", "Extract Interface"). Circle it twice so it doesn't get lost. |
| Prerequisite | A dependency that must be resolved before its parent node can be done. Becomes a child bubble in the graph. |
| Leaf node | A node with no further prerequisites. Safe to implement immediately without breaking anything. |
| Mikado Map / Graph | The full tree of goal + prerequisites. Your "save game" for the refactoring. |
| Revert | Undoing 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:
- Name the goal precisely — vague goals produce vague maps. Bad: "clean up the DB
layer". Good: "Replace with a
FileDatabase".DatabaseInterface - Draw the root node — on paper, whiteboard, or a tool like Mermaid or Excalidraw.
- Attempt the change naively in a throwaway branch or with ready.
git stash - List every error/breakage — each one becomes a child bubble.
- Revert immediately — or
git checkout ..git stash drop
当用户提出重构目标时,帮助他们完成以下步骤:
- 精准定义目标——模糊的目标会生成模糊的依赖图。反例:“清理数据库层”;正例:“将替换为
FileDatabase”。DatabaseInterface - 绘制根节点——可以画在纸上、白板上,或是用Mermaid、Excalidraw这类工具绘制。
- 进行初步尝试改动——在临时分支上操作,或者提前准备好。
git stash - 列出所有错误/功能破损——每个问题都对应一个子节点。
- 立即回滚——执行或
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:
- Make "add a test around this bug/feature" a node in the graph.
- Each prerequisite for that test (instantiating a tangled class) becomes a Test Data Builder node — a reusable builder other developers can leverage.
- Each completed builder increases system-wide testability virally.
- Avoid mocks for data setup — they duplicate real behavior and create rigidity.
使用 Mikado + Test Data Builder 组合方案:
- 将“为这个Bug/功能添加测试”作为依赖图中的一个节点。
- 这个测试的每个前置依赖(实例化耦合度高的类)都对应一个Test Data Builder节点——这是其他开发者也可以复用的构建器。
- 每完成一个构建器都会全局提升系统的可测试性。
- 避免在数据准备阶段使用Mock——它们会重复真实逻辑,导致代码僵化。
Circular dependencies
循环依赖
A classic Mikado target. Typical leaf sequence:
- Identify the cycle (compiler/linter output).
- Leaves: move classes, add interfaces, update imports.
- Work inward until the cycle is broken.
这是典型的Mikado适用场景,标准叶节点处理顺序:
- 识别循环(通过编译器/ linter输出)。
- 叶节点操作:移动类、添加接口、更新导入。
- 向内推进直到循环被打破。
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:
- No behavior changes in a refactoring commit. Renaming a variable ✓. Renaming a public API endpoint ✗ (that is a breaking change).
- One type of change per commit. Mixed commits (rename + extract + move) make the graph untrustworthy and rollback dangerous.
- Always return to green before picking the next leaf. If the build is red, revert — do not patch forward.
- 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.
- Prefer TDD. Fast test feedback makes error discovery immediate, shrinking the identify-prerequisites step dramatically.
在评审或生成重构代码时,强制执行以下规则:
- 重构提交中不能包含行为改动。 重命名变量 ✓;重命名公共API端点 ✗(这是破坏性改动)。
- 每次提交只包含一种类型的改动。 混合提交(重命名+提取方法+移动类)会让依赖图不可信,回滚风险很高。
- 选择下一个叶节点前必须回到稳定状态。 如果构建失败,回滚——不要在当前基础上打补丁。
- 不要出现“就多改一点”的范围蔓延。 如果在叶节点实现过程中发现了新的前置依赖,停止开发,把它添加到依赖图中然后回滚,不要链式修复问题。
- 优先使用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 —
— your map is saved, the broken code is not needed."
git checkout .在任何初步尝试之后,明确提醒用户:“现在回滚 —— 执行—— 你的依赖图已经保存,破碎的代码不需要保留。”
git checkout .Common Mistakes to Correct
需要纠正的常见错误
| Mistake | Correction |
|---|---|
| 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 itMIKADO 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