l

2011年12月31日 星期六

突然很想做專案(2)

December 31 12:08~13:04


昨天提到因為好友的專案成員(程式設計師)全部都是人力派遣過來的,全盛時期人數多達十數人,而且這些程式設計師是來自於幾個不同的派遣公司(因為同一家公司派不出這麼多人)。這些人力派遣公司所派出的程式設計師程度參疵不齊,而且工作態度通常不是很積極。這也不能怪他們,因為從他們的角度來看,他們只是被『販賣鐘點的工人』而已,實領薪水通常不高而且工作相對的也不是很有保障,未來發展也有限。據說運氣好的可能被客戶單位給相中,專案做到最後跳槽到客戶單位當全職員工


這還不打緊,好友這個專案的系統設計師(system designer)除了有一位是好友公司的員工外,其他幾位也是從人力派遣公司找來的。據好友表示,設計出來的分析文件,只要能夠清楚說明要從資料庫那一個表格(table)撈出那些資料,然後把資料再丟到那些表格中,這樣就該偷笑了。


聽到這邊,Teddy 傻住了。ㄟ,這樣的專案運作方式,這樣的團隊成員組成模式,這...要如何改善?


***


Teddy:有可能讓程式設計師做 pair programming 嗎,這樣可以讓程式設計師彼此之間『互相 監督 學習』(如果兩人一起作弊打混那就沒轍了...Orz),而且寫出來的程式問題應該會比較少。


好友:聽起來雖然可行,但是有兩個問題。首先,要專案經理(PM)同意,否則上層的人還是會有哪種『兩個人一起寫程式產出速度變成一半的疑慮』。其次,這些程式設計師來自四面八方,背景各不相同,很有可能在做 pair programming 的時候認為自己的作法最好,互不相讓吵起來。


Teddy:(舉白旗)投降。


***


仔細思考一下,好友的專案(應該說在台灣幾乎全部的專案)是採用傳統的『瀑布型流程(waterfall process)』,所以 coding 這件事,在專案中其實是最沒價值的,基本上就跟出賣勞力的工人是一樣的。所以根本沒人重視,反正要 coding,就從 台北橋下 人力派遣公司找一批『便宜的牛肉(便宜的人力)』就好了


這種想法已經根深蒂固地存留在台灣每間做專案的公司,Teddy 居然還傻傻地妄想要去改變這個現象,果真是涉世未深。幾天 Teddy 在 YouTube 上面看到 Linda Rising 女士在 Agile Connect 2011 的主題演講,題目是: Deception and Estimating - How We Fool Ourselves。裡面有一段 Linda Rising 引述 Max Planck(不知道此人是誰?)的一段話,聽完之後 Teddy 覺的真是太有道理了:


A new scientific truth does not triumph by convincing its opponents and making them see the light, but rather because its opponents eventually die, and a new generation grows up that is familiar with it. 


一個新的科學真理並非由說服反對者並使其相信而獲得成功。相反地,是因為這些反對者最後都掛點了(上天堂...XD),而新一代的人長大之後習慣了這種新的說法,所以就接受它了。


Linda Rising 開玩笑的說,等 waterfall 的人逐漸凋零之後,agile 就可以變成主流了。


看到這裡,Teddy 突然覺的自己怎麼這麼笨啊,沒想通這個道理。不過,等這些 waterfall 的人逐漸凋零之後,Teddy 也可能 60-70 歲了,應該也無法開發軟體了...Orz。


結論,ㄏ一....把自己的事做好先,這種移風易俗的偉大事業,就交給有能力的人吧。


***



友藏內心獨白:國父有交代,『有一人之力服一人之務;有十人之力服十人之務;有千百人之力,則服千百人之務』。 像 Teddy 這種聰明 財力 才力較小者,還是想想怎麼把自己養活先...Orz

2011年12月30日 星期五

突然很想做專案(1)

December 30 08:54~10:09


昨天午 Teddy 又厚臉皮的跑去找一位好友吃飯兼聊天,由於這位好友目前正在客戶端帶領若干個外派的程式設計師做專案走不開,於是就和 Teddy 直接約在客戶端的餐廳見面。好友已經卡在該專案一年半以上的時間,專案預計結案時間也延了 6 個月,現在已經接近收尾的階段(至少好友內心希望是這樣的...XD)。


好友提到最近客戶對系統執行一系列的壓力測試,看看系統的效率(performance)與同時上線人數(concurrent users)的極限在那裡。在測試的過程中,客戶也發現了系統對於『例外處理』有許多沒有考慮周詳的地方。由於當初的系統分析,設計幾乎都只有寫出『正常流程(normal scenarios)』的處理方法,對於例外鮮少描述。但是,分析文件客戶也看了啊,也簽名了,所以最後雙方就開始想辦法說服對方『這是你們的疏失』。當然廠商通常還是被ㄠ的那一方,但是至少要讓客戶覺的『你欠我們一個人情』,而不是因為『廠商當初沒有考慮到』。


***


聊到這邊 Teddy 感觸很深,因為 Teddy  的博速論文就是研究『例外處理設計』,這在軟體開發中基本上都是被忽略的一環,但是,如果你的軟體系統是要能夠『長時間執行不關機』的那一種,例外處理設計就變得很重要。不過例外處理設計不是今天 Teddy 想談的主題... 。


後來繼續聊著聊著突然聊到測試這件事,由於之前 Teddy 的另一位在做專案的好友告訴 Teddy,他們公司的高層告訴他:


做專案是不需要做自動化測試的,做產品才要(請參考 600 多個 bugs 要怎麼修?


於是 Teddy 也問了好友同樣的問題,你們的專案是否有做自動化測試?


很遺憾的,好友的專案並沒有做自動化測試,而且好友以前所參與過的所有專案,也都沒有做過自動化測試。根據好友的經驗,在台灣寶島做專案好像真的沒有人有在做自動化測試。


***


Teddy:為什麼不做自動化測試呢?


好友:因為一般人的直覺反應都是,如果寫了自動化測試,會拖慢寫程式的時間。換句話說,寫程式的時間都不夠了,那有時間去寫自動化測試


Teddy:那專案有因為沒寫自動化測試而準時上線的嗎?


好友:沒有,幾乎所有的專案都是 delay 居多。


Teddy:那大家都習慣了專案延遲,這樣做專案不是會虧本?


好友:在估算專案成本的時候,已經先 灌水 預留延遲 3 個月的成本,所以只要不延遲太久,還是有的賺。


***


聊到這邊 Teddy 心中突然想到一個名詞,


能量不滅定律(能量守恆定律)
Energy can neither be created nor be destroyed: it can only be transformed from one state to another. 


Teddy 認為,把一個專案做到一定的品質並結案,其『最少工作量』是不變的。省略了自動化測試,看起來好像少做了一件事,可以把時間省下來寫程式,但是太多實務經驗已經告訴我們,這是錯誤的想法。『 it can only be transformed from one state to another 』,跳過『自動化測試這個階段』,那麼原本應該花在自動化測試的時間不會消失,而是跑到『長時間 debug』與昂貴的『人工測試』上。後者(長時間 debug 與人工測試)的成本其實是遠大於投資在自動化測試的成本


『人工測試』最大的問題就是無法做 regression test,也就是說不能像自動化測試案例一樣可以不停的重複執行。為什麼要不停的重複執行?還記得 Teddy 在『亂談軟體設計(2)』裡面提過一句至理名言:


開發軟體最怕的不是『寫程式』或是『不會寫程式(寫不出程式)』,最怕的是『程式(改那些原本已經寫好測試過可以動的程式)


為什麼最怕改程式,因為相信大家都有這樣的經驗,改完程式之後原本可以動的其他程式卻不能動了,更慘的是,你可能不知道到底那些地方被改壞了,所以後續還要花費很多時間來『debug』。其實軟體開發(不管是做產品或是做專案)真正花在所謂『寫第一遍程式』的時間應該不到 1/3(搞不好不到  20%),那麼其他時間都在幹嗎?改程式(因為需求不清或是需求改變而改程式),debug,以及 testing 的時間加起來絕對是遠遠超過所謂的 coding(寫第一遍程式) 的時間。


所以,要如何加速專案的進行,讓專案『有可能』可以準時上線,或是至少不要延遲太久?答案很簡單,減少改程式,debug 與 testing 的時間


***



Teddy 也同意人工測試是必須的,但是光是依靠人工測試要達到一定的軟體品質,那麼花在人工測試的成本絕對是遠遠.............遠大於花在撰寫與維護自動化測試案例的成本。而且從另一個角度來看,如果你是客戶,當廠商把 source code 交接給你的時候,同時還附上一堆自動化測試,請問你對這個廠商所開發出來的系統是不是會比較有信心?下次如果還有案子,你會想找一個有提供自動化測試案例的產商,還是一個用人工方式做測試的廠商?



***


有一次 Teddy 在做 Scrum 經驗分享的時候,曾經有鄉民問 Teddy:


鄉民:Scrum 雖然聽起來很好,agile practices(例如持續整合,自動化測試,pair programming)也很好,但是我要如何說服公司採用呢?


Teddy:請問您公司的專案有曾經準時結案過的嗎?


鄉民:沒有耶。


Teddy:那有什麼好怕的,現在都已經這麼爛了,就以『死馬當活馬醫』的心態,採用 Scrum 與 agile practices  不會更差了。


***

這個故事還沒講完,因為好友的專案成員幾乎都是人力派遣過來的,所以 Teddy 下一集再來稍微談一下這個問題。

***


友藏內心獨白:Teddy 10 幾年前作專案也是沒寫自動化測試,也是都延遲(因為當初沒有人教 Teddy 啊)。怎麼過了 10 幾年做專案的方式都沒改善啊。





2011年12月29日 星期四

Scrum 是什麼(2):Scrum 的內涵

December 29 08:52~11:49

螢幕截圖 2015-05-20 23.54.01

泰迪軟體【Scrum敏捷方法實作班】招生中。

***

Scrum 是什麼(1):雙重回饋機制〉提到鄉民們可先簡單將 Scrum 視為一種敏捷專案管理框架(以官方說法,Scrum是一種流程框架),而 Scrum 與傳統專案管理最大的差異之一,就是 Scrum 擁有雙重回饋機制。這一集要談一下 Scrum 的內涵。

Scrum 的內涵可以透過兩張圖來說明:

  • 靜態圖:說明 Scrum 三個主要元素角色(roles),活動(activities)與產出物(artifacts)的意義。
  • 動態圖:說明上述三個元素之間彼此的互動關係。



▲Scrum 靜態圖




▲Scrum 動態圖


以上這兩張圖是 老師傅手工打造 Teddy 精心繪製的,請慢慢享用。首先看到 Scrum 靜態圖:

  • Role:Scrum 的角色可以分成兩大類,第一類叫做主要角色(core role),包含 Product Owner,ScrumMaster 與 Team(Developer),此三者合稱為Scrum Team。第二類叫做輔助角色(ancillary role),包含 stakeholder(利益相關者) 與 manager。廣義的來說,和軟體開發專案有關,但是卻沒有實際參與專案開發活動的人,都可以稱之為 stakeholder。所以鄉民們可以把輔助角色都稱為 stakeholder。在這張圖中,把輔助角色區分為 stakeholder(customer, vendor)這些公司以外的人以及 manager(專案經理或是老闆等)公司內部的人,不過鄉民們可以不用理會(迷之音:那幹麼把圖畫成這樣?!)。主要角色的責任為:
    • Product Owner(PO,產品負責人)與開發團隊合作一起定義產品需求,負責產品成敗。Product Owner 顧名思義就是「產品擁有者」,在傳統公司中「Product Manager」算是比較接近PO的角色(但不完全相同)。PO 在 Scrum 專案扮演客戶代表,負責管理產品需求並決定需求的施工順序(產品需求大多以user story 的形式呈現),並且當 Developer 對於產品需求不清楚的時候,要負責回答問題與釐清需求如果這個開發到最後不幸產品失敗了(可能因為客戶不喜歡),那麼 PO 要 有種 有擔當的負起全責,不可以把失敗的責任推給其他人。 (2017/04/26 revised)
    • Scrum Master(SM,Scrum大師):協助團隊依循敏捷開發與Scrum 精神來開發軟體,確定 Scrum 所規範的幾個活動都有定時且正確的進行。協助團隊持續改善開發流程,協助排除任何阻礙開發活動的事件(例如,不必要的會議與來自老闆突發的干擾)。
    • Developer(開發人員):負責開發軟體。Scrum 強調團隊成員的組成應該是一個 跨職能團隊(cross-functional team,團隊中要有能夠完成專案的所有人才,包含 UI/UX 設計、程式開發、資料庫操作以及測試人員等等。而且這些人才最好能夠擁有多技能(multi-skills),例如設計 UI 的人也能夠寫點程式或幫忙測試,寫程式的人也能夠操作資料庫或是做 UI 端的程式設計等等。
  • Activity:Scrum 的活動包含了:
    • Sprint planning meeting:在每個 sprint 開發活動的第一天,團隊要舉辦此會議,主要用意有兩點:(1)挑選這個 sprint 所要開發的需求(stories),(2)逐一將每一個 stories 細分為若干個 task(施工項目),並且估算完成每一個 task 所需的時間(以小時計算)。PO,SM 與 Developer 都需要參與這個會議,在此過程中,強調團隊成員之間的對話,藉由對話讓需求變得越來越清楚,使得 Developer 開始施工之後比較清楚「到底要做什麼」以及「該怎麼作」。此會議結束會產生一份叫做「Spring Backlog」的東東,基本上 Spring Backlog 就是這個 sprint 所以施工的需求(以 story 的方式撰寫)。
螢幕截圖 2015-05-25 05.30.25

▲Sprint planning meeting


    • Daily Scrum:每日Scrum,是一個重新規畫(replan)會議,讓團隊修正達成sprint目標的方法。會議通常以站立方式進行,在15分鐘之內舉辦完畢。在會議中團隊成員報告三件事情(1)昨天做了什麼以協助團隊達成sprint目標,(2)今天準備做什麼以協助團隊達成sprint目標,(3)有沒有遇到任何阻礙團隊達成sprint目標的事情(2018/07/04修訂)。


螢幕截圖 2015-05-25 05.26.26

▲Daily Scrum


    • Sprint:為期 2-4 週的開發活動,Teddy 的經驗是採用 2 週長度的 sprint。當一個 Scrum 團隊選擇 sprint 長度(例如 2 週)且實施過一段時間穩定下來之後,最好不要任意改變 sprint 長度(例如改成 3 週或四週),以避免打亂開發的步調。
    • Sprint review meeting:Sprint檢視會議,當 sprint 結束的那一天會舉辦此會議,參加對象至少包含 PO,SM,Developer 並可邀請輔助角色來參加。此會議主要是要展示團隊在此 sprint 中所完成的每一個 story,並且讓 PO 確認這些 story 有做到他心目中所想要的程度。PO 透過實際的軟體展示,可能會引發新的想法,那麼這些新的想法就可能變成新的需求,移到後續的 sprint 中實做(PO 要決定需求的施工順序)。

螢幕截圖 2015-05-25 05.37.16

▲Sprint Review


    • Sprint retrospective meeting:Sprint回顧會議,參加對象主要為 SM 與 Developer,如果 PO 有需要也可參加。此會議主要目的為檢討與改善『軟體開發流程』,在會議中開發人員列舉出在此 sprint 中有那些開發流程是好的,要繼續維持,有那些是不好的或是沒做到的,應該要改善的項目。最後團隊討論出改善行動方案(action plan),在下一個 sprint (或是連續若干個 sprints)中實施此改善項目。改善項目不要太多,因為假設一個 sprint 才兩週,不太可能改善一大堆問題,以 Teddy 的經驗通常改善行動方案只列出一條,例如,30% 的 tasks 都要採用 pair programming 的方式施工,或是 build 一次軟體的時間要縮短為 10 分鐘等等。

螢幕截圖 2015-05-25 05.34.47

▲Retrospective


    • Product backlog refinement meeting:又稱為Product Backlog Grooming,這個活動主要目的是讓 PO 與開發團隊每個 sprint 抽出 5%-10% 的時間來檢視 product backlog 裡面的項目,然後挑選一些下一個 sprint 準備要施工的 stories。
  • Artifact:Scrum 的產出物(文件)包含了:
    • Vision:遠景,老闆或是專案資助人有一個夢,然後團隊要把這個夢變成需求並且把實際的東西(軟體)給生出來。
    • User story:Scrum沒有規定需求要用何種方式撰寫,但許多Scrum團隊會將需求以user story(用戶故事) 表達,如果有學過 use case (使用案例)的人,可以把一個 user story 想像成一個 use case 中的一條執行路徑或是一個劇情(scenario)。一個典型的 user story 長成這樣:As a user, I can do [什麼功能] so that [獲得什麼好處]. 例如,As a user, I can install the software so that I can use it later.
    • Product backlog:所有關於此專案或是產品的代辦事項就稱為 product backlog,放在 product backlog 裡面的東西稱為product backlog item(PBI),需要依據優先順樹經過排序,比較重要,比較優先要施工的 PBI放在前面。鄉民們可以直接用 excel 來紀錄 product backlog,當然也可以用支援 Scrum 的軟體系統(例如免費的 ezScrum)甚至是一般的文字檔來管理 product backlog。
    • Sprint backlog:Sprint backlog 就是某一個 sprint 準備施工的 user story(可以想成是 product backlog 的子集合),同樣的 sprint backlog 裡面的 story也是要排序過的,比較重要的先開工。
    • Task:Task 是完成 Story 的施工項目,在 sprint planning meeting 時,團隊會將每一個 story 再細分若干個 task。典型的 task 有設計使用者介面,coding,寫自動化單元測試程式,設計資料庫表格格式,寫 DAO(data access object),寫自動化功能測試,寫使用手冊等等。
    • Burndown chart:嚴格講起來 brundown chart 可以分成三種,從大到小分別是 release burndown chart, story burndown chart 以及 task burndown chart,在這邊先解釋 task burndown chart 。在 sprint planning meeting 結束之後,先把所有 stories 的 tasks 施工的小時數加總起來,假設有 250 小時。然後第每一天 daily Scrum 會議之後,Developer  會報告說有一些 tasks 已經被做完了,假設第二天有 15 小時的工作已經完成了,那麼Scrum 團隊就可以畫一張圖,把 250 小時減掉每天完成的工作時數,剩下來的就是尚未完成的工作。所以只要每天看這張 burndown chart,團隊就可以知道進度是否正常(理論上在 sprint 最後一天剩下未完成的工作時間應該是 0)。


螢幕截圖 2015-05-25 05.23.50
▲Taskboard與 burndown chart

    • Running software:在 sprint 結束時,團隊要能夠產出一份 potentially shippable product increment,也就是說這個 sprint 所增加的軟體功能如果客戶馬上就要的話,要可以交付給客戶。所以要確定團隊隨時間可以產生一份 running software(自己開發的軟體要隨時都處於可執行的健康狀態)。
    • Sprint info page:後面這三項文件不是 Scrum 正式規範的文件,是 Teddy 從 Scrum and XP from the Trenches 這本書學來的,不過因為 Teddy 自己實際用了三年多覺的還滿有用的,所以一併介紹給鄉民們。當 sprint planning meeting 開完之後,Scrum Master 會寫一份 sprint info page 文件,這份文件包含了 sprint goal(這個 sprint 的目標)還有列出這個 sprint 所要施工的 stories,sprint 開始與結束時間,以及團隊成員。然後 Scrum Master 將這份文件寄給 Scrum Team 以及其他有興趣的輔助角色人員,讓他們知道一個新的 sprint 已經開始了。
    • Sprint demo agenda:Sprint 結束前一天(sprint demo meeting  前一天中午 12:00 之前)Scrum master 要寫出 sprint demo 的議程表,並將此文件寄給 Scrum Team 與其他有興趣的輔助角色人員。此議程表包含所有要 demo 的項目,以及每一個 demo 項目要花多少時間,由誰負責 demo。所以當 Developer 收到該議程表時,就可以準備明天要 demo 的資料。
    • Sprint summary report:當開完 sprint retrospective meeting 之後,Scrum Master 會準備此文件,文件內容包含對於本次 sprint 所完成功能的簡述,完成多少個 story points,團隊成員在 sprint retrospective meeting 中所列出好的以及有待改善的項目(Teddy 最多只各列三點),以及改善行動計畫。同樣的,將此文件寄給Scrum Team 以及其他有興趣的輔助角色人員,讓他們知道這個 sprint 已經正式結束了。
***

參照上面對於 Scrum 每個元素的解釋, Scrum 動態圖就應該很容易了解了。


泰迪軟體【Scrum敏捷方法實作班】招生中。

***

友藏內心獨白:寫這一篇又是破紀錄的久,突然有一種這一系列寫完又要去醫院做復健的不祥預感...Orz。

2011年12月28日 星期三

感謝鄉民鼎力相助

December 28 15:31~15:41


Teddy 剛剛從出版社回到家,跟某位漂亮又有氣質的編輯談了一下關於書籍出版的事情(這算是公開拍馬屁嗎...XD)。Teddy 很好奇為什麼該位出版社編輯小姐會知道 Teddy 想要出書,原來是他們公司集團有其他軟體開發部門的某位工程師有在看 Teddy 的部落格,將 Teddy 想要出書的訊息傳達給該位編輯


聽了之後真是『揪感心』,感謝這位不知名的好心鄉民。如果到時候 Teddy 的書真的順利出版了,請記得把聯絡地址告訴 Teddy 讓 Teddy 寄一本書給這位熱心媒人 鄉民



***

友藏內心獨白:要去準備寄給出版社的資料了。


PS:也要一併感謝另一位鄉民主動打電話給 Teddy 要介紹某位暢銷作者給 Teddy 認識。

亂談軟體設計(3):Single-Responsibility Principle

December 28 08:29~10:23


今天與後續的幾集會介紹 Robert C. Martin 在 Agile Software Development 這本書 Section 2 Agile Design 所提到的幾個 Teddy 覺個很有用的 design principles。今天先講第 95-98 頁的:


SRP: Single-Responsibility Principle
A class should have only one reason to change.


『A class should have only one reason to change』,這是什麼東東??一開始看到這些 principles 的解釋真的是會被氣死,覺的好像看到武俠小說裡面的武功口訣一樣,什麼『天之道,損有餘而補不足,是故虛勝實,不足勝有餘...』,讀完這些抽象的口訣之後還是學不會。不過別擔心,Martin 在書中其實解釋得很清楚,想學好設計的鄉民們 Teddy 是很推薦去看一下這本書,尤其是 Section 2 的內容。


Martin 的這本書是 2003 年出版的,但是在這之前 Martin 有把 Section 2 中所提到的五個設計原則的 pdf 檔放到網路上(不知道現在是否還找的到),所以 Teddy 是因為先看過這些設計原則覺的寫得很好,後來這本書出版後 Teddy 才買回家『收藏』。言歸正傳,不想看書的鄉民們就看 Teddy 的懶人版本說明吧。


還記得 Teddy 在『亂談軟體設計(1)』所提到的 cohesion(內聚)與 coupling(耦合)嗎,SRP 主要的目的就要是增強一個類別(class)或是介面(interface)內聚力。如何增強介面內聚力用三秒膠 藉由將介面中不相關的責任(responsibility)移到另外的介面中,也就是說不要讓一個介面『耦合(參雜)』一個以上的責任。


如果鄉民們有學過物件導向分析與設計(OOAD),可能也許應該還記得,OOAD(或是說軟體設計)從頭到尾都在講一件事:Responsibility。設計軟體系統的時候,要有那些類別或介面,而這些類別或介面要包含那些方法(methods)與資料(data members or attributes)。類別與類別之間要有什麼關係,是 associations,aggregation 或是 composition 的關係...等等等。在思考這些問題的時候,一個很基本的概念,就是 responsibility assignment(責任分配)。 


Responsibility assignment 看似容易其實是很難的(因為這只是一個抽象的概念),如果分派了不合適的責任給不相關的類別,或是類別之間的互動關係搞錯了,那麼系統就會變得不易了解當然也很難擴充與維護。所以 Teddy 可以大膽的假設一下,這些所謂的『設計原則(design principles)』其實都是在教鄉民們如何做好責任分配。


Martin 在第 96 頁提到:


If a class has more than one responsibility, then the responsibilities become coupled. Changes to one responsibility may impair or inhibit the ability of the class to meet the others. This kind of coupling leads to fragile designs that break in unexpected ways when changed.


...


A better design is to separate the two responsibilities into two completely different classes.


***


如果鄉民們有看懂上面這一段,SRP 講來講去還是又回到 Teddy 在『亂談軟體設計(2)』中提到的一個觀念:


開發軟體最怕的不是『寫程式』或是『不會寫程式(寫不出程式)』,最怕的是『程式(改那些原本已經寫好測試過可以動的程式)』。


假設一個類別或是介面同時存在兩種責任(稱之為 A,B),那麼很有可能當鄉民們想修改 A 的時候,而卻影響了 B。或是說,因為 B 的關係,卡住 A 讓 A 變得不好修改。Martin 在書中舉了兩個例子,Teddy 講另外一個親身體驗的例子。


當年 Teddy 還在唸書的時候,有一年 Teddy 當研究所 OOAD 課程的助教,幫忙 review 學生的設計。有一次 Teddy 看到某位學生設計了一個用來處理程式設定檔的類別,在此稱之為 ProfileManager,這些設定資料最後以 XML 格式存在檔案中。ProfileManager 就包含了至少三種以上的責任:

  • 有一堆 getter/setter 用來讓 client(caller)把讀取與設定資料(這些資料最後會以圖形的方式顯示在畫面上)。
  • 處理 XML 檔案。將 ProfileManager 的資料存成 XML 格式並且將 XML 檔案轉成 ProfileManager 物件。
  • 列印。將 ProfileManager 所代表的圖形列印出來。

這樣的設計是非常常見的設計,因為在物件導向程式設計會教大家把『動作(operations)』與『資料(data)』集中起來,然後『封裝』在一個類別中。所以,對這個學生來說,他就很自然的把上面三種 responsibilities 『封裝』在 ProfileManager 類別之中。因為從該學生的角度來看,他只看到『一種 responsibility』,而不是三種 


Responsibility assignment 和 separation of concerns 其實是很接近的觀念。如果把『處理 XML』與『列印』抽離出來(separation of concerns),那麼 ProfileManager 的確是同時涵蓋了三種不同的責任。但是,如果真的把不同的責任都逐一分開放到不同的類別中,可能會造成系統中有太多很小的別,而這些被切割出來的類別(例如處理列印或是 persistence 類別)很可能並不會被重複使用(因為系統規模還很小),那麼這樣的設計就有 過度包裝 over design 的嫌疑。


講到這邊鄉民們應該會有一個問題,也是最後,最重要的問題,那就是:


到底什麼情況應該把兩個以上的責任徹底分開?什麼情況放在一起是 OK 的?


課本第 97 頁有答案:


If the application changes in ways that affect the signature of the connection functions, then the design will smell of Rigidity... In that case the two responsibilities should be separated. If, on the other hand, the application is not changing in ways that cause the two responsibilities to change at different times, then there is no need to separate them. 


***

友藏內心獨白:這樣也叫做懶人版本?太長了啦,看不懂。


2011年12月27日 星期二

Scrum 是什麼(1):雙重回饋機制

December 27 09:35~11:11

昨天中午 Teddy 跟一位多年未見的好友一起吃飯,沒想到多年不見,這位朋友已是三個孩子的媽了,好友增產報國的決心,令 Teddy 肅然起敬。聊著聊著,突然談到 Scrum。正當 Teddy 想要跟這位好友解釋什麼是 Scrum 的時候,Teddy 腦海中冒出的淨是『sprint』,『story』,『daily scrum』,『retrospective meeting』這些東東,此時 Teddy 突然發現居然無法用簡單的一句話來說明 Scrum 是什麼玩意兒,這幾年白混了...Orz。

此時 Teddy 才想起來,在部落格中寫了那麼多關於 Scrum 與 agile practices 的文章,但是從來沒有一篇的主題是專門介紹什麼是 Scrum 的,乾脆今天就來講這個題目好了。

以下為幾種常見對於 Scrum 的說明:

  • 首先看看 Wikipedia上面的英文中文解釋:Scrum is an iterative, incremental framework for project management often seen in agile software development, a type of software engineering.(Scrum是一種迭代式增量軟體開發過程,通常用於敏捷軟體開發。)這可能是絕大多數鄉民對於 Scrum 的印象,一種敏捷專案管理框架。請把重點放在專案管理這四個字上面,所以想到 Scrum 就想到專案管理。
  • 接著看看 Ken Schwaber 與 Mike Beedle 在 Agile Software Development with Scrum, p 2, 的說法:Scrum is a management and control process that cuts through complexity to focus on building software that meets business needs. 相較於專案管理這四個字,Scrum 是一種『management and control process (管理與控制流程)』感覺起來比較抽象一點。

把 Schwaber 與 Beedle 所寫得書讀到最後,會發現作者想要表達的『management and control process』的精神。不過,廣義的來講,專案管理也包含了『management and control process』。為了簡單起見,就先把 Scrum 當成是一種『敏捷專案管理方法』或是『敏捷專案管理框架』吧...雖然 Teddy 潛意識中不太喜歡把 Scrum 說成專案管理的方法。

***
 
接下來是重點,如果把 Scrum 看成是一種敏捷專案管理方法,那麼這個方法的內含是什麼?和傳統的專案管理方法有何不同?在介紹 Scrum 內含之前,先看一下 Scrum 與傳統一般專案管理最大的差異之一,在於 Scrum 有如下圖所示的『雙重回饋機制』。在軟體開發中,下圖左邊的『輸入』是『軟體需求』,中間『流程』那一塊表示軟體開發活動,最後的『輸出』表示軟體本身(也可以包含設計與使用文件等)。從輸入經過開發流程到產品輸出,在 Scrum 的術語中這一段時間稱之為『sprint(短跑或衝刺)』,另一個與 sprint 相同意思但卻更一般化的說法叫做『iteration』。廣義的來說,敏捷方法(agile methods)將一個軟體專案的開發時程(假設 6 個月)切割成若干個『時間長度固定(time-boxing),例如兩個禮拜的開發活動,這種時間長度固定的週期就稱之為一個 sprint 或是一個 iteration。如果一個專案是 6 個月後要釋出產品,開發團隊採用為期兩週的 sprint,那麼這個專案就一共有 12 個 sprints(先不要管每一個 sprint 要做什麼,以及如何將需求分配到每個sprint 這些問題)。

 
image
所以,採用 Scrum 的團隊就是要在每一個 sprint 結束之前(每兩週)完成上圖從輸入端丟入軟體需求,然後經過開發流程,最後產生產品。圖中從輸出那端拉了『兩條回饋線』,一條透過『demo meeting(sprint demo or sprint review meeting)』回饋到『輸入的需求端』,另一條透過『retrospective meeting,回顧或是反省會議』回饋到『開發流程』。
 
這兩條回饋線的含意是:
  • Review meeting: 每個 sprint 結束時,開發團隊要展示本此所完成的功能給客戶(或是客戶代表)看,讓客戶確定此次所開發的功能是否符合客戶期待。如果不符合則可以在之後的 sprint 加以修正(此為回饋機制的意義,有錯則改之)。由於每個 sprint 週期很短(一般 Scrum 團隊採用 2 週至 4 週的 sprint),所以可以避免傳統開發專案在專案晚期客戶才發現問題但卻沒時間加以修正的困境。
  • Retrospective meeting: 軟體開發除了需求可能不符合客戶所需,軟體開發流程本身如果沒有做好管理,也很容易開發出『低品質』的軟體。例如,bugs 太多,程式無法擴充,沒有自動化測試等等。所以,在每個 sprint 結束時,除了review meeting 以外,Scrum 還有一個稱之為 retrospective meeting 的活動,用來檢討與軟體開發流程有關的議題。在這個活動中,團隊成員們探討(1)那些開發作法是好的,應該要繼續維持下去。例如,有導入持續整合,或是有持續做 pair programming;(2) 有那些與開發流程有關的地方沒有做好需要改善的。例如,自動化單元測試做的不夠多,或是測試硬體設備不夠;(3)擬定改善計畫(action plan)。
在了解 Scrum 的內含之前,希望鄉民們先了解與細細品味一下 Scrum  雙重回饋機制』的重要性。其實這個雙重回饋機制』是一種很簡單的作法,但是對於改善軟體開發(需求與流程)卻是相當有用(PS:還有 time-boxing 的觀念也是很重要滴)

今天先講到這裡,Scrum 的內含下次再說明。

下一集:〈Scrum 是什麼(2):Scrum 的內涵

***

友藏內心獨白:啊,這一篇寫太久了,還有重要事情要辦說。

2011年12月26日 星期一

Pair Programming 成本太高,嗎?

December 26 09:05~10:57


兩個禮拜前有人對 Teddy 說他們公司有採用 Scrum 但是他們不用 pair programming,因為 pair programming 『成本太高』。何謂成本太高?因為 pair programming 顧名思義就是『兩個人黏在一起開發軟體』,大部分的人直覺的想法便是:


原本一個人可以做的事情,用 pair programming 人力成本變成兩倍,所以『成本太高』,不划算


很久以前其實 Teddy 也有這樣的困擾,一直到三年半前採用 Scrum 並且實施 pair programming 的初期,在 Sprint Planning Meeting 估算做完一個 task 所需時間的時候,Teddy 都有類似的疑惑,例如:


一個 task 假設預估需要 5 小時做完,那麼這個 task 如果採用 pair programming,需要幾小時?


有三個可能的選項:

  • 5 小時不管多少人一起完成一個 task,反正原本估算多少小時可以完成就用原本估算的值。這個選項是否合理呢?假設團隊有 6 個全職投入的開發人員,一個 sprint 兩週,那麼這個團隊可以用來『燃燒的時間(可以投入的工時)』為:6 (人)* 10 (兩週 10 個工作天)* 5 (一天五個小時)= 300 小時。如果不管多少人一起完成該 task 都以花費 5 小時計算,那麼最後團隊可以投入的時間其實是『被高估了』,所以這個選項感覺不太合理(所有 task 的預估時間加總起來應該要接近團隊成員所可以貢獻到該 sprint 的時間,以這個例子而言總時間為 300 小時)。
  • 2.5 小時:原本需要 5 小時,兩個人一起做所以只要 2.5 小時。聽起來好像很有道理,但是現在預估的工作是『程式設計』,不是『掃地』或是『刷油漆』。Teddy 的經驗上很少有工作因為 pair programming 的關係而比原先預估的時間還要提早 50% 以上可以完成的。所以,把原本預估時間除以二這個選項也排除了。
  • 10 小時:一件『程式設計』的工作一個人做 5 個小時,兩個人需要 10 個小時(直接把時間乘以二),這是 Teddy 最後採用的方案。耶,這樣看起來不正是證實了『pair programming 成本太高』的批評嗎?請接著看下去。
先講結論,Teddy 的經驗是,只要有 task 是採用 pair programming 方式施工的,Teddy 都比較放心該 task 的施工品質。所以說,如果某個 sprint 絕大部分的 tasks 都是採用 pair programming,那麼依據 Teddy 的經驗 sprint 結束後的產出物品質都會比較好。所以只要看到團隊成員都在『配對做事』,Teddy 就會很放心。反倒是如果某個 sprint 團隊成員都在『各作各的』,這樣好像看起來每個人都很忙,但是經驗告訴 Teddy 最後的產出物相對來講品質會比較差。

看到這邊鄉民們可以能會說,Teddy 你用『兩倍的成本(pair programming)』來做『一半的事情』所以產出物的品質當然會比較好啊。

上面這個問題很好,但是反過來思考,假設我們對於品質的要求是固定的(我們要求好的品質),再假設 pair programming 可以達到我們對於品質的要求,那麼這樣是不是意味著『原本的施工方式(不採用 pair programming)』有一些該做的 tasks 被隱藏起來了?

***

那麼那些該做的 tasks 被隱藏起來了?
  • 設計:當一人獨自設計程式的時候(包含 coding),經常會出現一些『自己看不到的盲點』,這些盲點小至可能耽誤你幾分鐘的時間去發現,大到可以埋入一個不容易被發現的 bug。另外,有時候一個人設計程式做的很累的時候,可能會取巧只要讓『程式可以動』就好,所以所寫出來的程式其實是不容易閱讀與維護。有時候因為自己能力不足的關係也可能做出不易閱讀與維護的程式。這些都是增加日後開發的成本,但是這些成本卻都被隱藏在『程式可以動啊』的大帽子下面(請記住 all programming is maintenance programming 這個道理)。
  • 測試:和設計問題很像,一個人寫程式(此人也被要求要寫單元測試)假設程式已經可以動了,此時腦袋可能已經有點累了,所以會有一種想要休息的欲望,導致有時候無法把單元測試寫得很完整。也有可能是自己的盲點導致漏寫了某些單元測試。同樣的,不足夠的單元測試除了可能少抓到一些 bugs 以外,還會增加做 refactoring 的困難度與風險。這些被隱藏的工作也都會增加日後開發的成本。
  • Review:不管是 design review 或是 code review 都是找出設計或是程式問題的有效方法。Pair programming 有一個很重要的精神就是『隨時隨地都在 review』。這些 review 的工作在很多團隊中其實是被忽略了。
  • 除錯:很多時候寫程式可能只花了 1 小時『就寫好了』,但是除錯(debug)可能花了一整天(8 小時)甚至更久。在 pair programming 的模式之下通常發生這種狀況的機率會比較低一點。
  • 派工(分工並合作):採用 Scrum 或是任何軟體開發方法,當需求被細分為 tasks(施工項目)的時候,接下來就要思考工作分派的問題。傳統單人施工模式,很容易造成每個人對自己所做的工作(或是分配到的程式模組)很熟,但是對於其他人在做什麼卻完全不知。這個現象其實是一個很嚴重的問題,但是大部份的時候都被隱藏起來了,直到有人請假,或是更慘的,有人離職,問題才凸顯出來。Pair programming 可以讓開發經驗在團隊成員彼此分享,尤其是如果配對開發的對象經常性的輪替交換,那麼久而久之團隊成員就比較有能力可以修改『其他人所寫得程式』。更好的狀況是,最後團隊達到 shared code 的境界。


***

扯了這麼多,Teddy 要再強調一次,以上說明都基於某個假設,這個假設要成立 pair programming 才有意義,什麼假設,就是:

軟體的品質是重要的


如果鄉民們的公司或是專案強調的是寫出看起來可以動的程式就好,先把客戶的錢 收進來其他事情以後再說。亦或是公司文化要求比賽誰留在公司的時間比較長,誰比較晚下班而不是誰工作效率與績效比較好,那麼請忘記 Teddy 剛剛所說得一切,並且立即將腦袋運作模式切換為『派大星』模式,謝謝。


***

Pair programming『看起來』花費兩倍的時間,但實際上節省去了後續很多開發與維護的成本,從專案的『總成本』這個角度來看,還是非常非常值得一試的方法。

***

友藏內心獨白:今天的功課提早做完了。




2011年12月25日 星期日

亂談軟體設計(2):Open-Closed Principle

December 25 20:48~20:12


今天原本應該要講第二個重要的設計原則『program to an interface』,不過這個原則之前 Teddy 已經講過了(請參考這篇 Program to an interface),所以直接跳下一個:


The Open-Closed principle (OCP)


OCP 是 Teddy 相當喜歡而且經常應用的一個設計原則,Teddy 第一次看到這個原則是在 Bertrand Meyer 所寫得長達一千兩百多頁的巨著 Object-Oriented Software Construction, 2nd,57 頁。後來 Robert C. Martin 在 Agile Software Development 這本書第 99-109 頁有重新詮釋,這本書的解釋比較容易理解。Teddy 引用一下  Martin 對於 OCP 的解釋:


OCP: the Open-Closed Principle
Software entities (class, modules, functions, etc.) should be open for extension, but closed for modification.


一個軟體個體應該要夠開放使得它可以被擴充,但是也要夠封閉以避免不必要的修改。這樣解釋鄉民們應該還是看不懂,接著看 Robert 在書中所說得這段話就會很清楚了 (p. 99):


When a single change to a program results in a cascade of changes to dependent modules, the design smells of Rigidity. The OCP advises us to refactor the system so that further changes of that kind will not cause more modifications. If the OCP is applied well, then further changes of that kind are achieved by adding new code, not by changing old code that already works.


鄉民們知道開發軟軟體最怕的是什麼嗎?請花 30 秒想一下...




***




開發軟體最怕的不是『寫程式』或是『不會寫程式(寫不出程式)』,最怕的是『程式(改那些原本已經寫好測試過可以動的程式)』。先談一下既然程式已經寫好了,為什麼還要去改它呢?兩個主要的原因:

  • 要增加功能。
  • 要修正問題(bugs)。

那為什麼改程式那麼可怕?因為要修改一個已經可以動的系統的某個模組,很容易造成『a single change to a program results in a cascade of changes to dependent modules』,這也就是昨天提到的因為模組之間會有 coupling(耦合),因此產生『牽一髮而動全身』的效應。如果鄉民們的系統都有足夠的『自動化測試案例』來驗證『此次修改沒有破壞原本可以正常動作的功能』,那麼相對來講這種『漣波效應(ripple effect)』其實也就沒有那麼可怕。但是實務上大家都知道『自動化測試永遠都不夠多』,所以如果能從『設計面』著手從而避免掉這種牽一髮而動全身的漣波效應,則軟體系統將會變得很容易修改,擴充,了解,與維護


所以,套用 OCP 的最高境界就是做到:


藉由增加新的程式碼來擴充系統的功能,而不是藉由修改原本已經存在的程式來擴充系統的功能
( If the OCP is applied well, then further changes of that kind are achieved by adding new code, not by changing old code that already works.)


Teddy 第一次看到這段話的時候真的是百思不解,奇怪,要增加新的功能不就是要把程式拿出來改嗎?不改原本的程式,光靠『增加新的程式』要如何擴充系統的功能啊?


先解釋一下為什麼 OCP 最高境界要求鄉民們『藉由增加新的程式碼來擴充系統的功能,而不是藉由修改原本已經存在的程式碼來擴充系統的功能』。因為如果能夠不修改原本已經存在的程式,那麼就可以完全避免掉a single change to a program results in a cascade of changes to dependent modules 這種牽一髮而動全身的漣波效應』...乍看之下覺的有點逃避的鴕鳥心態...XD。


那麼要如何做到藉由增加新的程式碼來擴充功能?講穿了也是很間單,又回到昨天所說得『abstract coupling』與『Program to an interface』這些原則上面。Robert 在書中有舉了一個淺顯易懂的例子並附上範例程式,有興趣的鄉民們請自行參考。Teddy 要講的是不用看程式碼就可以讓鄉民們了解的例子-- Plug-in architecture


如果有用過 Eclipse,對於 plug-in architecture(外掛架構 or 插件架構)應該很了解。不會寫程式的鄉民也沒關係,像 Firefox 或是 Chrome 這些瀏覽器,也都有支援所謂的 plug-in architecture。Plug-in architecture 就是一種十分符合 OCP 的設計。因為在 Plug-in architecture 架構中,開發者是藉由『撰寫新的 plug-ins 來擴充系統的功能』,使用者也不太可能(也不需要)去修改 Eclipse 來擴充功能


類似的例子還有很多,例如現在很流行的 Dependency Injection(例如 spring framework),還有古早用查表方式,透過 service registry 或是 service look-up 的分式,以及透過 ini 或是 XML 設定檔來改變系統行為,甚至是 Windows 系統的 hook 程式 Teddy 認為都可以算是某種 OCP 的實踐。


總之,OCP 的精神『further changes of that kind are achieved by adding new code, not by changing old code that already works.』這句話背下來放在心裡面就對了。

***

友藏內心獨白:要學『美味關係』每天都寫一篇部落格文章還真是很拼耶。