l

2010年5月31日 星期一

600 多個 bugs 要怎麼修?

5/31 22:36~23:56

昨天晚上 Teddy 接到以前公司同事(M小姐)打來的電話,問了幾個她在新公司所遇到的問題。M小姐是個很稱職的 PM,最近到了國內獲得 CMMI Level 3 認證的某大資服業(資訊服務業,就是去 接案子的公司啦)的某部門負責維護專案。她們部門負責某軟體(在本篇的代號為 F 軟體)的維護,她們公司有一個產品的 team 負責開發 F 軟體,完成之後就用這個 F 軟體去搶專案,搶到之後由於每個專案都需要做『客製化』,因此每接一個專案就產生一份 F' 軟體。專案結束之後,為這個專案所客製化的功能並不會回饋到原本的 F 軟體中 (錢都到手了,誰還管那麼多。)。M 小姐所在的維護部門,養了幾個 programmers,每一個人負責 10 來個專案的維護工作(就是修 bugs 啦),但是這些負責維護的 programmers 其實並不全然了解整個系統。F 1.0 版是在 10 年前用 微軟 ASP 技術開發出來的,目前有幾十個客戶,也就是說有幾十個不同的 F 1.0 版本。目前產品 team 即將完成 以 .NET 技術開發的 F 2.0 版。

10 年前開發的 F 1.0 版與其衍生的幾十個版本(據說新的 F2.0 版也是)都沒有任何的『自動化測試』。目前以 F 1.0 版為基礎的客戶所回報的 bugs 一共有 『 600 多個尚未解決的 bugs』。客戶對於 bugs 修復的進度緩慢感到非常不滿意,甚至直接打電話跟公司高層抱怨。

公司高層:M小姐,妳評估一下需要多少的人,在多少的時間內,可以把全部的 bugs 解決?

M小姐:??? (我又不是算命的... 這句是 Teddy 幫她回答的)

***

M小姐問 Teddy 幾個問題:
  • 這 600 多個 bugs 要怎麼解決?(Teddy 內心獨白:我也不是算命的啊)
  • F 1.0 版所衍生的幾十個專案,日後要如何維護?
  • F 2.0 版即將完成,如果依照公司之前的模式,日後一定又會產生 N 個 F 2.0 版的衍生物,又會遇到維護的問題。
人客啊,你說這 600 多個 bugs 要怎麼解?Teddy 怎麼可能會知道,只能依照常理來開藥方:

  1. 先把這 600 多個  bugs 分類,看看能否找出 bugs 的  patterns。例如,memory leak bugs,database transaction control bugs,UI validation bugs,business logic bugs,concurrent control bugs,exception handling 不良所產生的 bugs  等等。
  2. 從這幾十個 F 1.0 的專案中找出功能最多的,目前 bugs 最少,或是客戶最急的專案作為基礎,然後實施 code review。對照步驟 1 所整理出的  bugs 分類,看看能否從 code review 的過程中找出一些發生錯誤的蛛絲馬跡。
  3. 補寫  test cases。(3.1) 針對每一個準備修復的 bug,寫出一個自動化測試案例來重現這個 bug。(3.2) 或是對於不了解的功能,以寫 test cases 的方式來驗證與理解這些功能。(3.3) 針對準備 refactoring 的功能寫自動化測試。由於古早以 ASP 技術所開發的系統程式碼和 UI 大概都是混在一起,要寫自動化單元測試可能不是那麼容易。所以要依據程式結構實際狀況來研究一下這種自動化測試要怎麼寫。
  4. 導入持續整合。
  5. 如果一切順利,則看看有沒有可能用同樣的方法來修正其他專案的 bugs。
M小姐:可是要求 programmers 寫自動化測試不太可能。其他專案的 PM 會認為『寫程式的時間都沒有了哪有時間寫測試』。Programmers 也會有類似的想法。

Teddy:頑皮頑皮推一推...Teddy 內心獨白...
  • 這是什麼鳥公司...
  • Automatic test cases 不會寫,失敗。不願意寫,失敗中的失敗。
  • 一個號稱獲得 CMMI Level 3 的公司,要他們寫點自動化測試居然是那麼的困難,可見 CMMI 真的是很博大精深。CMMI,我真是猜不透你啊。
  • 本校資工系大一學生修程式設計的課都要寫自動化測試了,號稱專業的資服業者居然都是用人工測試。
  • 台灣的軟體開發團隊對於軟體工程的知識與實踐上的『貧富差距』真的很大。
  • 地鼠 (bugs) 是打不完滴,只有把地鼠給徹底剷除,剷完再除,牠們才不會一直不停地冒出來。
  • 也許應該考慮採用 Scrum 或是 Kanban 來改善軟體開發與維護流程。
  • 把公司的電話線和網路線剪掉,手機關機,這樣就不會接到客戶的抱怨。
  • 再次驗證了 Dave Thomas 所說的『All programming is maintenance programming』這句話。
Teddy 和 M小姐通了一個半小時的電話,講了一堆有的沒的,最後還是請她回去請示一下她的老闆,確認一下她老闆是屬於『袁世凱』還是『孫中山』。如果是前者,那就千萬不要想太多,做一天算一天,有空就更新一下 104 上面的履歷表,隨時準備開啟。如果是後者,則可以考慮找人幫忙導入 Scrum  或是一些軟體開發的 practices。

***

友藏內心獨白:那些導入 CMMI 的顧問到底都教了人家什麼東西啊?

2010年5月30日 星期日

導入 Scrum?謝謝再聯絡。

05/29 22:51~05/30 00:22

在台灣很多軟體開發團隊還是採用很傳統的方法來開發軟體(路人甲:Teddy 你不愛台灣喔,一直唱衰台灣... ),PM 不斷逼迫 programmers 要趕上進度,programmers 不斷加班試圖趕上不可能達成的進度表。為了『回報』PM 的壓迫,programmers 很大方的送給 PM 為數可觀的 bugs。這種合作共生的模式,讓大家看起來都有事可作,有班可加,工作『看起來』很辛苦卻又不用花什麼腦筋。搞不好年終時老闆大發慈悲,多賞幾個月的年終或是多發幾張股票,以慰勞員工這一年來的辛勞。

如果軟體開發團隊導入 Scrum,則 PM 的角色消失了,取而代之的只剩下  Product Owner,Scrum Master,以及強調『自我管理』的 Developers。每天工作  8 小時,準時下班。整個 Scrum Team 一團和諧,大家互相幫忙,共同解決問題。每個 sprint 結束,便可立即看到可以 demo 的成果。Product Owner (顧客的代理人)在每個 sprint 開始可以依序對顧客價值的高低來決定實做功能(stories)的先後順序,或是修改需求的內容。團隊的開發流程有 Scrum Master 關照(團隊是否有依循 Scrum 精神來開發軟體),並且將持續改善的精神落實到每個團隊成員身上。慢慢地,bugs 變少了,對於軟體開發進度的『猜測』越來越準,開發的功能和顧客的落差越來越小,每個 sprint 結束時都有一版可以交付給顧客使用的軟體,開發人員的流動率極低,每個開發人員也都有能力可以修改整個系統。

這不就是軟體開發團隊的『大同世界』嗎?

這麼棒的方法,人客啊,你要不要用?

***

鄉民甲:不要。

Teddy:Why?

