2011年3月23日 星期三

Smell good? [釋疑篇]

Compose Method [Beck, SBPP]

You can't rapidly understand a method's logic.

Transform the logic into a small number of intention-revealing steps at the same level of detail

以下 by [Kerievsky, Refactoring to Patterns]

Motivation:
這個 pattern 看起來很簡單, 好像每個 programmer 都應該這樣寫 code, 但是如果你仔細檢視一下自己寫的 code, 你會發現, 應該大部份的 code 都沒有做到這個 pattern 的要求. Compose Method 簡單來說, 就是 method 裡面 compose 其他的東西, 都必須要在同個 detail 等級之下(Mechanics 第五點).


通常要使用 Refactoring to Compose method 的時候, 如何決定要從 long method 裡切出哪些 method, 和每個 method 該多大, 名稱該怎麼取才不會語意不清, 是一件不是很容易決定的事, 所以, 可以多利用 Extract Method 和 Inline Method 來回調整責任. Compose Method 常常會伴隨著產生一大堆 small and private methods.

很多人可能會認為切成這麼多 small method, 會讓程式沒有效率, 原本一次回圈可以要到一堆東西的值, 現在要拆成好幾個 small method 來達成. 不是會讓程式變得慢很多嗎? 而且 debug 的難度會隨著在不同 method 的切換下變高. 而且一堆 small method 也會讓整個 class 變得 complicate. 所以 compose method 只是一個沒有什麼幫助的 pattern?

事實上, 這幾個理由雖然是問題, 但是根本不影響 compose method 的重要性!!

Why?

關於效率?
一個好的程式設計師, 永遠永遠別做 premature optimization.

"They are only a performance problem when a profiler says they are."

一堆 small and private methods 和解?
如果這些 method 功能性上跟別的 class 的 method 有 duplicate, 請用 Extract Method and make it Public,
那假設沒有值得 extract 的呢? 那請問您覺得 debug 語意明確又沒幾行的 small method 比較難, 還是一個幾百行捲來捲去的 long method 哪個比較讓你想砍人阿? 而且想想看, 看連續的 method call 去了解一個原本功能複雜的 method 會多麼的有效率阿?

Benefits and Liabilities
+: 很有效率的傳達一個 method 在做什麼, 以及如何做什麼.
+: 讓 method 由充滿著語意清楚的 small method 來解釋他, 簡單明瞭又省 comment 力氣.
-: 可能會多出很多 small method
-: Debug 難度上升

Mechanics:
1. Think small:
通常一個 small method 是由 5 ~ 10 行 code 組成.

2. Remove duplication and dead code:
請把明顯的和不明顯得 duplicate code 都消滅掉, 明顯就不說明了, 不明顯是指 code 長得不一樣, 但其實都在做同一件事 (ex: 用 for loop and iterator loop 來得到某些值). 那些已經不知道被 comment 掉很久的 code, 直接幹掉吧~ 別忘了你應該要有一個東西叫做 subversion.

3. Communicate intention:
把你的 method 都取的簡單明瞭, 意思明確.

4. Simplify:
多想想看, 怎麼寫會讓你某段邏輯看起來更簡單.

5. Use the same level of Detail:
假如你的 method 裡有 method call, 那每行 code 應該都是同等於 method call 的形態. 如果 method 裡面都是基本的 statement, 那每行 code 也都是基本的 statement.

Example:
程式片斷請看前一篇 smell good? 來對照吧. 複雜的 example 就不寫了.


後記:
為什麼會想寫這篇呢? 是因為最近維護很多別人的 project, 看到了很多很可怕的用法. 仔細想想為什麼最後會變成這種慘不忍睹的悲劇. 很多很多都是沒從小地方注意起. 當功能一增加, SPEC 又改變之後, 原本單純的 method 不再單純, 甚至早已面目全非. 而這些很多都是由於沒做好 compose method 這件事造成的. 寫下這篇來跟大家分享, 也順便給自己留個重重的警告, 決不要讓自己的 code 變成這付德性.

Reference:
[Kerievsky, Joshua]
Refactoring to Patterns

[Beck, SBPP]
Beck, Kent. Smalltalk Best Practice Patterns.
Upper Saddle River, NJ: Prentice Hall, 1977

沒有留言:

張貼留言