refactoring-patterns

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Refactoring Patterns Framework

重构模式框架

A disciplined approach to improving the internal structure of existing code without changing its observable behavior. Apply these named transformations when reviewing code, reducing technical debt, or preparing code for new features. Every refactoring follows the same loop: verify tests pass, apply one small structural change, verify tests still pass.
这是一种严谨的方法,用于改进现有代码的内部结构,同时不改变其可观测的外部行为。在评审代码、减少技术债务或为新增功能准备代码时,可应用这些命名转换手法。每一次重构都遵循相同的循环:验证测试通过,应用一项小型结构变更,再次验证测试通过。

Core Principle

核心原则

Refactoring is not rewriting. It is a sequence of small, behavior-preserving transformations, each backed by tests. You never change what the code does -- you change how the code is organized. The discipline of taking tiny verified steps is what makes refactoring safe. Big-bang rewrites fail because they combine structural change with behavioral change, making it impossible to know which broke things.
The foundation: Bad code is not a character flaw -- it is a natural consequence of delivering features under time pressure. Code smells are objective signals that structure has degraded. Named refactorings are the proven mechanical recipes for fixing each smell. The catalog of smells tells you where to look; the catalog of refactorings tells you what to do.
重构并非重写。它是一系列小型、保留行为的转换操作,每一步都有测试作为保障。 你永远不会改变代码的功能——只会改变代码的组织方式。采用微小且经过验证的步骤进行操作,是重构安全性的关键所在。大爆炸式重写之所以失败,是因为它将结构变更与行为变更混为一谈,导致无法定位问题根源。
基础认知: 糟糕的代码并非编写者的能力缺陷——它是在时间压力下交付功能时的自然结果。代码坏味道是结构退化的客观信号。命名重构手法是经过验证的、可解决各类坏味道的标准化方案。坏味道目录告诉你需要关注哪里,而重构手法目录告诉你该做什么

Scoring

评分标准

Goal: 10/10. When reviewing or refactoring code, rate the structural quality 0-10 based on adherence to the principles below. A 10/10 means: no obvious smells remain, each function does one thing, names reveal intent, duplication is eliminated, and the test suite covers the refactored paths. Always provide the current score and specific refactorings needed to reach 10/10.
目标:10/10。 在评审或重构代码时,根据以下原则对结构质量进行0-10分的评分。10分意味着:不存在明显的代码坏味道,每个函数只负责一件事,命名能清晰表达意图,消除了重复代码,测试套件覆盖了所有重构路径。请始终给出当前分数,以及达到10分所需的具体重构手法。

The Refactoring Patterns Framework

重构模式框架

Six areas of focus for systematically improving code structure:
系统改进代码结构的六大核心方向:

1. Code Smells as Triggers

1. 以代码坏味道为触发点

Core concept: Code smells are surface indicators of deeper structural problems. They are not bugs -- the code works -- but they signal that the design is making the code harder to understand, extend, or maintain. Each smell maps to one or more named refactorings that fix it.
Why it works: Without a shared vocabulary of smells, code review devolves into subjective "I don't like this." Named smells give teams objective criteria: "This is Feature Envy -- the method uses six fields from another class and only one of its own." The name points directly to the fix.
Key insights:
  • Smells cluster into five families: Bloaters, Object-Orientation Abusers, Change Preventers, Dispensables, and Couplers
  • Long Method is the most common smell and the gateway to most other refactorings
  • Duplicate Code is the single biggest driver of maintenance cost
  • A method that needs a comment to explain what it does is a smell -- extract and name the block instead
  • Shotgun Surgery (one change requires edits in many classes) and Divergent Change (one class changes for many reasons) are opposites that both signal misplaced responsibilities
  • Primitive Obsession -- using raw strings, ints, or arrays instead of small domain objects -- causes errors and duplication throughout the codebase