鄉民甲:原因如下...
  • 沒有 PM?那現在的 PM 要吃什麼? 台灣的失業率已經夠高了,為了不讓吳院長下台,PM 第一個跳出來誓死反對。
  • 整個軟體開發流程變得這麼透明,哪來的混水摸魚空間。Teddy 你沒聽過『水清則無魚』嗎,Scrum 違反人性啊。
  • 我們的 developers 跟牛一樣,都很被動的啦,一定要一個口令一個動作,不可能『自我管理』。要不然到最後一定會亂成一團,變成沒人管理。
  • 每個 sprint 都可以修改需求?!那不是被客戶搞死。
  • 每天準時下班,這不是討打嗎。老闆會認為我們過的太爽了,不夠努力,操的不夠。不然就是進度訂的太鬆,原本三個月要完成現在改成一個月就要生出來,看你加不加班。
  • 聽說 agile methods 都沒在計畫,不寫文件也不畫甘特圖,這樣老闆和客戶都不會同意的啦。
  • 現在的模式 run 的好好地(操的是員工又不是我),幹麼改用這個連聽都沒聽過的 Scrum。萬一失敗不是害我被老闆罵,還是少做少做,不做不錯比較保險。
  • 什麼,導入 Scrum 還要收費?太貴了啦,我們自己慢慢 try 就好了(自己隨便 try 了一個月後失敗,因此認為 Scrum 不適合公司文化)。
Teddy:總而言之,你就是對我的 撒尿蝦牛丸 Scrum 沒有信心?

鄉民甲:謝謝再聯絡。

***

涉世未深的 Teddy 曾經認為軟體從業人員總是希望能用最好(至少也要是比較好)的方法來開發軟體。錯,Teddy 又再次大錯特錯。如果大家的開發模式都一樣爛,那這種模式就不叫做爛了,而是叫做『主流』。導入一種和現行作法差異很大的軟體開發新『思維』(流程),是需要很大的『勇氣』的。嗯,越來越能夠體會為什麼 Kent Beck 要把『courage』列為 XP 四個 values  之一了。用的人和推導的人都需要有打死不退的精神才有可能成功。

***

友藏內心獨白:本來這一篇要寫 『從 The Timeless Way of Building 學設計 (4)』,寫著寫著居然變成在談 Scrum。


2010年5月29日 星期六

敏捷式例外處理設計 (9):VMWare 越獄之 alternative methods

05/28 23:05~05/29 00:28

虛擬化的技術這幾年變得十分的流行,記得早在 10 多年前 VMWare 剛出來的時候,Teddy 的同事發現了這個好東西,於是我們就在 VMWare Workstation 上面建了好幾個 VMs (virtual machines),安裝不同版本的瀏覽器作為測試之用。Teddy 目前則是使用免費的 VMWare Server 3.x 來作為虛擬化測試平台,它可以讓我們透過網頁介面來產生與管理 VMs,很方便也很好用。

VMWare Server 用了一陣子之後,Teddy 發現了幾個不方便的地方:
  • Teddy 最近安裝了 Ubuntu 10.4 64-bit 作業系統,免費版的 WMWare Server 似乎無法直接安裝。雖然 google 了一下發現網路上也有人提到一些偏方,但是屬於 Linux 幼稚園小班的 Teddy 在嘗試了一下無法成功之後就自暴自棄輕易地放棄了。
  • WMWare Server 無法設定配置給每一個 VM 的 CPU 數目,用起來爽度有點不夠(雖然在 Teddy 的使用情境下,大部分的 VM 也只需要配給它一顆 CPU... XD)。
  • VMWare 的網頁介面有點小不穩,偶爾會出現一些不預期的錯誤,要 reload 好幾次才會正常。
  • 沒有支援 live migration 功能(雖然此功能 Teddy 從來也沒用過,不過這又是牽涉到『爽度』的問題)。

就這樣,Teddy 最近安裝了 Sun Oracle VirtualBox 3.2 版,並且將原本 VMWare  所產生的 VMs 移到 VirtualBox 上面。整個過程『大致上』還算 ok,VirtualBox 可以直接讀取 VMWare 的 VMs(不過還是需要做一些小設定),不過,重點來了,原本我們跑在 VMWare VMs 裡面的測試程式,搬到 VirtualBox 上面居然會錯!不是說『虛擬化』就是可以把 VMs 隨便移來移去的嗎,現在是什麼情況?

經過一番奮鬥之後,原來問題出在於 VirtualBox 對於 DMI (Desktop Management Interface) 的模擬實在是太遜了,不像 VMWare 做的那麼好,而我們的測試程式剛好需要透過 DMI 讀取一些關於主機板的資料,所以就槓龜了。

稍微解釋一下 DMI 是做什麼的,簡單的說,就是 BIOS 裡面會紀錄著一些主機板相關的資料,這些資料會被作業系統映射到某一塊特定的記憶體中。所以,如果應用程式需要得知與硬體相關的資料,例如主機板型號,BIOS 版本,實體記憶體大小等等,便可以讀取這些資料。讀取的方法有很多種,在 Linux 下有一個叫做 dmidecode 的程式可以直接看到這些資料,大概長成這個樣子:

root@Ubuntu:~# dmidecode
# dmidecode 2.9
SMBIOS 2.5 present.
30 structures occupying 1477 bytes.
Table at 0x0009F400.

Handle 0x0000, DMI type 0, 24 bytes
BIOS Information
    Vendor: American Megatrends Inc.
    Version: R01-C0L
    Release Date: 06/17/2009
    Address: 0xE0000
    Runtime Size: 128 kB
    ROM Size: 1024 kB
    Characteristics:
        ISA is supported
        PCI is supported
        PNP is supported
        APM is supported
        BIOS is upgradeable
        BIOS shadowing is allowed
        ESCD support is available
        Boot from CD is supported
        Selectable boot is supported
        BIOS ROM is socketed
        EDD is supported
        5.25"/1.2 MB floppy services are supported (int 13h)
        3.5"/720 KB floppy services are supported (int 13h)
        3.5"/2.88 MB floppy services are supported (int 13h)
        Print screen service is supported (int 5h)
        8042 keyboard services are supported (int 9h)
        Serial services are supported (int 14h)
        Printer services are supported (int 17h)
        CGA/mono video services are supported (int 10h)
        ACPI is supported
        USB legacy is supported
        LS-120 boot is supported
        ATAPI Zip drive boot is supported
        BIOS boot specification is supported
        Targeted content distribution is supported
    BIOS Revision: 8.14

Handle 0x0001, DMI type 1, 27 bytes
System Information
    Manufacturer: Acer
    Product Name: Aspire M3203  <----- Teddy  花了 9999 所買的電腦型號
    Version:        
    Serial Number:                      
    UUID: Not Present
    Wake-up Type: Power Switch
    SKU Number: To Be Filled By O.E.M.
    Family: To Be Filled By O.E.M.

(族繁不及備載,以下省略 )

***

講到這邊,以上所說和 exception handling 有何關聯?有滴,雖然這些 DMI 的資料和硬體有關,不是所有的主幾版都會提供完整的資料,但是幾個常見的資料結構都是會存在的。因此,我們的程式在開發的時候根本不會去想到會出現『讀不到 DMI 資料的問題』。在 VMWare 中,我們所需要的資料剛好都有被模擬到,因此程式在 VMs 裡面執行都沒問題。但是,VirtualBox 模擬的資料很少,因此我們的程式搬到 VirtualBox 中就有問題了。

原本我們的程式 RL = 2 (不知道什麼是 RL 的鄉民們請參考這一系列之前的文章),但是現在為了解決這個問題,必須要把 RL 提昇為 3,也就是要作到『behavior recovery』

