l

2010年3月15日 星期一

敏捷式例外處理設計 (3):我到底哪裡做錯之 ignored checked exception

03/15 20:2821:00

以下的內容需要先閱讀『敏捷式例外處理設計的第一步:決定例外處理等級』比較容易理解。

今天 Teddy 要談另一個會導致程式無法達到 G1 (error-reporting) 例外處理等級的 exception handling bad smell: ignored checked exception 。請看以下 Java 程式片段:

public void doIt(){

  try {
       // Do IO operations
  }
  catch (IOException e) {
   // ignored
  }
}

所謂的 ignored check exception表示例外被捕捉但是沒有作任何的處裡,換句話說就是例外被『忽略』或是『隱藏』了。Ignored check exception dummy handler 對程式狀態造成的影響其實是很類似的,但是由於兩者『表現的方式不同』(在程式碼中長得不一樣),所以還是將其紀錄成兩個不同的 smells


相同點:
  • Caller 無法得知 callee是否發生了例外。
  • 都無法達到 G1

相異點:
  • 當錯誤發生的時候,ignored check exception dummy handler 還難偵錯。因為前者連將例外輸出到 console 的動作也沒有,所以當程式狀態錯誤時更難找到問題。
  • 到看到程式碼的時候,dummy handler 會讓 programmers 誤以為例外已經妥善處裡,但是 ignored check exception 比較容易被看出來是一個問題。

*******


Replace Ignored Checked Exception with Unchecked Exception

只要套用Replace Ignored Checked Exception with Unchecked Exception 這個 refactoring 就可以移除 ignored checked exception 並達到 G1 例外處理等級。實做方法和移除 dummy handler 其實很像,都是丟出一個 RuntimeException 來取代原本的例外,請看:



public void doIt(){

  try {
     // Do IO operations
  }
  catch (IOException e) {
     // ignored
  }
}



變成


public void doIt(){

  try {
     // Do IO operations
  }
  catch (IOException e) {
     throw new UnhandledException(“message”, e);
  }
}

如果上面的程式要達到 G2 或是 G3 還需要其他方法,暫且不表。


友藏內心獨白:昨天和今天這兩篇出場順序有點搞錯,應該先講 ignored checked exception 再講 dummy handler

2010年3月14日 星期日

敏捷式例外處理設計 (2):我到底哪裡做錯之 dummy handler

 03/14 20:43~21:50


以下的內容需要先閱讀『敏捷式例外處理設計的第一步:決定例外處理等級』比較容易理解。

今天 Teddy 要談一個導致程式無法達到 G1 (error-reporting) 例外處理等級的 exception handling bad smell (例外處理壞味道): dummy handler 。先看一個 Java 程式片段的例子:

public void doIt(){

  try {
     // Do IO operations
  }
  catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
  }
}

寫過 Java 程式的鄉民們,應該對上面這個 catch clause 裡面的程式碼不陌生,這就是一個 dummy handler。所謂的 dummy handler,就跟政客的競選政見一樣,聽(看)起來頭頭是道,實際上卻是空無一物,看不到牛肉。e.printStackTrace(); 這一行程式,事實上並沒有實質地 handle (處理) 例外,只是單純把例外印到 console 中。這樣的訊息通常只有 programmers 在程式開發的時候才看得到,對於這個 method 的呼叫者 (caller) 而言當例外發生之後並不會得到任何通知,因此會以為該 method 的執行沒有問題而繼續執行下去,但實際上系統的狀態可能已經發生了錯誤了。

Dummy handler 還會讓 programmers 產生一種『我已經把裡外處理好』的錯覺,實際上這樣的例外處理卻連 G1 等級都沒有達到。

*******

Replace Dummy Handler with Rethrow

要移除 dummy handler 這個 bad smell 很簡單,只要套用 Replace Dummy Handler with Rethrow 這個 refactoring 就可以達到 G1 例外處理等級,請看:


public void doIt(){

  try {
     // Do IO operations
  }
  catch (IOException e) {
     throw new UnhandledException(“message”, e);
  }
}

附註說明一下,其中 UnhandledException 是一個在其他地方事先定義好的 RuntimeException。另外,在 main program 中需要有一個超大的 try block 用來捕捉所有的例外並回報個使用者知道,如此便可達到 G1。

如果上面的程式要達到 G2 或是 G3 還有其他相對應的方法,改天有空再談。

*******

以下為 QA 時間。

鄉民甲:為什麼不直接把 IOException 丟出去,還要轉成另一個 RuntimeException?

Teddy 回答:G1 的目的只是為了讓例外可以被回報,也就是保證沒有例外會被隱藏或忽略。由於 IOException 是一個 checked exception,所以如果只是為了『回報例外』這個目的,而直接把它往外丟,那麼就需要修改 doIt() 的介面如下:

public void doIt() throws IOException;