Code applications:
ContextPatternExample
Method > 10 linesExtract MethodPull the loop body into
calculateLineTotal()
Class > 200 linesExtract ClassMove shipping logic into a
ShippingCalculator
Switch on type codeReplace Conditional with PolymorphismCreate subclasses for each order type
Multiple methods use same paramsIntroduce Parameter ObjectGroup
startDate, endDate
into
DateRange
Method uses another object's dataMove MethodMove
calculateDiscount()
to the
Customer
class
Copy-pasted logicExtract Method + Pull Up MethodShare via a common method or base class
See: references/smell-catalog.md
核心概念: 代码坏味道是深层结构问题的表面征兆。它们并非bug——代码仍能正常工作——但预示着当前设计会让代码更难理解、扩展或维护。每种坏味道都对应一种或多种可解决它的命名重构手法。
为何有效: 如果没有统一的坏味道术语体系,代码评审会退化为主观的“我不喜欢这段代码”。命名的坏味道为团队提供了客观标准:“这是特性依恋(Feature Envy)——该方法使用了另一个类的六个字段,而仅使用了自身的一个字段。” 这个名称直接指向了修复方案。
关键见解:
  • 坏味道可分为五大类:臃肿类(Bloaters)、面向对象滥用类(Object-Orientation Abusers)、变更阻碍类(Change Preventers)、冗余类(Dispensables)、耦合类(Couplers)
  • 过长方法(Long Method)是最常见的坏味道,也是大多数重构的起点
  • 重复代码(Duplicate Code)是维护成本居高不下的最大诱因
  • 如果某个方法需要注释来解释它做了什么,这就是一种坏味道——应将代码块提取为方法并使用注释作为方法名
  • 霰弹式修改(Shotgun Surgery,一项变更需要修改多个类)和发散式变更(Divergent Change,一个类因多种原因被修改)是对立的两种情况,但都表明职责分配不当
  • 原始类型痴迷(Primitive Obsession,使用原始字符串、整数或数组而非小型领域对象)会在整个代码库中引发错误和重复
代码应用场景:
场景重构手法示例
方法行数>10行Extract Method将循环体提取到
calculateLineTotal()
方法中
类行数>200行Extract Class将物流逻辑迁移到
ShippingCalculator
类中
基于类型码的Switch语句Replace Conditional with Polymorphism为每种订单类型创建子类
多个方法使用相同参数Introduce Parameter Object
startDate, endDate
组合为
DateRange
对象
方法使用另一个对象的数据Move Method
calculateDiscount()
方法迁移到
Customer
复制粘贴的逻辑Extract Method + Pull Up Method通过公共方法或基类共享逻辑
参考:references/smell-catalog.md

2. Composing Methods

2. 方法组合

Core concept: Most refactoring starts here. Long methods are broken into smaller, well-named pieces. Each extracted piece should do one thing and its name should say what that thing is. The goal is methods you can read like prose -- a sequence of high-level steps, each delegating to a clearly named helper.
Why it works: Short methods with intention-revealing names eliminate the need for comments, make bugs obvious (each method is small enough to verify at a glance), and enable reuse. The cognitive cost of a method call is near zero when the name tells you everything.
Key insights:
  • Extract Method is the single most important refactoring -- master it first
  • If you feel the urge to write a comment, extract the code block and use the comment as the method name
  • Inline Method when a method body is as clear as the name -- indirection without value is noise
  • Replace Temp with Query when a temporary variable holds a computed value that is used in multiple places
  • Split Temporary Variable when one variable is reused for two different purposes
  • Replace Method with Method Object when a method is too tangled to extract from (many local variables referencing each other)