我們的程式原本是呼叫 native code 的方式來讀取 DMI 的資料,但是這段 code 在 VirtualBox 就是無法正常執行,而且不知道為什麼會讓整個 JVM 『卡住』。為了先避開這個問題,於是對於相同的工作,必須要多提供另外的實做,也就是 alternative methods。最後改完的程式有一個 primary method(或稱為 primary implementation) 與一個 alternative method (或稱為 alternative implementation):

  • primary method:透過外部程式的方式呼叫 Linux 提供的 dmidecode 程式來讀取 DMI 資料。如果這個方法失敗,則改用 alternative method。因為 dmidecode 程式已經成為 Linux 內建的程式,因此原則上 primary method 應該都會成功。但是考慮到也許不同的 Linux 版本的 dmidecode 輸出格式可能不同,以及萬一遇到很念舊的 users 把我們的程式安裝在很古老的 Linux 版本中,因此還是保留一個 alternative method 當作備胎
  • alternative method:以原本呼叫 native code 的方式來讀取 DMI 資料。

***

鄉民甲:為什麼不在開發之初就把程式設計成 RL3?

Teddy:如果把每一個 methods 都設計成  RL3 則開發成本至少要變成兩倍(因為至少要有一個 primary method 和一個 alternative method),這樣做成本太高。此外,在設計階段很可能根本沒辦法預期到會有哪些錯誤情況發生,因此也無從針對不同的錯誤情況來設計不同的 alternative。所以,採取『演進式』的方法,逐步提昇程式的 robustness 是比較符合 agile methods 的精神。

 ***

友藏內心獨白:例外處理的好,軟體系統才會頭好壯壯。

2010年5月27日 星期四

The power of duplicate code

05/27 22:22~23:18

本篇的主題是 The power of duplicate code,翻成中文是『重複的程式碼的力量』。奇怪,duplicate code 不是一種寫程式應該要避免的 bad smell 嗎,為什麼這種壞東西還會有『力量』?別忘了星際大戰中尤達大師也曾經說過要留意『the power of dark side』,這種暗黑勢力有時候比正義的力量來的還要強大(不然黑武士為什麼那麼強)。

那麼,duplicate code 到底有什麼力量?Teddy 發現 duplicate code 最大的力量就是可以讓 programmers 看起來很忙且生產力很高。多麼神奇的力量啊!

講一個 Teddy 從朋友那裡聽來的的故事,真的是聽來的喔,絕對不是發生在 Teddy 周遭的人身上。故事是這樣的,有一個小型的軟體開發團隊,在沒有採用 Scrum 之前,team members 都各自負責若干個 sub-projects,彼此也幾乎不會去看其他人所寫的 code。後來,這個團隊不小心無緣無故被強迫中獎採行了 Scrum。經過若干 sprints 之後,閒閒沒事的 Scrum Master 突然去 review 某一個 sub-project,發現雖然是用 OO (物件導向) 語言來開發系統,但是裡面的 code 設計的很不 OO ,理解度大該只有 10% 不到(另一種說法是這個 Scrum Master 太遜了,看不懂別人寫什麼...)。但是由於當時這個 sub-project 的程式可以正常執行,Scrum Master 也就沒有立即建議要 refactor 該模組,反而是偷偷保佑永遠都不需要改到它。

但是,如果真的不用修改那麼這個故事也就講不下去了。某一天,該團隊突然發現這個 sub-project 在 multiple-threaded 的情況會出錯,而原本的負責人 (在此稱之為 X 先生)在事蹟敗露之前早已想辦法『落跑』到其他專案中。為了解決此問題,Scrum Master 花了一點時間以 OO 的方式來重新設計該 sub-project,然後與其中一位有一點了解這個 sub-project 的 team member 一起採用 pair programming 的方式重新寫了這個 sub-project。完成之後,原本在 multiple-threaded 環境所遇到的 bug 也自然消失了。不過這不是重點,重點是 Scrum Master 很無聊的去算了一下該 sub-project『改造前』和『改造後』的 LOC (line of code):
  • 改造前:約 10000 行 。
  • 改造後:約 2000 行 (包含 unit tests)。
再仔細一看,原本的程式充滿了 duplicate code 以及很奇怪的參數傳遞方式。除了原作者以外,地球上可能找不到第二個人可以維護這個系統。改造後,由於採用良好的 OO 設計,不但程式行數大減,而且所有的 team members 都有能力也實際參與了這個 sub-project 的開發。

***

在真實世界中,有多少人(多少主管或同事)會幫你做 code review?在台灣應該極少,因此誰說 duplicate code 是  bad smell,從 X 先生的觀點,duplicate code 可是 good smell 呢!要不是有 duplicate code,如何讓每天都有生產力呢。

老闆:我的員工每天都加班,工作好認真,好辛苦喔。

Teddy :你確定...

也許大部分的老闆或主管都忙到只能對員工實施『black-box testing』,無法實際了解員工每日的工作。此時,duplicate code may be a good smell。如果鄉民們的公司採行的是 TPS(Toyota Production System),強調『現場管理』,那麼 duplicate code 肯定是 bad smell。但是,話說回來,在台灣有誰開發軟體那麼『精實』啊。

結論,duplicate code 因為文化因素因此在台灣可能有 90% 的機率是屬於 good smell。

***

友藏內心獨白:故事真的是聽來的喔。

2010年5月25日 星期二

剽竊

05/25 22:06~23:05 

當年 Teddy 在念研究所的時候,修了一門『英文科技論文寫作』的課。老師在課堂中提到,『剽竊』(plagiarism) 這種行為對於學術論文寫作來說是一個大忌,千萬要避免,否則一旦被抓到將死無葬身之地。對於習慣『抄襲』,『盜版』,『copy』,『山寨』(ㄟ,那時候還沒這個名詞)的研究生們,要發表學術論文千萬不可以秉持『天下文章一大抄』的態度來寫作。因此,老師特別幫我們定義了何謂『剽竊』:

Writing facts, quotations, or opinions that you got from another source without citing them is plagiarism.

接著,老師列出了四種寫作上的剽竊 (Teddy 內心獨白:抄襲就抄襲,居然還可以搞到分類,真是太神了。)

  • Language Plagiarism:這類的抄襲最容易了解也很常見,就是把別人寫的內容原封不動直接拿來變成你的。
  • Structural Plagiarism:這是指抄襲別人文章的結構。這一點 Teddy 當年其實沒有聽懂,不過自由發揮一下。例如,鄉民們要寫一個 design pattern,而目前已經有很多種常見的 design pattern 寫作結構。如果鄉民們採用了某種結構,但是在文章中沒有提到這是你引用別人的結構,這樣也算是一種剽竊。
  • Idea Plagiarism:這個很容易了解,抄襲別人的想法據為已有。例如,鄉民們從別人口中聽到一個不錯的研究方法,直接以自己的名義寫成文章發表,這樣也算剽竊。
  • Mosaic Plagiarism:這種剽竊方法現在的學生常常使用,就是把別人的文章打上『馬賽克』然後就變成自己的文章。例如,老師要學生交報告,學生就把 google 到的內容 copy 下來,東改幾個字,西改幾個字,或是把句子前後交換等等,以為可以偷天換日,瞞天過海。很遺憾,這樣還是剽竊。
自從上了這門課之後,Teddy 就更加了解到寫作時要避免有心或無意的剽竊。

***

除了寫作上要避免剽竊,其實『為人處事』更應該避免剽竊。『避免剽竊』就是當鄉民們在『合理使用』別人的『智慧財產』時,要把『功勞』(credit ) 給原作者,不能讓別人以為這是你自己的貢獻。試想,假設鄉民們有一位同事(姑且稱之為 X 先生),當他來跟你請教一些問題的時候,你很大方的把你所知的都告訴他。之後,X 先生就把你告訴他的解決方案,跑去跟別人(這個『別人』,可能是你們的主管,其他部門的主管,或是任何的阿貓阿狗)講,並且完全沒有提到這是你告訴他的作法,讓別人認為:『哇,X 先生真行』;這就是一種剽竊。久而久之,當鄉民們發現 X 先生是這樣的人,也就不想與他分享知識。