而呼叫 doIt() 的人也需要修改,造成所謂的漣波效應。為了避免這個問題,才使用一個 RuntimeException 來回報錯誤。


鄉民乙:這個 dummy handler 是不是只有在 Java 才會出現?

Teddy 回答:應該說在 Java 程式中很容易出現,而其他語言也『不排除』會有這個 smell (鄉民乙:講得很心虛喔...)。由於絕大多數的程式語言只有 unchecked exceptions (也就是 runtime exceptions) ,因此 programmers 沒有必要為了符合類似 Java 所規定的 catch or declare rule 而需要去捕捉這些 unchecked exceptions,因此預設情況下所有未被捕捉的 unchecked exceptions 直接就往上層傳遞 (propagate) ,而自動達到 G1(記得在程式最外層加上一個大的 try block)。

友藏內心獨白:看得懂 Teddy 在講什麼東東的人請到前面來領糖果...

2010年3月13日 星期六

敏捷式例外處理設計的第一步:決定例外處理等級

03/13 20:12~23:25

今天 Teddy 想談一下例外處理設計 (exception handling design) 這個問題(PS:終於回歸到 Teddy 的本業...)。N 年前曾經有人研究過,軟體中大概有 2/3 的程式都是用來做例外處理或是錯誤處理。既然例外處理佔了軟體系統那麼大的篇幅,理當受到分析師或是開發人員極大的重視才對。錯!在實務上,相較於討論如何設計正常功能的文獻(書籍,論文,文章,程式範例),關於如何做例外處理設計的討論就少了很多。鄉民們可以回想一下,在求學的過程中,在程式語言的課程或是軟體設計課程中,有多少老師曾經教過你如何設計例外處理,而且你實際用過之後還真的可行?如果有,Teddy 在此先恭喜老爺,賀喜夫人。如果沒有,也沒關係,看看本篇就是一個好的開始。

************

例外處理在軟體開發中面臨的困難

Teddy 本身覺得從整個軟體開發流程的角度來看,要把例外處理做好是件蠻難的工作。為什麼難,簡單可歸類下面三個原因:

  • 屬於非功能性需求的例外處理很容易被忽略:大體上軟體開發的順序,是先從功能性需求 (functional requirements) 開始做起,然後再考慮像是可用性,安全性,強建性 (robustness),易用性等非功能性需求 (non-functional requirements,或稱為 quality attributes)。在軟體開發專案普遍面臨開發時間不夠的問題,因此類似例外處理這些非功能性需求就經常變成被忽略,犧牲的對象。開發人員常常會對自己說:『我先把功能做出來,之後再來處理例外』。可是,通常等功能寫好之後,這些暫時被列為 TO DO 的例外,就永遠被世人所遺忘了。
  • 有些例外是需求面看不到的,要到實做時才會出現:有寫過 use cases 的鄉民們都知到,use cases 有所謂的 failure scenarios,因此在撰寫需求時分析師便可規劃對於這些 failure scenarios 要如何處理。但是,有很多例外是和實做方法或是選擇的軟體元件有關,因此這種與實做相關的例外就沒有被列在需求分析中,而通常依靠 programmers 的良心來辦事。至於 programmers 有沒有良心,套句特偵組發言人的口頭禪:『不便說明』。不過,Teddy 可以確定的是,就算是很有良心的 programmers,也不見得有能力把例外處理做好(請看下一點)。
  • 真的不知道要怎麼處理:寫過 Java 程式的人都知道,呼叫與 IO 相關的 methods 時,會丟出 IOException 這個 checked exceptions (註:Java 的例外和『斯斯』一樣有兩種:checked 和 unchecked。Checked exceptions 表示 compiler 會檢查收到這類例外的人有沒有遵循 catch or declare 這個規則。翻成白話文就是說如果你呼叫某個會丟出 checked exception 的 method ,那麼你只有兩個選擇:寫一個 try block 把這個例外抓下來,或是把這個例外宣告在你自己這個 method 上頭繼續往外丟。Java 對於 unchecked exceptions 就沒有這樣的限制)有沒有什麼通用的設計準則告訴開發人員,當你收到 IOException 時要如何處理?好像沒有(有的話請好心地通知 Teddy 一下)。因此,要如何處理就看 programmers 的良心了。有人會反射性的把例外捕捉之後直接忽略,然後假裝沒事繼續做其他功能;有人把例外往外丟將這個難題交給下一個人;有人會把例外 log 下來然後認為這樣就算是把例外處理好了;有的人捕捉這個例外然後丟出一個新的例外;有的人捕捉例外之後,嘗試修復例外造成的問題,但是通常越補越大洞。簡單的說,在大部分的情況下,由於不知道例外要如何處理,不同的 programmers 通常依據自己的喜好隨機做出決定,而這樣的決定通常會降低程式的強健度。

************