Code applications:
ContextPatternExample
Block with a commentExtract Method
// check eligibility
becomes
isEligible()
Temp used onceInline VariableRemove
const price = order.getPrice()
if used once
Temp used in multiple placesReplace Temp with QueryReplace
let discount = getDiscount()
with method calls
Temp assigned twice for different reasonsSplit Temporary VariableIntroduce
perimeterWidth
and
perimeterHeight
Trivial delegating methodInline MethodInline
moreThanFiveDeliveries()
if it's
return deliveries > 5
and only used once
Complex method with many localsReplace Method with Method ObjectMove the method into its own class where locals become fields
See: references/composing-methods.md
核心概念: 大多数重构都从这里开始。将过长的方法拆分为更小、命名清晰的片段。每个提取出的片段应只负责一件事,且其名称应明确表达该职责。目标是让方法像散文一样易读——由一系列高层步骤组成,每个步骤都委托给命名清晰的辅助方法。
为何有效: 短小且意图明确的方法无需注释,能让bug无所遁形(每个方法足够小,可快速验证),并支持代码复用。当方法名能告诉你所有信息时,方法调用的认知成本几乎为零。
关键见解:
  • Extract Method是最重要的重构手法——首先掌握它
  • 如果你想写注释,就将对应的代码块提取为方法,并将注释作为方法名
  • 当方法体与方法名一样清晰时,使用Inline Method(内联方法)——无意义的间接性是冗余噪声
  • 当临时变量存储的计算值被多处使用时,使用Replace Temp with Query(以查询取代临时变量)
  • 当一个变量被用于两种不同用途时,使用Split Temporary Variable(拆分临时变量)
  • 当方法过于复杂无法直接提取(存在大量相互引用的局部变量)时,使用Replace Method with Method Object(以方法对象取代方法)
代码应用场景:
场景重构手法示例
带有注释的代码块Extract Method
// 检查资格
变为
isEligible()
方法
临时变量仅使用一次Inline Variable如果
const price = order.getPrice()
仅使用一次,则移除该变量
临时变量被多处使用Replace Temp with Query
let discount = getDiscount()
替换为方法调用
临时变量被赋予两种不同用途的值Split Temporary Variable引入
perimeterWidth
perimeterHeight
两个变量
仅做简单委托的方法Inline Method如果
moreThanFiveDeliveries()
仅返回
deliveries > 5
且仅使用一次,则内联该方法
包含大量局部变量的复杂方法Replace Method with Method Object将该方法移至独立类中,局部变量变为类的字段
参考:references/composing-methods.md

3. Moving Features Between Objects

3. 在对象间转移特性

Core concept: The key decision in object-oriented design is where to put responsibilities. When a method or field is in the wrong class -- evidenced by Feature Envy, excessive coupling, or unbalanced class sizes -- move it to where it belongs.
Why it works: Well-placed responsibilities reduce coupling and increase cohesion. When a method lives in the class whose data it uses, changes to that data affect only one class. Misplaced methods create invisible dependencies that cause Shotgun Surgery.
Key insights:
  • Move Method when a method uses more features of another class than its own
  • Move Field when a field is used more by another class than the class it lives in
  • Extract Class when one class does two things -- split along the axis of change
  • Inline Class when a class does too little to justify its existence
  • Hide Delegate to enforce the Law of Demeter -- a client shouldn't navigate a chain of objects
  • Remove Middle Man when a class does nothing but forward calls
  • The tension between Hide Delegate and Remove Middle Man is resolved case by case: hide the delegate when the chain is unstable; remove the middle man when forwarding becomes the entire class
Code applications:
ContextPatternExample
Method envies another classMove MethodMove
calculateShipping()
from
Order
to
ShippingPolicy
Field used by another class constantlyMove FieldMove
discountRate
from
Order
to
Customer
God class with 500+ linesExtract ClassPull
Address
fields and methods into their own class
Tiny class with one fieldInline ClassMerge
PhoneNumber
back into
Contact
if no behavior
Client calls a.getB().getC()Hide DelegateAdd
a.getCThroughB()
so client doesn't know about C
Class only forwards callsRemove Middle ManLet client call the delegate directly
See: references/moving-features.md
核心概念: 面向对象设计中的关键决策是职责的归属。当某个方法或字段位于错误的类中(表现为特性依恋、过度耦合或类大小失衡)时,应将其移至合适的类中。
为何有效: 职责分配合理能降低耦合度并提高内聚性。当方法位于其使用数据的类中时,数据变更只会影响一个类。错误放置的方法会产生隐形依赖,导致霰弹式修改。
关键见解:
  • 当方法使用另一个类的特性多于自身类时,使用Move Method(搬移方法)
  • 当字段被另一个类使用的次数多于其所属类时,使用Move Field(搬移字段)
  • 当一个类承担两种职责时,使用Extract Class(提取类)——按变更维度拆分
  • 当一个类的职责少到不足以独立存在时,使用Inline Class(内联类)
  • 使用Hide Delegate(隐藏委托)来遵循迪米特法则——客户端不应遍历对象链
  • 当一个类仅做转发调用时,使用Remove Middle Man(移除中间人)
  • Hide Delegate和Remove Middle Man的权衡需视情况而定:当对象链不稳定时隐藏委托;当转发成为类的全部职责时移除中间人
