蔣煒航:敏捷開發(fā)的實(shí)戰(zhàn)經(jīng)驗(yàn)
作者:蔣煒航,網(wǎng)易有道筆記負(fù)責(zé)人
注:名詞詳細(xì)解釋見文末
有道云筆記團(tuán)隊(duì)成立于從2010年,從成立伊始我們就一直積極地在實(shí)踐中嘗試Scrum(敏捷開發(fā)的一種項(xiàng)目管理方法)的做法。到2012年底,3.0發(fā)布時(shí),我們在5個(gè)主要平臺(tái)(PC、iPhone、Android、iPad、Web)上總共發(fā)布了46個(gè)版本,累計(jì)了近千萬激活用戶。在這個(gè)過程中,我們逐漸摸索出一套適合以產(chǎn)品和技術(shù)創(chuàng)新為核心的中等規(guī)模(數(shù)十人)研發(fā)團(tuán)隊(duì)的Scrum實(shí)踐經(jīng)驗(yàn)。
1、Scrum不是萬能藥,要在時(shí)機(jī)成熟時(shí)推行。
什么時(shí)候算時(shí)機(jī)成熟呢?我們的經(jīng)驗(yàn)是需要兩點(diǎn):一、團(tuán)隊(duì)有三名或以上的研發(fā)工程師;二、團(tuán)隊(duì)內(nèi)有一名合適的Scrum Master。
剛開始的時(shí)候,一個(gè)開發(fā)團(tuán)隊(duì)可能只有一名或者兩名研發(fā)工程師。這時(shí)候并沒有全面推行Scrum的必要,而可以借鑒Scrum中的一些做法。比如有道云筆記的Web團(tuán)隊(duì)最初就是這個(gè)情況。當(dāng)Web團(tuán)隊(duì)只有一名研發(fā)工程師時(shí),我們就盡可能地尊重他的工作方式。同時(shí)為了保證項(xiàng)目進(jìn)度可控,我們引入了 Scrum的sprint機(jī)制——以sprint為開發(fā)周期,每個(gè)sprint進(jìn)行一次Web產(chǎn)品演示。這不但能夠讓工程師有一個(gè)以sprint為期限的壓力,還能夠讓其他同事即時(shí)地了解項(xiàng)目的進(jìn)展,以便做出相應(yīng)調(diào)整。當(dāng)Web團(tuán)隊(duì)擴(kuò)充為兩名工程師時(shí),我們又引入了結(jié)對編程、持續(xù)集成、相互代碼審核等做法。直到Web團(tuán)隊(duì)的規(guī)模進(jìn)一步擴(kuò)張時(shí),我們才開始考慮全面啟用Scrum。
當(dāng)團(tuán)隊(duì)內(nèi)無法找到合適的Scrum Master時(shí),不要輕易推行敏捷。如果你的團(tuán)隊(duì)是由新人組成,或者即使有資深員工但是他并不了解或認(rèn)同敏捷開發(fā)的話,那么你需要等待合適的Scrum Master出現(xiàn)。
合適的Scrum Master需要具備幾個(gè)特質(zhì):首先,他要認(rèn)可敏捷開發(fā)這種方式;其次,他要熟悉業(yè)務(wù),起到教練的作用,能帶領(lǐng)團(tuán)隊(duì)走正確的流程;并且,當(dāng)團(tuán)隊(duì)遇到問題時(shí),他要有能力和擔(dān)當(dāng)引導(dǎo)團(tuán)隊(duì)做出決定,在團(tuán)隊(duì)成員遇到困難時(shí),他要協(xié)助成員解決;最后,他要能識別重要和緊急的事情,而并不是事無巨細(xì)的反饋到產(chǎn)品負(fù)責(zé)人那里。
敏捷開發(fā)雖然希望團(tuán)隊(duì)自我管理,但是這需要一個(gè)過程,開始的時(shí)候,一個(gè)合適的Scrum Master至關(guān)重要。有道云筆記的Web團(tuán)隊(duì)在成立一年多以后才開始推行Scrum,很大的一個(gè)原因是在培養(yǎng)合適的Scrum Master。依據(jù)我們的經(jīng)驗(yàn),最勝任Scrum Master的人選是技術(shù)主管。我們也曾嘗試過讓產(chǎn)品經(jīng)理擔(dān)任Scrum Master,但是由于產(chǎn)品經(jīng)理本身往往擔(dān)當(dāng)產(chǎn)品負(fù)責(zé)人,兼任Scrum Master會(huì)影響他在產(chǎn)品機(jī)會(huì)和產(chǎn)品體驗(yàn)等方面的投入。
2、限制Scrum團(tuán)隊(duì)的規(guī)模,建立Scrum團(tuán)隊(duì)之間的協(xié)作機(jī)制。
隨著業(yè)務(wù)的發(fā)展,團(tuán)隊(duì)會(huì)變大。這個(gè)時(shí)候不拆分團(tuán)隊(duì)的話,效率會(huì)變低。
有道云筆記移動(dòng)端團(tuán)隊(duì)就經(jīng)歷過這樣一個(gè)過程。很長一段時(shí)間Android和iOS的研發(fā)工程師組成一個(gè)Scrum團(tuán)隊(duì),有共同的產(chǎn)品負(fù)責(zé)人和 Scrum Master。但是隨著移動(dòng)端團(tuán)隊(duì)人數(shù)的增長,Scrum會(huì)議的效率卻降低了。雖然Scrum會(huì)議只有不到半小時(shí),但是當(dāng)說一個(gè)平臺(tái)的事情的時(shí)候,另一個(gè)平臺(tái)的工程師會(huì)覺得無所事事。發(fā)現(xiàn)了這個(gè)情況后,我們把移動(dòng)端團(tuán)隊(duì)按照平臺(tái)拆分成了兩個(gè)Scrum團(tuán)隊(duì),以確保Scrum會(huì)議上說的是每一名參與者都關(guān)心的事情??偟膩碚f,參加Scrum會(huì)議的所有人,包括產(chǎn)品、開發(fā)和測試,不應(yīng)該超過9個(gè)人。
按照平臺(tái)拆分團(tuán)隊(duì),限制了Scrum團(tuán)隊(duì)的規(guī)模,提高了Scrum的效率。與此同時(shí),多個(gè)Scrum團(tuán)隊(duì)之間必須進(jìn)行有效的協(xié)作。
在初期,我們鼓勵(lì)研發(fā)工程師通過面對面地商量,快速推進(jìn)來處理平臺(tái)之間協(xié)作的需求。但是隨著業(yè)務(wù)的發(fā)展,這樣的協(xié)作越來越多,也越來越復(fù)雜,這樣面對面的討論往往會(huì)疏忽細(xì)節(jié)需求。比如說,有道云筆記3.0版本中的待辦事項(xiàng)功能,就需要PC、Web、Android、iPhone以及Server 等多個(gè)Scrum團(tuán)隊(duì)一起,對這個(gè)功能進(jìn)行產(chǎn)品定義和確定技術(shù)方案。這樣復(fù)雜的協(xié)同需求需要額外的機(jī)制來保證。這個(gè)機(jī)制就是Scrum Master的定期會(huì)議。在這個(gè)會(huì)議上,我們會(huì)討論各個(gè)Scrum團(tuán)隊(duì)相互依賴的項(xiàng)目,安排好各Scrum團(tuán)隊(duì)的開發(fā)順序。對某一件具體的事情,其中的一位Scrum Master會(huì)被指定為具體負(fù)責(zé)人來驅(qū)動(dòng)跨Scrum團(tuán)隊(duì)的協(xié)作。同樣,只有當(dāng)Scrum團(tuán)隊(duì)間的協(xié)作任務(wù)比較復(fù)雜的時(shí)候才需要引入這個(gè)機(jī)制。
3、產(chǎn)品經(jīng)理和研發(fā)工程師要擁抱Scrum帶來的變化。
在引入Scrum之前,一般的項(xiàng)目管理方式是版本式(瀑布式)的,產(chǎn)品經(jīng)理決定下一個(gè)版本做什么,預(yù)期發(fā)布的時(shí)間,然后由產(chǎn)品負(fù)責(zé)人或者技術(shù)負(fù)責(zé)人來兼做項(xiàng)目經(jīng)理。這個(gè)時(shí)候遇到的問題是項(xiàng)目往往會(huì)延期,但是產(chǎn)品經(jīng)理會(huì)有一種對項(xiàng)目把控的感覺。
引入敏捷開發(fā)之后,這個(gè)事情變了,發(fā)布是跟著sprint走的。基于持續(xù)交付的原則,一次發(fā)布包含一個(gè)或者多個(gè)sprint的內(nèi)容,而這些內(nèi)容是由團(tuán)隊(duì)整體決定的,而不是產(chǎn)品經(jīng)理個(gè)人決定。產(chǎn)品經(jīng)理只是定義了功能需求的優(yōu)先級,這些功能需求與代碼重構(gòu)、開發(fā)工具、以及市場運(yùn)營等的推廣支持等需求一起排期,最后由整個(gè)團(tuán)隊(duì)決定一個(gè)sprint做哪些東西。
從表面上看起來,產(chǎn)品經(jīng)理對產(chǎn)品的把控小了,為此,團(tuán)隊(duì)一位資深產(chǎn)品經(jīng)理有過質(zhì)疑。最后,我們還是說服了他接受敏捷。事實(shí)上,接受Scrum并不困難。這樣,產(chǎn)品經(jīng)理可以把重心放在對產(chǎn)品需求的把握上,而不必整天問這個(gè)咋樣了那個(gè)咋樣了。而且,團(tuán)隊(duì)的開發(fā)效率,功能點(diǎn)完成的速度并沒有因此而降低。
研發(fā)工程師同樣要擁抱Scrum,調(diào)整自己的工作方式。Scrum不鼓勵(lì)過度設(shè)計(jì),而采用涌現(xiàn)式設(shè)計(jì)。這意味著開始往往不會(huì)把技術(shù)架構(gòu)做得大而全,而是鼓勵(lì)快速出成果。當(dāng)然這并不是說程序架構(gòu)能夠設(shè)計(jì)得很糟糕,而是說不要花太多的精力在未知的事情上,小步快跑。為此,代碼重構(gòu)是必須的(編者注:在不改變軟件現(xiàn)有功能的基礎(chǔ)上,通過調(diào)整程序代碼改善軟件)。我們并不建議整個(gè)sprint都去做重構(gòu),更建議持續(xù)重構(gòu),把代碼調(diào)整也分解成任務(wù),每個(gè)sprint做一些。在一些大版本發(fā)布之后,重構(gòu)任務(wù)的比例可以適當(dāng)高一些。
4、量化衡量團(tuán)隊(duì)的執(zhí)行力的指標(biāo):完成度、評估準(zhǔn)確度、計(jì)劃合理度。
當(dāng)Scrum團(tuán)隊(duì)不大的時(shí)候,可以依靠主觀感覺來評估執(zhí)行力。有道云筆記團(tuán)隊(duì)在初創(chuàng)的一年內(nèi),對sprint的完成情況是沒有量化的評估的。
Scrum教材對執(zhí)行力的量化評估用的是故事點(diǎn)和速率。由于團(tuán)隊(duì)成員實(shí)際上都是有道云筆記的用戶,能夠直觀理解產(chǎn)品經(jīng)理提出的需求。因此我們省去了用戶故事,由產(chǎn)品經(jīng)理提產(chǎn)品需求,而團(tuán)隊(duì)把需求分解成任務(wù)。經(jīng)過一段時(shí)間的探索,我們定義了幾個(gè)量化指標(biāo),其中最重要的是完成度,我們用這個(gè)指標(biāo)來衡量團(tuán)隊(duì)的執(zhí)行力:
完成度=1-計(jì)劃內(nèi)未完成任務(wù)的剩余時(shí)間/計(jì)劃內(nèi)任務(wù)評估時(shí)間
(完成度的數(shù)值在80~90%之間比較好。過高的完成度說明sprint計(jì)劃過于保守。)
有些管理者會(huì)懷疑完成度的準(zhǔn)確性:第一是,團(tuán)隊(duì)是否會(huì)把計(jì)劃內(nèi)任務(wù)的評估時(shí)間評估得過長,使得完成度看起來高?事實(shí)上根據(jù)我們的經(jīng)驗(yàn),團(tuán)隊(duì)對計(jì)劃內(nèi)任務(wù)的評估往往是偏樂觀的;第二是,計(jì)劃內(nèi)未完成任務(wù)的剩余時(shí)間是如何出來的?這個(gè)是由團(tuán)隊(duì)在sprint末尾評估出來的,因?yàn)檫@時(shí)技術(shù)設(shè)計(jì)多已完成,這個(gè)時(shí)間是比較準(zhǔn)確的。我們也曾嘗試過燃盡圖,發(fā)現(xiàn)并不如完成度來得直觀。
另外,我們還定義了兩個(gè)指標(biāo)來作為輔助參考。一個(gè)是評估準(zhǔn)確度(計(jì)劃內(nèi)任務(wù)評估時(shí)間/實(shí)際使用時(shí)間),一個(gè)是計(jì)劃合理度(計(jì)劃內(nèi)任務(wù)使用時(shí)間/計(jì)劃外任務(wù)使用時(shí)間)。這兩個(gè)指標(biāo)的歷史數(shù)值可以讓我們更加了解團(tuán)隊(duì)執(zhí)行的情況。
當(dāng)Scrum團(tuán)隊(duì)不大的時(shí)候,可以依靠主觀感覺來評估執(zhí)行力。團(tuán)隊(duì)擴(kuò)大后,詳細(xì)的數(shù)值評估必不可少。
5、高效的sprint計(jì)劃會(huì)的要素:預(yù)先梳理需求、合適的任務(wù)粒度、隨機(jī)認(rèn)領(lǐng)任務(wù)、運(yùn)營調(diào)研任務(wù)、任務(wù)評估。
Scrum開發(fā)中,最重要的會(huì)議是sprint計(jì)劃會(huì)。但是在這之前,產(chǎn)品經(jīng)理和研發(fā)工程師可以預(yù)先梳理一下需求,以保證sprint計(jì)劃會(huì)可以更加高效和準(zhǔn)確。我們嘗試過多種方式來預(yù)先梳理需求:發(fā)郵件、產(chǎn)品與研發(fā)面對面溝通、開需求梳理會(huì)。哪種方式更好,目前還沒有定論。
Sprint計(jì)劃會(huì)主要討論幾件事情:將需求分解成任務(wù)、評估每個(gè)任務(wù)的工作量、分配任務(wù)。每件事情都有各自的技巧。
首先,任務(wù)分解的粒度應(yīng)該如何?Scrum開發(fā)一般認(rèn)為任務(wù)分解得越細(xì)越好,但是在實(shí)際操作中我們發(fā)現(xiàn)如果分得太細(xì)的話是有問題的。比如說,認(rèn)領(lǐng)任務(wù)、記錄每個(gè)任務(wù)的工時(shí)和完成情況,都會(huì)帶來時(shí)間消耗。我們經(jīng)過較長時(shí)間的實(shí)踐,發(fā)現(xiàn)0.5至3天一個(gè)任務(wù)是一個(gè)合適的粒度范圍。
如何評估工作量和分配任務(wù)這兩個(gè)事情是關(guān)聯(lián)的,不同的人做同一個(gè)任務(wù),往往時(shí)間會(huì)相差很大。所以這時(shí)候有一個(gè)艱難的選擇,是讓大家做自己熟悉擅長的事情,還是隨機(jī)認(rèn)領(lǐng)任務(wù)以達(dá)到團(tuán)隊(duì)人員對所有模塊都很熟悉的狀態(tài)。一個(gè)短期見效,另一個(gè)長期可發(fā)展。
有道云筆記PC平臺(tái)的Scrum團(tuán)隊(duì)經(jīng)歷了一個(gè)從前者轉(zhuǎn)向后者的過程。在開始很長一段時(shí)期里,Scrum團(tuán)隊(duì)把自己PC客戶端按模塊進(jìn)行拆分,每個(gè)模塊由一位研發(fā)工程師負(fù)責(zé),工作量的評估也以這個(gè)人判斷為準(zhǔn)。這個(gè)辦法幫助團(tuán)隊(duì)快速開發(fā)了PC的第一個(gè)版本和后續(xù)幾個(gè)小版本。但是慢慢的,這種做法的瓶頸就出現(xiàn)了。之前的模塊劃分隨著項(xiàng)目發(fā)展變得有些過時(shí),有的模塊出現(xiàn)了瓶頸。在最近的幾個(gè)sprint里,PC平臺(tái)的Scrum團(tuán)隊(duì)已經(jīng)開始隨機(jī)認(rèn)領(lǐng)任務(wù)的方式。
此外,在實(shí)際研發(fā)工程中,往往會(huì)有一些由于團(tuán)隊(duì)沒有相關(guān)的經(jīng)驗(yàn)而比較不確定的事情。對于這樣的事情,我們會(huì)先安排一個(gè)調(diào)研任務(wù),并且將這個(gè)任務(wù)盡量安排在sprint的早期,并且憑借經(jīng)驗(yàn)會(huì)在計(jì)劃會(huì)上留出后續(xù)實(shí)際開發(fā)的時(shí)間。如果調(diào)研任務(wù)確定這個(gè)事情的復(fù)雜度可控,我們會(huì)在后續(xù)的sprint會(huì)議上根據(jù)調(diào)研成果分解出詳細(xì)的任務(wù),另一方面,如果這個(gè)事情的復(fù)雜度太大,那么我們會(huì)把完不成的內(nèi)容放到下個(gè)sprint。
任務(wù)評估的辦法,或者用紙筆寫下后同時(shí)公布或者用估算撲克,兩者本質(zhì)上沒有區(qū)別。當(dāng)有較大分歧時(shí)經(jīng)過討論后再次評估,次數(shù)不宜過多,一般1-2 次就好,不超過3次。如果討論不清楚,Scrum Master不妨先定一個(gè)時(shí)間,讓會(huì)議進(jìn)行下去。后面實(shí)際開發(fā)過程中會(huì)越來越清楚。敏捷開發(fā)本來就是漸進(jìn)的過程。
6、流水化安排開發(fā)環(huán)節(jié)與測試環(huán)節(jié)。
如何安排測試與開發(fā),是從項(xiàng)目一開始我們就反復(fù)思考和嘗試的問題。經(jīng)過一段時(shí)間的實(shí)踐,我們目前采用流水化的方式來安排開發(fā)環(huán)節(jié)與測試環(huán)節(jié)。具體來說,就是在開發(fā)sprint結(jié)束后再開始測試這個(gè)sprint的產(chǎn)出版本;而在開發(fā)的sprint內(nèi),開發(fā)團(tuán)隊(duì)解決上一個(gè)sprint的產(chǎn)出版本測試出的bug。雖然這意味著開發(fā)團(tuán)隊(duì)要在測試環(huán)節(jié)還未開始之時(shí)(Sprint計(jì)劃會(huì)上),就要估計(jì)并預(yù)留出上個(gè)sprint產(chǎn)出版本的bug修改時(shí)間,但在實(shí)際操作中,開發(fā)團(tuán)隊(duì)能夠通過歷史數(shù)據(jù)做出比較準(zhǔn)確的估計(jì)。因此這種方式的效果是良好的。
7、版本發(fā)布基本按照sprint周期。
我們通常在一個(gè)或者多個(gè)sprint之后(在測試環(huán)節(jié)之后)發(fā)布版本。具體選取幾個(gè)sprint往往會(huì)參考一些市場情況的考慮,比如說將一個(gè)做了較多重構(gòu)的sprint與一個(gè)做了較多新功能開發(fā)的sprint打包作為一個(gè)新版本發(fā)布出來。我們基本上不會(huì)為某個(gè)大版本打亂我們的sprint周期。
8、Scrum需要配備合適的工程實(shí)踐,例如單元測試、代碼審核、持續(xù)集成、項(xiàng)目管理工具。
我們要求研發(fā)工程師必須要寫單元測試和相互審核代碼。測試驅(qū)動(dòng)開發(fā)和結(jié)對編程目前還有許多爭議,我們也不建議貿(mào)然嘗試。在實(shí)踐中,我們采用了簡化版本,對可以寫單元測試的模塊都要求測試覆蓋,并且通過測試覆蓋率來量化單元測試的力度。此外我們將研發(fā)工程師兩兩結(jié)對,相互檢查對方的代碼,只有經(jīng)過檢查的代碼才能最終提交。
此外,我們對代碼進(jìn)行了持續(xù)集成。每天凌晨持續(xù)集成系統(tǒng)會(huì)自動(dòng)下載前一天的代碼,進(jìn)行編譯和部署。Web端會(huì)直接部署到Web測試服務(wù)器,而客戶端(PC、iPhone、iPad、Android)會(huì)自動(dòng)拷貝到一個(gè)內(nèi)部服務(wù)器上。測試人員或者感興趣的人每一天一上班就可以用到最新的版本。
關(guān)于Scrum的任務(wù)管理,我們采用過不同的項(xiàng)目管理工具,包括白板、開源軟件等等??偟膩碚f,工具只是簡化了一些統(tǒng)計(jì),Scrum最重要的還是敏捷開發(fā)本身的思想。
編者注:名詞詳細(xì)解釋(感謝李瑋對本文編輯的貢獻(xiàn))
敏捷開發(fā):相對于傳統(tǒng)的版本式(瀑布式)開發(fā)模式。以往的開發(fā)模式中,一次會(huì)做一個(gè)大版本,在這個(gè)版本的開發(fā)過程中定義需要開發(fā)哪些功能,需要多少資源,需要多長周期,最終一次性交付這樣一個(gè)版本。敏捷開發(fā)則是將一個(gè)很大的版本盡量細(xì)分為小的功能、模塊或階段,每次做其中一部分,做完以后立即發(fā)布一個(gè)小版本給用戶。
Scrum:敏捷開發(fā)的一種項(xiàng)目管理方法,通常表示敏捷開發(fā)所承擔(dān)的一個(gè)階段性任務(wù),做完這個(gè)任務(wù)就可以發(fā)布小版本。在做這個(gè)任務(wù)的過程中團(tuán)隊(duì)稱作Scrum團(tuán)隊(duì),負(fù)責(zé)人是Scrum Master。這種Scrum團(tuán)隊(duì)和以往的團(tuán)隊(duì)相比,要求每一個(gè)團(tuán)隊(duì)成員掌握更全面的知識,而不是以往軟件開發(fā)不懂測試,軟件測試不懂開發(fā)。每個(gè)人都需要有獨(dú)立解決問題的能力。對Scrum Master來說,需要了解整個(gè)Scrum的全貌,并具備整個(gè)過程中各個(gè)領(lǐng)域的知識,因此通常是技術(shù)牛人,而不是項(xiàng)目管理者去做Scrum Master。
Sprint:表示Scrum中的一個(gè)階段,是對Scrum繼續(xù)的細(xì)分。比如分給某個(gè)人開發(fā)50行代碼的一個(gè)任務(wù),他的第一個(gè)sprint可以是閱讀需求文檔,第二個(gè)是寫代碼,第三個(gè)是debug。好的敏捷開發(fā)中每個(gè)Sprint的任務(wù)量需要有較好的定義,不能太少,也不能讓人做不完,因?yàn)槊總€(gè)Sprint的時(shí)間是固定的。
原文鏈接:http://tech.sina.com.cn/i/csj/2013-01-22/18528003613.shtml