定義例外處理等級

Teddy 要傳授的方法很簡單,就是請開發團隊定義軟體的『強健性等級』(參考 Table 1),之後這個強健性等級就變成例外處理的『需求』。有了需求,programmers 遇到例外的時候就知道要如何處理才能滿足這個需求。有點玄... 好滴,Teddy 先解釋一下這四個強健性等級的含意,再舉例子說明之。
 

G0: Undefined (未定義)

如果你還沒有幫你的程式貼上『強健性等級』,那麼你的程式就屬於 G0 這個等級。G0 表示當某個 service (可以想成整個系統,呼叫某個元件,SOA 中的 service call 或是一般的 function call)  發生錯誤的時候,可能會讓呼叫者知道錯誤發生,也有可能會假裝沒事 (failing implicitly or explicitly)。也就是說使用該 service 的人,其實是無法確切得知它是否有成功達成任務。而當錯誤發生的時候,service 處於不明或是錯誤的狀態 (state)。例外發生時系統可能會終止也可能繼續執行 (terminated or continued)。

G1: Error-reporting (錯誤回報)

G1 表示當某個 service 發生錯誤的時候,一定要讓呼叫者知道,絕對不能假裝沒事 (failing explicitly)。因此,使用該 service 的人便可確切得知它是否有成功達成任務。而當錯誤發生的時候,service 處於不明或是錯誤的狀態。例外發生時系統要終止執行(因為此時狀態已經不明,所以繼續執行下去可能會讓整個系統錯得更離譜,所以要立刻終止)。

要達到 G1 強健度等級很簡單,就是把所有的例外都往外丟,然後在主程式 (main program) 捕捉所有的例外並回報給使用者知道。G1 又稱為 failing-fast。

G2: State-recovery (狀態回復)

和 G1 一樣,G2 要求當某個 service 發生錯誤的時候,一定要讓呼叫者知道,絕對不能假裝沒事 (failing explicitly)。和 G1 不同,G2 要求當錯誤發生之後,service 必須保證還是處於正確的狀態。由於整個系統的狀態還是正確的,因此例外發生時系統可以繼續執行(continued)

要達到 G2 強健度等級就要多做兩件事情。第一件事情就是 service 要想辦法回復到別人呼叫它之前的正確狀態 (error recovery)。例如,如果該 service 修改了資料庫裡面的資料,當例外發生時就要執行 rollback (簡單說就是要 undo  之前修改過的狀態)。第二件事情就是釋放資源 (cleanup)。例如,把要來的記憶體,file handlers,connections 等資源釋放。G2 又稱為 weakly tolerant。


G3: Behavior-recovery (行為回復)

由 G3 的名字鄉民們應該可以猜到 G3 是很有責任感的,要求『使命必達』。因此,當某個 service 發生錯誤的時候,要另外想辦法排除困難,總之就是要達成任務。和 G2 相同,G3 要求當錯誤發生之後,service 必須保證還是處於正確的狀態 (註:唯有在狀態正確的前提下,在例外發生之後想其他方法繼續達成任務才有意義。) 由於整個系統的狀態還是正確的,因此例外發生時系統可以繼續執行(continued)

要達到 G3 強健度等級除了要做到 G2 的 error recovery 和 cleanup 之外,還需要『想其他方法達成原本的任務』。這些其他方法包含 retry,design diversity, data diversity, functional diversity 等等 (google 一下會有這些方法的詳細說明)。G3 又稱為 strongly tolerant。

鄉民甲:等一下,萬一遇到八八水災,或是秘魯大地震,一個 G3 的 service 真的沒辦法達成使命,那怎麼辦?請參考圖1,此時 G3 就會降級變成 G2...依此類推...





************

要怎麼用

重點來了,這些強健度等級要如何使用?以下是 Teddy 實際在團隊中推導此作法的步驟:

  1. 花 1-2 個小時教導強健度等級觀念。
  2. 在沒有特別規定之下,預設所有的 classes/methods 一定要達到 G1。如此一來,在開發階段經由各種測試我們便可盡量找出應該處理而沒有被處理的問題。在做這個規定之前,其實有滿多例外都被忽略了,從使用者介面上看不到錯誤,可是系統的狀態已經不對了,在這種情況下除錯變得更加困難。所以乍看之下 G1 (failing-fast) 好像很不負責的把所有的例外都往外丟,但是反而可以在開發階段發現問題並加以修復(此時便可決定針對該例外是否必須由 G1 提昇至 G2 或 G3),因此整體而言提昇軟體的強健度。
  3. 對於特定的操作,例如資料庫處理,由於有 transaction 可以使用,可以很容易達到 G2,因此剛開始實做時就必須達到 G2。
  4. 除非客戶要求,或是不達到 G3 會變得很難用,否則不會要求程式要達到 G3。 