鄉民甲:以上所說,和軟體開發有何關係?

Teddy:有滴,因為軟體開發是一種『獲得知識的過程』。如果你的團隊裡面,有這種喜歡剽竊的人,就會造成團隊成員不願意分享知識,因而影響軟體開發的速度或是品質。不知道有沒有人研究過這種人在軟體開發團隊中佔了多少比例?很不幸的,Teddy 就認識一 個。這種防同事跟防賊一樣的生活,還真是辛苦啊。

PS:請勿對號入座。

***

友藏內心獨白:應該去買『小人玩偶』嗎?

2010年5月18日 星期二

從 The Timeless Way of Building 學設計 (3)

05/17 23:19 ~ 05/18 00:14

沒時間了,廢話不多說,翻到課本第 24 章:The Process of Repair

Next, 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.

上面這一句先讀一次,看不懂最後回頭再看一次。

No building is ever perfect.

Each building, when it is first built, is an attempt to make a self-maintaining whole configuration.

But our predictions are invariably wrong. People use buildings differently from the way they thought they would. And the larger the pieces become, the more serious this is.

把上面這三句裡面的 building 用 software 替換,people 用 customers,clients 或是 users 替換,是不是也完全講的通?這一段的重點還沒完,繼續往下讀。

The process of design, in the mind's eye, or on the site, is an attempt to simulate in advance, the feeling and event which will emerge in the real building, and to crate a configuration which is in repose with respect to these events.

But the prediction is all guesswork; the real events which happen there are always at least slightly different; and the larger the building is, the more likely the guesses are to be inaccurate.

It is therefore necessary to keep changing the buildings, according to the real events which actually happen there.

And the larger the complex of buildings, neighborhood, or town, the more essential it is for it to be build up gradually, from thousands of acts, self-correcting acts, each on improving and repairing the acts of the others.

看完上面這幾句,鄉民們應該有聞到『iterative and incremental development』和『refactoring』的味道吧(鄉民甲:我鼻子不通,沒聞到...)。傳統 waterfall 開發流程強調 big up-front design,希望藉此讓之後的實做變得很順利。因此也就造成有人認為軟開發只要經過架構師與分析師分析設計好之後就可以把設計文件丟給 programmers,然後把 programmers 當成生產線工人一樣『操』,之後系統就自然而言生出來啦。看官們,有可能嗎?看看第三句就知道了 (But our predictions are invariably wrong...)。

Alexander 認為建築物不是設計好,蓋好就沒事了,還需要依據實際使用的狀況去改善與修復。這個精神和 agile methods 所談的避免 big up-front design 改採用 evolutionary design,並且頻繁地套用 refactoring 來增進現有系統的品質是相似的(Teddy 不敢說完全一樣啦...)。這個也和 David Thomas 在 http://www.artima.com/intv/dry.html 所提到的:

All programming is maintenance programming

的精神很類似。Programmers 其實隨時隨地都處在『維護模式』,因為很少真正的開發活動是『全新的』。就算是開發一個新的 story,也都是這邊寫一寫,那邊改一改,總是多多少少會和已存在的程式碼打交道。如果抱持著 all programming is maintenance programming 的心態,看到設計不良的地方,隨手做 refactoring,則系統的品質便可逐漸改善,這也使得未來增加新的功能變得更容易。但是如果沒有這種『時時勤拂拭,勿使惹塵埃』的精神(很遺憾,很多人都沒有...),認為『幹嘛改,程式可以動就好了啊』,那麼軟體便逐漸朝向『比硬體還要硬的硬體』邁進(這是什麼東東?)。


***

友藏內心獨白:救命啊,這一系列快掰不下去了啦。

2010年5月15日 星期六

你重視什麼?

05/15 22:21 ~23:50

今天上午是北科大資工系創系十週年聚會,下午指導教授邀請實驗室畢業的校友留下來聊聊天。在逐一自我介紹之後,各自帶開成小組討論隊形。這個故事便開始於指導教授,Teddy 與另一位學弟聊天的場景中。當話題正圍繞在 Scrum 的時候...

學弟:Scrum 在我們公司可能不太適合。
指導教授:(偶然往實驗室的書櫃方向一看) 耶,實驗室怎麼會有一本 PMP 的書?
學弟:我們公司也有很多人去考 PMP。
指導教授:PMP 的作法與 Scrum 完全不同...
學弟:我們公司好像也沒重視 PMP。公司去考 PMP 的人原本以為考上之後可以加薪,但是結果什麼都沒有。
Teddy :哪你們公司重視什麼?
學弟:... (苦思五秒) ... (無言)
Teddy :重視拍馬屁?!

***

Teddy 是一個有話直說,經常在有意無意中得罪人的人。更慘的是,Teddy 還樂此不疲... 這種天生反骨的個性,在古代應該是早就被『推出午門』不知道斬了幾次。Teddy 很幸運,第一份工作遇到的老闆(懷念朱先生...),以及念研究所時的指導教授們,都是很有肚量,也不是喜歡被吹捧的人,因此讓 Teddy 可以真誠的說出自己的想法,不必為了『揣摩上意』而講一些言不由衷的話。這一兩年 Teddy 才慢慢見識到什麼叫做『拍馬屁』與『揣摩上意』的最佳實務作法 (這種事也有 best practices... 應該可以寫成 pattern languages...)。在小公司裡面,苦幹實幹的人比較有可能被老闆重視,但是隨著公司規模逐漸擴大,老闆無形之中覺的越來越覺的自己天縱英明,也聽不進去反對意見,此時要升官發財就需要向『和珅』學另一套本領。

耶,這怎麼跟古代的皇帝那麼像?!沒錯,就是這麼像。Teddy 之前在談 Scrum 的時候曾經說過:『如果你的老闆是屬於袁世凱這一類型的,你跟他談民主只是找死』。然而,一個組織如果只有一種聲音是很危險的,就好像生態系中只有少數物種,是很容易因為環境改變而整體滅亡。

***

這幾天 Teddy 在讀『你可以不一樣:嚴長壽和亞都的故事』這本書,看了很感動。其中有一段提到:

有一天,嚴長壽無意中讀到一本跟佛教有關的書,看到『借觀』二字,他像忽然被打醒一般。一個人一輩子所能擁有有形的物質、財富,其實都不過是『借』來看看而已...

很可惜 Teddy 天生笨手笨腳,體力又差,又只會開發軟體,沒有其他一技之長,也沒有老家在鄉下。否則有時還真的很想學習日本『自給自足過生活 (自給自足物語)』電視節目中的那些人,反璞歸真過過自給自足的生活。

Kay:Teddy 你應該會餓死...因為睡太晚農作物都沒有照顧,雞也沒餵...

友藏內心獨白:本集的重點到底是什麼?

2010年5月14日 星期五

從 The Timeless Way of Building 學設計 (2)

5/13 23:29 ~ 5/14 00:20

有些人在念研究所的時候研究 design patterns 相關的題目,指導教授可能叫你寫幾個 patterns 出來再舉一些例子就可以畢業了。不知道鄉民們有沒有想過這個問題:『要如何生出一個新個 pattern』?今天 Teddy 來談一下這個問題(醜話說在前面,Teddy 部落格上的內容純粹為 Teddy 個人狂想曲,產品成分可能包含重金屬與不明配方,鄉民們自行服用之後若有任何副作用 Teddy 恕不負責)。

***