代码应用场景:
场景重构手法示例
方法依恋另一个类Move Method
calculateShipping()
Order
类移至
ShippingPolicy
字段被另一个类频繁使用Move Field
discountRate
Order
类移至
Customer
行数超500行的上帝类Extract Class
Address
相关字段和方法提取到独立类中
仅含一个字段的小型类Inline Class如果
PhoneNumber
类无任何行为,将其合并回
Contact
客户端调用
a.getB().getC()
Hide Delegate添加
a.getCThroughB()
方法,使客户端无需知晓C的存在
类仅做转发调用Remove Middle Man让客户端直接调用委托对象
参考:references/moving-features.md

4. Organizing Data

4. 数据组织

Core concept: Raw data -- magic numbers, exposed fields, type codes represented as integers, parallel arrays -- creates subtle bugs and scatters domain knowledge. Replace primitive representations with objects that encapsulate behavior and enforce invariants.
Why it works: An
int
representing a currency amount has no concept of rounding rules, currency codes, or formatting. A
Money
object encapsulates all of that. When domain concepts are represented as first-class objects, business rules live in one place, validation happens automatically, and the type system catches errors at compile time.
Key insights:
  • Replace Magic Number with Symbolic Constant as the simplest data refactoring -- it names the intent
  • Replace Data Value with Object (Primitive Obsession cure) -- wrap strings and numbers in domain objects (
    EmailAddress
    ,
    Money
    ,
    Temperature
    )
  • Encapsulate Field -- never expose a raw field; a getter/setter allows you to add validation, logging, or computation later
  • Encapsulate Collection -- return an unmodifiable view; never let callers mutate your internal list
  • Replace Type Code with Subclasses when the type code affects behavior; use Strategy when subclassing is impractical
  • Change Value to Reference when you need identity semantics (one shared
    Customer
    object, not copies)