Teddy 採用此方法兩年來覺的實務上還滿可行的。強健度等級這個觀念不但簡單易懂,而且也很符合 agile 精神。為什麼?因為強健度等級基本上就是秉持『階段性,逐步改善例外處理設計』的精神。在許多情況下,正常功能還沒有全部完成時,是不太容易決定例外處理到底應該做在整個系統的那一層,此時過早,過於精細的例外處理實做不見得有用,反而可能造成時間上的浪費。舉個例子,假設你採用 Scrum 開發某個軟體,而有某個『功能組』(例如,權限管理)需要2 - 3 個 sprint 才可以把全部的『正常功能』做完。當然在做此功能組的第一個 story 就有可能會遇到很多例外,如果此時對於要如何處理這些例外還沒有很清楚的解法時,可以規定這個 story 只要滿足 G1 便可。等這個功能組的全部 stories 都做完,或是等到做完足夠多的 stories,讓該功能組的例外處理變得可以決定之後,再增加一個 story 來提昇這些 stories 的強健度。如此一來,你個客戶也可以知道每一個已經完成的 story 的強健度,甚至可以讓客戶在『增加新功能』與『提昇強健度』等級這兩種不同類型的 stories 做取捨。


友藏內心獨白:寫這一篇所花得時間有點久...

2010年3月10日 星期三

Shared Code:讓我們變成博格人吧

03/10 21:51~23:48

螢幕截圖 2016-04-29 15.52.59

▲圖片節錄自Google搜尋結果

在「星艦迷航記」系列的影集裡面可能有幾千種不同的種族, 其中最厲害的應該就屬格人」。博格人可以直接同化其他種族,把他們的知識直接吸收過來,形成一個集合體(宇宙中數十億的博格人都擁有一個共同的集合意識)。由於博格人擁有集體意識因此能夠有效地協調分派工作,而博格人做事情在宇宙間也以『高品質,高效率』著稱。

XP 裡面有一個 practice 叫做 shared code (原本叫做 collective ownership),大意就是說專案的程式碼屬於所有開發人員所共有,無論程式原始的作者是誰,只要大家看到程式中有問題或是設計不良的地方,都可以動手修改。數年前 Teddy 看到 collective ownership 這個作法,直覺就想到難道這是在模仿博格人的『集體意識』嗎?在軟體開發中,collective ownership 的概念讓 source code 成為所有開發人員的『集體意識』,這個「集體意識」(source code)由所有的開發人員所貢獻,維護,成長。這種作法至少有以下三點好處:

  1. 高品質的 source code:由於 source code 是大家共同擁有的,因此有很多雙眼睛盯著它。當開發人員把自己寫好的 code 貢獻進去這個『集體意識』的時候,如果程式寫得太爛,也會怕別人看到會偷笑。所以,潛意識中不知不覺就會想把程式設計的好一點,code 寫得乾淨一點。這就像就算你家裏亂的跟豬舍一樣,當朋友到你家作客的時候,總是要稍微打掃一下,留點名聲給別人探聽的道理是一樣的。其次,因為任何人有權只要看到『集體意識』有不良成份,就可以直接改善,因此長久下來品質自然會變好。最後,當你發現原本你所寫的程式被別人改過之後,你也學到了如何把程式設計的更好的技巧。當然也有可能是被你的同事越改越爛,此時就換你機會教育對方了。總之抱持著『互相漏氣求進步』的精神就對了。
  2. 提高工作分派的彈性:幾乎所有的軟體開發方法,都會告訴我們要挑選最優先的需求(通常是對客戶價值最高的需求)來開發。理論上是如此,但實際上卻很難。為什麼?假設現在客戶覺 UI 很難用,要求做出容易操作的系統。此時可能絕大部分的工作都和 UI 的開發有關。如果 source code 是大家的,通常表示每個人或多或少都有能力處理不同模組的程式。所以長期下來,因為開發人員專業分工不同而導致派工困難的問題就會比較少一點 (但也許不可能全部消失)。另外,團隊也比較不會因為某人請假,而導致功能無法開發的問題。放假的人也可以放心去休假,不用怕被電話騷擾。萬一團隊中有人離職,對於專案的影響也會比較小。
  3. 提昇開發人員的技能:由於 source code 是大家共有的,因此開發人員有機會可以輪流開發不同性質的程式,長期下來可以提高自己的專業技能。這樣可以避免開發人員長久下來都做同樣的事情,造成工作疲乏的現象。
看到這邊,相信很多鄉民必然抱持不贊同的態度。因為大家都習慣把程式當成自己生命的某種延伸,寫程式也都會有特定的習慣,如果把對於程式的界線或是控制權開放出去,這樣到時候被亂改一通,倒楣的還不是自己?對老闆而言,shared code 更是『違反祖制,大逆不道』的行為(來人啊,拖出去斬了)。程式碼沒有 owner,到時候出系統問題(而且一定會出問題)老闆要找哪一個倒楣鬼負責?

