最近在與一位總經(jīng)理交流的時(shí)候,他談到他們公司的軟件研發(fā)管理,說(shuō):“我們公司最大的問(wèn)題是項(xiàng)目不能按時(shí)完成,總要一拖再拖。”他問(wèn)我有什么辦法能改變這個(gè)境況。從這樣一個(gè)問(wèn)題開(kāi)始,在隨后的交談中,又引出他一連串在軟件研發(fā)管理中的遇到的問(wèn)題,包括:
. 現(xiàn)有代碼質(zhì)量不高,新來(lái)的開(kāi)發(fā)人員接手時(shí)寧愿重寫(xiě),也不愿意看別人留下的“爛”代碼,怎么辦?
. 重構(gòu)會(huì)造成回退,怎樣避免?
. 有些開(kāi)發(fā)人員水平相對(duì)不高,如何保證他們的代碼質(zhì)量?
. 軟件研發(fā)到底需不需要文檔?
. 要求提交代碼前做Code Review,而開(kāi)發(fā)人員不做,或敷衍了事,怎么辦?
. 當(dāng)有開(kāi)發(fā)人員在開(kāi)發(fā)過(guò)程中遇到難題,工作無(wú)法繼續(xù),因而拖延進(jìn)度,怎么解決?
. 如何提高開(kāi)發(fā)人員的主觀能動(dòng)性?
其實(shí),每個(gè)軟件研發(fā)團(tuán)隊(duì)的管理者都面臨著或曾經(jīng)面臨過(guò)這些問(wèn)題,也都有著自己的管理“套路”來(lái)應(yīng)對(duì)這些問(wèn)題。我把我的“套路”再此絮叨絮叨。
1. 項(xiàng)目不能按時(shí)完成,總要一拖再拖,怎么改變?
找解決辦法前,當(dāng)然要先知道問(wèn)題為什么會(huì)出現(xiàn)。這位總經(jīng)理說(shuō):“總會(huì)不斷地有需求要改變和新需求提出來(lái),使原來(lái)的開(kāi)發(fā)計(jì)劃不得不延長(zhǎng)。”原來(lái)如此。知道根源,當(dāng)然解決辦法也就有了,那就是“敏捷”。敏捷開(kāi)發(fā)因其迭代(Iterative)和增量(Incremental)的思想與實(shí)踐,正好適合“需求經(jīng)常變化和增加”的項(xiàng)目和產(chǎn)品。在我講述了敏捷的一些概念,特別是Scrum的框架后,總經(jīng)理也表示了對(duì)“敏捷”的認(rèn)同。
其實(shí)仔細(xì)想想,這里面還有一個(gè)非常普遍的問(wèn)題。對(duì)于產(chǎn)品的交付時(shí)間或項(xiàng)目的完成時(shí)間,往往由高級(jí)管理層根據(jù)市場(chǎng)情況決策和確定。在很多軟件企業(yè)中,這些決策者在決策時(shí)往往忽略了一個(gè)重要的參數(shù),那就是團(tuán)隊(duì)的生產(chǎn)率(Velocity)。生產(chǎn)率需要量化,而不是“拍腦門(mén)子”感覺(jué)出來(lái)的。敏捷開(kāi)發(fā)中有關(guān)于如何估算生產(chǎn)率的方法。所以使用敏捷,在估算產(chǎn)品交付時(shí)間或項(xiàng)目完成時(shí)間時(shí),是相對(duì)較準(zhǔn)確的。Scrum創(chuàng)始人之一的Jeff Sutherland說(shuō),他在一個(gè)風(fēng)險(xiǎn)投資團(tuán)隊(duì)做敏捷教練時(shí),團(tuán)隊(duì)中的資深合伙人會(huì)向所有的待投資企業(yè)問(wèn)同一個(gè)問(wèn)題:“你們是否清楚團(tuán)隊(duì)的生產(chǎn)率?”而這些企業(yè)都很難做出明確的答復(fù)。軟件企業(yè)要想給產(chǎn)品定一個(gè)較實(shí)際的交付日期,就首先要弄清楚自己的軟件生產(chǎn)率。
2. 現(xiàn)有代碼質(zhì)量不高,新來(lái)的開(kāi)發(fā)人員接手時(shí)寧愿重寫(xiě),也不愿意看別人留下的“爛”代碼,怎么辦?
這可能是很多軟件開(kāi)發(fā)工程師都有過(guò)的體驗(yàn),在接手別人的代碼時(shí),看不懂、無(wú)法加新功能,讀代碼讀的頭疼。這說(shuō)明什么?排除接手人個(gè)人水平的因素,這說(shuō)明舊代碼可讀性、可擴(kuò)展性比較差。怎么辦?這時(shí),也許重構(gòu)是一種兩全其美的辦法。接手人重構(gòu)代碼,既能改善舊代碼的可讀性和可擴(kuò)展性,又不至于因重寫(xiě)代碼帶來(lái)的時(shí)間上的風(fēng)險(xiǎn)。
從接手人心理的角度看,重構(gòu)還有一個(gè)好的副作用,就是代碼重構(gòu)之后,接手人覺(jué)得那些原來(lái)的“爛”代碼被修改成為自己引以自豪的新成就。《Scrum敏捷軟件開(kāi)發(fā)》的作者M(jìn)ike Cohn寫(xiě)到過(guò):“我的女兒們畫(huà)了一幅特別令人贊嘆的杰作后,她們會(huì)將它從學(xué)校帶回家,并想把它展示在一個(gè)明顯的位置,也就是冰箱上面。有一天,在工作中,我用C++代碼實(shí)現(xiàn)了某個(gè)特別有用的策略模式的程序。因?yàn)槲艺J(rèn)定冰箱門(mén)適合展示我們引以為豪的任何東西,所以我就將它放上去了。如果我們一直對(duì)自己工作的質(zhì)量特別自豪,可以驕傲地將它和孩子的藝術(shù)品一樣展示在冰箱上,那不是很好嗎?”所以這個(gè)積極的促進(jìn)作用,將使得接手人感覺(jué)修改的代碼是自己的了,而且期望能夠找到更多的可以重構(gòu)的東西。
3. 重構(gòu)會(huì)造成回退,怎樣避免?
重構(gòu)確實(shí)很容易造成回退(Regression)。這時(shí),重構(gòu)會(huì)起到與其初衷相反的作用。所以我們應(yīng)該盡可能多地增加單元測(cè)試。有些老產(chǎn)品,舊代碼,可能沒(méi)有或者沒(méi)有那么多的單元測(cè)試。但我們至少要在重構(gòu)前,增加對(duì)要重構(gòu)部分代碼的單元測(cè)試。基于重構(gòu)目的的單元測(cè)試,應(yīng)該遵循以下的原則(見(jiàn)《重構(gòu)》第4章:構(gòu)筑測(cè)試體系):
- 編寫(xiě)未臻完善的測(cè)試并實(shí)際運(yùn)行,好過(guò)對(duì)完美測(cè)試的無(wú)盡等待。測(cè)試應(yīng)該是一種風(fēng)險(xiǎn)驅(qū)動(dòng)行為,所以不要去測(cè)試那些僅僅讀寫(xiě)一個(gè)值域的訪問(wèn)函數(shù),應(yīng)為它們太簡(jiǎn)單了,不大可能出錯(cuò)。
- 考慮可能出錯(cuò)的邊界條件,把測(cè)試火力集中在哪兒。扮演“程序公敵”,縱容你心智中比較促狹的那一部分,積極思考如何破壞代碼。
- 當(dāng)事情被公認(rèn)應(yīng)該會(huì)出錯(cuò)時(shí),別忘了檢查是否有異常如期被拋出。
- 不要因?yàn)?#8220;測(cè)試無(wú)法捕捉所有Bug”,就不撰寫(xiě)測(cè)試代碼,因?yàn)闇y(cè)試的確可以捕捉到大多數(shù)Bug。
- “花合理時(shí)間抓出大多數(shù)Bug”要好過(guò)“窮盡一生抓出所有Bug”。因?yàn)楫?dāng)測(cè)試數(shù)量達(dá)到一定程度之后,測(cè)試效益就會(huì)呈現(xiàn)遞減態(tài)勢(shì),而非持續(xù)遞增。
說(shuō)到《重構(gòu)》這本書(shū),其實(shí)在每個(gè)重構(gòu)方法中都有“作法(Mechanics)”一段,在重構(gòu)的實(shí)踐中按照上面所述的步驟進(jìn)行是比較穩(wěn)妥的,同時(shí)也能避免很多不經(jīng)意間制造的回退出現(xiàn)。
4. 要求提交代碼前做Code Review,而開(kāi)發(fā)人員不做,或敷衍了事,怎么辦?
如果每個(gè)開(kāi)發(fā)人員都是積極主動(dòng)的,Code Review的作用能落到實(shí)處。但如果不是呢?團(tuán)隊(duì)管理者需要一些手段促使其有效地進(jìn)行Code Review。首先,我們采用的Code Review有2種形式,一是Over-the-shoulder,也就是2個(gè)人座在一起,一個(gè)人講,另一個(gè)人審查。二是用工具Code Collaborator來(lái)進(jìn)行。無(wú)論哪種形式,在提交代碼時(shí),必須注明關(guān)于審查的信息,比如:審查者(Reviewer)的名字或?qū)彶樘?hào)(Review ID,Code Collaborator自動(dòng)生成),每天由一名專(zhuān)職人員來(lái)檢查Checklist中的每一條,看是否有人漏寫(xiě)這些信息,如果發(fā)現(xiàn)會(huì)提醒提交的人補(bǔ)上。另外,某段提交的代碼出問(wèn)題,提交者和審查者都要一起來(lái)解決出現(xiàn)的問(wèn)題,以最大限度避免審查過(guò)程敷衍了事。
博主Inovy在某個(gè)評(píng)論說(shuō)的很形象:“木(沒(méi))有賞罰的制度,就是帶到廁所的報(bào)紙,看完就可以用來(lái)擦屁股了。”沒(méi)有獎(jiǎng)懲制度作保證,當(dāng)然上面的要求沒(méi)有什么效力。所以,當(dāng)有人經(jīng)常不審查就提交,或?qū)彶闀r(shí)不負(fù)責(zé)任,它的績(jī)效評(píng)定就會(huì)因此低一點(diǎn),而績(jī)效的評(píng)分是跟每年工資漲落掛鉤的。說(shuō)白了,可能某個(gè)人會(huì)因?yàn)槎啻伪徊槌鰶](méi)有做Code Review就提交代碼,而到年底加薪時(shí)比別人少漲500塊錢(qián)。
5. 軟件研發(fā)到底需不需要文檔?
軟件研發(fā)需要文檔的起原可能有2種,一是比較原始的,需要文檔是為了當(dāng)開(kāi)發(fā)人員離職后,企業(yè)需要接手的人能根據(jù)文檔了解他所接手的代碼或模塊的設(shè)計(jì)。二是較高層次的,企業(yè)遵從ISO9001質(zhì)量管理體系或CMMI。
對(duì)于第一種,根源可能來(lái)自于兩個(gè)方面:
- 原開(kāi)發(fā)人員設(shè)計(jì)編碼水平不高,其代碼可讀性較差。
- 設(shè)計(jì)思想和代碼只有一個(gè)人了解,此人一旦離職,無(wú)人知道其細(xì)節(jié)。
在編碼前寫(xiě)一些簡(jiǎn)單的設(shè)計(jì)文檔,有助于理清思路,尤其是輔以一些UML圖,在交流時(shí)也是有好處的。但同時(shí),我們也應(yīng)該提高開(kāi)發(fā)人員的編碼水平增加其代碼的可讀性,比如增強(qiáng)其變量命名的可讀性、用一些被大家所了解的設(shè)計(jì)模式來(lái)替代按自己某些獨(dú)特思路編寫(xiě)的代碼、增加和改進(jìn)注釋等等,以減少不必要的文檔。另外推行代碼的集體所有權(quán)(Collective Ownership),避免某些代碼只被一個(gè)人了解,這樣可以減少以此為目的而編寫(xiě)的文檔。
對(duì)于第二種,情況有些復(fù)雜。接觸過(guò)敏捷開(kāi)發(fā)的人都知道《敏捷宣言》中的“可以工作的軟件勝于面面俱到的文檔”。接觸過(guò)CMMI開(kāi)發(fā)或者ISO9001質(zhì)量管理體系的人知道它們對(duì)文檔的要求是多么的高。它們看起來(lái)水火不相容。但是,它們的宗旨是一致的,即:構(gòu)建高質(zhì)量的產(chǎn)品。
對(duì)于敏捷,使用手寫(xiě)用戶(hù)故事來(lái)記錄需求和優(yōu)先級(jí)的方法,以及在白板上寫(xiě)畫(huà)的非正式設(shè)計(jì),是不能通過(guò)ISO9001的審核的,但當(dāng)把它們復(fù)印、拍照、增加序號(hào)、保存后,可以通過(guò)審核。每次都是成功的Daily Build和Auto Test報(bào)告無(wú)法證明它們是否真正被執(zhí)行并真正成功,所以不能通過(guò)ISO9001的審核。但添加一個(gè)斷言失敗(類(lèi)似assert(false)的斷言)的測(cè)試后,則可以通過(guò)審核。
CMMI與敏捷也是互補(bǔ)的,前者告訴組織在總體條款上做什么,但是沒(méi)有說(shuō)如何去做,后者是一套最佳實(shí)踐。SCRUM之類(lèi)的敏捷方法也被引入過(guò)那些已通過(guò)CMMI5級(jí)評(píng)估的組織。很多企業(yè)忘記了最終目標(biāo)是改進(jìn)他們構(gòu)建軟件及遞交產(chǎn)品的方式,相反,它們關(guān)注于填寫(xiě)按照CMMI文檔描述的假想的缺陷,卻不關(guān)心這些變化是否能改進(jìn)過(guò)程或產(chǎn)品。
所以敏捷開(kāi)發(fā)在過(guò)程中只編寫(xiě)夠用的文檔,和以“信息的溝通、符合性的證據(jù)以及知識(shí)共享”作為主要目標(biāo)的質(zhì)量體系文檔要求并不矛盾。在實(shí)踐中,我們可以按以下方法做,在實(shí)現(xiàn)SCRUM的同時(shí),符合審核和評(píng)估的要求:
- 制作格式良好的、被細(xì)化的、被保存的和能跟蹤的Backlog。復(fù)印和照片同樣有效。
- 將監(jiān)管需要的文檔工作也放入Backlog。除了可以確保它們不被忘記,還能使監(jiān)管要求的成本是可見(jiàn)的。
- 使用檢查列表,以向?qū)徍藛T或評(píng)估員證明活動(dòng)已執(zhí)行。團(tuán)隊(duì)對(duì)“完成”的定義(Definition of “Done”)可以很容易轉(zhuǎn)變?yōu)橐环輽z查列表。
- 使用敏捷項(xiàng)目管理工具。它其實(shí)就是開(kāi)發(fā)程序和記錄的電子呈現(xiàn)方式。
總而言之,軟件研發(fā)需要文檔(但文檔的形式可以是多種多樣的,用Word寫(xiě)的文字式的文件是文檔,用Visio畫(huà)的UML圖也是文檔,保存在Quality Center中的測(cè)試用例也是文檔),同時(shí)我們只需寫(xiě)夠用的文檔。
6. 當(dāng)有開(kāi)發(fā)人員在開(kāi)發(fā)過(guò)程中遇到難題,工作無(wú)法繼續(xù),因而拖延進(jìn)度,怎么解決?
這也是個(gè)常遇到的問(wèn)題。如果管理者對(duì)于某個(gè)工程師的具體問(wèn)題進(jìn)行指導(dǎo),就會(huì)陷入過(guò)度微觀管理的境地。我們需要找到宏觀解決辦法。一,我們基于Scrum的“團(tuán)隊(duì)有共同的目標(biāo)”這一規(guī)則,利用前面提到的集體所有權(quán),當(dāng)出現(xiàn)這些問(wèn)題時(shí),用團(tuán)隊(duì)中所有可以使用的力量來(lái)幫助其擺脫困境,而不是任其他人袖手旁觀。當(dāng)然這里會(huì)牽扯到績(jī)效評(píng)定的問(wèn)題,比如:提供幫助的人會(huì)覺(jué)得,他的幫助無(wú)助于自己績(jī)效評(píng)定的提高,為什么要提供幫助。這需要人力資源部門(mén)在使用Scrum開(kāi)發(fā)的團(tuán)隊(duì)的績(jī)效評(píng)估中,盡量消除那些傾向個(gè)人的因素,還要包含團(tuán)隊(duì)協(xié)作的因素,廣泛聽(tīng)取個(gè)方面的意見(jiàn),更頻繁地評(píng)估績(jī)效等等。
二,即使動(dòng)用所有可以使用的力量,如果某個(gè)難題真的無(wú)法逾越,為了減少不能按時(shí)交付的風(fēng)險(xiǎn),產(chǎn)品負(fù)責(zé)人應(yīng)當(dāng)站出來(lái),并有所作為。要么重新評(píng)估Backlog的優(yōu)先級(jí),使無(wú)法繼續(xù)的Backlog遲一點(diǎn)交付,先做一些相對(duì)較低優(yōu)先級(jí)的Backlog,以保證整體交付時(shí)間不至于延長(zhǎng);要么減少部分功能,給出更多的時(shí)間去攻克難題。總之逾越技術(shù)上難關(guān)會(huì)使團(tuán)隊(duì)的生產(chǎn)率下降,產(chǎn)品負(fù)責(zé)人必須作出取舍。
7. 有些開(kāi)發(fā)人員水平相對(duì)不高,如何保證他們的代碼質(zhì)量?
當(dāng)然首先讓較有經(jīng)驗(yàn)的人Review其要提交的代碼,這幾乎是所有管理者會(huì)做的事。除此之外,管理者有責(zé)任幫助這些人(也包括水平較高的人)提高水平,他們可以看一些書(shū),上網(wǎng)看資料,讀別人的代碼等等,途經(jīng)還是很多的。但問(wèn)題是你如何去衡量其是否真正有所收獲。我們的經(jīng)驗(yàn)是,在每年大約3月份為每個(gè)工程師制定整個(gè)年度的目標(biāo),每個(gè)人的目標(biāo)包括產(chǎn)品上的,技術(shù)上的,個(gè)人能力上的等4到5項(xiàng)。半年后和一年后,要做兩次Performance Review,目標(biāo)是否實(shí)現(xiàn),也會(huì)跟績(jī)效評(píng)定掛鉤。我們?cè)谥贫繕?biāo)時(shí),遵循SMART原則,即:
Specific(明確的):目標(biāo)應(yīng)該按照明確的結(jié)果和成效表述。
Measurable(可衡量的):目標(biāo)的完成情況應(yīng)該可以衡量和驗(yàn)證。
Aligned(結(jié)盟的):目標(biāo)應(yīng)該與公司的商業(yè)策略保持一致。
Realistic(現(xiàn)實(shí)的):目標(biāo)雖然應(yīng)具挑戰(zhàn)性,但更應(yīng)該能在給定的條件和環(huán)境下實(shí)現(xiàn)。
Time-Bound(有時(shí)限的):目標(biāo)應(yīng)該包括一個(gè)實(shí)現(xiàn)的具體時(shí)間。
比如:某個(gè)人制定了“初步掌握本地化技術(shù)”的目標(biāo),他要確定實(shí)現(xiàn)時(shí)間,要描述學(xué)習(xí)的途經(jīng)和步驟,要通過(guò)將技術(shù)施加到公司現(xiàn)有的產(chǎn)品中,為公司產(chǎn)品的本地化/國(guó)際化/全球化作一些探索,并制作Presentation給團(tuán)隊(duì)演示他的成果,并準(zhǔn)備回答其他人提出的問(wèn)題。團(tuán)隊(duì)還為了配合其實(shí)現(xiàn)目標(biāo),組織Tech Talk的活動(dòng),供大家分享每個(gè)人的學(xué)習(xí)成果。通過(guò)這些手段,提高開(kāi)發(fā)人員的自學(xué)興趣,并逐步提高開(kāi)發(fā)人員的技術(shù)水平。
8. 如何提高開(kāi)發(fā)人員的主觀能動(dòng)性?
提高開(kāi)發(fā)人員的主觀能動(dòng)性,少不了激勵(lì)機(jī)制。不能讓開(kāi)發(fā)人員感到,5年以后的他和現(xiàn)在比不會(huì)有什么進(jìn)步。你要讓他感到他所從事的是一個(gè)職業(yè)(Career),而不只是一份工作(Job)。否則,他們是不會(huì)主動(dòng)投入到工作中的。我們的經(jīng)驗(yàn)是提供一套職業(yè)發(fā)展的框架。框架制定了2類(lèi)發(fā)展道路,管理類(lèi)(Managerial Path)和技術(shù)類(lèi)(Technical Path),6個(gè)職業(yè)級(jí)別(1-3級(jí)是Entry/Associate,Intermediate,Senior。4級(jí)管理類(lèi)是Manager/Senior Manager,技術(shù)類(lèi)是Principal/Senior Principal。5級(jí)管理類(lèi)是Director/Senior Director,技術(shù)類(lèi)是Fellow/Architect。6級(jí)是Executive Management)。每個(gè)級(jí)別都有13個(gè)方面的具體要求,包括:范圍(Scope)、跨職能(Cross Functional)、層次(Level)、知識(shí)(Knowledge)、指導(dǎo)(Guidance)、問(wèn)題解決(Problem Solving)、遞交成果(Delivering Result)、責(zé)任感(Responsbility)、導(dǎo)師(Mentoring)、交流(Communication)、自學(xué)(Self-Learning),運(yùn)作監(jiān)督(Operational Oversight),客戶(hù)響應(yīng)(Customer Responsiveness)。每年有2次提高級(jí)別的機(jī)會(huì),開(kāi)發(fā)人員一旦具備了升級(jí)的條件,他的Supervisor將會(huì)提出申請(qǐng),一旦批準(zhǔn),他的頭銜隨之提高,薪水也會(huì)有相對(duì)較大提高。從而使每個(gè)開(kāi)發(fā)人員覺(jué)得“有奔頭”,自然他們的主觀能動(dòng)性也就提高了。
上面的“套路”涉及了軟件研發(fā)團(tuán)隊(duì)管理中的研發(fā)過(guò)程、技術(shù)實(shí)踐、文檔管理、激勵(lì)機(jī)制等一些方面。但只是九牛一毛,研發(fā)團(tuán)隊(duì)管理涵蓋的內(nèi)容還有很多很多,還需要管理者在不斷探索和實(shí)踐的道路上學(xué)習(xí)和掌握。