Teddy 第一份工作做的是 e-learning,因此當 Teddy 辭掉工作去念博速班的時候,指導教授建議 Teddy 可以研究『E-learning patterns』。這個主意還不錯,因為 Teddy 對於 e-learning domain knowledge 與 design patterns 都滿熟的,又有 e-learning 實務經驗,於是 Teddy 便開始了三年 (還是四年,這麼快就忘了!) 的 e-learning pattern languages 研究生涯。

俗話說:『事情不是笨蛋想得那麼簡單』,真正要自己『生』出一套 patterns 出來,才發現箇中的難處。雖然 design patterns 還算熟,但是『用 patterns』『生出 patterns』是兩回事,此時想到 GoF 的書裡面提到他們的研究是得到 The Timeless Way of Building 的啟發,指導教授與 Teddy 就想這本書裡面會不會有教導『如何生出 patterns』的方法,所以萌生看這本書的想法。

翻開課本第 14 章:Patterns which can be shared

To work our way toward a shared and living language once again, we must first learn how to discover patterns  which are deep, and capable of generating life.

第一個重點來了,patterns 不是被『創造』出來的,而是老早就存在,等著被『發現』。就好像生物不是被『創造』出來的,而是被『發現』。(當然以現在的技術也許真的可以無中生有創造出一個全新的物種,但這畢竟是人工的,不是天然的...記得嗎...電視廣告有交代:『天然A尚好』)這也是為什麼有些 patterns 用起來會覺得很好,很自然,有些卻覺得很生硬。後者可能就是『基因改造』的 patterns...

Each pattern is a three-part rule, which expresses a relation between a certain context, a problem, and a solution.

As an element in the world, each pattern is a relationship between a certain context, a certain system of forces which occurs repeatedly in that context, and a certain spatial configuration which allows these forces to resolve themselces.

上面這一段有學過 design patterns 的鄉民們應該就比較熟悉了,從結構上來說,patterns 的三大要素:context, a problem, and a solution。在 GoF 第三頁則說一個 pattern 有四個基本元素:pattern name, problem, solution, consequences,耶怎麼不一樣...基本上還是一樣的,pattern name 就不用提了,一定要有,至於 Alexander (The Timeless Way of Building 的作者) 所說的 context 和 GoF 所說的 consequences 從字面上來解釋只是套用 pattern『之前』和『之後』的差別(美容前,美容後),因此 consequences 也叫做 resulting context (美容後)。如果不要把 context 特別侷限在套用 pattern 之前,那麼 context 應該包含了 consequences。簡單的公式

context --> applying a pattern --> resulting context (consequences)

看不懂請跳過...

As an element of language, a pattern is an instruction, which shows how this spatial configuration can be used, over and over again, to resolve the given system of forces, wherever the context makes it relevant.

The pattern is, in short, at the same time a thing, which happens in the world, and the rule which tells us how to create that thing, and when we must create it. It is both a process and a thing; both a description of a thing which is alive, and a description of the process which will generate that thing.

這邊有一個重點,pattern 是一個『東西』同時也是一個描述如何產生這個東西的『流程』。所以,如果鄉民們發現了一個新的 pattern 打算將它寫下來,而其他人在看過你所寫的 pattern 之後了解到這個 pattern 的確有意義,但卻無法如法泡製,那麼這可能表示你所描述的 pattern 只是一個『thing』,而還不具備『process』的特質。

***

講了這麼多,那到底要如何發現一個 pattern?如果是要寫 pattern,可能會以  context -> problem -> solution 的順序出現,但是發現 pattern 的順序剛好相反。

We must first define some physical feature of the place, which seems worth abstracting.

因為 Alexander 尋找的是建築領域的 patterns,所以他提到『define some physical feature (i.e., spatial relationships, 空間上的關係)of the place』。例如,你到了總統府旁邊的『台北賓館』,覺的這裡面怎麼那麼漂亮啊,雖然是老建築物,但是裡面的一些設計用在當代還是很有用。因此,你想要找出這些你覺的好的設計,這就是『尋找 pattern』的第一步,從好的建築物(或是軟體,或是其他領域裡面被認為是好的東西)中定義出 physical feature (如果是軟體的話,就可能包含靜態結構關係與動態互動關係)。

Next, we must define the problem, or the field of forces which this pattern brings into balance.

Finally, we must define the range of contexts where this system of forces exists and where this pattern of physical relationships will indeed actually bring it into balance.

***

最後 Teddy 要補充說明,找出 patterns 的研究是一種『empirical study』,就是說要從實務經驗中來尋找 patterns。就好像新物種幾乎都是在野外原產地被發現是一樣的道理,不太可能坐在冷氣房裡面理論推導一番就可以『發現』新物種。Alexander 和他的同事也是花了 10 幾年以上的時間來發現與實際驗證建築領域的 patterns,而 GoF 裡面的 patterns 也都有 Known Use 這的段落(說明那些知名的軟體也用了這個 design pattern)。而 Erich Gamma  (GoF 的第一個人) 自己也是開發了很多軟體來驗證這些 design pattern,包含比較沒人知道的 HotDraw 以及很有名的 JUnit 還有 Eclipse。

結論就是,除非鄉民們對於某個領域很熟,也有多年的實務經驗,不然隨便亂找 patterns 可是會變成『誤入叢林的小白兔』,害人害己啊。

PS:Teddy 當年也很想研究 A Pattern Language for Computer Game...但是 Teddy 只會玩『青蛙過馬路』這一種等級的遊戲,所以只好放棄啦。當時真恨自己沒有從小卯起來玩 game...

***  

友藏內心獨白:言語無法形容,只能用心體會。

2010年5月8日 星期六

從 The Timeless Way of Building 學設計 (1)

05/07 23:07 ~ 05/08 01:05

有一陣子 Teddy 很熱心地不斷跟周遭認識的人『推銷』The Timeless Way of Building 這本書,告訴他們這本書有多好,多棒,看了之後可以深入了解 design patterns 背後的理論基礎 (鄉民甲:知道這個東東要幹嘛?)。有少數幾個意志不堅的朋友誤信 Teddy 之言買了這本書,但是好像都沒有人認真的去讀這本書。Teddy 當年很幸運有好學不倦的指導教授與 Teddy 一起看這本書,一起討論,所以讀起來不孤單。也許這些被 Teddy 拐騙的朋友們沒有那麼幸運能有讀伴,所以可能看了幾頁就看不下去(如果曾經有鼓起勇氣打開這本書的話...)。

也許光是靠一張嘴是沒有用的,必須要舉例子說明讀這本書真的可以幫助提昇軟體分析與設計的能力,這樣才會有誘因下定決心去讀這本書。Teddy 為了『生出』一篇部落格文章(奇怪,明明沒有料還要硬擠),在此就舉個例子說明一下。

請翻到這本書第 19 章 Differentiating Space,接下來 Teddy 節錄本章的若干句子:

Within this process, every individual act of building is a process in which space gets differentiated. It is not a process of addition, in which pre-formed parts are combined to create a whole: but a process of unfolding, like the evolution of an embryo, in which the whole preceds its parts, and actually gives birth to them, by splitting.

看懂了,恭喜老爺,賀喜夫人。看不懂也沒關係,繼續看下去,看到最後再回頭看這一段。

***

Design is often thought of as a process of synthesis, a process of putting together things, a process of combination.

According to this view, a whole is created by putting together parts. The parts come first: and the form of the whole comes second.

But it is impossible to form anything which has the character of nature by adding performed parts.

