項目背景
這個項目的客戶是歐洲一家人壽保險公司。該保險公司目前進行的一個計劃是對現(xiàn)有的業(yè)務(wù)流程(business process)和IT系統(tǒng)進行較大規(guī)模的改造,以適應(yīng)新的市場要求。我們的項目是這個計劃的一個組成部分,它的目標是建立一個瀏覽系統(tǒng)與保險公司的后端保險管理系統(tǒng)相連。這個瀏覽系統(tǒng)用Web瀏覽器作為用戶界面,以取代目前使用的字符終端界面。 2002年初,公司的有關(guān)部門(專門作金融服務(wù))曾作了一些可行性研究工作。項目于2002年四月底正式啟動,主要的開發(fā)工作于10月底結(jié)束。然后由另一組人馬進行用戶接收測試(user acceptance test)。
技術(shù)與系統(tǒng)構(gòu)架
系統(tǒng)采用J2EE技術(shù),系統(tǒng)基本上是三層(3-tier)結(jié)構(gòu),即Web接口(web presentation),應(yīng)用邏輯(application logic)和后端服務(wù)器(backend)。
系統(tǒng)需求與規(guī)范
該項目主要有兩種文檔提供給開發(fā)人員:一種是系統(tǒng)功能描述,由一系列的模塊組成。每個模塊類似于一個use case,主要給出了該模塊需實現(xiàn)的屏幕/窗口(screen shot),并一般地描述了這些屏幕上的操作以及它們之間的切換。這樣的模塊描述文件在項目中被稱之為“故事板”(story board)?!肮适掳濉庇蓸I(yè)務(wù)分析人員(business analyst)會同用戶產(chǎn)生。另一種文檔是與后端服務(wù)器接口的規(guī)范說明,如命令格式,數(shù)據(jù)格式等,由后端系統(tǒng)設(shè)計開發(fā)組提供。按照項目規(guī)定,兩種文件都需要經(jīng)過充分討論并基本穩(wěn)定下來之后,由相關(guān)負責人員簽發(fā)(sign off),然后交給開發(fā)組。
項目團隊與工作地點
項目組有14個開發(fā)人員,2個業(yè)務(wù)分析人員(business analyst),一個項目經(jīng)理。主要開發(fā)組在英國(10個開發(fā)人員),項目經(jīng)理和其余人員則在客戶所在地(與英國有一小時的飛行的距離)。
工作筆記
由于工作習慣,我一般每天都作工作筆記。而在這個項目中前兩個多月中,我也每周都寫一篇小結(jié),主要是對項目運行的觀察(所計述的都是對我所在的公司本部開發(fā)組而言)以下便是稍作整理后的前十周的小結(jié)(略去了公司和人員的名字)。這些筆記可能顯得有些雜亂和瑣碎,列在這里的主要目的是想忠實地把我眼中的項目進展情況展現(xiàn)出來。
第一周
開發(fā)組成員逐步聚集到項目組所在地。我們十來個人都坐在一起,邊上一個大白板。這種坐位設(shè)置非常利于交流,特別是Cockburn所稱的“滲透”式交流。各成員的技能方面也各有所專,如Java,EJB,JSP等。
項目有個時間錄入跟蹤系統(tǒng)(time tracker/timesheet)。每人需錄入每天所做的任務(wù)和時間。這主要用于項目管理,而這些歷史數(shù)據(jù)也是對新任務(wù)進行規(guī)劃評估的基礎(chǔ)。
這周的主要工作是設(shè)置工作環(huán)境。每人一個Windows NT或XP 2000作為工作站。我們選用的 IDE(Integrated Development Environment)是NetBeans。選用NetBeans的主要原因是經(jīng)費問題(NetBeans是開放式源碼并免費)。源碼控制是用的Microsoft SourceSafe。源碼庫放在一個項目所用的專門服務(wù)器上。而項目的文檔材料,如需求分析,系統(tǒng)架構(gòu)以及開發(fā)管理文件,如時間進度表等。
雖然項目已決定使用J2EE技術(shù),但具體的系統(tǒng)架構(gòu)仍然需要建立。初步的選擇是一個應(yīng)用框架(application framework)。這個框架是由我以前參加的一個項目發(fā)展而來,我對它的起源和演化都相當了解,因此我也開始對這個框架進行評審(review)。
我注意到?jīng)]有單元測試環(huán)境,便開始作一些這方面的工作,因為組里只有我有過建立及使用單元測試的經(jīng)驗。
第二周
我建立了一個基于JUnit的單元測試框架,并寫了一份2頁紙的簡短介紹,包括單元測試的概念與實踐,以及一種稱之為“Mock Object”的技術(shù),因為我認為我們的系統(tǒng)需用到這種技術(shù)。
本周有一次角色分配。一位精于JSP的同事將主要負責前端(front-end presentation),兩位對項目所涉的后端有較多知識并參加過可行性研究的同事將更多地與在客戶地點的business people (業(yè)務(wù)人員)打交道,一位對編碼標準(coding standards)有濃厚興趣的同事負責收集大家在編碼方面的問題并執(zhí)筆編碼標準文檔,還有一位精于Ant的同事主要做工具開發(fā)與配置管理(configuration management),等等。
我們的編碼標準主要是以Sun Microsystem的“Java Code Conventions”為藍本。另外,客戶要求源碼中所有的public and protected methods必須要有JavaDoc說明。一些與我們的特定系統(tǒng)有關(guān)的問題,如命名慣例(naming convention),將隨著開發(fā)進程不斷地編入文檔中。
大家對現(xiàn)有的“故事板”進行的討論分析,并分解出一些具體任務(wù),然后大家根據(jù)自己的角色和興趣sign up(“認購”)任務(wù)并開始設(shè)計與編碼。
關(guān)于源碼控制與源碼庫,大家同意每天早上更新自己的工作版本(working copy)。如果要修改或加入文件,在check in之前,一定要保證整個源碼能通過編譯。
第三周
大家繼續(xù)上周的設(shè)計與編碼工作。同事們似乎都是Cockburn所說的“good citizen”,工作中人人爭先,個個奮勇。
隨著編碼的進展,一個問題開始出現(xiàn)了。我們這里沒有后端系統(tǒng),所以不能對開發(fā)的程序進行完整的測試與集成。
星期四,項目安排了一次電視會議(video conference),參加者是我們這邊的成員與在客戶那邊的成員。兩邊的同事通過電視見見面,每人作一簡短的自我介紹。然后主要是討論了當前開發(fā)中的問題。最嚴重的問題包括需求與規(guī)范文檔沒能按時簽發(fā)(signoff),以及我們這邊沒有測試環(huán)境。
第四周
由于客戶對我們選用的應(yīng)用框架(application framework)仍有疑慮,應(yīng)客戶要求,我們公司找了一位有著非常豐富的開發(fā)經(jīng)驗的、并且在我們目前所用的應(yīng)用框架(application framework)上做出過系統(tǒng)的技術(shù)權(quán)威向客戶解答他們的問題。
新來的技術(shù)權(quán)威是位敏捷方法(agile methodology)的熱心者,我們在他的建議下準備采用類似XP的過程,首要目標是向客戶,也是向我們自己顯示出我們能出活(we can deliver)。周一下午,全組開了一個兩小時的會議:
確定了要實現(xiàn)的一個很基本的功能,該功能其實大部分的編碼已完成。
圍繞這個功能,分解出若干需完成的任務(wù),如:源碼審查(code review),源碼修改, 單元測試,建立“啞”(dummy)后端以作為初步功能測試與集成,找一臺空機器以作 系統(tǒng)建造與演示,等等。
大家根據(jù)自己的特長與興趣來“瓜分”把這些任務(wù)。
根據(jù)每人對完成自己任務(wù)所需時間的估計制訂出工作流程與進度,以0.5天為一單元。
根據(jù)進度表,“交貨”時間為下周四中午12:00點。屆時,我們需提供一份release notes, 上面將列出系統(tǒng)安裝的步驟。按照這些步驟,我們需要:
在一臺只有操作系統(tǒng)的空機器上建立運行系統(tǒng)所需的環(huán)境;
編譯源碼并安裝系統(tǒng);
運行系統(tǒng)并演示所完成的功能。
因為下周一周二放假(慶祝女王登基五十周年),時間非常緊迫。大家開足馬力,開始工作。
第五周
盡管大家盡了最大努力,星期四的期限沒能完全達到,其主要原因是系統(tǒng)安裝上有些沒預料到的 困難。但最終在星期五中午完成了所有的要求并進行了系統(tǒng)演示。
星期五下午全組會議,主要是對這一周期中的開發(fā)過程進行討論,特別是那些感到最困難的事情。 大家發(fā)現(xiàn)以下這些任務(wù)花的時間比預想的多:
熟悉應(yīng)用框架和系統(tǒng)架構(gòu);
建立“啞”后端服務(wù)系統(tǒng)以作測試環(huán)境
建立單元測試
系統(tǒng)安裝。
第六周
根據(jù)上周的討論,編碼標準(coding standards)進行了更新。
對第二三周所作的工作重新進行了討論并制訂了新的進度表。這個周期的工作其實包含了 三個use case(或“故事板”),每塊“故事板”基本上由兩個人負責。其他人則主要完善 單元測試框架及建造“啞”后端系統(tǒng)。
本周工作中發(fā)現(xiàn),有一處設(shè)計/模型需修改以適應(yīng)新的功能。多數(shù)人被吸引到討論中并提出 了若干方案。我提出用一種“角色模式(role pattern)”,因為我認為它非常適用我們 現(xiàn)在的情形。
第七周
關(guān)于修改模型的討論繼續(xù)。
討論與思考
下面的討論將主要圍繞一些XP的實踐原則展開。
用戶在場(On site custome r)
盡管開發(fā)組的一部分在客戶地點,但主要的開發(fā)工作卻是在公司本部進行的。這里沒有用戶,沒有業(yè)務(wù)分析人員。這點顯然與XP的原則相違背,而其造成的不利影響貫穿于項目始終。首先是對制訂計劃與進度表的影響。一般來說,在制訂計劃之前,開發(fā)人員需要花一兩天讀一個“故事板”,然后作出初步估計。故事板簡單易讀,能使人很快地大致了解一個功能模塊的需求。但是,很多地方比較模糊,有些地方在閱讀文檔中仔細一點就能看出來。這時最好有用戶/業(yè)務(wù)人員在場,馬上就能澄清。象我們靠電話和email,時間花的多,還不見得能說得很清楚。
第二個影響要更嚴重一些?!肮适掳濉敝械牟淮_定性有些在讀故事板時能發(fā)現(xiàn),而有些就只能到了編碼的時候才能暴露出來。由于業(yè)務(wù)分析人員在客戶那邊,只能靠電話和email,其質(zhì)量當然不如面對面的討論好。特別是當不能及時得到答案而時間又緊迫時,程序員往往得靠經(jīng)驗和“推理”作一些假定。如果是錯的話,就只能在功能測試和用戶接收測試時再改了。
另外一個類似問題是與后端系統(tǒng)通訊的規(guī)范說明,這是由另一個項目組提供。那么我們與他們之間也是有個溝通的問題。而糟糕的是該項目組也是在客戶那邊,因此只能靠電話和email??傊?,我覺得這個項目的實踐是從反面證明了用戶在場的重要性。
制訂計劃與進度
如上所言,制訂計劃和進度表是從閱讀“故事板”和規(guī)范說明開始。經(jīng)過若干電話與email的往來后,制訂出一個計劃,主要是把需完成的模塊進一步分解成一些任務(wù),以及估計完成每個任務(wù)要花的時間,以0.5天為一個
單元。該計劃是一個spreadsheet文件,放在項目的文檔服務(wù)器上,大家隨時可查看。
“并行開發(fā)”
我們的項目有一點和正規(guī)的use case driven的過程不太一樣。一般是一個周期主要是做一個 use case。在我們項目中,一個“故事板”大概算一個use case。如在“工作筆記”中所言,在項目走上“正軌”后(從第六周開始),一般是2-3人做一個“故事板”。所以,一般同時可能有兩三個“故事板”在進行。每個“故事板”的周期約3-4周。這樣做的好處是提高了生產(chǎn)率,但我覺得這樣做的前提條件是每個開發(fā)人員必須是有足夠的經(jīng)驗與技能,還有就是熟悉開發(fā)過程(第4-5周的實踐是非常重要的)。
單元測試
單元測試是客戶的一個要求。在前兩個月,我們做還有些“過分”。我們是用NetBeans提供的工具對每個類(class)都生成相應(yīng)的JUnit測試類(test class)。對一個類而言,其中的每一個 public和protected method都在test class中有對應(yīng)的一個test method。而這個test method 里只有一個fail語句。這樣強迫你用測試來替換這個fail(當然你也可以把它刪掉)。結(jié)果我們發(fā)現(xiàn)花了很多時間去寫getter和setter的測試,實在不值得,因為這些methods非常簡單。我們因此說服客戶,允許我們不用對getter和setter些測試。不過,我
倒是發(fā)現(xiàn),對 getter的測試,實際上是在測試相應(yīng)attribute的初始值。設(shè)置初始值常常被忽略,而會在運行中引起一些問題,如最常見的NullPointerException。
單元測試通常要求把被測的對象孤立起來,即測試不要用到其他的類。而實際中,一個類往往要用到其他的class提供的服務(wù)來完成自己的功能,最常見的如使用數(shù)據(jù)庫或一個遠程服務(wù)。單元測試需要切斷這種依賴性,即一次只測試某個我們需要測的類。這可以利用Mock Object (“模擬對象”)技術(shù)來達到,例如,用一個mock service來代替真正的service,而我們可以很方便地對這個mock service進行狀態(tài)設(shè)置。在我們的單元測試中就大量地運用了這種技術(shù)。網(wǎng)上有一些工具可用來幫助產(chǎn)生mock objects,如MockMaker,可以節(jié)省一些時間。
總的來說,單元測試的確提高了源碼質(zhì)量。那些逐步建立起來的test cases,我感覺是起到了一張 “警戒網(wǎng)”的作用。源碼修改需要作改動時,這種作用特別明顯。不過,我們也注意到,對一個類進行完整的單元測試所花的時間往往不少于編碼的時間。因此,一個很重要的問題是決定測試到什么程度。XP的建議是對“可能會出問題”的地方要重點測試。但什么是“可能會出問題”的地方則需視具體情況而定。
系統(tǒng)集成與功能測試
由于我們這里沒有一個真正的后端系統(tǒng),因此沒辦法作真正的集成與功能測試。在項目的前半期,我們曾建立了一個“啞”后端,這的確對我們的測試/調(diào)試起到了很大作用。但是,當越來越多的功能加入后,“啞”后端變得越來越負責和不可維護。最后,我們只得放棄這種做法。
項目的管理層曾作了很大努力,想使我們這里能直接連上客戶那里的后端系統(tǒng),這在技術(shù)上是完全沒有問題的(畢竟這是網(wǎng)絡(luò)時代)。但不幸的是,這個合理要求沒能得到滿足。所以項目后半期,當一個“故事板”的的編碼與單元測試完成后,一般由編碼者或測試者飛到客戶那里去做集成與功能測試。
結(jié)對編程(pair programming)
在我們這個項目的實際中,pair programming與“傳統(tǒng)”上的意義有些不同。首先,因為我們坐得都很靠近,如果某人有什么問題,只要一叫,一般就會有人跳起來跑過去幫忙。這可算是一種 “基于解決問題”的pair programming。
另外一種更主要的是方式是編碼與單元測試的結(jié)對。由于測試者對于如何使用一個(待測試)的類一般不會有著與編碼者完全一致的思路,這樣對于發(fā)現(xiàn)問題是很有幫助的。另外,由于測試者一般都會在測試時詳細閱讀源碼并與編碼者討論,這對于改進一個class的細部設(shè)計與實現(xiàn)也是很有用的。但這種審閱與源碼有所不同,這里主要是著重“邏輯”的正確與有效,而源碼審閱則偏重于源碼的風格與標準的統(tǒng)一。
還有一種方式可稱之為“結(jié)對排故”(pair debugging),我發(fā)現(xiàn)這種情況多在系統(tǒng)功能測試中出現(xiàn)。如果在測試中出現(xiàn)一個問題(bug),找來找去找不到(因為這時涉及的東西的較多),搞得昏頭脹腦。那么最好是抓一個同事到屏幕邊上(最好不是和你搞同一個部分的),然后給他講講是怎么回事。他可能會一眼看出問題所在(如果他曾遇到過類似的問題),或者會從另一個角度來提供一個思路。另外,常常也有這種情況,來幫忙的可能只是聽著,而你在講的時候可能就自己發(fā)現(xiàn)問題了。我想這是因為你在給其他人解釋一件事的時候,你實際上是在強迫你自己清理自己的思路,而這肯定是有助于找到問題的(特別是在昏頭脹腦的時候)。
編碼標準(coding standards)
項目開始的時候,我們就決定采用Sun的“Java Code Conventions”作為我們編碼標準的藍本。隨著項目的進行,大家不斷地討論并同意加入一些與項目有關(guān)的標準,例如:
所有的classes和所有的public and protected methods都必須要有JavaDoc注釋;
對于packages,classes,variables的命名標準;
如何使用集合(collection)類型,如變量的類型需是interface,如Map而非HashMap;
如何使用實數(shù)類型,如規(guī)定用double而非float;
如何使用logging(我們使用log4j);
如何處理exceptions,等等
源碼審閱(code review)
源碼審閱一直是項目的要求之一。但在項目的前半期,這點做得不是很正式。當然,一個主要的原因是大家想盡快地做出一些功能。這樣造成的一個后果是源碼開始有些雜亂并且不一致。項目后半期開始比較嚴格地進行源碼審閱,并且規(guī)定一個“故事板”的源碼在進入系統(tǒng)測試之前一定要有正規(guī)的源碼審閱。
進行源碼審閱時,審閱者一般是根據(jù)編碼標準上所列的條款對源碼進行檢查,看是否符合標準。同時,也可對一些具體實現(xiàn)上提出自己的看法。這些意見用一張專門的表格一項一項地記錄下來,交給編碼者修改或給出進一步的說明。最后,審閱者對源碼復查,對每一項進行核對,滿意之后簽字認可。我們的經(jīng)驗表明,這樣的源碼審閱大大地提高了源碼的質(zhì)量以及可讀性和可維護性。另外一個作用是使refactoring得以經(jīng)常及時的進行。
源碼重整(refactoring)
我們項目里,refactoring基本上是與編碼標準和源碼審閱同步進行的。項目的前半期,基本沒有refactoring,盡管有些不好的碼段或?qū)崿F(xiàn)被不斷的發(fā)現(xiàn)并記錄在案。當然,主要原因還是由于大家想集中精力先做出一些功能。在項目的后半期,開始和源碼審閱一起較嚴格地執(zhí)行。和源碼審閱一樣,這樣做的結(jié)果是大大地提高了源碼的質(zhì)量。
以上這些就是對這個項目的一些觀察與思考。總之,對開發(fā)人員來說,這個項目有許多的不確定性,這主要反映在需求與規(guī)范文件上,也反映在相關(guān)項目組之間的協(xié)調(diào)(或扯皮)上。項目組分散兩地,測試環(huán)境的缺乏都是開發(fā)中
的很大問題。在這種情況應(yīng)用XP的實踐原則,如密切溝通,單元測試,源碼審閱與重整,能有效的(也許是艱苦地)推進項目的進展。
后記
記得幾年前曾看過一篇文章是講中國的MBA的教育的。大意是說工商管理是個實踐性很強的專業(yè),做MBA的一項主要工作是做大量的個案分析。而目前中國似乎還沒有足夠的個案,有待于現(xiàn)在的MBA們畢業(yè)后在工作中去積累。這些積累起來的個案將是今后MBA們一筆寶貴資源。由此想到軟件開發(fā),何嘗不是如此。軟件開發(fā)是個實踐性很強的群體/團隊工作,這點從三十幾年前“軟件工程”的提出時,人們就已經(jīng)認識到了。提出的方法也是層出不窮,但真正在實踐中運用的并不多。這幾年出現(xiàn)的以XP為代表的agile方法興起,主要原因就是在于它們是從工程實踐中提煉出來,而其可行性至少在一定條件下或范圍內(nèi)又為他人的實踐所證明。那么我覺得現(xiàn)在最重要的不是高談闊論,而是扎扎實實的實踐,即在了解這些原則后如何在工程實踐中加以運用。更進一步,如果能把這些實踐記錄下來,加以總結(jié),這對自己和同道都是一件好事?;谶@樣的想法,在下不避瑣碎,把自己對一個項目的觀察與思考寫下來,期望能拋磚引玉,看到更多的同道能把自己的經(jīng)驗寫下來,與大家共享。
【?發(fā)表評論?0條?】