[閱讀筆記] 重構 Refactoring: Improving the Design of Existing Code

Title: Refactoring: Improving the Design of Existing Code
Author: Martin Fowler
Publisher : Addison-Wesley
Date: 1999/6/28

本書的中譯本為:《重構:改善既有程式的設計》。原文本

在工作中,我們常常會需要在既有的軟體上,加入新的功能。但既有的code若設計不當,會讓我們很難改得動,或者是改動的過程中會產生許多bug。本書提出refactoring的觀念,提出一套完整的流程,幫助我們把舊有的code改善成為易讀、易改的code。

Chapter 1 Refactoring, a First Example

當你要加new feature,但發現原本的code結構不夠好,使得加new feature並不容易,這時候,就表示該做refactor了。

在refactor之前,一定要先做好嚴謹的「自動化測試」

Refactor的過程中,每次做了一點小改變,做要重跑一次「自動化測試」,如此,如果不小心改壞了,立刻就可以知道問題出在哪裡。

Anyone can write code that a computer can understands.
Good programmers write code that humans can understand.

Chapter 2 Principles in Refactoring

Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.

Refactor (verb): to restructure software by applying a series of refactorings without changing its observable behavior.

Why Refactor?

Improves the design of software
Makes software easier to understand - leads to higher levels of understanding
Helps to find bugs
Helps to be more effective at writing robust code
Helps to program faster

Kent Beck:
I'm not a great programmer; I'm just a good programmer with great habits.

When To Refactor?

Three strikes and you refactor.
When you add functionality.
When you need to fix a bug.
When you do a code review.

What makes programs hard to work with?

Kent Beck:

We want programs:
easy to read,
have all logic specified in one and only place,
do not allow changes to endanger existing behavior,
allow conditional logic to be expressed as simply as possible.

Refactoring and Design

在design的過程中,常常一開始想到的解不見得是最佳解。因此design是會改變的。Refactoring使得design change的overhead是較小的,因此較容易適應design change。

Refactoring and Performance

Refactoring will make software run more slowly, but it also makes the software more easy for performance tuning. The secret to fast software is to write tunable software first and then to tune it for sufficient speed.

Run a profiler to find the performance hot spots.
Focus on these performance hot spots and optimize them.
Rerun the profiler, if the performance does not improve, back out the change.
Continue the process until the performance satisfies your users.

Chapter 3 Bad Smells in Code

* Duplicated Code

* Long Method

* Large Class

* Long Parameter List

* Divergent Change

One class that suffers many kinds of changes.

* Shotgun Surgery

One class that alters many classes.

* Feature Envy

The fundamental rule of thumb is to put things together that change together.

* Data Clumps

* Primitive Obsession

* Switch Statements

The problem with switch statements is essentially that of duplication. Most times you see a switch statement you should consider polymorphism.

* Parallel Inheritance Hierarchies

* Lazy Class

Each class you create costs money to maintain and understand. A class that isn't doing enough to pay for itself should be eliminated.

* Speculative Generality

If all this machinery were being used, it would be worth it. But if it isn't, it isn't.

* Temporary Field

An instance variable is set only in certain circumstances. A common case occurs when a complicated algorithm needs several variables.

* Message Chains

* Middle Man

* Inappropriate Intimacy

* Alternative Classes with Different Interfaces

* Incomplete Library Class

* Data Class

* Refused Bequest

* Comments

When you feel the need to write a comment, first try to refactor the code so that any comment becomes superfluous.

Chapter 4 Building Tests

Test case的特性:

自動化測試,test case要能夠自行檢查結果是否正確。如此每次做refactoring後,run test case,over-head才不會太大。

寫test case的時機:

在coding之前。如此可以讓自己在實際coding前先想清楚這個function的行為。也可以專注在interface而不是implementation。也可以容易判斷是否coding done--當unit test cases pass時,明確顯示coding done。

在做refactoring之前。

收到bug report時,寫test case來trigger這個bug。(這表示之前的test case是不足的,藉機加以補足)

寫test case時的叮嚀:

測試你覺得最可能出錯的部份。

測試boundary conditions。

測試預期會出錯的部份--例如傳回error code或產生exception的情況。

Chapter 5 Towards a Catalog of Refactorings

Don't just search and replace blindly. Inspect each reference to ensure it really refers to the thing you are replacing.

GoF: Design Patterns ... provide targets for your refactorings.

Patterns are where you want to be; refactorings are ways to get there from somewhere else.