作者的意思『應該』是說設計不是把『紅茶 + 牛奶 + 糖 = 奶茶』,或是說 『客廳 + 房間 + 廚房 + 廁所 + 陽台 + 玄關 = 房子』 的一種『合成過程』。作者在書中不斷強調『建築物要有生氣 (alive)』,不是買集合式住宅蓋好直接搬進去住就好了,因為集合式住宅的建築師根本不知道誰會搬進來住,因此不可能依據個別家庭的需求來建造與設計房屋。Teddy 『猜想』作者的想法應該比較接近日本電視節目『全民住宅改造王』那樣,要考慮到個別居民(家庭)的需求以及住宅地點特性來設計與建造。但是,要如何達到這樣的目的?請看下去。

***

It is only possible to make a place which is alive by a process in which each part is modified by its position in the whole.

In short, each part is given its specific from by its existence in the context of the larger whole.

This is a differentiating process.

設計應該是一種『差異化』(有人翻譯成『分化』...聽起來好像是要搞破壞...)的過程。什麼意思?上面這幾句應該很清楚了:每一個 part 要依據它所在位置的『地形地物』(context) 來調整,修正。這種調整,修正就是一種『差異化』的過程,使得這個 part 可以適應其所在的特定的『地形地物』。還是太抽象...Teddy 也知道...舉個例子,前一陣子 Teddy 看了另一個日本的節目,內容也是和蓋房子有關。一對夫妻在山坡地上買了一小塊地要蓋房子,建築師考慮到太太在廚房作家事時(站著)也可以和坐在客廳地板上的先生在聊天時有『目光接觸』,而不是只聽到彼此的聲音而已,以便增加夫妻相處時間的感情。夫妻都是上班族,每天一大早就要出門搭很久的電車到公司,平常在家裡相處的時間並不長。因此建築師特別做了兩項設計:
  • 把廚房安排在客廳旁邊
  • 廚房和客廳之間有若干 落差(好像是廚房地面比客廳地面要矮 50 公分之類的)
一般正常情況下我們都不希望室內有任何落差,尤其是家裡有老人家或是行動不便的人。因為就算是幾公分的落差都可能造成不便或是不小心跌倒。在這個 case 中,建築師設計了 50 公分這麼高的落差,乍看之下覺的很『瞎』(有多瞎...大概和『熊貓人』差不多瞎),但是這樣的設計,卻是可以讓太太在廚房作家事的時候,眼睛就可以直接看到坐在客廳地板上的先生的眼睛 (目光接觸),看到電視畫面之後覺的真的很完美。

因為屋主的錢大部分都花在買地上面了,剩下蓋房子的預算變得很少,因此設計師只能減少蓋房子的建地面積(就是蓋小一點的房子,例如本來可以蓋 50 坪現在只能蓋 30 坪之類的 )。加上屋主夫妻的特別需求,因此出現了有『落差』的室內空間。這就是『差異化』的過程,這種差異化使得這棟房子和全世界其他地方的房子都不相同,住在屋內的人也因為這樣的設計生活的很愉快。

***

書的內容就先講到這邊(因為 Teddy 已經超過就寢時間),那麼上面屁了這一大段,到底和『軟體設計』有何關聯?長話短說,用兩點說明:
 
  • 許多 design patterns 的初學者經常犯的一個應用 patterns 錯誤就是以為只要直接把 pattern A + pattern B + pattern C = System X。這種設計思考模式通常做出來的 System X 會變成四不像,雖然『設計圖上』看起來很熱鬧,這邊一個 pattern,那邊又一個 pattern,但是仔細一看又覺的這個設計怪怪的,但是卻又說不出為什麼怪怪的。這就是看這本書的用途啦,現在鄉民有幸讀到 Teddy 這一篇,就可以大聲說出:光是用『合成』的方式是無法得到好設計滴
  • 既然用合成方式不行,那麼到底要怎樣用『差異化』來設計軟體?簡單舉例,講錯不負責(周公在趕 Teddy 了,無法仔細思考):首先,要有 whole 與 part 的概念,然後當逐一將 part 擺到 whole 裡面的時候,依據 part 所在的位置調整 part 使其可以完美的融合到地形地物之中,最後變成其中不可分割的一部分。還是有聽沒有懂... 假設把 software architecture patterns 當成是 whole,design patterns 當成是 parts。今天有某個設計,預計採用 layered architecture (whole),其中 UI layer 要用 MVC (part),而 MVC 裡面用了 observer pattern (此時 MVC 變成 whole, observer 變成 part...),但是由於這個 AP 是一個網路分散式系統,因此 View 可能在網路的不同端,因此這個 observer pattern 就和 GoF 中標準的 observer 有點不同 (差異化)。仔細讀一下 design patterns 這本書,書中有很多 patterns 其實也都有提到差異化的作法,例如 proxy pattern 就可以依據應用環境再區分為 remote proxy, virtual proxy, 與 protection proxy。
***  

要做好差異化其實不是一件容易的事情,很多設計成功與失敗的地方,就在於差異化的好壞。大家平平都是套用差不多種類的 patterns,為什麼有的人開發的系統就比較容易了解,開發與維護,有的人的系統就好像麵線一樣,一坨一坨黏在一起。


讀懂 GoF 的 Design Patterns: Elements of Reusable Object-Oriented Software 可以從物件導向的角度來解釋設計,讀了 The Timeless Way of Building 讓鄉民們可以用更一般性,更抽象的觀點來解釋設計,這也是讓自己與一般平民百姓有所區別的『差異化』過程喔。

*** 

友藏內心獨白:奇怪了,Teddy 又不認識作者也不是出版社的人幹麼一直推銷這本書?

2010年5月7日 星期五

兩分鐘能講什麼?

05/06 23:09 ~ 05/07 00:20

母校資工系(所)成立即將滿 10 週年,系上邀請畢業的系友下個禮拜回去聚會,並準備成立系友會。雖然 Teddy 才畢業一年半,但是由於 Teddy 的年齡屬於『資深系友』等級,系主任基於台灣人傳統的『敬老』美德,請 Teddy 代表畢業系友在聚會開始時發表『兩分鐘』談話。系主任有交代,在這兩分鐘內談一下系上給 Teddy 哪些訓練使得 Teddy 可以在險惡的社會中存活下來。Teddy 左想右想,關於這樣的談話,有兩個疑問:

  1. 參加對象和 Teddy 一樣都是系友,Teddy 走過的路他們也都走過(修過的課,寫過的作業,考過的試,罵過的xxx)。那還需要 Teddy 多說嗎?
  2. 真的要說,兩分鐘哪夠用啊。

所以,Teddy 就在自己的部落格上無時間限制的先說一下給無辜的鄉民們聽。如果要用一句話來說明 Teddy 研究所生活,那就是:

寫不完的作業

作業多到 Teddy 常常會有一種自己在念『國小』的錯覺。奇怪了,據 Teddy 從馬路上聽到的消息,台灣 許多 極少數資工研究所上課時老師都是讓學生上台報告,也沒有什麼作業,只要期末交報告就 OK 了(這就是傳說中訓練研究生思考和表達能力的方法嗎?)。由於修課很輕鬆,因此很多學生研一就把課全部都修完了,利用研二的一整年時間可以好好 寫論文。相比之下,不禁讓 Teddy 想唱『金包銀』。有一次和指導教授們談起這個問題,他們告訴 Teddy,他們當年在美國念研究所,也是有一大堆很難且寫不完的作業。聽完之後, Teddy 突然覺的自己幸福多了。

Teddy 也有修過一門不用寫作業,只要憑 唬爛功力 口頭報告就可以拿到高分的課。這種類型的課修的時候當然很爽,但是畢業之後回頭看卻是覺得很可惜,少了一次深入學習的機會(路人甲:騙肖ㄟ,學分都輕鬆拿到了才這樣說)。在研究所修課寫很多作業的訓練方式對 Teddy 這種中等資質的人來講還滿受用的,雖然寫完作業之後經常需要刷牙 (因為邊寫邊罵髒話...)。