在傳統的心態下,同一個團隊的人,每個人負責若干的模組,界線劃分的非常清楚。好處是,由於你一直在做類似的工作,你這一項技能變得越來越強,因此看起來你的工作效率也越來越高。另外,乍看之下責任很清楚,哪個模組有問題就找那個負責人。這樣做的缺點是,每個人矇著頭各做各的,程式的品質好壞通常沒有人關心(除非團隊有持續做 code review... 不過應該很少)。當你遇到問題的時候,由於你的同事正好也在忙著他自己所負責的模組,所以通常沒有時間也沒有很大的熱誠來幫助你,因此你需要花費更久的時間來自行摸索。另外,開發人員萬一離職對於整個專案的影響就比較大。由於每個人的地盤劃分得很清楚,要是你不小心踩到別人的地盤,例如問了一句:『這個功能怎麼會需要做那麼久』,那麼你很可能被反嗆一句:『你那麼厲害不然你來做好了』。最後,大家各自負責的結果,可能導致『整合』的問題沒有人管。每一個人負責的模組都宣稱沒有問題,但是整合起來就有問題。那誰要管?

當然,要實施 shared code 也是有它的困難。大家都聽過『三個和尚沒水喝』,如何確保這份『集體意識』不會被越改越亂而又沒有人要負責?Teddy 目前的經驗如下:
  1. 剛開始的時候,還是採用傳統的方法,每個人依據專長或興趣分配到若干個專案。
  2. 要盡早導入持續整合,確定不同的模組可以整合在一起。
  3. 要求開發人員一定要寫 unit tests。
  4. 等系統雛型大致穩定之後,鼓勵大家 pair programming。在這個過程中,由不同模組的創始人帶另一個開發人員,讓他可以慢慢具備接手的能力。平均起來這個過程最短通常也需要1~2個月。
  5. 持續下去,至少達到每一個模組至少都有兩個人非常熟悉為止。
要達到團隊成員全部都完全了解整個 codebase 是很不容易的一件事,但是只要肯做,一定可以慢慢地朝向這個目標邁進。這是一條有點艱辛,緩慢,且遙遠的路程,不過報酬卻是十分豐厚。這麼說好了,就好比要去『西天取經』,亦或是『魔戒遠征隊』,出發之前大家都知道旅途十分凶險,達到目的地之後卻可以拯救世人啦。


友藏內心獨白:當博格人又不好,博格人當中只有 Voyager 的「 7 of 9」比較討喜,而且還是在變回人類之後。

2010年3月9日 星期二

就是這個光: Scrum + Lean + XP

03/09 22:18~ 03/10 00:10

Teddy 凡致力軟體開發十餘年來,無不在追求一個『正確答案』:軟體到底要怎麼開發才會順?用 RUP (Rational Unified Process) 太沈重,用 XP (eXtreme Programming) 又太自由。話說 10 幾年前 RUP, XML 正當流行的時候,當時 Teddy 有一個 8人/年 (8 個人做了一年) 的專案,就是試著採用 RUP 的方式來進行。Teddy 和另外一位同事每天熬夜寫出十分詳細的分析設計文件,隔天立刻拿給 programmers 實做。由於設計文件寫得太詳細,所以實做上沒有遇到什麼大問題。大部分的工作只是寫寫 SQL,設計精美的 UI,以及實做控制流程。

這一年內公司停掉接專案的機會,全心投入所有人力開發這個系統。完成後產品還沒大賣,但資金卻已經花得差不多了,因此要找人增資。Teddy 跟著老闆東找西找,後來找到某上櫃軟體公司願意投資我們一筆資金。事後 Teddy 問這家公司負責評估的人,為什麼要投資我們。他說:『我沒有看過台灣的軟體公司把開發文件寫得這麼詳細的』。(路人甲:可能是他見識不廣?!)

這...原來不是對方認為我們軟體做的好,而是覺的我們開發文件寫得好,所以軟體功力應該不錯,值得投資。當時 Teddy 有一句話一直不敢說出口:『其實我們的文件已經和程式碼不同步了!』軟體做好後,陸陸續續依據客戶要求還是有一些改變。而之後的功能修改根本不可能還有那美國時間回頭去更新文件。

不知道鄉民們是否和 Teddy 一樣有著相同的疑問:大部分 OOAD 的書不都是教我們要寫很多不同的文件,而且越詳細越好。此外,還要保持文件與程式碼的一致性。實務上,台灣軟體公司大多是中小企業,客戶願意付出的費用通常不足以支付『完美開發團隊』的費用。所以,怎麼辦?

