14.6開發(fā)階段的日常管理
14.6.1閉門造車(leave me alone)
荔荔:我今天真失敗!在辦公室里坐了10個小時,但是真正能花在開發(fā)工作上的可能只有3個小時,然后我的工作進(jìn)展大概只有兩個小時!
阿超:那你的時間都花到哪里去了?
荔荔:就是我們以前說的“我沒看見你在寫軟件,你到底在忙什么”上面列出來的破事兒。每一件隨機(jī)事情看起來都是挺重要的,我就放下手里的開發(fā)工作。但是好不容易做完了,剛想進(jìn)入狀態(tài),又一件隨機(jī)事情來了……
阿超:你要厚著臉皮,說“不”。
當(dāng)場景、功能都計劃好的時候,要給員工足夠多的時間,讓他們投入到工作中去,而不要經(jīng)常打斷他們。
要盡量減少非開發(fā)時間,不要動不動就開“全體會議”。團(tuán)隊成員們自我時間管理也很重要。由于MSF鼓勵溝通,TFS也設(shè)置了不少提示(Alert)自動報告全體成員項目個方面的情況,因此團(tuán)隊的E-mail會特別多。在這種情況下不要整天被E-mail牽著鼻子走。在Outlook上設(shè)置好郵件規(guī)則,按下面的規(guī)則把郵件自動分類到不同的郵件夾中:
(1)從直接老板來的,發(fā)給你一個人的——馬上處理。
(2)從團(tuán)隊成員來的、和項目有關(guān)的事情,自動分配到一個叫“Team”的郵件夾中。
?。?)從TFS來的狀態(tài)信息,如團(tuán)隊的check-in email,自動分配到一個叫“Check-In”的郵件夾中。
?。?)從其公司他同事來的與工作無關(guān)的消息(如笑話,大減價的消息等),自動分配到一個叫“Other”的郵件夾中。
最好每隔兩三小時集中閱讀和回復(fù)一下E-mail。
荔荔:河對岸的河曲數(shù)碼經(jīng)常把所有人都拉去做“封閉開發(fā)”,這樣是否就能避免干擾?
阿超:我們做開發(fā)軟件,并不是讓團(tuán)隊像被關(guān)在監(jiān)獄里一樣。要有大家自由交流的時間,團(tuán)隊成員們在無拘束的環(huán)境中,會更樂意提問和分享,這會比召開正式會議,強(qiáng)迫每個人分享好得多。在“封閉開發(fā)”的情形下,領(lǐng)導(dǎo)也更有可能每天、每小時來詢問項目的進(jìn)度,這種團(tuán)隊內(nèi)部的干擾源,并不會因為團(tuán)隊搬到一個監(jiān)獄里而消失。大家還記得MSF的“充分的授權(quán)和信任”?
果凍:我這里還有筆記。
小飛:另外,我經(jīng)常去看測試人員又發(fā)現(xiàn)了什么bug,有時就花時間研究和修復(fù)它們。
阿超:可以等第二天會診之后再看看是否值得馬上修復(fù)。
果凍:這樣新建的bug 要等到第二天門診之后才能給開發(fā)人員處理,是不是影響進(jìn)度?
阿超:不一定。
提示:
(1)開發(fā)人員在開發(fā)階段最重要的任務(wù)是把規(guī)定的功能完成!
?。?)在項目初期,可以不用集體會診,開發(fā)/測試人員可以直接處理“缺陷”,不必等待。
?。?)在任何時候,測試人員都可以把“缺陷”交給開發(fā)人員,但是只有會診的人員才能改變會診決定。
14.6.2每日構(gòu)建
阿超:我好像有幾天沒有受到每日構(gòu)建(Daily Build)的報告了。
小飛:已經(jīng)有一陣子 Daily Build 沒成功了。
阿超:哦?我們上課的時候不是說過“每日構(gòu)建”的重要性么?
小飛:我同意在我們有時間的情況下,我們要做每日構(gòu)建,但是當(dāng)我們忙的時候,我們的確實沒有時間去管構(gòu)建的問題。
阿超:這么說還是應(yīng)了那句話——在理論上,理論和實踐是一回事,而在實踐上,理論和實踐是兩回事。
阿超指著窗外,河對面的工地。
阿超:他們在建樓房吧。
小飛:對,據(jù)說是軟件學(xué)院的新大樓。
阿超:那,他們的腳手架自從搭好了之后,就沒有垮下來過吧。
小飛:那當(dāng)然不會,俺爹是干這一行的,所有的工人和材料都得運上運下,腳手架要搭得特別結(jié)實。
阿超:那你爹他們有沒有因為工期緊,就湊合著搭個架子,就往上蓋樓?或者腳手架倒了也不管?
小飛:那哪成!要倒下了,就要出人命了,哪還能蓋樓?!
阿超:對呀,我們的軟件構(gòu)建,就和腳手架一樣,每天都要立著,倒下來就麻煩了。
小飛:不過,我們搞開發(fā)的都有點不屑搞構(gòu)建,沒有寫程序來勁。
阿超:不會建腳手架的小工,你爹會要么?
小飛:不會。
阿超:不會做構(gòu)建的程序員,就像不會搭腳手架的小工,運球不熟練的球員。這樣的程序員,我們也不要。
小飛:我明白了。
下午,阿超在喝水的時候碰到小飛來報告說Daily Build正在運行中。發(fā)現(xiàn)的幾個錯誤都改正了。估計晚上就可以產(chǎn)生一個新的構(gòu)建了。
阿超:了不起,這么快就做好了。
小飛:超總,我想提一個和我職業(yè)發(fā)展有關(guān)的問題。我們接受的可都是本科軟件工程教育,我們當(dāng)時的院領(lǐng)導(dǎo)說我們畢業(yè)后都是要朝CTO發(fā)展的,至少是軟件金領(lǐng),我當(dāng)然知道這是遙遠(yuǎn)的將來的事,但是我總覺得我可以做一個軟件白領(lǐng)吧,這些構(gòu)建之類的事情,嘿嘿,是不是要由所謂軟件藍(lán)領(lǐng)來做?
阿超:問題提得好……
他望著這位將來的CTO、軟件金領(lǐng),突然想抄起身邊的塑料水桶,把水都從他的白領(lǐng)里灌進(jìn)去。他喝了一大口水,退到窗邊,勉強(qiáng)把這個念頭壓了下去。阿超看著窗外的操場——
阿超:聽說你籃球打得不錯?
小飛:還行,常和二柱幾個玩。
阿超:你提到大學(xué)的課程,讓我想起大學(xué)的籃球課。我們當(dāng)時考試的科目之一是定點投籃。老師叫每個要考試的同學(xué)站在罰球線上,別的同學(xué)負(fù)責(zé)撿球,考生就站著不動,一個一個地瞄準(zhǔn)了投,如果進(jìn)了一個球,老師才開始算分。平時玩球的同學(xué)都是十個進(jìn)七八,連運動細(xì)胞不多的同學(xué)都是十個球中五個以上,皆大歡喜,好像大鯊魚奧尼爾罰球也不過50%上下,大家都有NBA球星的感覺。另一個考試科目是兩人配合上籃,當(dāng)然這是在球場空蕩蕩的時候進(jìn)行的,大家接/傳/投一氣呵成,頗有馬龍和斯多克頓的風(fēng)范,覺得籃球“技止此耳”!考試后,我們意猶未盡,和在一邊玩球的同學(xué)打球賽,盡管我們“定點投籃”和“二人配合”的分?jǐn)?shù)都很高,但是我們都輸?shù)煤軕K……
小飛:為啥?
阿超:因為我們運球、傳球都不熟。這都是我們平時不屑練習(xí)的東西,即使勉強(qiáng)到了籃下,投籃都是在踉蹌之中完成,當(dāng)然沒有考試時候的準(zhǔn)星。
小飛:超總,您把我繞遠(yuǎn)了,您的意思是?
阿超:我覺得大學(xué)的軟件工程課,本來要教全面的技術(shù),但是考試往往只考定點投籃和無防守情況下的配合。所以有些大學(xué)的高材生到了實際工作中,很多“藍(lán)領(lǐng)”的基本功,比如實戰(zhàn)中的運球、傳球都不靈,他們津津樂道的定點投籃十中八九的功夫也沒有發(fā)揮的機(jī)會了。我還沒有見過從天而降的白領(lǐng)或者金領(lǐng)。所謂的大拿們都是從藍(lán)領(lǐng)摸爬滾打出來的。換句話說,我眼里沒有白領(lǐng)或藍(lán)領(lǐng),只有“汗領(lǐng)”——就是大家都得出汗干活。
小飛:你是說構(gòu)建就像運球、傳球……好,我明白了。超總,下班后我們球場見!
14.6.3構(gòu)建大師
頭碰頭會上,大家發(fā)現(xiàn),最近連續(xù)幾個構(gòu)建都不成功,測試組都拿不到新的版本,沒法進(jìn)行測試。
阿超手里拿了小飛整理的“導(dǎo)致構(gòu)建失敗的失誤列表”分送到每人手里,表上列舉了錯誤的類型和導(dǎo)致錯誤的簽入,以及牽涉的成員。
大拴: 看來拿不到新的構(gòu)建版本的原因有這些——
?。?)構(gòu)建在開發(fā)人員本地機(jī)器上就不成功。
?。?)構(gòu)建在本地成功,在服務(wù)器上失敗。
(3)構(gòu)建在本地及服務(wù)器上成功,但是基本功能不能使用,導(dǎo)致無法進(jìn)行測試。
阿超:試著對癥下藥,很多事情我們在培訓(xùn)時都講過了——
?。?)強(qiáng)調(diào)基本開發(fā)流程(注意編譯要產(chǎn)生debug|release兩個版本)。
?。?)簽入時,必須從TFS同步下所有最新的版本再編譯,而且個人的簽入要做成一個Shelveset,成為原子操作,而不能把一次修改中的所有文件分成幾次簽入。
?。?)這時,我們以前做的單元測試和構(gòu)建驗證測試(BVT)就要發(fā)揮作用了,每一個開發(fā)人員在簽入前都要運行所有的單元測試和構(gòu)建驗證測試,確保沒有問題后,才能簽入。
我們要讓團(tuán)隊中做事不仔細(xì)的人慢下來,這樣能減少他們的危害。
欲取之,必先予之。阿超進(jìn)而建議——
對于下一個導(dǎo)致構(gòu)建失敗的成員,授予“構(gòu)建大師”(Build Master)稱號,構(gòu)建大師做下面的事:
?。?)負(fù)責(zé)管理構(gòu)建服務(wù)器。
?。?)調(diào)試構(gòu)建,負(fù)責(zé)找錯,并分析出錯的原因。
(3)負(fù)責(zé)把“構(gòu)建大師”稱號和責(zé)任交給下一個導(dǎo)致構(gòu)建失敗的成員。
?。?)“構(gòu)建大師”同時向團(tuán)隊的“腐敗基金”存入50元,以供大家將來“腐敗”之用(此項可選)。
14.6.4寬嚴(yán)皆誤
上次頭碰頭會議后,各個小組都進(jìn)一步強(qiáng)化了單元測試和BVT。
下午,果凍發(fā)了一封E-mail,標(biāo)題是“我受不了啦!”內(nèi)容如下——
我的簽入流程:
(1)代碼寫好,本地測試通過,代碼復(fù)審?fù)ㄟ^??梢院炄肓?。
(2)同步TFS上最近更新,編譯debug |release,解決版本沖突(半小時)。
?。?)安裝最新版本,運行本地單元測試,BVT(一個小時)。
?。?)提交到TFS上,發(fā)現(xiàn)有版本合并沖突,因為在2、3步的時候,有人簽入了和我的代碼有關(guān)的新修改。
?。?)如果我簡單地合并版本,并且簽入,很有可能會導(dǎo)致TFS 上編譯失敗。但是如果我為了保證質(zhì)量,在合并后,本地編譯并運行各種測試,這相當(dāng)于重復(fù)了2、3步。當(dāng)我再次提交簽入(重復(fù)第4步)時,有可能碰到新的版本沖突。這樣循環(huán)往復(fù)以至無窮……
二柱發(fā)了E-mail,第一句話就是:
在理論上,理論和實踐是一回事,而在實踐上,理論和實踐是兩回事。
然后也抱怨了類似的問題,似乎大部分時間都花在了沒有價值的“同步/編譯/驗證/再同步……”的循環(huán)中。
荔荔:似乎應(yīng)該在簽出一個文件的時候,加上一個“防止別人簽出”的鎖,這樣就沒有沖突了。
果凍:但是如果你鎖住了file1,要簽出file2;與此同時,我鎖住了file2,要簽出file1,這樣我們都進(jìn)入了死鎖……
小飛:我剛剛同步TFS,然后編譯就不成功了。我在一臺全新的機(jī)器上重新試了一次,也不行。這至少證明不是我引起的問題?,F(xiàn)在我已經(jīng)沒法工作,我只好到“頂球”喝兩杯去了。誰把錯誤修好了,就給我發(fā)短信,我就回來上班。
阿超:除了構(gòu)建大師,所有開發(fā)人員都可以到“頂球”去玩。
構(gòu)建大師:我已經(jīng)連續(xù)三天錯過了午飯時間,誰能幫我從頂球帶兩個燒餅回來?另外,能不能不要在午飯前安排構(gòu)建?要不然鐵打的胃也受不了。
經(jīng)過一個多小時的忙碌,構(gòu)建終于好了,但是構(gòu)建大師問阿超,現(xiàn)在構(gòu)建成功了,明天呢?
阿超:讓我想想……
阿超晚上把情況和同事們的意見報告了愚公,阿超在E-mail最后寫到:
有兩條路團(tuán)隊可以實行:
?。?)很嚴(yán)的規(guī)則和流程控制,這樣會保證很高的簽入成功率,如果一個人根據(jù)流程來做,幾乎肯定能成功。這樣構(gòu)建質(zhì)量高,但是團(tuán)隊的進(jìn)展會受到限制。極端情況下,整個團(tuán)隊的進(jìn)展被序列化為一系列個人串行簽入操作。
?。?)寬松的規(guī)則和流程,每個人隨時可以簽出簽入,簽入時的成本很低,但是簽入成功率不高,構(gòu)建質(zhì)量低,極端情況下,所有人都可以簽入,同步,但是沒有人能正常工作。
哪一種是最好的呢?
第二天一早,阿超就看到了愚公的回復(fù):
不審勢即寬嚴(yán)皆誤,從來治蜀要深思。
阿超心想,那什么是我們這個團(tuán)隊目前的“勢”呢?他列出了對每一個步驟,寬、嚴(yán)各是什么做法,當(dāng)前團(tuán)隊的情況(勢)是什么,這樣就得出了一個用“寬”或者“嚴(yán)”的決定,如表14-7所示。
當(dāng)行為只是影響到個人的時候,盡量放松,讓個人根據(jù)自己情況處理;當(dāng)行為影響到整個團(tuán)隊的時候,盡量嚴(yán)格,因為整個團(tuán)隊都有可能會受影響。同時,我們要提高可預(yù)見性——明確構(gòu)建大師的職責(zé),公開顯示固定的構(gòu)建時間。
表14-7寬嚴(yán)表
步驟 |
寬 |
嚴(yán) |
勢 |
簽出 |
自由簽出 |
簽出時候,將文件上鎖 |
很多人都會同時編輯同一文件 |
本地單元測試 |
不要求 |
要求 |
每個模塊都要求寫單元測試 |
本地check-in test(簽入測試) |
不要求 |
要求 |
BVT還沒有完成 |
簽入時間 |
任何時候 |
每天固定時間開放 |
目前簽入情況很混亂 |
簽入沖突處理 |
合并后即可簽入 |
合并后,再重新編譯,測試,再提交 |
重新測試會花費比較多的時間 |
續(xù)表
步驟 |
寬 |
嚴(yán) |
勢 |
簽入必須經(jīng)過代碼復(fù)審 |
隨意 |
必須 |
開放人員有一半是新員工,必須通過代碼復(fù)審建立良好的規(guī)范 |
簽入時必須運行代碼分析工具 |
不要求 |
要求 |
代碼分析工具尚未配置好 |
簽入時單元測試必須同時簽入 |
不要求 |
要求 |
每個模塊都要求寫單元測試 |
簽入必須是多個相關(guān)文件同時簽入 |
不要求,可以簽入單個文件 |
要求 |
保證每一個簽入都不會導(dǎo)致構(gòu)建失敗 |
簽入必須和一個工作項關(guān)聯(lián) |
不要求 |
要求 |
所有的工作必須有工作項跟蹤 |
設(shè)定專用網(wǎng)絡(luò)服務(wù),自動處理提交的ShelveSet,構(gòu)建,BVT,然后簽入代碼 |
不要求 |
設(shè)置 |
需要很多人力來設(shè)計并維護(hù) |
簽入必須經(jīng)過代碼復(fù)審 |
隨意 |
必須 |
開放人員有一半是新員工,必須通過代碼復(fù)審建立良好的規(guī)范 |
簽入時必須運行代碼分析工具 |
不要求 |
要求 |
代碼分析工具尚未配置好 |
簽入時單元測試必須同時簽入 |
不要求 |
要求 |
每個模塊都要求寫單元測試 |
表14-8 具體流程
時間 |
總體 |
管理/程序 經(jīng) 理 |
開發(fā) |
構(gòu)建 大師 |
測試 |
8am~10pm |
開發(fā)人員可以同步代碼,這時只有非常要緊的簽入才能經(jīng)過批準(zhǔn),簽入TFS |
9am—— 頭碰頭會議,bug會診,分配bug |
同步代碼,構(gòu)建,根據(jù)自己的任務(wù)/bug情況決定今天的工作 |
測試新版本,新建bug |
|
10pm~12pm |
代碼簽入時間,經(jīng)過正常代碼復(fù)審及其他流程后,代碼(連同單元測試)才能簽入 |
程序經(jīng)理組織必要的會議 |
單元測試 |
準(zhǔn)備構(gòu)建服務(wù)器 |
|
12pm~1pm |
午飯時間 |
續(xù)表
時間 |
總體 |
管理/程序 經(jīng)理 |
開發(fā) |
構(gòu)建 大師 |
測試 |
1pm~3pm |
構(gòu)建/安裝/基本測試/宣布版本質(zhì)量(見后) |
待命,隨時準(zhǔn)備攻克問題 |
全程監(jiān)督執(zhí)行,負(fù)責(zé)把導(dǎo)致構(gòu)建失敗的缺陷(找人)修復(fù)并簽入 |
運行基本測試 |
|
3pm~6pm |
開發(fā)/測試人員繼續(xù)工作 |
運行BVT后,宣布此次構(gòu)建質(zhì)量(失敗/可測/可用) |
聰明的測試人員此時就開始測試并報告缺陷 |
||
6pm |
晚飯及機(jī)動時間 |
阿超:我特地把緊張的構(gòu)建及待命階段安排在午飯之后,這樣大家至少可以安心吃飯了。
14.6.5 小強(qiáng)地獄(Bug Hell)
在這一次的頭碰頭會議上,平時不主動發(fā)言的阿亨也說話了。
阿亨:開發(fā)的同志們,你們手里有那么多小強(qiáng),為什么都揣著掖著,不舍得修復(fù),讓測試人員有事情做?測試人員反映因為現(xiàn)有的小強(qiáng)沒有被修復(fù),有越來越多的小功能點不能進(jìn)行測試,我們都要沒事做了。
大拴:我們的開發(fā)任務(wù)很重,必須先把新功能全部實現(xiàn)后,再修復(fù)舊的小強(qiáng)。
阿亨:這是不對的,我們有些小強(qiáng)在你們手頭很久了,看似舉手之勞,為什么不盡快修復(fù),讓我們測試組能繼續(xù)完成測試?
二柱:我們都是按優(yōu)先級來進(jìn)行,開發(fā)新功能的優(yōu)先級遠(yuǎn)大于修復(fù)小強(qiáng)。
阿亨:但是有些開發(fā)人員手里頭有二三十個小強(qiáng),難道數(shù)量不是一個考慮因素?
阿超:我同意,隨著項目的深入,每個人同時要開發(fā)新的功能,修復(fù)以前的缺陷。由于沒有明確的優(yōu)先次序,一般人都愿意把時間花在開發(fā)新功能上。但是我們的確需要平衡進(jìn)度和質(zhì)量。有這樣的一種方法:
小強(qiáng)地獄(Bug Hell)
如果開發(fā)人員的小強(qiáng)(bug)數(shù)量超過一規(guī)定值,則此君被送入“小強(qiáng)地獄”,在地獄中,他能做的唯一一件事就是修復(fù)小強(qiáng),直到小強(qiáng)數(shù)量數(shù)量低于此閾值。
這一閾值由團(tuán)隊根據(jù)實際情況來確定,要注意:開發(fā)人員同時“入獄”的人數(shù)應(yīng)在全體成員的5%~30%之間,若比例太高,則要考慮閾值或者小強(qiáng)數(shù)量的計算方式是否合理(是否只包括某一嚴(yán)重程度以上的bug)。
在項目過程中,閾值不宜頻繁調(diào)整,最好事先宣布閾值。
大拴:但是我們已經(jīng)違反了“最好事先宣布閾值”這一規(guī)定。
阿超:如果我們現(xiàn)在要讓20% 的同志入獄,我們馬上運行一個TFS 查詢看看這一個閾值是多少?是15?好,那我們現(xiàn)在宣布給大家三天時間,第三天后,小強(qiáng)數(shù)量達(dá)到或超過15 的開發(fā)人員請入獄,然后每天早上9點頭碰頭會議時統(tǒng)計并宣布入獄/出獄名單。
大牛: 其實先把所有的功能寫完也不錯,至少我可以告訴客戶“功能寫完了”,讓他們高興高興。
大拴:大牛,這不就是咱們以前項目的情況么?你一直問“功能都寫完了,為什么還不能用”? 我們一直說“還有一些小問題”,然后小問題總是不能解決,因為要真正解決這些“小問題”的話,我們還得重寫一些功能。
阿超:對,很多問題,甚至是大問題,都隱藏在目前的小強(qiáng)后面,如果一味趕所謂的“進(jìn)度”,到時候有些小強(qiáng)就變成了大怪物,因為我們已經(jīng)在錯誤的基礎(chǔ)上搭建了很多新的邏輯和功能,這時再來處理一些歷久彌新的小強(qiáng),就有投鼠忌器的麻煩。
阿亨:那怎么辦?
阿超:我們要分析小強(qiáng),看看這是一個小問題,解決了就萬事大吉呢?還是冰山的一角,解決后也許會發(fā)現(xiàn)更多、更棘手的問題?;蛘呖此撇唤?jīng)意的一個小強(qiáng)會讓很多人加班重新實現(xiàn)功能——這就成了設(shè)計變更需求——DCR。
14.6.6 DCR Tell mode v.s. Ask mode設(shè)計變更
在項目早期,如果大家覺得要做一個設(shè)計變更,可以用告知模式(Tell-mode)的形式,就是說,修改方必須通告所有關(guān)系人:“我在這里修改了某某界面。”但是修改方不必取得其他關(guān)系人(或者模塊)的事先同意,就是說可以先行設(shè)計并編碼。當(dāng)然,如果其他關(guān)系人不同意,修改還是不能簽入。
當(dāng)項目進(jìn)行到穩(wěn)定階段,Tell-mode 要改為請求模式(Ask-mode),這時,修改方必須先問“我是否可以在這里修改某某界面?”(當(dāng)然還要有更詳盡和充分的理由)得到肯定的答復(fù)后,才能進(jìn)行修改。這時的缺省回答是“不”。
14.6.7 每周進(jìn)度報告——還有多少事沒做完
頭碰頭會議。
大拴:我有一點不太放心……
大牛:哦,為啥?我們大家都干得很歡。完成任務(wù)應(yīng)該沒問題吧。
大拴:我們每天都在簽入新的代碼,每人都很忙,但是我總覺得不太對勁。會不會越做事情越多呢?
阿超:這時我們可以看看各種報表,首要推薦的是“RemainingWork”。
請看下頁的圖14-2。
這個報表告訴我們究竟還剩下多少事情要做。我們要分析這么多簽入到底是否解決(Resolve)了相應(yīng)的任務(wù),如果是,那么我們的任務(wù)數(shù)量應(yīng)該逐漸下降,但是從圖上我們看到紅色的任務(wù)和缺陷還在緩慢增長。而綠色的“已完成任務(wù)”,卻一動不動,這就要引起我們的注意了。
可以在報表設(shè)置控制板中,進(jìn)一步選擇你要報告的內(nèi)容,如:Iteration,選擇里程碑;Area,選擇項目的不同部分,也可以修改報告的起始和終止日期等。
圖14-2 還有多少事