看看時間 Teddy 也差不多該睡了,在此做個結論。念敝校資工所對 Teddy 最大的幫助有:

  • 遇到好的指導教授 (切記,這一點比什麼都重要的啦)。
  • 利用修課擴展了知識領域 (像 PSP 這種古怪的東西,要不是修課所逼這輩子應該不會想去碰)。
  • 被迫 自願讀了很多書和 papers。
  • 幫忙指導學弟妹(為了指導學弟妹讀了很多書和 papers,讀了書和 papers 之後沒事手癢又指導更多學弟妹...無限迴圈...)。
  • 養成紀錄 time log 的習慣。
報告完畢,講完收功。
 ***

友藏內心獨白:大家辛苦了,這一篇也是在擠不出料的情況下硬寫出來的...

2010年5月4日 星期二

Retrospective Meeting 之我謝謝你

05/04 22:49~23:55

10 幾年前 Teddy 退伍後出社會的第一份工作,就是到一個小公司寫程式。Teddy 是該公司第一位 programmer,後來公司陸陸續續招募了好幾位剛畢業的新人,原本是希望大家共同開發一個產品,但是公司為了生存下去,在不知不覺中接了好幾個性質各不相同的案子,導致每個人手邊都有一件以上的案子要負責。由於各自的工作都忙不過來了,因此大家都是各做各的,鮮少有團隊合作的氣氛。Teddy 還因此做過可能是台灣第一個以 Java 開發並且實際使用的『進銷存系統』,用 VB 做過『支援 one-to-one marketing』的洗衣店系統,還有一些奇奇怪怪的東西。當時 Teddy 做的累的要死,而 Teddy 的主管與公司的顧問一直灌輸 Teddy 一個觀念,『一個人負責很多案子在業界是很平常滴』,因此 Teddy 心中一直有兩個疑問:

  • 難道 Teddy 真的這麼遜嗎?為什麼案子會做的這麼累而 bugs 卻又這麼多?客戶一直要求要改東改西的,而 Teddy 只能無奈的接受?
  • 軟體開發真的是這樣嗎?一個人同時負責好幾的案子是很平常滴? Teddy 覺的就算是一個人負責一個軟體開發的案子也是一件很困難的工作,從需求訪談,寫分析文件,coding,測試 (當時還沒有什麼自動化單元測試的概念,都是人工手動測試),製作安裝程式,寫手冊,教育訓練,甚至包含要幫戶客買硬體設備,裝機,還有更慘的『後續維護』等等。

經過 N 年之後,對於軟體開發流程的知識 Teddy 已經有了更深入的了解,因此 Teddy 天真的以為大家都知道『軟體開發是一種團隊活動』錯,Teddy 大錯特錯。在台灣,很多軟體還是由一個人完成。有些軟體雖然可能有好幾個人共同開發,但是專案切分成幾個子專案,每個人認領一些模組,自己做自己的那一份工作,結果還是走回『分工,但不合作』的老路子。

不知道是不是因為大家從小為了分數競爭慣了,養成了『藏私』與『獨立作業』的習性。這樣的個性或是做事態度,對於要採用 agile methods 的開發團隊而言,是一大挑戰,也是造成導入 agile methods 失敗的主要原因之一。要如何『根治』這個問題,Teddy 也不知道,不過有一個『小撇步』對於採用 Scrum 的團隊可以參考一下,就是在 retrospective meeting 的時候實施一個『感謝 某某某』的活動。


這個方法是 Teddy 從 Agile Retrospectives: Making Good Teams Great 這本書學來的,作法很簡單,就是在 retrospective meeting 的時候,請每個團隊成員輪流感謝在這個 sprint 當中幫助他的其他團隊成員,例如:

小胖:我要感謝『小明』,在和他 pair programming 的時候他教我如何在 Eclipse 中使用 refactoring 工具。

小英:我要感謝『阿呆』,他在測試的時候找到好幾個我程式裡面的 bugs,讓我可以把功能做對。


阿呆:我要感謝『小英』,當我找到 bugs 的時候,她很快就把這些 bugs 修正了,讓我可以繼續測試下去。


小明:我也要感謝『小英』,他告訴我要如何修改持續整合系統的 ant script,讓我可以把新增加的模組放到持續整合系統上面。

小胖:我要感謝 ...


就這樣繞一圈一直感謝下去,如果團隊成員沒有對象可以感謝了,那就說 pass,一直到所有的人都 pass 為止。以 Teddy 的經驗,通常繞個三圈左右就差不多大家都 pass 了,所以這個活動只需要短短幾分鐘的時間 。當聽到別人公開的感謝你的時候,心情總是會比較愉快一點。就算在開發時有些不爽的情緒,也會因此慢慢氣消。此外這個活動還會有一種很奇妙的正面效果,讓團隊成員在之後的 sprint 中更願意幫助其他團隊成員 (因為如果你從頭到尾都沒有被別人感謝到,這樣會覺得自己挺遜的...XD)

Teddy 覺的這是一個 C/P 值頗高的活動,有興趣的鄉民不妨一試。

友藏內心獨白:說感激,說不完的感激... (用唱的)

如何估算 story point?

5/03 22:29 5/04 00:30

前幾天實驗室學弟問了 Teddy 一個在 Scrum 中如何估算 story point 的問題,在此 Teddy 談一下自己曾經試過的兩種估算方法。首先假設 Scrum 團隊有四個開發人員,每一個 sprint 長度為兩週 (10 個工作天)。

方法一

【2015/05/26】方法一已不建議使用,請直接看方法二。原因請參考Scrum 是什麼(13):為什麼不建議使用focus factor?〉。

首先將 1 個 story point 定義為『一個理想的工作天 (八小時)』。在估算Story 與 Task 的時候採用相同的單位 (也就是都以 story point 估算來估算),並使用 focus factor 來調整團隊實際可貢獻於專案的時間。

這個方法是 Teddy 從《 Scrum and XP from the Trenches》這本書學來的,在 sprint planning 開始的時後,要知道這個 sprint 可以挑多少 story 出來做,首先就要估算這個團隊可用的 story point。估算方法如下:

開發人數 x 可以獲得的工作天數 x focus factor

在一個四個開發人員,sprint 長度為兩週的專案裡 (沒有人請假,如果有人請假要扣掉請假的天數),可以得到

4 x 10  = 40, 也就是說理想上這個團隊有 40 個 story points 可以使用。也就是說,理論上這個團隊可以完成 40 個 story points 的需求。

但是大家都知道,不可能一天 8 個小時都在從事開發工作,有時候要開會,回 e-mail,MSN 打屁一下,泡杯咖啡,上廁所,吃下午茶等等。有時候要回答客戶問題,或是應付老闆三不五時丟出來奇怪的要求。也可能公司環境太吵或是在大熱天冷氣突然壞掉,害你無法專心寫程式。有太多因素造成實際上不可能達到 40 story points 這個『理想值』。所以,就必須要把這個理想值打個折,至於要打幾折的這個數字,就叫做『focus factor』。focus factor = 1 就表示理想值 (買東西不打折),facus factor = 0 就表示沒有任何生產力 (買東西不用錢啦)。當然 1 和  0 應該都是不合理的數值,至於這個值應該要給多少,每個團隊不一定,總之概念上就是 focus factor 越高表示團隊專注力越高,也就是大部分的時間都可以用來從事 sprint planning 所規劃的開發活動。對於一個剛開始採用 Scrum 的團隊,可以選用 70% 左右的值。