這個問題當年困惑了 Teddy 許久。後來,XP 變得很熱門,也引起了 Teddy 的注意。在一次偶然的機會中 Teddy 讀了Jack W. Reeves 所寫的 "What is Software Design?" 這篇文章,當場茅塞頓開。簡單的說,傳統上軟體設計(廣義的說所有的工程設計)產出物就是文件 (現在的一般作法就是寫 UML 文件),而『寫程式』這件事算是低層次的『施工』,或是『生產』。基於此種想法,自然會要求軟體開發者要把『設計文件寫得很清楚』,這樣 programmers 就可以『按圖施工,保證成功』。更進一步,programmers 變成生產線的作業員,景氣好的時候可以多找一些人來加速生產,景氣不好就放無薪假。找 programmers 也變得很簡單,只要高中程度稍加訓練即可。更極端一點,分析文件寫好直接就可以產生程式碼,連 programmers 都不用了。傑克,真是太神奇了。

而 Reeves 在該文章說明,code (程式碼) 本身才是『軟體設計』的產出物,而不是文件。至於 compile, link 這些活動才是軟體生產活動,成本趨近於零 (IDE 上面按個按鈕就 OK?)。從這個角度來看,coding 或是 programming 便成為一種『設計活動』,而非『生產活動』。既然 code 是設計文件,而 coding 是設計活動,那麼傳統的文件重要性自然就大大降低了,而應該把焦點放在『如何寫好程式(等於如何做好設計)』上面。從 XP 的眾多活動中可以看出來這種 code-centric design (以程式碼為中心的設計) 的味道,每個 programmers 其實都是設計師。

剛接觸 XP 時,Teddy 簡直把 Kent Beck 當神一樣來崇拜,終於看到一種比較像是給人使用的軟體開發方法了。但是,實務上,XP 的採行還是遇到很多阻礙。一方面有些人覺的 XP 的主張太過極端(軟體領域的邪教?!),有些人則是誤解了 XP 的精神,加上大家對於改變總是怕怕的,因此在台灣實際實施的團隊應該不多。舉一個 XP 所提倡的活動 pair programming 來講,老闆一聽到兩個人一起寫程式,馬上想到成本增加一倍,不被罵死才怪。就算你跟老闆解釋:『這樣可以隨時做 code review,提高品質』,老闆可能會回你一句:『code review 是蝦米碗糕?』。另外,programmers 也不見得願意和別人一起寫程式,因為這樣會剝奪他 MSN 的時間....%!@#!~@

一方面,Teddy 覺的 XP 的很多 practices 很棒,例如 testing, continuous integration, pair programming, refactoring 等。另一方面,可能是 Teddy 沒把 XP 全部看懂,總覺的 XP 在 planning 這方面似乎太抽象了一點,真的要來規劃一整個專案時,還真不知道要如何著手。

一直到兩年前接觸到 Scrum,似乎可以用來填滿原本 XP 在 Teddy 心中懸缺那一塊空間。嗯,Scrum 的 Roles (Product Owner, Scrum Master, Team),Activities (sprint planning, daily scrum, sprint, sprint review, retrospective),Artifacts (stories, product backlog, sprint backlog, tasks, burndown chart),加上 XP practices,真是太速配了。難道這組搭配就是 Teddy 多年來尋尋覓覓的『正確答案』嗎?

很接近了,但是還差那麼一丁點。在某些情況下,Scrum 並不太合適。例如,假設你工作的團隊是要維護某個產品,每天可能都會有客戶回報關於這個產品的 bugs,而你必須要儘快處理。在這種情況下,sprint 長度就算是訂成一週,都嫌太長。如果訂成一天,又可能連一個 story 都無法做完。前幾天看了 Lean 的書籍,裡面提到了 Kanban (看板) ,似乎可以填補這個空缺。就是這個光,Teddy 現在覺的這一套組合產品 Scrum + Lean + XP (ㄟ,其實都是 agile methods) 滿有潛力成為 Teddy 心目中的『正確答案』。不過目前還沒有機會去嘗試 Kanban,所以暫時沒有任何實際的經驗可以報告。


友藏內心獨白:別再找了,根本沒有什麼『正確答案』,只有『適合或不適合的答案』。

2010年2月11日 星期四

非加班不能搞定之台灣經濟奇蹟幕後無名英雄

02/11 00:30~01:54

今天聯絡了一位以前公司的同事,告知他 3/11 日有一個 Scrum 講座,看看他有沒有興趣去聽。這位前同事目前從事嵌入式系統領域的工作,而他的碩士論文又是研究 XP,所以 Teddy 認為他應該會有興趣。



不料,前同事的第一個反應卻是:『這個活動在禮拜四下午喔...如果是晚上或是假日,我還可以喬一下時間...』奇怪了,Teddy 心裡想,這種活動辦在上班時間不是很正常嗎,晚上和假日誰還要來聽啊?