Code applications:
ContextPatternExample
if (status == 2)
Replace Magic Number with Symbolic Constant
if (status == ORDER_SHIPPED)
String email
passed everywhere
Replace Data Value with ObjectCreate
EmailAddress
class with validation
Public fieldEncapsulate FieldReplace
order.total
with
order.getTotal()
Getter returns mutable listEncapsulate CollectionReturn
Collections.unmodifiableList(items)
int typeCode
with switch
Replace Type Code with Subclasses
Employee
->
Engineer
,
Manager
,
Salesperson
Duplicated customer recordsChange Value to ReferenceShare one
Customer
instance via a registry
See: references/organizing-data.md
核心概念: 原始数据——魔法数字、暴露的字段、用整数表示的类型码、并行数组——会引发隐蔽的bug,并分散领域知识。应使用封装行为、强制不变量的对象替代原始数据表示。
为何有效: 表示货币金额的
int
类型不具备舍入规则、货币代码或格式化的概念。而
Money
对象封装了所有这些逻辑。当领域概念被表示为一等对象时,业务规则集中存放,验证自动执行,类型系统可在编译时捕获错误。
关键见解:
  • Replace Magic Number with Symbolic Constant(以符号常量取代魔法数字)是最简单的数据重构手法——它能明确表达意图
  • Replace Data Value with Object(以对象取代数据值,解决原始类型痴迷问题)——将字符串和数字包装为领域对象(如
    EmailAddress
    Money
    Temperature
  • Encapsulate Field(封装字段)——永远不要暴露原始字段;getter/setter允许你后续添加验证、日志或计算逻辑
  • Encapsulate Collection(封装集合)——返回不可修改的视图;永远不要让调用者修改你的内部列表
  • 当类型码影响行为时,使用Replace Type Code with Subclasses(以子类取代类型码);当子类化不可行时使用策略模式(Strategy)
  • 当需要身份语义时,使用Change Value to Reference(以引用取代值对象)——使用一个共享的
    Customer
    对象,而非多个副本
代码应用场景:
场景重构手法示例
if (status == 2)
Replace Magic Number with Symbolic Constant改为
if (status == ORDER_SHIPPED)
String email
被到处传递
Replace Data Value with Object创建带验证逻辑的
EmailAddress
公共字段Encapsulate Field
order.total
替换为
order.getTotal()
Getter返回可变列表Encapsulate Collection返回
Collections.unmodifiableList(items)
基于
int typeCode
的Switch语句
Replace Type Code with Subclasses
Employee
派生出
Engineer
Manager
Salesperson
子类
重复的客户记录Change Value to Reference通过注册表共享单个
Customer
实例
参考:references/organizing-data.md

5. Simplifying Conditional Logic

5. 简化条件逻辑

Core concept: Complex conditionals -- deeply nested if/else trees, long switch statements, null checks scattered everywhere -- are the hardest code to read and the most likely to contain bugs. Named refactorings decompose, consolidate, and replace conditionals with clearer structures.
Why it works: A conditional with six branches and nested sub-conditions requires the reader to simulate every path mentally. Decomposing the condition into well-named methods makes each branch self-documenting. Replacing conditionals with polymorphism eliminates entire categories of "forgot to handle this case" bugs.
Key insights:
  • Decompose Conditional: extract the condition, the then-branch, and the else-branch into named methods
  • Consolidate Conditional Expression: merge multiple conditions that lead to the same result into one named check
  • Replace Nested Conditional with Guard Clauses: handle edge cases early and return, leaving the main path unindented
  • Replace Conditional with Polymorphism: the gold standard for type-based conditionals -- each type knows its own behavior
  • Introduce Special Case (Null Object): eliminate
    if (x == null)
    checks by providing an object that represents "nothing" with safe default behavior
  • Introduce Assertion: make assumptions explicit so they fail fast in development
Code applications:
ContextPatternExample
Long
if
with complex condition
Decompose ConditionalExtract
isSummer(date)
and
summerCharge()
Multiple
if
s return same value
Consolidate ConditionalCombine into
isDisabled()
returning early
Deeply nested
if/else
Replace with Guard ClausesCheck edge cases first, return early, flatten the main path
Switch on object typeReplace Conditional with PolymorphismEach type implements its own
calculatePay()
if (customer == null)
everywhere
Introduce Special CaseCreate
NullCustomer
with default behavior
Hidden assumption in codeIntroduce Assertion
assert quantity > 0
at method entry
See: references/simplifying-conditionals.md
核心概念: 复杂的条件语句——深层嵌套的if/else树、冗长的Switch语句、随处可见的空值检查——是最难阅读的代码,也最容易包含bug。命名重构手法可将条件逻辑分解、合并,替换为更清晰的结构。
为何有效: 包含六个分支和嵌套子条件的条件语句,要求读者在脑中模拟所有路径。将条件分解为命名方法后,每个分支都能自我解释。用多态替代条件语句可消除一整类“忘记处理该情况”的bug。
关键见解:
  • Decompose Conditional(分解条件表达式):将条件、then分支、else分支提取为命名方法
  • Consolidate Conditional Expression(合并条件表达式):将多个导致相同结果的条件合并为一个命名检查
  • Replace Nested Conditional with Guard Clauses(以卫语句取代嵌套条件):提前处理边缘情况并返回,使主路径代码无缩进
  • Replace Conditional with Polymorphism(以多态取代条件语句):基于类型的条件语句的黄金解决方案——每个类型都知晓自身行为
  • Introduce Special Case(引入特例,即空对象模式):通过提供代表“无”的对象并实现安全默认行为,消除
    if (x == null)
    检查
  • Introduce Assertion(引入断言):明确假设,使其在开发阶段快速失败
代码应用场景:
场景重构手法示例
带有复杂条件的长
if
语句
Decompose Conditional提取
isSummer(date)
summerCharge()
方法
多个
if
语句返回相同值
Consolidate Conditional合并为
isDisabled()
方法并提前返回
深层嵌套的
if/else
Replace with Guard Clauses先检查边缘情况并提前返回,扁平化主路径代码
基于对象类型的Switch语句Replace Conditional with Polymorphism每个类型实现自身的
calculatePay()
方法
到处都是
if (customer == null)
检查
Introduce Special Case创建
NullCustomer
类实现默认行为
代码中的隐藏假设Introduce Assertion在方法入口添加
assert quantity > 0
参考:references/simplifying-conditionals.md

6. Safe Refactoring Workflow

6. 安全重构工作流

Core concept: Refactoring is only safe when wrapped in tests. The workflow is mechanical: run tests (green), apply one small transformation, run tests (green), commit. If tests go red, revert the last change -- don't debug a broken refactoring.
Why it works: Small steps make it trivial to find what went wrong (it was the last thing you did). Reverting a failed step costs seconds. Debugging a failed big-bang rewrite costs days. Frequent commits create save points you can return to.
Key insights:
  • The refactoring cycle: test -> refactor -> test -> commit (repeat)
  • Rule of Three: tolerate duplication once, note it twice, refactor on the third occurrence
  • Preparatory refactoring: restructure code to make the feature easy before adding the feature
  • Comprehension refactoring: refactor to understand code as you read it -- leave it clearer than you found it
  • Litter-pickup refactoring: small improvements whenever you touch a file (Boy Scout Rule)
  • When NOT to refactor: when it's easier to rewrite from scratch, when there are no tests and adding them first isn't feasible, or when the code will be deleted soon
  • Refactoring and performance: refactor for clarity first, then profile and optimize the measured bottleneck -- refactored code is easier to tune because the hot path is isolated
  • Branch by Abstraction and Parallel Change enable large refactorings in production systems without feature branches
Code applications:
ContextPatternExample
About to add a featurePreparatory RefactoringExtract method to make new feature's insertion point clean
Reading unfamiliar codeComprehension RefactoringRename variables and extract methods to understand intent
Saw a small issue while workingLitter-Pickup RefactoringFix the smell before moving on (Boy Scout Rule)
Third copy of same logicRule of ThreeExtract the shared logic into a common method
Large API change in productionBranch by AbstractionIntroduce abstraction layer, migrate callers, remove old path
Renaming a widely-used methodParallel ChangeAdd new name, deprecate old, migrate callers, remove old
See: references/refactoring-workflow.md
核心概念: 只有在测试的保障下,重构才是安全的。工作流是机械性的:运行测试(绿色),应用一项小型转换,运行测试(绿色),提交代码。如果测试变红,回滚上一次变更——不要调试失败的重构。
为何有效: 小型步骤让定位问题变得微不足道(问题就是你上一步做的变更)。回滚失败的步骤只需几秒钟,而调试失败的大爆炸式重写则需要数天。频繁提交会创建可回溯的保存点。
关键见解:
  • 重构循环:测试→重构→测试→提交(重复)
  • 三次原则(Rule of Three):第一次重复时容忍,第二次重复时记录,第三次重复时重构
  • 预备性重构:在添加功能之前重构代码,使新增功能的实现更简单
  • 理解性重构:在阅读代码时进行重构,让代码比你发现它时更清晰
  • 随手重构:每次修改文件时进行小型改进(童子军规则:让营地比你发现时更干净)
  • 不应重构的场景:从头重写更简单时;没有测试且无法先添加测试时;代码即将被删除时
  • 重构与性能:先重构以提升清晰度,再通过性能分析优化已确认的瓶颈——重构后的代码更易于调优,因为热点路径已被隔离
  • 抽象分支(Branch by Abstraction)和平行变更(Parallel Change)可在生产系统中实现大型重构,无需使用功能分支
代码应用场景:
场景模式示例
即将添加新功能预备性重构提取方法,使新功能的插入点更简洁
阅读不熟悉的代码理解性重构重命名变量、提取方法以明确代码意图
工作时发现小型问题随手重构修复坏味道后再继续工作(童子军规则)
第三次出现相同逻辑三次原则将共享逻辑提取到公共方法中
生产系统中的大型API变更抽象分支引入抽象层,迁移调用者,移除旧路径
重命名被广泛使用的方法平行变更添加新方法名,标记旧方法为废弃,迁移调用者,最后删除旧方法
参考:references/refactoring-workflow.md

Common Mistakes

常见错误

MistakeWhy It FailsFix
Refactoring without testsNo safety net -- you can't tell if behavior changedWrite characterization tests first, then refactor
Big-bang rewrite instead of incremental stepsCombines structural and behavioral changes; impossible to debugTake the smallest step possible, run tests after each
Refactoring and adding features at the same timeTwo hats at once -- you can't verify either change in isolationSeparate the hats: refactor first (commit), then add feature (commit)
Renaming without updating all callersBreaks the build or introduces dead codeUse IDE rename refactoring; search for all references
Extracting too many tiny methodsCreates indirection without clarity when names are poorEach extracted method must have a name that removes the need to read the body
Ignoring the smell catalogReinventing fixes instead of applying proven recipesLearn the named smells; each one maps to specific refactorings
Refactoring code that will be deletedWasted effort -- polish on condemned codeAsk first: is this code's lifespan long enough to justify the investment?
Optimizing prematurely during refactoringConflates clarity with performance; optimized code is often harder to readRefactor for clarity first, then profile, then optimize the measured hot path only
错误失败原因修复方案
无测试情况下重构没有安全保障——无法判断行为是否改变先编写或修复测试,再进行重构
采用大爆炸式重写而非增量步骤混合了结构变更与行为变更,无法调试采用尽可能小的步骤,每步后运行测试
重构与添加功能同时进行同时扮演两种角色——无法单独验证任何一项变更分离角色:先重构(提交),再添加功能(提交)
重命名时未更新所有调用者导致构建失败或引入死代码使用IDE的重命名重构功能;搜索所有引用
提取过多过小的方法当命名不佳时,会产生无意义的间接性每个提取的方法必须有一个无需阅读方法体就能理解其意图的名称
忽略坏味道目录重复发明修复方案,而非应用经过验证的成熟手法学习命名的坏味道;每种坏味道都对应特定的重构手法
重构即将被删除的代码浪费精力——为即将废弃的代码做优化先确认:这段代码的生命周期是否足够长,值得投入时间重构?
重构时过早优化将清晰度与性能混淆;优化后的代码通常更难阅读先重构以提升清晰度,再进行性能分析,仅优化已确认的热点路径

Quick Diagnostic

快速诊断

QuestionIf NoAction
Do tests pass before you start?You have no safety netWrite or fix tests first -- do not refactor without green tests
Can you name the smell you're fixing?You're refactoring by instinct, not by catalogIdentify the smell from the catalog, then apply its prescribed refactoring
Is each method under ~10 lines?Long Methods are likely presentApply Extract Method to break long methods into named steps
Does each class have a single reason to change?Divergent Change or Large Class smellApply Extract Class to separate responsibilities
Are there duplicated code blocks?Duplicate Code is the most expensive smellExtract shared logic into a common method or base class
Do conditionals use polymorphism where appropriate?Switch Statements or complex
if/else
trees remain
Apply Replace Conditional with Polymorphism
Are you committing after each refactoring step?You risk losing work and mixing changesCommit after every green-to-green transformation
Is the code easier to read after your change?The refactoring may have added complexityRevert and try a different approach
问题如果答案为否行动
开始重构前测试是否通过?你没有安全保障先编写或修复测试——不要在测试未通过的情况下进行重构
你能说出正在修复的坏味道名称吗?你是凭直觉重构,而非依据标准目录从目录中识别对应的坏味道,再应用其指定的重构手法
每个方法的行数是否都在~10行以内?可能存在过长方法应用Extract Method将过长方法拆分为命名步骤
每个类是否只有一个变更原因?存在发散式变更或过大类的坏味道应用Extract Class分离职责
是否存在重复的代码块?存在重复代码这种高成本的坏味道将共享逻辑提取到公共方法或基类中
条件语句是否在合适的场景下使用了多态?仍存在Switch语句或复杂的
if/else
应用Replace Conditional with Polymorphism
每次重构步骤后是否都提交了代码?你可能会丢失工作成果,或混合不同变更每次从绿色到绿色的转换后都提交代码
变更后的代码是否更易读?重构可能增加了复杂度回滚并尝试其他方法

Reference Files

参考文件

  • smell-catalog.md: Comprehensive catalog of code smells organized by family -- Bloaters, Object-Orientation Abusers, Change Preventers, Dispensables, and Couplers -- with detection heuristics and fix mappings
  • composing-methods.md: Extract Method, Inline Method, Extract Variable, Inline Variable, Replace Temp with Query, Split Temporary Variable, Remove Assignments to Parameters, Replace Method with Method Object -- motivation, mechanics, and examples
  • moving-features.md: Move Method, Move Field, Extract Class, Inline Class, Hide Delegate, Remove Middle Man -- when and how to redistribute responsibilities between objects
  • organizing-data.md: Replace Data Value with Object, Change Value to Reference, Replace Array with Object, Replace Magic Number, Encapsulate Field, Encapsulate Collection, Replace Type Code with Class/Subclasses/Strategy
  • simplifying-conditionals.md: Decompose Conditional, Consolidate Conditional, Replace Nested Conditional with Guard Clauses, Replace Conditional with Polymorphism, Introduce Special Case, Introduce Assertion -- with before/after examples
  • refactoring-workflow.md: The refactoring cycle, when to refactor, when NOT to refactor, refactoring and performance, Branch by Abstraction, Parallel Change
  • smell-catalog.md: 按类别(臃肿类、面向对象滥用类、变更阻碍类、冗余类、耦合类)组织的代码坏味道综合目录,包含检测方法和修复映射
  • composing-methods.md: Extract Method、Inline Method、Extract Variable、Inline Variable、Replace Temp with Query、Split Temporary Variable、Remove Assignments to Parameters、Replace Method with Method Object——动机、步骤和示例
  • moving-features.md: Move Method、Move Field、Extract Class、Inline Class、Hide Delegate、Remove Middle Man——何时以及如何在对象间重新分配职责
  • organizing-data.md: Replace Data Value with Object、Change Value to Reference、Replace Array with Object、Replace Magic Number、Encapsulate Field、Encapsulate Collection、Replace Type Code with Class/Subclasses/Strategy
  • simplifying-conditionals.md: Decompose Conditional、Consolidate Conditional、Replace Nested Conditional with Guard Clauses、Replace Conditional with Polymorphism、Introduce Special Case、Introduce Assertion——包含前后对比示例
  • refactoring-workflow.md: 重构循环、何时重构、何时不应重构、重构与性能、抽象分支、平行变更

Further Reading

延伸阅读

This skill is based on the definitive guide to improving the design of existing code:
本内容基于改进现有代码设计的权威指南:

About the Author

关于作者

Martin Fowler is the Chief Scientist at Thoughtworks and one of the most influential voices in software engineering. He is the author of Refactoring: Improving the Design of Existing Code (1999, 2nd edition 2018), which introduced the concept of named, catalog-based refactoring transformations to mainstream software development. Fowler is also the author of Patterns of Enterprise Application Architecture, UML Distilled, and numerous influential articles on software design, agile methodology, and continuous delivery. He was a signatory of the Agile Manifesto and has spent decades advocating for evolutionary design -- the practice of continuously improving code structure through disciplined, incremental refactoring rather than upfront big design. His refactoring catalog, originally written in Java, has been adapted to virtually every programming language and is built into the automated refactoring tools of every major IDE.
Martin Fowler 是Thoughtworks的首席科学家,也是软件工程领域最具影响力的声音之一。他是《重构:改善既有代码的设计》(1999年首版,2018年第2版)的作者,该书将命名的、基于目录的重构转换概念引入主流软件开发。Fowler还著有《企业应用架构模式》、《UML精粹》,以及多篇关于软件设计、敏捷方法论和持续交付的有影响力的文章。他是敏捷宣言的签署者之一,数十年来一直倡导进化式设计——通过严谨的增量重构持续改进代码结构,而非进行前期的大型设计。他的重构目录最初以Java编写,现已被适配到几乎所有编程语言,并内置到各大IDE的自动重构工具中。