所以,我們得到了 40 * 0.7 = 28 (story points)

接下來假設  Product Owner  挑選了 A, B, C, D, E 這五個 stories,團隊成員估算出這五個 stories 的 story point 分別為:

A : 8 story points   ......8
B : 5 story points   ......13
C : 13 story points ......26
D : 3 story points   ......29
E : 5 story points    ......34

由於團隊預計只有 28 story points 可以使用,如果要完成 A-D,則需要 29 story points,因此如果保守一點那麼這個 sprint 就只會挑出 A-C (26 story points) 這三個 stories 來施工。當然此時 Scrum Master 也可以詢問團隊成員,是否有信心可以完成 A-D,如果大家都覺的 ok,那麼也可以挑選 A-D 。

假設我們保守一點選擇了 A-C 這三個 stories,接下來就是將 story 細分,列出完成每一個 story 所需的 tasks (task 才是真正的施工內容)。典型的 task 有:寫 acceptance test cases, 設計物件,設計介面,設計資料庫,coding,unit testing,寫文件等等。基本上估算 task 所使用的單位應該是『小時』。但是由於 story point 是沒有單位的 (當然你可以用 1 story point = 8 hours 這種『匯率』來換算),如果估算 story 用 story point,而估算 task 用 hour,那麼團隊成員會不自主的去換算,造成估算困擾,因此有一種簡單的方法就是 task 也用 story point 估算。

舉個例子,假設 Story A 是 8 story points,經過 task breakdown 之後團隊列出了以下幾個 tasks:

  • Write acceptance tests: 8 hours (1 story point)
  • Design UI: 8 hours (1 story point)
  • Write UI code: 13 hours (1.625 story point)
  • Write DAO code: 13 hours (1.625 story point)
  • Write DAO unit tests: 8 hours (1 story point)
  • Test: 5 hours (0.625 story point)

Task 所需時間加起來 55 hours = 6.875  story points。這時候你會想,ㄟ (馬總統上身),剛剛估算 Story A 是 8 story points,但是實際列出完成這個 story 所需的 tasks 只需要 6.875 story points,那麼是要把 Story A 改成 6.875 story points,還是增加 task 所需的時間,想辦法把 task 的總時間也變成 8 story points?不知道鄉民們在剛開始嘗試 Scrum 時會不會有類似的困擾?Teddy 剛開始採用 Scrum 時是有這樣的困擾,也嘗試過三種修正方案:

  1. 不理他,還是用原本估算的 Story 所得到的 story point 來作為這個 sprint 可以完成多少 stories 的依據。
  2. 不理他,但是改用所有 task 加總的時間來作為這個 sprint 可以完成多少 stories 的依據。
  3. 改用 bottom-up 的方式來估算一個 Story 的 story point。也就是說,先不估算 A, B, C, D, E 的 story point,而是直接做 task break down,然後把每一個 story 的 task 的加總作為該 story 的 story point (有點繞口)。

先講修正方案三,這種方法開發人員很容易了解,但是其實是不太符合 Scrum 精神。因為原本估算 story point 的目的是用來評估不同 story 之間的『相對大小』,並不是要得到一個精確的數值說 Story A 是 6.25 story points,Story B 是 5.125 story points ...。先估算 task 然後再把 task 加總的時數換成該 Story 的 story points 看起來很合理也比較『精確』,但是卻完全失去了原本估算 『Story 相對大小』的精神,而且還會引伸出『當實際施工時,發現原本估算的 task 時間不準,那麼是否要重新調整 Story 的 story point 這類的問題』 。

***

後來 Teddy 上過 Certified ScrumMaster 課程之後,慢慢體會修正方案二應該是比較好的方法,這也衍生出 Teddy 在這邊要介紹的第二種方法:

方法二

估算 Story 採用 story point,估算 Task 採用小時。Story point 本身沒有單位,每一個 Story 的 story point 是採用『相對大小』來估算的,不用拘泥於 1 story point = 8 hours 這樣的單位換算。至於每個 sprint 可以完成多少 stories,則是以 task 加總的時數來計算。

在 sprint planning 開始的時後,要先計算團隊在這個 sprint 可用的『工作時數』,計算方法如下:

開發人數 x 可以獲得的工作天數 x 每日工作小時

在一個四個開發人員,sprint 長度為兩週的專案裡 (沒有人請假,如果有人請假要扣掉請假的天數),可以得到

4 人 x 10  天 x 一天工作時數 (5 小時) = 200 小時

這邊雖然省略了 focus factor,直接填入團隊(平均)每天可實際投入開發的時數,當然這個時數也是打過折的,所以效果和 focus factor 是類似。Teddy 曾經在某本書中 (忘了哪一本了) 看到一個員工平均一天可以有 5 個小時不受干擾的工作時間就已經很不錯了,因此後來 Teddy 都直接用 5 個小時來估算團隊可以投入的時間。

得到了預計可以投入的工作時數之後,其他的步驟就和 Teddy 在方法一中所說得很類似了,只是這個 sprint 可以完成多少 stories 是在估算 task 階段才決定的。以剛剛的例子:

A : 8 story points   ......8
B : 5 story points   ......13
C : 13 story points ......26
D : 3 story points   ......29
E : 5 story points    ......34

當估算完 Story 的 story points 時,這時候還不確定可以完成多少個 stories。假設經過 task breakdown,得到完成這些 stories 所需的時間為:

A : 55 hours       ....55
B : 16 hours       ....71
C : 48 hours       ....119
D : 22 hours       ....141
E : 25 hours       ....166

結果發現雖然 A-E 的 story points 為 34,但是實際施工預估時間卻只要 166 小時,所以在這個 sprint 除了可以完成 A-E 之外,還可以再選新的 story 進來。

鄉民甲:為什麼 Story A (8 story points) 需要 55 小時,而 Story C (13 story points) 明明比 Story A 要大,卻只要 48 小時?是不是代表 Story C 的 story points 要重估?

Teddy 回答:不需要。再強調一次,Story 的是估算彼此之間的『相對大小』,例如,你要做使用者新增,查詢,刪除,修改這四個 stories。團隊成員認為這四個 stories『大小』是差不多的,因此都估 5 story points。假設你在 Sprint 10 先完成了『新增』這個 story,由於這是這系列的第一個 story,你需要設計資料庫,所以你花了 35 小時,但是後面三個 stories 並不需要設計資料庫,你可能分別花了 28, 25, 31 小時。實際施工所花的時間會受到很多因素影響,例如認領工作的人對於該工作的熟悉度,是否在該工作中使用到新的技術,不確定性的高低,發生難解的 bugs,生病或是和男女朋友吵架導致精神不佳等等。但是這並不代表『Story 的大小改變了』,所以不需要因為 task 預估或是實際花費的時間來修改 story points,除非當初估算 story 的相對大小估錯了。

再舉個日常生活的例子。老師叫學生去操場拔草,小胖身強體壯,『預估』只要 1 小時就可以拔完。如果是換成瘦小體弱的小英,則『預估』需要 3 小時。同樣一個 Story (操場拔草),小胖 1 個小時可以做完,小英需要 3 小時,我們需要重估這個 Story 的『大小』嗎?當然不需要,因為操場裡面的草,不會因為要去拔它的人不同而有任何改變。所以,只要在估算所有 story 時採用『相對大小』的方式來預估,那麼就不需要因為『預估』所需完成該 story 的 task 時間或是『實際完成』的 task 來重新調整 story point 了。長此以往,團隊還是會得到一個穩定的 velocity (每一個 sprint 實際完成的 story points)。

***

友藏內心獨白:以上來賓言論不代表本台立場。