前同事目前工作專案團隊包含他老闆一共有六個人,平常他都忙到 11~12 點左右才下班。『這在業界很正常啊』... 前同事說....聽到這裡,Teddy 也了解前同事的難處。工作這麼忙,怎麼可能利用上班時間聽這個和工作看起來沒什麼關係的 Scrum。對一般公司而言,除非是 Linux kernel 或是 Intel 新 CPU, 晶片組介紹,公司才可能放員工在上班時間出來聽課吧。想在上班時間外出聽軟體工程相關的課程...想太多...不予通過...

不過,Teddy 還是很厚臉皮的想把他騙出來。

Teddy:你可以把資料寄給你老闆,找他一起來。
前同事:我老闆更忙,每天都在開會。
Teddy:!@#%~@@zzzZ

這個對話最後以交換 Facebook 帳號作為結束。

***

以下是 Teddy 聽來據說是真人真事的故事。某個『X碩』的員工,每天下班都搭最後一班的捷運。有一天下班後他在台北車站換車,在月台上遇到一位不認識的老先生,這位老先生突然對他說:『年輕人,你看起來氣色很不好,要多注意身體』。連不認識的陌生人的看得出來『X碩』是很操滴。

等一下,看到這邊『X碩』的員工可能會不服氣的說:『我們都很少加班啊...因為過了12點才算加班...』所以,不算操,OK 的啦。

 ***

相信各位鄉民們或多或少都有親身經歷或是聽過這些『台灣經濟奇蹟幕後無名英雄』的加班史。想當年 Teddy 年幼無知的時候,也是經常凌晨 12 點之後才下班,有時候還直接睡在公司,晚上還煮稀飯或是綠豆湯當宵夜和同事一起分享。但是,專案有準時結案嗎?幾乎從來沒有(除了少數幾個接公家機關做做網頁的案子會準時結案以外)。採用 Scrum 之後,現在 Teddy 相信如果上班時間是 9:00,每天應該在 18:30 左右就差不多要下班了。由於強迫自己與團隊必須在 18:30 之前把每天的事情都做完,工作起來反而比較有效率,加上應用敏捷實務作法(agile practices)得宜,專案反而進行的非常順利。

根據一些來源不可考的馬路消息,軟體開發團隊平均一天能有五個小時有效率且專心的工作(coding)時間就已經很了不起了。

鄉民甲:亂講,那我每天在公司待那麼久是在做假的喔 ...

關於工時和工作成果的討論,長久以來已經有太多文獻可以參考,在這邊 Teddy 就不再說明(偷懶一下)。不過鄉民們如果剛好是程式設計師的話,可以做一個實驗,如果我們狹義的單獨計算每天『專心寫程式』所花費的時間,平均下來這個時間應該也是五~六小時左右吧。等一下,不要把『無意識 coding,無意識 debugging,開批鬥大會,MSN 打屁,收發 email,看新聞,在走廊上聊天,泡咖啡,喝下午茶,上廁所,看股票,使用網路 ATM 或網路銀行,填假單,申請費用,發呆假裝思考』的時間也算進去喔。

除了加班以外,是不是有可能藉由改善做事情的效率或是減少做錯事情的機率,來提昇競爭力呢? Teddy 覺的 Scrum 是一個不錯的入門方法,門檻低,很容易上手,可以分階段逐步改善軟體開發團隊的做事方法並且提高生產力。有空可以來聽聽或是自己找資料看。

友藏內心獨白:現場有沒有請 show girls?

2010年2月7日 星期日

還少一本書: The Timeless Way of Building

02/06 23:33 ~ 02/07 02:19

幾天前在 Facebook 上的『Scrum Community in Taiwan』看到十分熱心的柯兄轉貼的一篇文章 Top 20 Best Agile Development Books, Ever,這20本書 Teddy 碰巧翻過 18 本 (請注意,翻過並不等於看完,更不等於看懂...只是... 翻過,沒什麼特別的意思...),這些書有空的話都應該要『翻』一下。不過,Teddy 對於原作者的排名,略有一點意見。引用一下原作者的資料,看一下前10名的排行榜:
  1. Agile Software Development: Principles, Patterns and Practices by Robert C. Martin
  2. Refactoring: Improving the Design of Existing Code by Martin Fowler
  3. Agile Estimating and Planning by Mike Cohn
  4. User Stories Applied: For Agile Software Development by Mike Cohn
  5. The Pragmatic Programmer: From Journeyman to Master by Andrew Hunt and David Thomas
  6. Agile Software Development: The Cooperative Game (2nd Edition) by Alistair Cockburn
  7. Agile and Iterative Development: A Manager's Guide by Craig Larman
  8. Extreme Programming Explained: Embrace Change (2nd Edition) by Kent Beck
  9. Agile Project Management: Creating Innovative Products by Jim Highsmith
  10. Continuous Integration: Improving Software Quality and Reducing Risk by Paul M. Duvall, Steve Matyas, and Andrew Glover

