2009年4月18日

[InfoQ QCon] 10 ways to improve our code

早上看了這個 talk (InfoQ Video link, Summary),主題是講 10 個改善程式碼品質的原則,有些不錯的地方值得記錄一下。

主講人 Neal Ford 先生是 ThoughtWorks 的架構師(跟 Martin Fowler 同一家公司),
演講的內容是從他寫的書:The Productive Programmer 裡面整理出來的,他講的很流暢,也蠻幽默的,演講時間大約一小時,投影片可以在這裡下載。

由於重點在 Summary 裡面都有列出來了,因此以下採用補充的形式記錄我印象深刻的部份,請搭配 Summary 服用。

Composed Method & SLAP (Single Level of Abstraction Principle)
Composed Method 這個原則講的是透過 method 的切割,盡可能的縮短每個 method 的行數,最後完整的 class 會由很多小小的 method 組成。

以切割 method 的方式來縮短行數的目的在於將程式碼的權責劃分清楚,以便達到最大程度的 reuse。但是在設計上也不應該為了切割而切割,此時可利用 SLAP 作為切割 method 時的 guideline。

SLAP 看來是 Neal 發明的縮寫,在 Wikipedia 上目前查不到,原始出處就是他寫的 The Productive Programmer,另外可以參考 Microsoft Architect Journal 2004 年 7 月號:Secrets of Great Architects(Levels of Abstraction: A Powerful Weapon for All Engineers)。

簡單的說,程式碼本來就是很抽象的,但還是可以區分出不同的抽象層次。最粗略的分法是,對 DB 的操作歸類為系統中較底層的程式碼,而 Domain Logic 則是系統的核心,UI 則是系統與使用者互動的介面,因此這三個層次的程式碼不應該混淆在同一個 method 中,就算不抽離到其他的 class 中,起碼也要拆解成不同的 method。

以下是同一個 method 中包含多個抽象層次的 pseudo code(節錄自投影片):
addOrder(WithMixedLevelOfAbstraction)

在這個未經 refactor 的版本中,可以看到非常詳細的操作 DB、Transaction 的程式碼,跟此 method 要處理的「新增訂單」Domain Logic 混雜在一起,因此閱讀的時候你的”心智”(mind)要多次在不同的抽象層次間的切換(mental shift),這種額外的負擔會造成閱讀程式碼時的不順暢。

以下是 refactor 之後的結果:
addOrder(WithSeparatedLevelOfAbstraction)

經過 refactor 後程式碼明顯縮短很多,而且現在此 method 中的抽象層次(大致)是一致的,如「completeTransaction」、「rollbackTransactionFor」等等的 method 不但名稱更有 business 上的意義,也隱藏了與 business 無關的、底層 API call(操作 DB、Transaction), 因此這段程式碼閱讀起來比上一個版本順暢很多,一行一行的順著讀下來比較接近日常生活的會話
(撰寫此 method 的目的:新增訂單)
  1. 建立所需的 DB Connection 和 SQL Statement。
  2. 開啟 Connection 和準備 SQL Statement。
  3. 設定 transaction 的狀態。
  4. 新增一筆訂單。
  5. 設定訂單號碼。
  6. 將購物車中的物品資料寫入訂單。
  7. 完成交易。
Question Authority
這個原則中文應該可以稱為「挑戰權威」吧!例如挑戰 coding convention,或者(公司內)常見的系統設計方式。Neal 舉的例子是一個有名的猴子實驗,我找到一篇文章:The Origin of Tradition: A Monkey Experiment (圖文說明),另外很久之前在書上看過一篇類似的文章,我自己打字以後做成 PDF 檔,可以在這裡下載(這都是文字,沒有圖,但是內容比較充實)。
比較有趣的是上面那篇我另外找的文章裡面有引述愛因斯坦的話:

Only two things are infinite, the universe and human stupidity, and I’m not sure about the former.
                                                                                               -Albert Einstein

建立 convention 對 productivity 是一件好事,但是深入的了解 convention 形成的原因,才有辦法在適當的時候打破 convention,以新的方法做事情,創造更大的價值!

詳細內容就不贅述了,不管這是真的實驗還是一個故事,總之很發人深省!

Use the Anti-Objects Pattern
在這裡 Neal 利用早年大型機台上的老遊戲 – Pac-Man(中譯:小精靈)來解釋何謂 Anti-Objects Pattern。在 Wikipedia 上有個 entry 就叫做 Antiobjects,剛好裡面就有講到 Pac-Man(警告!以下資訊可能會破壞你對小精靈這款遊戲美好的回憶 XD)
The notion of antiobjects is a computational metaphor useful to conceptualize and solve hard problems by swapping computational foreground and background.
If we implement, as part of a Pac-Man game, a ghost we are tempted to think of the necessary behavior associated with the ghost object.
Antiobjects turn things on their head. In the case of Pacman we put the main computation into the maze.
                                                                                                            - Wikipedia


在當年運算能力十分缺乏的平台上,是無法將「追逐小精靈」的 AI 設計到「鬼」這個 object 上的(由鬼來計算迷宮中的 shortest path ),因此反過來設計者把 AI 設計到迷宮的地板上去,並且提出一個 Pac-Man Scent(小精靈的氣味)的觀念,也就是目前小精靈所在的那塊地板氣味最強,而這個氣味是交由迷宮的地板來記錄的,當小精靈遠離這塊地板時,它的氣味就逐漸減弱。

因此鬼實際上沒辦法知道小精靈的位置,鬼都是漫無目的的瞎逛,若剛好踩到一段有小精靈氣味殘留的地板,才會一路往氣味更強的方向去「追殺」小精靈。

透過 antiobjects 可以簡化 AI 的設計,另外也是訓練你如何 think outside of the box 的好方法喔!

最後來回憶一下經典的小精靈遊戲畫面吧!
6

沒有留言:

Google Spreadsheet 裡用規則運算式

最近因為工作關係,遇到要用 Google Form 及 Google Sheet 所以研究了 Google Sheet 裡的一些 function 怎麼用 首先,分享一下如何在 Google Sheet 裡用規則運算 :D