再怎麼輪,榜首也不應該是 Agile Software Development 這一本啊。Teddy 認為這本書寫得最棒的是專門講設計原則的章節(第8到12章以及第20章,The Single-Responsibility Principle, The Open-Closed Principle, The Liskov Substitution Principle, The Dependency-Inversion Principle, The Interface-Segregation Principle, Principles of Package Design)... 自首無罪... 其實 Teddy 也只看了這幾章... 不過這不是重點,重點是,雖然學會並實用這幾個設計原則就可以騙吃騙喝 一輩子 一陣子,但是很多原則並不是作者原創性的作品 。例如,The Open-Closed Principle 和 The Liskov Substitution Principle 在更早之前 Bertrand Meyer  的名著 Object-Oriented Software Construction 這本書就有提到了(這本書很大一本,裡面還有一狗票的設計原則等待鄉民們去挖寶)。

從抽象到具體的順序來看,Teddy 覺得第一名應該是 Kent Beck 寫的 Extreme Programming Explained: Embrace Change (第一版和第二版都應該看一下),因為 Teddy 是讀了 Kent Beck 的書才接觸 agile methods 的,所以本書自然榮登 Teddy 心目中的第一名。

********************

依照往例,以上內容也不是本篇的重點,以下才是本篇的重點。

俗話說『女人的衣櫃總是少一件衣服,女人的鞋櫃總是少一雙鞋子,男人的車庫總是少一部車子,小朋友的卡通總是少看一個小時,宅男的電腦總是少一顆硬碟』。依此類推,『程式設計師的書櫃,應該 總是少一本書』。今天 Teddy 要補上這一本書,一本 agile people 應該要看的書:The Timeless Way of Building (建築的永恆之道)。

看過 Design Patterns 的鄉民們應該有聽過 The Timeless Way of Building 這本書。Teddy 當年因為要研究 patterns 在其他領域的應用才去看 The Timeless Way of Building。在看這本書的當下,只知道它是啟發 software patterns 理論與應用的始祖,並不覺的它和 agile methods 有什麼特別的關係。簡單的說,作者在這本書對於『如何建構有活力,有生氣的建築物』闡述自己的一套理論,這個理論就是 pattern languages 理論。以 Teddy 有限的智慧,無法三言兩語說明清楚(ㄟ,其實 Teddy 也懷疑是否真的了解... 鄉民甲:你是來鬧的嗎?),直接看一段書上的文字比較快:

It (i.e., the timeless way) is a process which brings order out of nothing but ourselves; it cannot be attained, but it will happen of its own accord, if we will only let it.

對應一下 agile 精神... agile 方法是一種流程(process, 也許有些人不喜歡把 agile methods 看作是 process,不過這裡把 process 看成做事情的步驟或方法就好,不用想成重量級的大部頭流程), 可以為開發團隊帶來某種『秩序』或『結構』。要變成一個 agile team 需要靠團隊自身的實踐,無法以強制規定或是工廠管理的方式來建立 agile teams。
 
The prople can shape buildings for themselves, and have done it for centuries, by using languages which I call pattern languages. A pattern language gives each person who uses it the power to create an infinite variety of new and unique buildings, just as his ordinary language gives him the power to create an infinite variety of sentences.

對應一下 agile 精神... agile methods 強調 no big upfront design, evolutionary design, simple design,除非開發團隊成員具有很強的 software patterns 基礎(當然還要有 testing 和 refactoring 等配套,等一下會提到),否則要滿足這些設計精神是很不容易達到的目標。

Once the building are conceived like this, they can be built, directly, from a few simple marks made in the ground---again within a common language, but directly, and without the use of drawings.

對應一下 agile 精神...XP 不是告訴我們,沒什麼事不要畫太多設計圖的啦 (source code is the design)。

Several acts of building, each one done to repair and magnify the product of the previous acts, will slowly generate a larger and more complex whole than any single act can generate.

對應一下 agile 精神... 有沒有聞到 refactoring,iterative and incremental 的味道。

Within the framework of a common language, millions of individual acts of building will together generate a town which is alive, and whole, and unpredictable, without control. This is the slow emergence of the quality without a name, as if from nothing.

對應一下 agile 精神...Scrum 本身是一個 framework,採用 empirical management model 而不是用傳統的 defined processes 來管理負責專案。

寫到這邊 Teddy 和周公的約會已經遲到兩個多小時了,加上這本書的內容實在過於豐富又有點抽象,在沒有準備的情況下 Teddy 也掰不下去了。總之,這本帶點哲學味道的書,對於想要獲得『華山論劍』資格的 agile 鄉民們,是屬於不可不搶的『九陰真經上卷』,練完之後如果沒有走火入魔保證內力大增。

友藏內心獨白:Teddy,你不要看到英文單字一樣就隨便連連看,小心被抓包。