架构设计方法学
架構(gòu)設(shè)計(jì)的方法學(xué)
約公元前25年,古羅馬建筑師維特魯威說(shuō):“理想的建筑師應(yīng)該既是文學(xué)家又是數(shù)字家,他還應(yīng)通曉歷史,熱衷于哲學(xué)研究,精通音樂(lè),懂得醫(yī)藥知識(shí),具有法學(xué)造詣,深諳天文學(xué)及天文計(jì)算。”(好難哪,軟件構(gòu)架設(shè)計(jì)師的要求呢?大家好好想想吧。)?
本文目錄?
一、與構(gòu)架有關(guān)的幾個(gè)基本概念;?
二、構(gòu)架設(shè)計(jì)應(yīng)考慮的因素概攬;?
三、程序的運(yùn)行時(shí)結(jié)構(gòu)方面的考慮;?
四、源代碼的組織結(jié)構(gòu)方面的考慮;?
五、寫(xiě)系統(tǒng)構(gòu)架設(shè)計(jì)文檔應(yīng)考慮的問(wèn)題?
六、結(jié)語(yǔ)?
一、與構(gòu)架有關(guān)的幾個(gè)基本概念:?
1、模塊(module):一組完成指定功能的語(yǔ)句,包括:輸入、輸出、邏輯處理功能、內(nèi)部信息、運(yùn)行環(huán)境(與功能對(duì)應(yīng)但不是一對(duì)一關(guān)系)。?
2、組件(component):系統(tǒng)中相當(dāng)重要的、幾乎是獨(dú)立的可替換部分,它在明確定義的構(gòu)架環(huán)境中實(shí)現(xiàn)確切的功能。?
3、模式(pattern):指經(jīng)過(guò)驗(yàn)證,至少適用于一種實(shí)用環(huán)境(更多時(shí)候是好幾種環(huán)境)的解決方案模板(用于結(jié)構(gòu)和行為。在 UML中:模式由參數(shù)化的協(xié)作來(lái)表示,但 UML 不直接對(duì)模式的其他方面(如使用結(jié)果列表、使用示例等,它們可由文本來(lái)表示)進(jìn)行建模。存在各種范圍和抽象程度的模式,例如,構(gòu)架模式、分析模式、設(shè)計(jì)模式和代碼模式或?qū)嵤┠J健DJ綄⒖梢詭椭覀冏プ≈攸c(diǎn)。構(gòu)架也是存在模式的。比如,對(duì)于系統(tǒng)結(jié)構(gòu)設(shè)計(jì),我們使用層模式;對(duì)于分布式系統(tǒng),我們使用代理模式(通過(guò)使用代理來(lái)替代實(shí)際的對(duì)象,使程序能夠控制對(duì)該對(duì)象的訪(fǎng)問(wèn));對(duì)于交互系統(tǒng),我們使用MVC(M模型(對(duì)象)/V視圖(輸出管理)/C控制器(輸入處理))模式。模式是針對(duì)特定問(wèn)題的解,因此,我們也可以針對(duì)需求的特點(diǎn)采用相應(yīng)的模式來(lái)設(shè)計(jì)構(gòu)架。?
4、構(gòu)架模式(architectural pattern):表示軟件系統(tǒng)的基本結(jié)構(gòu)組織方案。它提供了一組預(yù)定義的子系統(tǒng)、指定它們的職責(zé),并且包括用于組織其間關(guān)系的規(guī)則和指導(dǎo)。?
5、層(layer):對(duì)模型中同一抽象層次上的包進(jìn)行分組的一種特定方式。通過(guò)分層,從邏輯上將子系統(tǒng)劃分成許多集合,而層間關(guān)系的形成要遵循一定的規(guī)則。通過(guò)分層,可以限制子系統(tǒng)間的依賴(lài)關(guān)系,使系統(tǒng)以更松散的方式耦合,從而更易于維護(hù)。(層是對(duì)構(gòu)架的橫向劃分,分區(qū)是對(duì)構(gòu)架的縱向劃分)。?
6、系統(tǒng)分層的幾種常用方法:?
1) 常用三層服務(wù):用戶(hù)層、業(yè)務(wù)邏輯層、數(shù)據(jù)層;?
2) 多層結(jié)構(gòu)的技術(shù)組成模型:表現(xiàn)層、中間層、數(shù)據(jù)層;?
3) 網(wǎng)絡(luò)系統(tǒng)常用三層結(jié)構(gòu):核心層、匯聚層和接入層;?
4) RUP典型分層方法:應(yīng)用層、專(zhuān)業(yè)業(yè)務(wù)層、中間件層、系統(tǒng)軟件層;?
5) 基于Java的B/S模式系統(tǒng)結(jié)構(gòu):瀏覽器端、服務(wù)器端、請(qǐng)求接收層、請(qǐng)求處理層;?
6) 某六層結(jié)構(gòu):功能層(用戶(hù)界面)、模塊層、組裝層(軟件總線(xiàn))、服務(wù)層(數(shù)據(jù)處理)、數(shù)據(jù)層、核心層;?
7、構(gòu)架(Architecture,愿意為建筑學(xué)設(shè)計(jì)和建筑物建造的藝術(shù)與科學(xué)): 在RUP中的定義:軟件系統(tǒng)的構(gòu)架(在某一給定點(diǎn))是指系統(tǒng)重要構(gòu)件的組織或結(jié)構(gòu),這些重要構(gòu)件通過(guò)接口與不斷減小的構(gòu)件與接口所組成的構(gòu)件進(jìn)行交互;《軟件構(gòu)架實(shí)踐》中的定義:某個(gè)軟件或者計(jì)算系統(tǒng)的軟件構(gòu)架即組成該系統(tǒng)的一個(gè)或者多個(gè)結(jié)構(gòu),他們組成軟件的各個(gè)部分,形成這些組件的外部可見(jiàn)屬性及相互間的聯(lián)系;IEEE 1471-2000中的定義:the fundamental organization of a system emboided in its components,their relationships to each other,and to the enviroment and the principles guiding its design and evolution,構(gòu)架是系統(tǒng)在其所處環(huán)境中的最高層次的概念。軟件系統(tǒng)的構(gòu)架是通過(guò)接口交互的重要構(gòu)件(在特定時(shí)間點(diǎn))的組織或結(jié)構(gòu),這些構(gòu)件又由一些更小的構(gòu)件和接口組成。(“構(gòu)架”可以作為名詞,也可作為動(dòng)詞,作為動(dòng)詞的“構(gòu)架”相當(dāng)于“構(gòu)架設(shè)計(jì)”)?
8、構(gòu)架的描述方式:“4+1”視圖(用例視圖、設(shè)計(jì)視圖、實(shí)現(xiàn)視圖、過(guò)程視圖、配置視圖)是一個(gè)被廣為使用的構(gòu)架描述的模型;RUP過(guò)程的構(gòu)架描述模板在“4+1”視圖的基礎(chǔ)上增加了可選的數(shù)據(jù)視圖(從永久性數(shù)據(jù)存儲(chǔ)方面來(lái)對(duì)系統(tǒng)進(jìn)行說(shuō)明);HP公司的軟件描述模板也是基于“4+1”視圖。?
9、結(jié)構(gòu):軟件構(gòu)架是多種結(jié)構(gòu)的體現(xiàn),結(jié)構(gòu)是系統(tǒng)構(gòu)架從不同角度觀(guān)察所產(chǎn)生的視圖。就像建筑物的結(jié)構(gòu)會(huì)隨著觀(guān)察動(dòng)機(jī)和出發(fā)點(diǎn)的不同而有多種含義一樣,軟件構(gòu)架也表現(xiàn)為多種結(jié)構(gòu)。常見(jiàn)的軟件結(jié)構(gòu)有:模塊結(jié)構(gòu)、邏輯或概念結(jié)構(gòu)、進(jìn)程或協(xié)調(diào)結(jié)構(gòu)、物理結(jié)構(gòu)、使用結(jié)構(gòu)、調(diào)用結(jié)構(gòu)、數(shù)據(jù)流、控制流、類(lèi)結(jié)構(gòu)等等。?
二、構(gòu)架設(shè)計(jì)應(yīng)考慮的因素概攬:?
模塊構(gòu)架設(shè)計(jì)可以從程序的運(yùn)行時(shí)結(jié)構(gòu)和源代碼的組織結(jié)構(gòu)方面考慮。?
1、程序的運(yùn)行時(shí)結(jié)構(gòu)方面的考慮:?
1) 需求的符合性:正確性、完整性;功能性需求、非功能性需求;?
2) 總體性能(內(nèi)存管理、數(shù)據(jù)庫(kù)組織和內(nèi)容、非數(shù)據(jù)庫(kù)信息、任務(wù)并行性、網(wǎng)絡(luò)多人操作、關(guān)鍵算法、與網(wǎng)絡(luò)、硬件和其他系統(tǒng)接口對(duì)性能的影響);?
3) 運(yùn)行可管理性:便于控制系統(tǒng)運(yùn)行、監(jiān)視系統(tǒng)狀態(tài)、錯(cuò)誤處理;模塊間通信的簡(jiǎn)單性;與可維護(hù)性不同;?
4) 與其他系統(tǒng)接口兼容性;?
5) 與網(wǎng)絡(luò)、硬件接口兼容性及性能;?
6) 系統(tǒng)安全性;?
7) 系統(tǒng)可靠性;?
8) 業(yè)務(wù)流程的可調(diào)整性;?
9) 業(yè)務(wù)信息的可調(diào)整性?
10) 使用方便性?
11) 構(gòu)架樣式的一致性?
注:運(yùn)行時(shí)負(fù)載均衡可以從系統(tǒng)性能、系統(tǒng)可靠性方面考慮。?
2、源代碼的組織結(jié)構(gòu)方面的考慮:?
1) 開(kāi)發(fā)可管理性:便于人員分工(模塊獨(dú)立性、開(kāi)發(fā)工作的負(fù)載均衡、進(jìn)度安排優(yōu)化、預(yù)防人員流動(dòng)對(duì)開(kāi)發(fā)的影響)、利于配置管理、大小的合理性與適度復(fù)雜性;?
2) 可維護(hù)性:與運(yùn)行可管理性不同;?
3) 可擴(kuò)充性:系統(tǒng)方案的升級(jí)、擴(kuò)容、擴(kuò)充性能;?
4) 可移植性:不同客戶(hù)端、應(yīng)用服務(wù)器、數(shù)據(jù)庫(kù)管理系統(tǒng);?
5) 需求的符合性(源代碼的組織結(jié)構(gòu)方面的考慮)。?
三、程序的運(yùn)行時(shí)結(jié)構(gòu)方面的考慮:?
1、 需求的符合性:正確性、完整性;功能性需求、非功能性需求?
軟件項(xiàng)目最主要的目標(biāo)是滿(mǎn)足客戶(hù)需求。在進(jìn)行構(gòu)架設(shè)計(jì)的時(shí)候,大家考慮更多的是使用哪個(gè)運(yùn)行平臺(tái)、編成語(yǔ)言、開(kāi)發(fā)環(huán)境、數(shù)據(jù)庫(kù)管理系統(tǒng)等問(wèn)題,對(duì)于和客戶(hù)需求相關(guān)的問(wèn)題考慮不足、不夠系統(tǒng)。如果無(wú)論怎么好的構(gòu)架都無(wú)法滿(mǎn)足客戶(hù)明確的某個(gè)功能性需求或非功能性需求,就應(yīng)該與客戶(hù)協(xié)調(diào)在項(xiàng)目范圍和需求規(guī)格說(shuō)明書(shū)中刪除這一需求。否則,架構(gòu)設(shè)計(jì)應(yīng)以滿(mǎn)足客戶(hù)所有明確需求為最基本目標(biāo),盡量滿(mǎn)足其隱含的需求。(客戶(hù)的非功能性需求可能包括接口、系統(tǒng)安全性、可靠性、移植性、擴(kuò)展性等等,在其他小節(jié)中細(xì)述)?
一般來(lái)說(shuō),功能需求決定業(yè)務(wù)構(gòu)架、非功能需求決定技術(shù)構(gòu)架,變化案例決定構(gòu)架的范圍。需求方面的知識(shí)告訴我們,功能需求定義了軟件能夠做些什么。我們需要根據(jù)業(yè)務(wù)上的需求來(lái)設(shè)計(jì)業(yè)務(wù)構(gòu)架,以使得未來(lái)的軟件能夠滿(mǎn)足客戶(hù)的需要。非功能需求定義了一些性能、效率上的一些約束、規(guī)則。而我們的技術(shù)構(gòu)架要能夠滿(mǎn)足這些約束和規(guī)則。變化案例是對(duì)未來(lái)可能發(fā)生的變化的一個(gè)估計(jì),結(jié)合功能需求和非功能需求,我們就可以確定一個(gè)需求的范圍,進(jìn)而確定一個(gè)構(gòu)架的范圍。(此段From林星)?
這里講一個(gè)前幾年因客戶(hù)某些需求錯(cuò)誤造成構(gòu)架設(shè)計(jì)問(wèn)題而引起系統(tǒng)性能和可靠性問(wèn)題的小小的例子:此系統(tǒng)的需求本身是比較簡(jiǎn)單的,就是將某城市的某業(yè)務(wù)的全部歷史檔案卡片掃描存儲(chǔ)起來(lái),以便可以按照姓名進(jìn)行查詢(xún)。需求階段客戶(hù)說(shuō)卡片大約有20萬(wàn)張,需求調(diào)研者出于對(duì)客戶(hù)的信任沒(méi)有對(duì)數(shù)據(jù)的總量進(jìn)行查證。由于是中小型數(shù)據(jù)量,并且今后數(shù)據(jù)不會(huì)增加,經(jīng)過(guò)計(jì)算20萬(wàn)張卡片總體容量之后,決定使用一種可以單機(jī)使用也可以聯(lián)網(wǎng)的中小型數(shù)據(jù)庫(kù)管理系統(tǒng)。等到系統(tǒng)完成開(kāi)始錄入數(shù)據(jù)時(shí),才發(fā)現(xiàn)數(shù)據(jù)至少有60萬(wàn),這樣使用那種中小型數(shù)據(jù)庫(kù)管理系統(tǒng)不但會(huì)造成系統(tǒng)性能的問(wèn)題,而且其可靠性是非常脆弱的,不得不對(duì)系統(tǒng)進(jìn)行重新設(shè)計(jì)。從這個(gè)小小的教訓(xùn)可以看出,需求階段不僅對(duì)客戶(hù)的功能需求要調(diào)查清楚,對(duì)于一些隱含非功能需求的一些數(shù)據(jù)也應(yīng)當(dāng)調(diào)查清楚,并作為構(gòu)架設(shè)計(jì)的依據(jù)。?
對(duì)于功能需求的正確性,在構(gòu)架設(shè)計(jì)文檔中可能不好驗(yàn)證(需要人工、費(fèi)力)。對(duì)于功能需求完整性,就應(yīng)當(dāng)使用需求功能與對(duì)應(yīng)模塊對(duì)照表來(lái)跟蹤追溯。對(duì)于非功能需求正確性和完整性,可以使用需求非功能與對(duì)應(yīng)設(shè)計(jì)策略對(duì)照表來(lái)跟蹤追溯評(píng)估。?
“軟件設(shè)計(jì)工作只有基于用戶(hù)需求,立足于可行的技術(shù)才有可能成功。”?
2、 總體性能?
性能其實(shí)也是客戶(hù)需求的一部分,當(dāng)然可能是明確的,也有很多是隱含的,這里把它單獨(dú)列出來(lái)在說(shuō)明一次。性能是設(shè)計(jì)方案的重要標(biāo)準(zhǔn),性能應(yīng)考慮的不是單臺(tái)客戶(hù)端的性能,而是應(yīng)該考慮系統(tǒng)總的綜合性能;?
性能設(shè)計(jì)應(yīng)從以下幾個(gè)方面考慮:內(nèi)存管理、數(shù)據(jù)庫(kù)組織和內(nèi)容、非數(shù)據(jù)庫(kù)信息、任務(wù)并行性、網(wǎng)絡(luò)多人操作、關(guān)鍵算法、與網(wǎng)絡(luò)、硬件和其他系統(tǒng)接口對(duì)性能的影響;?
幾點(diǎn)提示:算法優(yōu)化及負(fù)載均衡是性能優(yōu)化的方向。經(jīng)常要調(diào)用的模塊要特別注意優(yōu)化。占用內(nèi)存較多的變量在不用時(shí)要及時(shí)清理掉。需要下載的網(wǎng)頁(yè)主題文件過(guò)大時(shí)應(yīng)當(dāng)分解為若干部分,讓用戶(hù)先把主要部分顯示出來(lái)。?
3、 運(yùn)行可管理性?
系統(tǒng)的構(gòu)架設(shè)計(jì)應(yīng)當(dāng)為了使系統(tǒng)可以預(yù)測(cè)系統(tǒng)故障,防患于未然。現(xiàn)在的系統(tǒng)正逐步向復(fù)雜化、大型化發(fā)展,單靠一個(gè)人或幾個(gè)人來(lái)管理已顯得力不從心,況且對(duì)于某些突發(fā)事件的響應(yīng),人的反應(yīng)明顯不夠。因此通過(guò)合理的系統(tǒng)構(gòu)架規(guī)劃系統(tǒng)運(yùn)行資源,便于控制系統(tǒng)運(yùn)行、監(jiān)視系統(tǒng)狀態(tài)、進(jìn)行有效的錯(cuò)誤處理;為了實(shí)現(xiàn)上述目標(biāo),模塊間通信應(yīng)當(dāng)盡可能簡(jiǎn)單,同時(shí)建立合理詳盡的系統(tǒng)運(yùn)行日志,系統(tǒng)通過(guò)自動(dòng)審計(jì)運(yùn)行日志,了解系統(tǒng)運(yùn)行狀態(tài)、進(jìn)行有效的錯(cuò)誤處理;(運(yùn)行可管理性與可���護(hù)性不同)?
4、 與其他系統(tǒng)接口兼容性(解釋略)?
5、 與網(wǎng)絡(luò)、硬件接口兼容性及性能(解釋略)?
6、 系統(tǒng)安全性?
隨著計(jì)算機(jī)應(yīng)用的不斷深入和擴(kuò)大,涉及的部門(mén)和信息也越來(lái)越多,其中有大量保密信息在網(wǎng)絡(luò)上傳輸,所以對(duì)系統(tǒng)安全性的考慮已經(jīng)成為系統(tǒng)設(shè)計(jì)的關(guān)鍵,需要從各個(gè)方面和角度加以考慮,來(lái)保證數(shù)據(jù)資料的絕對(duì)安全。?
7、 系統(tǒng)可靠性?
系統(tǒng)的可靠性是現(xiàn)代信息系統(tǒng)應(yīng)具有的重要特征,由于人們?nèi)粘5墓ぷ鲗?duì)系統(tǒng)依賴(lài)程度越來(lái)越多,因此系統(tǒng)的必須可靠。系統(tǒng)構(gòu)架設(shè)計(jì)可考慮系統(tǒng)的冗余度,盡可能地避免單點(diǎn)故障。系統(tǒng)可靠性是系統(tǒng)在給定的時(shí)間間隔及給定的環(huán)境條件下,按設(shè)計(jì)要求,成功地運(yùn)行程序的概率。成功地運(yùn)行不僅要保證系統(tǒng)能正確地運(yùn)行,滿(mǎn)足功能需求,還要求當(dāng)系統(tǒng)出現(xiàn)意外故障時(shí)能夠盡快恢復(fù)正常運(yùn)行,數(shù)據(jù)不受破壞。?
8、 業(yè)務(wù)流程的可調(diào)整性?
應(yīng)當(dāng)考慮客戶(hù)業(yè)務(wù)流程可能出現(xiàn)的變化,所以在系統(tǒng)構(gòu)架設(shè)計(jì)時(shí)要盡量排除業(yè)務(wù)流程的制約,即把流程中的各項(xiàng)業(yè)務(wù)結(jié)點(diǎn)工作作為獨(dú)立的對(duì)象,設(shè)計(jì)成獨(dú)立的模塊或組件,充分考慮他們與其他各種業(yè)務(wù)對(duì)象模塊或組件的接口,在流程之間通過(guò)業(yè)務(wù)對(duì)象模塊的相互調(diào)用實(shí)現(xiàn)各種業(yè)務(wù),這樣,在業(yè)務(wù)流程發(fā)生有限的變化時(shí)(每個(gè)業(yè)務(wù)模塊本身的業(yè)務(wù)邏輯沒(méi)有變的情況下),就能夠比較方便地修改系統(tǒng)程序模塊或組件間的調(diào)用關(guān)系而實(shí)現(xiàn)新的需求。如果這種調(diào)用關(guān)系被設(shè)計(jì)成存儲(chǔ)在配置庫(kù)的數(shù)據(jù)字典里,則連程序代碼都不用修改,只需修改數(shù)據(jù)字典里的模塊或組件調(diào)用規(guī)則即可。?
9、 業(yè)務(wù)信息的可調(diào)整性?
應(yīng)當(dāng)考慮客戶(hù)業(yè)務(wù)信息可能出現(xiàn)的變化,所以在系統(tǒng)構(gòu)架設(shè)計(jì)時(shí)必須盡可能減少因?yàn)闃I(yè)務(wù)信息的調(diào)整對(duì)于代碼模塊的影響范圍。?
10、 使用方便性?
使用方便性是不須提及的必然的需求,而使用方便性與系統(tǒng)構(gòu)架是密切相關(guān)的。WinCE(1.0)的失敗和后來(lái)改進(jìn)版本的成功就說(shuō)明了這個(gè)問(wèn)題。WinCE(1.0)有太多層次的視窗和菜單,而用戶(hù)則更喜歡簡(jiǎn)單的界面和快捷的操作。失敗了應(yīng)當(dāng)及時(shí)糾正,但最好不要等到失敗了再來(lái)糾正,這樣會(huì)浪費(fèi)巨大的財(cái)力物力,所以在系統(tǒng)構(gòu)架階段最好能將需要考慮的因素都考慮到。當(dāng)然使用方便性必須與系統(tǒng)安全性協(xié)調(diào)平衡統(tǒng)一,使用方便性也必須與業(yè)務(wù)流程的可調(diào)整性和業(yè)務(wù)信息的可調(diào)整性協(xié)調(diào)平衡統(tǒng)一。“滿(mǎn)足用戶(hù)的需求,便于用戶(hù)使用,同時(shí)又使得操作流程盡可能簡(jiǎn)單。這就是設(shè)計(jì)之本。”?
11、構(gòu)架樣式的一致性?
軟件系統(tǒng)的構(gòu)架樣式有些類(lèi)似于建筑樣式(如中國(guó)式、哥特式、希臘復(fù)古式)。軟件構(gòu)架樣式可分為數(shù)據(jù)流構(gòu)架樣式、調(diào)用返回構(gòu)架樣式、獨(dú)立組件構(gòu)架樣式、以數(shù)據(jù)為中心的構(gòu)架樣式和虛擬機(jī)構(gòu)架樣式,每一種樣式還可以分為若干子樣式。構(gòu)架樣式的一致性并不是要求一個(gè)軟件系統(tǒng)只能采用一種樣式,就像建筑樣式可以是中西結(jié)合的,軟件系統(tǒng)也可以有異質(zhì)構(gòu)架樣式(分為局部異質(zhì)、層次異質(zhì)、并行異質(zhì)),即多種樣式的綜合,但這樣的綜合應(yīng)該考慮其某些方面的一致性和協(xié)調(diào)性。每一種樣式都有其使用的時(shí)機(jī),應(yīng)當(dāng)根據(jù)系統(tǒng)最強(qiáng)調(diào)的質(zhì)量屬性來(lái)選擇。?
四、源代碼的組織結(jié)構(gòu)方面的考慮:?
1、 開(kāi)發(fā)可管理性?
便于人員分工(模塊獨(dú)立性、開(kāi)發(fā)工作的負(fù)載均衡、進(jìn)度安排優(yōu)化、預(yù)防人員流動(dòng)對(duì)開(kāi)發(fā)的影響:一個(gè)好的構(gòu)架同時(shí)應(yīng)有助于減少項(xiàng)目組的壓力和緊張,提高軟件開(kāi)發(fā)效率)、利于配置管理、大小的合理性、適度復(fù)雜性;?
1)便于人員分工-模塊獨(dú)立性、層次性?
模塊獨(dú)立性、層次性是為了保證項(xiàng)目開(kāi)發(fā)成員工作之間的相對(duì)獨(dú)立性,模塊聯(lián)結(jié)方式應(yīng)該是縱向而不是橫向, 模塊之間應(yīng)該是樹(shù)狀結(jié)構(gòu)而不是網(wǎng)狀結(jié)構(gòu)或交叉結(jié)構(gòu),這樣就可以把開(kāi)發(fā)人員之間的通信、模塊開(kāi)發(fā)制約關(guān)系減到最少。同時(shí)模塊獨(dú)立性也比較利于配置管理工作的進(jìn)行。現(xiàn)在有越來(lái)越多的的軟件開(kāi)發(fā)是在異地進(jìn)行,一個(gè)開(kāi)發(fā)組的成員可能在不同城市甚至在不同國(guó)家,因此便于異地開(kāi)發(fā)的人員分工與配置管理的源代碼組織結(jié)構(gòu)是非常必要的。?
2)便于人員分工-開(kāi)發(fā)工作的負(fù)載均衡?
不僅僅是開(kāi)發(fā)出來(lái)的軟件系統(tǒng)需要負(fù)載均衡,在開(kāi)發(fā)過(guò)程中開(kāi)發(fā)小組各成員之間工作任務(wù)的負(fù)載均衡也是非重要的。所謂工作任務(wù)的負(fù)載均衡就是通過(guò)合理的任務(wù)劃分按照開(kāi)發(fā)人員特點(diǎn)進(jìn)行分配任務(wù),盡量讓項(xiàng)目組中的每個(gè)人每段時(shí)間都有用武之地。這就需要在構(gòu)架設(shè)計(jì)時(shí)應(yīng)當(dāng)充分考慮項(xiàng)目組手頭的人力資源,在實(shí)現(xiàn)客戶(hù)需求的基礎(chǔ)上實(shí)現(xiàn)開(kāi)發(fā)工作的負(fù)載均衡,以提高整體開(kāi)發(fā)效率。?
3)便于人員分工-進(jìn)度安排優(yōu)化;?
進(jìn)度安排優(yōu)化的前提是模塊獨(dú)立性并搞清楚模塊開(kāi)發(fā)的先后制約關(guān)系。利用工作分解結(jié)構(gòu)對(duì)所有程序編碼工作進(jìn)行分解,得到每一項(xiàng)工作的輸入、輸出、所需資源、持續(xù)時(shí)間、前期應(yīng)完成的工作、完成后可以進(jìn)行的工作。然后預(yù)估各模塊需要時(shí)間,分析各模塊的并行與串行(順序制約),繪制出網(wǎng)絡(luò)圖,找出影響整體進(jìn)度的關(guān)鍵模塊,算出關(guān)鍵路徑,最后對(duì)網(wǎng)絡(luò)圖進(jìn)行調(diào)整,以使進(jìn)度安排最優(yōu)化。?
有個(gè)家喻戶(hù)曉的智力題叫烤肉片策略:約翰遜家戶(hù)外有一個(gè)可以同時(shí)烤兩塊肉片的烤肉架,烤每塊肉片的每一面需要10分鐘,現(xiàn)要烤三塊肉片給饑腸轆轆急不可耐的一家三口。問(wèn)題是怎樣才能在最短的時(shí)間內(nèi)烤完三片肉。一般的做法花20分鐘先烤完前兩片,再花20分鐘烤完第三片。有一種更好的方法可以節(jié)省10分鐘,大家想想。?
4)便于人員分工-預(yù)防員工人員流動(dòng)對(duì)開(kāi)發(fā)的影響?
人員流動(dòng)在軟件行業(yè)是司空見(jiàn)慣的事情,已經(jīng)是一個(gè)常見(jiàn)的風(fēng)險(xiǎn)。作為對(duì)這一風(fēng)險(xiǎn)的有效的防范對(duì)策之一,可以在構(gòu)架設(shè)計(jì)中考慮到并預(yù)防員工人員流動(dòng)對(duì)開(kāi)發(fā)的影響。主要的思路還是在模塊的獨(dú)立性上(追求高內(nèi)聚低耦合),組件化是目前流行的趨勢(shì)。?
5)利于配置管理(獨(dú)立性、層次性)?
利于配置管理與利于人員分工有一定的聯(lián)系。除了邏輯上的模塊組件要利于人員分工外,物理上的源代碼層次結(jié)構(gòu)、目錄結(jié)構(gòu)、各模塊所處源代碼文件的部署也應(yīng)當(dāng)利于人員分工和配置管理。(盡管現(xiàn)在配置管理工具有較強(qiáng)大的功能,但一個(gè)清楚的源碼分割和模塊分割是非常有好處的)。?
6)大小的合理性與適度復(fù)雜性?
大小的合理性與適度復(fù)雜性可以使開(kāi)發(fā)工作的負(fù)載均衡,便于進(jìn)度的安排,也可以使系統(tǒng)在運(yùn)行時(shí)減少不必要的內(nèi)存資源浪費(fèi)。對(duì)于代碼的可閱讀性和系統(tǒng)的可維護(hù)性也有一定的好處。另外,過(guò)大的模塊常常是系統(tǒng)分解不充分,而過(guò)小的模塊有可能降低模塊的獨(dú)立性,造成系統(tǒng)接口的復(fù)雜。?
2、 可維護(hù)性?
便于在系統(tǒng)出現(xiàn)故障時(shí)及時(shí)方便地找到產(chǎn)生故障的原因和源代碼位置,并能方便地進(jìn)行局部修改、切割;(可維護(hù)性與運(yùn)行可管理性不同)?
3、 可擴(kuò)充性:系統(tǒng)方案的升級(jí)、擴(kuò)容、擴(kuò)充性能?
系統(tǒng)在建成后會(huì)有一段很長(zhǎng)的運(yùn)行周期,在該周期內(nèi),應(yīng)用在不斷增加,應(yīng)用的層次在不斷升級(jí),因此采用的構(gòu)架設(shè)計(jì)等方案因充分考慮升級(jí)、擴(kuò)容、擴(kuò)充的可行性和便利?
4、 可移植性?
不同客戶(hù)端、應(yīng)用服務(wù)器、數(shù)據(jù)庫(kù)管理系統(tǒng):如果潛在的客戶(hù)使用的客戶(hù)端可能使用不同的操作系統(tǒng)或?yàn)g覽器,其可移植性必須考慮客戶(hù)端程序的可移植性,或盡量不使業(yè)務(wù)邏輯放在客戶(hù)端;數(shù)據(jù)處理的業(yè)務(wù)邏輯放在數(shù)據(jù)庫(kù)管理系統(tǒng)中會(huì)有較好的性能,但如果客戶(hù)群中不能確定使用的是同一種數(shù)據(jù)庫(kù)管理系統(tǒng),則業(yè)務(wù)邏輯就不能數(shù)據(jù)庫(kù)管理系統(tǒng)中;?
達(dá)到可移植性一定要注重標(biāo)準(zhǔn)化和開(kāi)放性:只有廣泛采用遵循國(guó)際標(biāo)準(zhǔn),開(kāi)發(fā)出開(kāi)放性強(qiáng)的產(chǎn)品,才可以保證各種類(lèi)型的系統(tǒng)的充分互聯(lián),從而使產(chǎn)品更具有市場(chǎng)競(jìng)爭(zhēng)力,也為未來(lái)的系統(tǒng)移植和升級(jí)擴(kuò)展提供了基礎(chǔ)。?
5、 需求的符合性?
從源代碼的組織結(jié)構(gòu)看需求的符合型主要考慮針對(duì)用戶(hù)需求可能的變化的軟件代碼及構(gòu)架的最小冗余(同時(shí)又要使得系統(tǒng)具有一定的可擴(kuò)展性)。?
五、寫(xiě)系統(tǒng)構(gòu)架設(shè)計(jì)文檔應(yīng)考慮的問(wèn)題?
構(gòu)架工作應(yīng)該在需求開(kāi)發(fā)完成約80%的時(shí)候開(kāi)始進(jìn)行,不必等到需求開(kāi)發(fā)全部完成,需要項(xiàng)目經(jīng)理以具體的判斷來(lái)評(píng)估此時(shí)是否足以開(kāi)始構(gòu)建軟件構(gòu)架。?
給出一致的輪廓:系統(tǒng)概述。一個(gè)系統(tǒng)構(gòu)架需要現(xiàn)有概括的描述,開(kāi)發(fā)人員才能從上千個(gè)細(xì)節(jié)甚至數(shù)十個(gè)模塊或?qū)ο箢?lèi)中建立一致的輪廓。?
構(gòu)架的目標(biāo)應(yīng)該能夠清楚說(shuō)明系統(tǒng)概念,構(gòu)架應(yīng)盡可能簡(jiǎn)化,最好的構(gòu)架文件應(yīng)該簡(jiǎn)單、簡(jiǎn)短,清晰而不雜亂,解決方案自然。?
構(gòu)架應(yīng)單先定義上層的主要子系統(tǒng),應(yīng)該描述各子系統(tǒng)的任務(wù),并提供每個(gè)子系統(tǒng)中各模塊或?qū)ο箢?lèi)的的初步列表。?
構(gòu)架應(yīng)該描述不同子系統(tǒng)間相互通信的方式,而一個(gè)良好的構(gòu)架應(yīng)該將子系統(tǒng)間的通信關(guān)系降到最低。?
成功構(gòu)架的一個(gè)重要特色,在于標(biāo)明最可能變更的領(lǐng)域,應(yīng)當(dāng)列出程序中最可能變更的部分,說(shuō)明構(gòu)架的其他部分如何應(yīng)變。?
復(fù)用分析、外購(gòu):縮短軟件開(kāi)發(fā)周期、降低成本的有效方案未必是自行開(kāi)發(fā)軟件,可以對(duì)現(xiàn)有軟件進(jìn)行復(fù)用或進(jìn)行外購(gòu)。應(yīng)考慮其對(duì)構(gòu)架的影響。?
除了系統(tǒng)組織的問(wèn)題,構(gòu)架應(yīng)重點(diǎn)考慮對(duì)于細(xì)節(jié)全面影響的設(shè)計(jì)決策,深入這些決策領(lǐng)域:外部軟件接口(兼容性、通信方式、傳遞數(shù)據(jù)結(jié)構(gòu))、用戶(hù)接口(用戶(hù)接口和系統(tǒng)層次劃分)、數(shù)據(jù)庫(kù)組織和內(nèi)容、非數(shù)據(jù)庫(kù)信息、關(guān)鍵算法、內(nèi)存管理(配置策略)、并行性、安全性、可移植性、網(wǎng)絡(luò)多人操作、錯(cuò)誤處理。?
要保證需求的可追蹤性,即保證每個(gè)需求功能都有相應(yīng)模塊去實(shí)現(xiàn)。?
構(gòu)架不能只依據(jù)靜態(tài)的系統(tǒng)目標(biāo)來(lái)設(shè)計(jì),也應(yīng)當(dāng)考慮動(dòng)態(tài)的開(kāi)發(fā)過(guò)程,如人力資源的情況,進(jìn)度要求的情況,開(kāi)發(fā)環(huán)境的滿(mǎn)足情況。構(gòu)架必須支持階段性規(guī)劃,應(yīng)該能夠提供階段性規(guī)劃中如何開(kāi)發(fā)與完成的方式。不應(yīng)該依賴(lài)無(wú)法獨(dú)立運(yùn)行的子系統(tǒng)構(gòu)架。將系統(tǒng)各部分的、依賴(lài)關(guān)系找出來(lái),形成一套開(kāi)發(fā)計(jì)劃。?
六、結(jié)語(yǔ)?
系統(tǒng)構(gòu)架設(shè)計(jì)和千差萬(wàn)別的具體的開(kāi)發(fā)平臺(tái)密切相關(guān),因此在此無(wú)法給出通用的解決方案,主要是為了說(shuō)明哪些因素是需要考慮的。對(duì)于每個(gè)因素的設(shè)計(jì)策略和本文未提到的因素需要軟件構(gòu)架設(shè)計(jì)師在具體開(kāi)發(fā)實(shí)踐中靈活把握。不同因素之間有時(shí)是矛盾的,構(gòu)架設(shè)計(jì)時(shí)需要根據(jù)具體情況進(jìn)行平衡。
架構(gòu)設(shè)計(jì)中的方法學(xué)?
架構(gòu)設(shè)計(jì)是一種權(quán)衡(trade-off)。一個(gè)問(wèn)題總是有多種的解決方案。而我們要確定唯一的架構(gòu)設(shè)計(jì)的解決方案,就意味著我們要在不同的矛盾體之間做出一個(gè)權(quán)衡。我們?cè)谠O(shè)計(jì)的過(guò)程總是可以看到很多的矛盾體:開(kāi)放和整合,一致性和特殊化,穩(wěn)定性和延展性等等。任何一對(duì)矛盾體都源于我們對(duì)軟件的不同期望。可是,要滿(mǎn)足我們希望軟件穩(wěn)定運(yùn)行的要求,就必然會(huì)影響我們對(duì)軟件易于擴(kuò)展的期望。我們希望軟件簡(jiǎn)單明了,卻增加了我們?cè)O(shè)計(jì)的復(fù)雜度。沒(méi)有一個(gè)軟件能夠滿(mǎn)足所有的要求,因?yàn)檫@些要求之間帶有天生的互斥性。而我們?cè)u(píng)價(jià)架構(gòu)設(shè)計(jì)的好壞的依據(jù),就只能是根據(jù)不同要求的輕重緩急,在其間做出權(quán)衡的合理性。
我們希望一個(gè)好的架構(gòu)能夠:
重用:為了避免重復(fù)勞動(dòng),為了降低成本,我們希望能夠重用之前的代碼、之前的設(shè)計(jì)。重用是我們不斷追求的目標(biāo)之一,但事實(shí)上,做到這一點(diǎn)可沒(méi)有那么容易。在現(xiàn)實(shí)中,人們已經(jīng)在架構(gòu)重用上做了很多的工作,工作的成果稱(chēng)為框架(Framework),比如說(shuō)Windows的窗口機(jī)制、J2EE平臺(tái)等。但是在企業(yè)商業(yè)建模方面,有效的框架還非常的少。?
透明:有些時(shí)候,我們?yōu)榱颂岣咝?#xff0c;把實(shí)現(xiàn)的細(xì)節(jié)隱藏起來(lái),僅把客戶(hù)需求的接口呈現(xiàn)給客戶(hù)。這樣,具體的實(shí)現(xiàn)對(duì)客戶(hù)來(lái)說(shuō)就是透明的。一個(gè)具體的例子是我們使用JSP的tag技術(shù)來(lái)代替JSP的嵌入代碼,因?yàn)槲覀兊腍TML界面人員更熟悉tag的方式。?
延展:我們對(duì)延展的渴求源于需求的易變。因此我們需要架構(gòu)具有一定的延展性,以適應(yīng)未來(lái)可能的變化。可是,如上所說(shuō),延展性和穩(wěn)定性,延展性和簡(jiǎn)單性都是矛盾的。因此我們需要權(quán)衡我們的投入/產(chǎn)出比。以設(shè)計(jì)出具有適當(dāng)和延展性的架構(gòu)。?
簡(jiǎn)明:一個(gè)復(fù)雜的架構(gòu)不論是測(cè)試還是維護(hù)都是困難的。我們希望架構(gòu)能夠在滿(mǎn)足目的的情況下盡可能的簡(jiǎn)單明了。但是簡(jiǎn)單明了的含義究竟是什么好像并沒(méi)有一個(gè)明確的定義。使用模式能夠使設(shè)計(jì)變得簡(jiǎn)單,但這是建立在我熟悉設(shè)計(jì)模式的基礎(chǔ)上。對(duì)于一個(gè)并不懂設(shè)計(jì)模式的人,他會(huì)認(rèn)為這個(gè)架構(gòu)很復(fù)雜。對(duì)于這種情況,我只能對(duì)他說(shuō),去看看設(shè)計(jì)模式。?
高效:不論是什么系統(tǒng),我們都希望架構(gòu)是高效的。這一點(diǎn)對(duì)于一些特定的系統(tǒng)來(lái)說(shuō)尤其重要。例如實(shí)時(shí)系統(tǒng)、高訪(fǎng)問(wèn)量的網(wǎng)站。這些值的是技術(shù)上的高效,有時(shí)候我們指的高效是效益上的高效。例如,一個(gè)只有幾十到一百訪(fǎng)問(wèn)量的信息系統(tǒng),是不是有必要使用EJB技術(shù),這就需要我們綜合的評(píng)估效益了。?
安全:安全并不是我們文章討論的重點(diǎn),卻是架構(gòu)的一個(gè)很重要的方面。
規(guī)則
為了達(dá)到上述的目的,我們通常需要對(duì)架構(gòu)設(shè)計(jì)制定一些簡(jiǎn)單的規(guī)則:
功能分解
顧名思義,就是把功能分解開(kāi)來(lái)。為什么呢?我們之所以很難達(dá)到重用目標(biāo)就是因?yàn)槲覀兙帉?xiě)的程序經(jīng)常處于一種好像是重復(fù)的功能,但又有輕微差別的狀態(tài)中。我們很多時(shí)候就會(huì)經(jīng)不住誘惑,用拷貝粘貼再做少量修改的方式完成一個(gè)功能。這種行為在XP中是堅(jiān)決不被允許的。XP提倡”O(jiān)nce and only once”,目的就是為了杜絕這種拷貝修改的現(xiàn)象。為了做到這一點(diǎn),我們通常要把功能分解到細(xì)粒度。很多的設(shè)計(jì)思想都提倡小類(lèi),為的就是這個(gè)目的。
所以,我們的程序中的類(lèi)和方法的數(shù)目就會(huì)大大增長(zhǎng),而每個(gè)類(lèi)和方法的平均代碼卻會(huì)大大的下降。可是,我們?cè)趺粗肋@個(gè)度應(yīng)該要如何把握呢,關(guān)于這個(gè)疑問(wèn),并沒(méi)有明確的答案,要看個(gè)人的功力和具體的要求,但是一般來(lái)說(shuō),我們可以用一個(gè)簡(jiǎn)單的動(dòng)詞短語(yǔ)來(lái)命名類(lèi)或方法的,那就會(huì)是比較好的分類(lèi)方法。
我們使用功能分解的規(guī)則,有助于提高重用性,因?yàn)槲覀兠總€(gè)類(lèi)和方法的精度都提高了。這是符合大自然的原則的,我們研究自然的主要的一個(gè)方向就是將物質(zhì)分解。我們的思路同樣可以應(yīng)用在軟件開(kāi)發(fā)上。除了重用性,功能分解還能實(shí)現(xiàn)透明的目標(biāo),因?yàn)槲覀兪褂昧斯δ芊纸獾囊?guī)則之后,每個(gè)類(lèi)都有自己的單獨(dú)功能,這樣,我們對(duì)一個(gè)類(lèi)的研究就可以集中在這個(gè)類(lèi)本身,而不用牽涉到過(guò)多的類(lèi)。
根據(jù)實(shí)際情況決定不同類(lèi)間的耦合度
雖然我們總是希望類(lèi)間的耦合度比較低,但是我們必須客觀(guān)的評(píng)價(jià)耦合度。系統(tǒng)之間不可能總是松耦合的,那樣肯定什么也做不了。而我們決定耦合的程度的依據(jù)何在呢?簡(jiǎn)單的說(shuō),就是根據(jù)需求的穩(wěn)定性,來(lái)決定耦合的程度。對(duì)于穩(wěn)定性高的需求,不容易發(fā)生變化的需求,我們完全可以把各類(lèi)設(shè)計(jì)成緊耦合的(我們雖然討論類(lèi)之間的耦合度,但其實(shí)功能塊、模塊、包之間的耦合度也是一樣的),因?yàn)檫@樣可以提高效率,而且我們還可以使用一些更好的技術(shù)來(lái)提高效率或簡(jiǎn)化代碼,例如Java中的內(nèi)部類(lèi)技術(shù)。可是,如果需求極有可能變化,我們就需要充分的考慮類(lèi)之間的耦合問(wèn)題,我們可以想出各種各樣的辦法來(lái)降低耦合程度,但是歸納起來(lái),不外乎增加抽象的層次來(lái)隔離不同的類(lèi),這個(gè)抽象層次可以是具體的類(lèi),也可以是接口,或是一組的類(lèi)(例如Beans)。我們可以借用Java中的一句話(huà)來(lái)概括降低耦合度的思想:”針對(duì)接口編程,而不是針對(duì)實(shí)現(xiàn)編程。
設(shè)計(jì)不同的耦合度有利于實(shí)現(xiàn)透明和延展。對(duì)于類(lèi)的客戶(hù)(調(diào)用者)來(lái)說(shuō),他不需要知道過(guò)多的細(xì)節(jié)(實(shí)現(xiàn)),他只關(guān)心他感興趣的(接口)。這樣,目標(biāo)類(lèi)對(duì)客戶(hù)來(lái)說(shuō)就是一個(gè)黑盒子。如果接口是穩(wěn)定的,那么,實(shí)現(xiàn)再怎么擴(kuò)展,對(duì)客戶(hù)來(lái)說(shuō)也不會(huì)有很大的影響。以前那種牽一發(fā)而動(dòng)全身的問(wèn)題完全可以緩解甚至避免。
其實(shí),我們仔細(xì)的觀(guān)察GOF的23種設(shè)計(jì)模式,沒(méi)有一種模式的思路不是從增加抽象層次入手來(lái)解決問(wèn)題的。同樣,我們?nèi)ビ^(guān)察Java源碼的時(shí)候,我們也可以發(fā)現(xiàn),Java源碼中存在著大量的抽象層次,初看之下,它們什么都不干,但是它們對(duì)系統(tǒng)的設(shè)計(jì)起著重大的作用。
夠用就好 :?
我們?cè)谏弦徽轮芯驼勥^(guò)敏捷方法很看重剛好夠用的問(wèn)題,現(xiàn)在我們結(jié)合架構(gòu)設(shè)計(jì)來(lái)看:在同樣都能夠滿(mǎn)足需要的情況下,一項(xiàng)復(fù)雜的設(shè)計(jì)和一項(xiàng)簡(jiǎn)單的設(shè)計(jì),哪一個(gè)更好。從敏捷的觀(guān)點(diǎn)來(lái)看,一定是后者。因?yàn)槟壳暗男枨笾挥?0項(xiàng),而你的設(shè)計(jì)能夠滿(mǎn)足100項(xiàng)的需求,只能說(shuō)這是種浪費(fèi)。你在設(shè)計(jì)時(shí)完全沒(méi)有考慮成本問(wèn)題,不考慮成本問(wèn)題,你就是對(duì)開(kāi)發(fā)組織的不負(fù)責(zé),對(duì)客戶(hù)的不負(fù)責(zé)。
應(yīng)用模式
這篇文章的寫(xiě)作思路很多來(lái)源于對(duì)模式的研究。因此,文章中到處都可以看到模式思想的影子。模式是一種整理、傳播思想的非常優(yōu)秀的途徑,我們可以通過(guò)模式的方式學(xué)習(xí)他人的經(jīng)驗(yàn)。一個(gè)好的模式代表了某個(gè)問(wèn)題研究的成果,因此我們把模式應(yīng)用在架構(gòu)設(shè)計(jì)上,能夠大大增強(qiáng)架構(gòu)的穩(wěn)定性。
抽象
架構(gòu)的本質(zhì)在于其抽象性。它包括兩個(gè)方面的抽象:業(yè)務(wù)抽象和技術(shù)抽象。架構(gòu)是現(xiàn)實(shí)世界的一個(gè)模型,所以我們首先需要對(duì)現(xiàn)實(shí)世界有一個(gè)很深的了解,然后我們還要能夠熟練的應(yīng)用技術(shù)來(lái)實(shí)現(xiàn)現(xiàn)實(shí)世界到模型的映射。因此,我們?cè)趯?duì)業(yè)務(wù)或技術(shù)理解不夠深入的情況下,就很難設(shè)計(jì)出好的架構(gòu)。當(dāng)然,這時(shí)候我們發(fā)現(xiàn)一個(gè)問(wèn)題:怎樣才能算是理解足夠深入呢。我認(rèn)為這沒(méi)有一個(gè)絕對(duì)的準(zhǔn)則。
一次,一位朋友問(wèn)我:他現(xiàn)在做的系統(tǒng)有很大的變化,原先設(shè)計(jì)的工作流架構(gòu)不能滿(mǎn)足現(xiàn)在的要求。他很希望能夠設(shè)計(jì)出足夠好的工作流架構(gòu),以適應(yīng)不同的變化。但是他發(fā)現(xiàn)這樣做無(wú)異于重新開(kāi)發(fā)一個(gè)lotus notes。我聽(tīng)了他的疑問(wèn)之后覺(jué)得有兩點(diǎn)問(wèn)題:
首先,他的開(kāi)發(fā)團(tuán)隊(duì)中并沒(méi)有工作流領(lǐng)域的專(zhuān)家。他的客戶(hù)雖然了解自己的工作流程,但是缺乏足夠的理論知識(shí)把工作流提到抽象的地步。顯然,他本身雖然有技術(shù)方面的才能,但就工作流業(yè)務(wù)本身,他也沒(méi)有足夠的經(jīng)驗(yàn)。所以,設(shè)計(jì)出象notes那樣的系統(tǒng)的前提條件并不存在。
其次,開(kāi)發(fā)一個(gè)工作流系統(tǒng)的目的是什么。原先的工作流系統(tǒng)運(yùn)作的不好,其原因是有變化發(fā)生。因此才有改進(jìn)工作流系統(tǒng)的動(dòng)機(jī)出現(xiàn)。可是,畢竟notes是為了滿(mǎn)足世界上所有的工作流系統(tǒng)而開(kāi)發(fā)的,他目前的應(yīng)用肯定達(dá)不到這個(gè)層次。
因此,雖然做不到最優(yōu)的業(yè)務(wù)抽象,但是我們完全可以在特定目的下,特定范圍內(nèi)做到最優(yōu)的業(yè)務(wù)抽象。比如說(shuō),我們工作流可能的變化是工組流路徑的變化。我們就完全可以把工作流的路徑做一個(gè)抽象,設(shè)計(jì)一個(gè)可以動(dòng)態(tài)改變路徑的工作流架構(gòu)。
有些時(shí)候,我們雖然在技術(shù)上和業(yè)務(wù)上都有所欠缺,沒(méi)有辦法設(shè)計(jì)出好的架構(gòu)。但是我們完全可以借鑒他人的經(jīng)驗(yàn),看看類(lèi)似的問(wèn)題別人是如何解決的。這就是我們前面提到的模式。我們不要把模式看成是一個(gè)硬性的解決方法,它只是一種解決問(wèn)題的思路。Martin Fowler曾說(shuō):”模式和業(yè)務(wù)組件的區(qū)別就在于模式會(huì)引發(fā)你的思考。
在《分析模式》一書(shū)中,Martin Fowler提到了分析和設(shè)計(jì)的區(qū)別。分析并不僅僅只是用用例列出所有的需求,分析還應(yīng)該深入到表面需求的的背后,以得到關(guān)于問(wèn)題本質(zhì)的Mental Model。然后,他引出了概念模型的概念。概念模型就類(lèi)似于我們?cè)谟懻摰某橄蟆artin Fowler提到了一個(gè)有趣的例子,如果要開(kāi)發(fā)一套軟件來(lái)模擬桌球游戲,那么,用用例來(lái)描述各種的需求,可能會(huì)導(dǎo)致大量的運(yùn)動(dòng)軌跡的出現(xiàn)。如果你沒(méi)有了解表面現(xiàn)象之后隱藏的運(yùn)動(dòng)定律的本質(zhì),你可能永遠(yuǎn)無(wú)法開(kāi)發(fā)出這樣一個(gè)系統(tǒng)。
關(guān)于架構(gòu)和抽象的問(wèn)題,在后面的文章中有一個(gè)測(cè)量模式的案例可以很形象的說(shuō)明這個(gè)問(wèn)題。
架構(gòu)的一些誤解
我們花了一些篇幅來(lái)介紹架構(gòu)的一些知識(shí)。現(xiàn)在回到我們的另一個(gè)主題上來(lái)。對(duì)于一個(gè)敏捷開(kāi)發(fā)過(guò)程,架構(gòu)意味著什么,我們?cè)撊绾蚊鎸?duì)架構(gòu)。這里我們首先要澄清一些誤解:
誤解1:架構(gòu)設(shè)計(jì)需要很強(qiáng)的技術(shù)能力。從某種程度來(lái)說(shuō),這句話(huà)并沒(méi)有很大的錯(cuò)誤。畢竟,你的能力越強(qiáng),設(shè)計(jì)出優(yōu)秀架構(gòu)的幾率也會(huì)上升。但是能力和架構(gòu)設(shè)計(jì)之間并沒(méi)有一個(gè)很強(qiáng)的聯(lián)系。即使是普通的編程人員,他一樣有能力設(shè)計(jì)出能實(shí)現(xiàn)目標(biāo)的架構(gòu)。
誤解2:架構(gòu)由專(zhuān)門(mén)的設(shè)計(jì)師來(lái)設(shè)計(jì),設(shè)計(jì)出的藍(lán)圖交由程序員來(lái)實(shí)現(xiàn)。我們之所以會(huì)認(rèn)為架構(gòu)是設(shè)計(jì)師的工作,是因?yàn)槲覀兿矚g把軟件開(kāi)發(fā)和建筑工程做類(lèi)比。但是,這兩者實(shí)際上是有著很大的區(qū)別的。關(guān)鍵之處在于,建筑設(shè)計(jì)已經(jīng)有很長(zhǎng)的歷史,已經(jīng)發(fā)展出完善的理論,可以通過(guò)某些理論(如力學(xué)原理)來(lái)驗(yàn)證設(shè)計(jì)藍(lán)圖。可是,對(duì)軟件開(kāi)發(fā)而言,驗(yàn)證架構(gòu)設(shè)計(jì)的正確性,只能夠通過(guò)寫(xiě)代碼來(lái)驗(yàn)證。因此,很多看似完美的架構(gòu),往往在實(shí)現(xiàn)時(shí)會(huì)出現(xiàn)問(wèn)題。
誤解3:在一開(kāi)始就要設(shè)計(jì)出完善的架構(gòu)。這種方式是最傳統(tǒng)的前期設(shè)計(jì)方式。這也是為XP所摒棄的一種設(shè)計(jì)方式。主要的原因是,在一開(kāi)始設(shè)計(jì)出完美的架構(gòu)根本就是在自欺欺人。因?yàn)檫@樣做的基本假設(shè)就是需求的不變性。但需求是沒(méi)有不變的(關(guān)于需求的細(xì)節(jié)討論,請(qǐng)參看拙作『需求的實(shí)踐』)。這樣做的壞處是,我們一開(kāi)始就限制了整個(gè)的軟件的形狀。而到實(shí)現(xiàn)時(shí),我們雖然發(fā)現(xiàn)原來(lái)的設(shè)計(jì)有失誤之處,但卻不愿意面對(duì)現(xiàn)實(shí)。這使得軟件畸形的生長(zhǎng)。原本一些簡(jiǎn)單的問(wèn)題,卻因?yàn)閯e扭的架構(gòu),變得非常的復(fù)雜。這種例子我們經(jīng)常可以看到,例如為兼容前個(gè)版本而導(dǎo)致的軟件復(fù)雜性。而2000年問(wèn)題,TCP/IP網(wǎng)絡(luò)的安全性問(wèn)題也從一個(gè)側(cè)面反映了這個(gè)問(wèn)題的嚴(yán)重性。
誤解4:架構(gòu)藍(lán)圖交給程序員之后,架構(gòu)設(shè)計(jì)師的任務(wù)就完成了。和誤解2一樣,我們借鑒了建筑工程的經(jīng)驗(yàn)。我們看到建筑設(shè)計(jì)師把設(shè)計(jì)好的藍(lán)圖交給施工人員,施工人員就會(huì)按照?qǐng)D紙建造出和圖紙一模一樣的大廈。于是,我們也企圖在軟件開(kāi)發(fā)中使用這種模式。這是非常要命的。軟件開(kāi)發(fā)中缺乏一種通用的語(yǔ)言,能夠充分的消除設(shè)計(jì)師和程序員的溝通隔閡。有人說(shuō),UML不可以嗎?UML的設(shè)計(jì)理念是好的,可以減輕溝通障礙問(wèn)題。可是要想完全解決這個(gè)問(wèn)題,UML還做不到。首先,程序員都具有個(gè)性化的思維,他會(huì)以自己的思維方式去理解設(shè)計(jì),因?yàn)閺脑O(shè)計(jì)到實(shí)現(xiàn)并不是一項(xiàng)機(jī)械的勞動(dòng),還是屬于一項(xiàng)知識(shí)性的勞動(dòng)(這和施工人員的工作是不同的)。此外,對(duì)于程序員來(lái)說(shuō),他還極有可能按照自己的想法對(duì)設(shè)計(jì)圖進(jìn)行一定的修改,這是非常正常的一項(xiàng)舉動(dòng)。更糟的是,程序員往往都比較自負(fù),他們會(huì)潛意識(shí)的排斥那些未經(jīng)過(guò)自己認(rèn)同的設(shè)計(jì)。
架構(gòu)設(shè)計(jì)的過(guò)程模式
通常我們認(rèn)為模式都是用在軟件開(kāi)發(fā)、架構(gòu)設(shè)計(jì)上的。其實(shí),這只是模式的一個(gè)方面。模式的定義告訴我們,模式描述了一個(gè)特定環(huán)境的解決方法,這個(gè)特定環(huán)境往往重復(fù)出現(xiàn),制定出一個(gè)較好的解決方法有利于我們?cè)谖磥?lái)能有效的解決類(lèi)似的問(wèn)題。其實(shí),在管理學(xué)上,也存在這種類(lèi)似的這種思維。稱(chēng)為結(jié)構(gòu)性問(wèn)題的程序化解決方法。所以呢,我們完全可以把模式的思想用在其它的方面,而目前最佳的運(yùn)用就是過(guò)程模式和組織模式。在我們的文章中,我們僅限于討論過(guò)程模式。 方法論對(duì)軟件開(kāi)發(fā)而言意味著什么?我們?nèi)绾慰创浖_(kāi)發(fā)中的方法論?方法論能夠成為軟件開(kāi)發(fā)的救命稻草嗎?在讀過(guò)此文后,這些疑惑就會(huì)得到解答。?
架構(gòu)設(shè)計(jì)中的方法學(xué)(1)——方法源于恐懼
方法論
方法論的英文為Methodology,詞典中的解釋為:“A series of related methods or techniques”,我們可以把它定義為軟件開(kāi)發(fā)(針對(duì)軟件開(kāi)發(fā))的一整套方法、過(guò)程、規(guī)則、實(shí)踐、技術(shù)。關(guān)于方法論出現(xiàn)的問(wèn)題,我很贊同Alistair Cockburn的一句話(huà),“方法論源于恐懼。”出于對(duì)項(xiàng)目的超期、成本失控等等因素的恐懼,項(xiàng)目經(jīng)理們從以前的經(jīng)驗(yàn)出發(fā),制定出了一些控制、監(jiān)測(cè)項(xiàng)目的方法、技巧。這就是方法論產(chǎn)生的原因。
在A(yíng)gile Software Development一書(shū)中,作者提到了方法論的十三個(gè)要素,基本能夠函蓋方法論的各個(gè)方面:
角色(Roles)、個(gè)性(Personality)、技能(Skills)、團(tuán)隊(duì)(Teams)、技術(shù)(Techniques)、活動(dòng)(Activities)、過(guò)程(Process)、工件(Work products)、里程碑(Milestones)、標(biāo)準(zhǔn)(Standards)、質(zhì)量(Quality)、工具(Tools)、團(tuán)隊(duì)價(jià)值(Team Values)。
它們之間的關(guān)系可以用一幅圖來(lái)表示:
圖 1. 方法論的十三個(gè)要素
很多的方法論,都涉及了上面列舉的十三要素中的部分要素,因此,我們可以把方法論看作是一個(gè)抽象的、無(wú)窮的超集,而現(xiàn)實(shí)中的方法論都是指超集的一個(gè)有限的子集而已。它們之間的關(guān)系就好像有理數(shù)和1到100之間的整數(shù)的關(guān)系一樣。不論是XP,還是UI設(shè)計(jì)經(jīng)驗(yàn)之類(lèi),都屬于方法論的一個(gè)子集,只是這兩個(gè)子集之間有大小的差別而已。我們還應(yīng)該看到,討論一個(gè)完備的方法論是沒(méi)有意義的,因此這種方法論鐵定不存在,就好像你視圖窮舉出所有的有理數(shù)一樣荒唐。因此,我們關(guān)于一個(gè)通用的方法論的說(shuō)法也是無(wú)意義的。好的方法論,比如說(shuō)XP、水晶系列,它們都有一個(gè)適合的范圍,因?yàn)樗鼈兞私庖稽c(diǎn),自己并不是一個(gè)無(wú)所不能的方法論。
在現(xiàn)實(shí)中,我們其實(shí)不斷的在接觸方法論。比如說(shuō),為了控制項(xiàng)目的進(jìn)度,項(xiàng)目經(jīng)理要求所有的開(kāi)發(fā)人員每周遞交一份詳細(xì)的進(jìn)度報(bào)告,這就是一種方法、一種技巧。如果把開(kāi)發(fā)過(guò)程中的這些技巧系統(tǒng)的組織起來(lái),就能夠成為一種方法論。你可能會(huì)說(shuō),那一種方法論的產(chǎn)生也太容易了吧。不,這樣產(chǎn)生的方法論并沒(méi)有太大的實(shí)用價(jià)值,沒(méi)有實(shí)用價(jià)值的方法論根本就沒(méi)有存在的必要。因此,一個(gè)成功的方法論是要能夠?yàn)槎鄠€(gè)的項(xiàng)目所接受,并且能夠成功實(shí)現(xiàn)軟件的交付的方法論。
我和我的同事在實(shí)踐中做了一些試驗(yàn),希望能夠把一些好的方法論應(yīng)用于開(kāi)發(fā)團(tuán)隊(duì)。試驗(yàn)的結(jié)果很無(wú)奈,方法論實(shí)施的效果并不理想,一開(kāi)始我們認(rèn)為是方法本身的原因,到后來(lái),我們發(fā)現(xiàn)事情并不是這么簡(jiǎn)單。在試驗(yàn)的過(guò)程中,開(kāi)發(fā)人員一致認(rèn)同方法論的優(yōu)勢(shì)所在,但是在實(shí)施過(guò)程中,鮮有堅(jiān)持的下來(lái)的。在A(yíng)gile Software Development中,我發(fā)現(xiàn)作者遇到了和我們一樣的問(wèn)題。
Alistair Cockburn在和大量的項(xiàng)目團(tuán)隊(duì)的訪(fǎng)談之后,寫(xiě)成了Agile Software Development一書(shū)。在訪(fǎng)談之前,他篤定自己將會(huì)發(fā)現(xiàn)高度精確的過(guò)程控制是成功的關(guān)鍵所在,結(jié)果他發(fā)現(xiàn)事實(shí)并非如此,他把他的發(fā)現(xiàn)歸結(jié)為7條定律。而我在實(shí)際中的發(fā)現(xiàn)也包含在這七條定律中,總結(jié)起來(lái)就只有兩點(diǎn):溝通和反饋。
只要能夠保證良好的溝通和即時(shí)的反饋,那么開(kāi)發(fā)團(tuán)隊(duì)即使并沒(méi)有采用先進(jìn)的方法論,一樣可以成功。相反,那些“高質(zhì)量”的團(tuán)隊(duì)卻往往由于缺乏這兩個(gè)因素而導(dǎo)致失敗(我們這里指的失敗是用戶(hù)拒絕使用最終的軟件)。最有效,而成本也最低的溝通方法就是面對(duì)面(face to face)的溝通,而隨著項(xiàng)目團(tuán)隊(duì)的變大,或是另外一些影響因素的加入(比如地理位置的隔絕),面對(duì)面的溝通越來(lái)越難實(shí)現(xiàn),這導(dǎo)致溝通的成本逐漸加大,質(zhì)量也慢慢下降。但這并不是說(shuō)非面對(duì)面的溝通不可,重要的是我們需要知道不同的溝通方式的成本和質(zhì)量并不相同。XP方法尤為強(qiáng)調(diào)面對(duì)面的溝通,通過(guò)現(xiàn)場(chǎng)客戶(hù)、站立會(huì)議、結(jié)對(duì)編程等方式來(lái)保證溝通的有效。在我的經(jīng)驗(yàn)中,一個(gè)開(kāi)發(fā)團(tuán)隊(duì)其實(shí)是需要多種溝通方式的結(jié)合的。完全的面對(duì)面的溝通對(duì)某些團(tuán)隊(duì)來(lái)說(shuō)是很難實(shí)現(xiàn)的,那么問(wèn)題的關(guān)鍵就在于你如何應(yīng)用溝通的方式來(lái)達(dá)到你希望的效果。在前不久結(jié)束的歐萊雅創(chuàng)業(yè)計(jì)劃大賽上,有一支團(tuán)隊(duì)特別引人注目,他們彼此間素未謀面,僅僅憑借Internet和電話(huà)完成了高效的合作。他們雖然沒(méi)有使用面對(duì)面的溝通方式,但是仍然達(dá)成了既定的目標(biāo)。軟件開(kāi)發(fā)也是一樣的,面對(duì)面的溝通是非常有必要的,但其它的溝通方式也是需要的。
再看反饋,不論是控制進(jìn)度,還是保證客戶(hù)的滿(mǎn)意度,這些活動(dòng)都需要管理成本。軟件開(kāi)發(fā)中的管理成本的一個(gè)通性就是伴隨有中間產(chǎn)出物(intermediate delivery)。比如說(shuō)我們的需求規(guī)約、分析文檔、設(shè)計(jì)文檔、測(cè)試計(jì)劃,這些都屬于中間產(chǎn)出物。中間產(chǎn)出物的增加將會(huì)帶來(lái)效率下降的問(wèn)題,因?yàn)殚_(kāi)發(fā)人員的時(shí)間都花在了完成中間產(chǎn)出物的工作上,花在給軟件新功能上的時(shí)間就減少了。而中間產(chǎn)出物的主要目的是兩個(gè),一個(gè)是為了保證軟件如客戶(hù)所愿,例如需求規(guī)約;另一個(gè)是為了作為團(tuán)隊(duì)中的其他成員工作的輸入,例如開(kāi)發(fā)計(jì)劃、測(cè)試計(jì)劃等。因此,我們也可以針對(duì)這兩點(diǎn)來(lái)商討對(duì)策,一種是采用迭代的思想,提高軟件發(fā)布的頻率,以保證客戶(hù)的需求被確實(shí)的滿(mǎn)足,另一種就是縮小團(tuán)隊(duì)的溝通范圍,保證成員能夠從其他人那里得到新的思路,而不是撰寫(xiě)規(guī)范的內(nèi)部文檔(內(nèi)部文檔指那些僅為內(nèi)部開(kāi)發(fā)人員之間的溝通所需要的文檔)。
因此,一個(gè)軟件項(xiàng)目的成功和你采用的開(kāi)發(fā)方法論并沒(méi)有直接的關(guān)系。
重量
我們根據(jù)把擁有大量artifact(RUP官方翻譯為工件,意思是軟件開(kāi)發(fā)過(guò)程中的中間產(chǎn)物,如需求規(guī)約、設(shè)計(jì)模型等)和復(fù)雜控制的軟件開(kāi)發(fā)方法稱(chēng)為重型(Heavy Weight)方法,相對(duì)的,我們稱(chēng)artifact較少的方法為輕型(Light Weight)方法。在傳統(tǒng)的觀(guān)念中,我們認(rèn)為重型方法要比輕型安全許多。因?yàn)槲覀冎韵氤鲋匦头椒?#xff0c;就是由于在中大型的項(xiàng)目中,項(xiàng)目經(jīng)理往往遠(yuǎn)離代碼,他無(wú)法有效的了解目前的工程的進(jìn)度、質(zhì)量、成本等因素。為了克服未知的恐懼感,項(xiàng)目經(jīng)理制定了大量的中間管理方法,希望能夠控制整個(gè)項(xiàng)目,最典型的莫過(guò)于要求開(kāi)發(fā)人員頻繁的遞交各種表示項(xiàng)目目前狀態(tài)的報(bào)告。
在Planning XP一書(shū)中有一段討論輕重型方法論的精辟論述,它把重型方法論歸結(jié)為一種防御性的姿態(tài)(defensive posture),而把輕型方法論歸結(jié)為一種渴望成功(Plan to win)的心態(tài)。如果你是采用了防御性姿態(tài),那么你的工作就集中在防止和跟蹤錯(cuò)誤上,大量的工作流程的制定,是為了保證項(xiàng)目不犯錯(cuò)誤,而不是項(xiàng)目成功。而這種方法也不可謂不好,但前提是如果整個(gè)團(tuán)隊(duì)能夠滿(mǎn)足前面所提到的兩個(gè)條件的話(huà),項(xiàng)目也肯定會(huì)成功,但是重型方法論的一個(gè)弊端就在于,大家都在防止錯(cuò)誤,都在懼怕錯(cuò)誤,因此人和人之間的關(guān)系是很微妙的,要達(dá)到充分的溝通也是很難的。最終,連對(duì)人的評(píng)價(jià)也變成是以避免錯(cuò)誤的多寡作為考評(píng)的依據(jù),而不是成就。我們?cè)谧鲈囼?yàn)的時(shí)候,一位項(xiàng)目經(jīng)理開(kāi)玩笑說(shuō),“方法論源自項(xiàng)目經(jīng)理的恐懼,這沒(méi)錯(cuò)。但最糟糕的是整個(gè)團(tuán)隊(duì)只有項(xiàng)目經(jīng)理一個(gè)人恐懼,如果能夠做到人人的恐懼,那大家也就沒(méi)有什么好恐懼的了。”這句話(huà)提醒了我們,如果一個(gè)團(tuán)隊(duì)的精神就是力求成功,那么這支團(tuán)隊(duì)的心態(tài)就和其它的團(tuán)隊(duì)不同了,尤其是對(duì)待錯(cuò)誤的心態(tài)上。根本就沒(méi)有必要花費(fèi)大量的精力來(lái)預(yù)防錯(cuò)誤,錯(cuò)誤犯了就犯了,即時(shí)改正就可以了。這其實(shí)就是渴望成功的心態(tài)。
方法論的藝術(shù)
管理,被稱(chēng)為科學(xué)和藝術(shù)的融合體,而管理的藝術(shù)性部分很大程度的體現(xiàn)在人的管理上。我說(shuō),方法學(xué),一樣是科學(xué)和藝術(shù)的融合體。這是有依據(jù)的,其實(shí)方法論和管理學(xué)是近親關(guān)系,管理學(xué)中有一門(mén)分支是項(xiàng)目管理,而在軟件組織中,項(xiàng)目管理是非常重要的,方法學(xué)就是一種針對(duì)軟件開(kāi)發(fā)的一種特定的項(xiàng)目管理(或是項(xiàng)目管理的一個(gè)子集)。
重型方法最大的一個(gè)問(wèn)題就在于他不清楚或忽略了藝術(shù)這個(gè)層次,忽視了人的因素,把人做為一個(gè)計(jì)量單位,一種資源,一種線(xiàn)性元素。而人的要素在軟件開(kāi)發(fā)中是非常重要的,軟件開(kāi)發(fā)實(shí)際上是一種知識(shí)、智力的轉(zhuǎn)移過(guò)程,最終形成的產(chǎn)品是一種知識(shí)產(chǎn)品,它的成本取決于開(kāi)發(fā)者的知識(shí)價(jià)值,因此,人是最重要的因素。而人這個(gè)要素是很難衡量的,每個(gè)人都有不同的個(gè)性、想法、經(jīng)驗(yàn)、經(jīng)歷,這么多復(fù)雜的因素加在一起,就導(dǎo)致了人的不可預(yù)見(jiàn)性。因此,我們強(qiáng)調(diào)管人的藝術(shù)。
最簡(jiǎn)單的例子是,在重型方法中,我們的基本假設(shè)是對(duì)人的不信任。項(xiàng)目經(jīng)理要控制項(xiàng)目。但不信任就會(huì)產(chǎn)生很多的問(wèn)題,比如士氣不高,計(jì)劃趕不上變化,創(chuàng)新能力低下,跳槽率升高等等。人都是希望被尊重的,技術(shù)人員更看重這一點(diǎn),而很多公司也口口聲聲說(shuō)自己多么多么以人為本,可是采用的卻是以不信任人為前提的開(kāi)發(fā)方法,言行不一。我們說(shuō)敏捷方法的出發(fā)點(diǎn)是相互信任,做到這一點(diǎn)是很難的,但是一旦做到了,那這個(gè)團(tuán)隊(duì)就是非常具有競(jìng)爭(zhēng)力的。因此,這就產(chǎn)生了一個(gè)問(wèn)題,在沒(méi)有做到完全的相互信任之前,我們到底相不相信他人呢,這就是我提到的藝術(shù)性的問(wèn)題,什么時(shí)候你要相信人?什么時(shí)候你不相信人,這些都是需要權(quán)衡的問(wèn)題,也都是表現(xiàn)你藝術(shù)性的問(wèn)題。
敏捷方法
敏捷代表著有效和靈活。我們稱(chēng)那些輕型的、有效的方法為敏捷方法。在重型方法中,我們?cè)谝恍┎槐匾⒅貜?fù)的中間環(huán)節(jié)上浪費(fèi)了太多的精力,而敏捷則避免了這種浪費(fèi)。我們的文章將會(huì)重點(diǎn)的討論敏捷(Agile)方法論的思想,敏捷這個(gè)名字的前身就是輕型。目前已經(jīng)有了一個(gè)敏捷聯(lián)盟,他們制定了敏捷宣言:
Individuals and interactions over processes and tools.
Working software over comprehensive documentation.
Customer collaboration over contract negotiation.
Responding to change over following a plan.
而我對(duì)敏捷的理解包括了幾個(gè)方面:
較低的管理成本和高質(zhì)量的產(chǎn)出。軟件開(kāi)發(fā)存在兩個(gè)極端:一個(gè)是沒(méi)有任何的管理成本,所有的工作都是為了軟件的產(chǎn)出,但是這種方式卻往往導(dǎo)致軟件開(kāi)發(fā)過(guò)程的混沌,產(chǎn)品的低質(zhì)量,團(tuán)隊(duì)士氣的低落。另一個(gè)是大量管理活動(dòng)的加入,評(píng)審、變更管理,缺陷跟蹤,雖然管理活動(dòng)的加入能夠在一定程度上提高開(kāi)發(fā)過(guò)程的有序性,但是成本卻因此提高,更糟糕的是,很容易導(dǎo)致團(tuán)隊(duì)的低效率,降低創(chuàng)新能力。因此,敏捷方法試圖尋找一個(gè)平衡點(diǎn),用低成本的管理活動(dòng)帶來(lái)最大的產(chǎn)出,即軟件的高質(zhì)量。
尊重人性。敏捷方法尊重人性,強(qiáng)調(diào)效率。軟件開(kāi)發(fā)可以說(shuō)是一種腦力的投入,如果不能保證開(kāi)發(fā)人員的自愿投入,產(chǎn)品就肯定要打折扣。事實(shí)多次的證明,一個(gè)愿意投入的開(kāi)發(fā)人員和一個(gè)不愿意投入的開(kāi)發(fā)人員效率相差在三倍以上,對(duì)組織的貢獻(xiàn)更是在十倍以上。
溝通和反饋是一切的基礎(chǔ)。我們已經(jīng)討論過(guò)溝通的重要程度,而即時(shí)的反饋是擁抱變化的前提條件。
客戶(hù)是上帝。沒(méi)有客戶(hù)就沒(méi)有一切,客戶(hù)的重要性可以用一句話(huà)來(lái)形容,就是以合理的成本建造合適的軟件(build the right system at the right cost)。
敏捷其實(shí)也有輕重之分,關(guān)鍵在于是否能夠做到有效和靈活。因此,敏捷方法論提倡的一個(gè)思想是“剛好夠(barely sufficient)”。不過(guò)這個(gè)“剛好夠”可不是那么容易判斷的。一支8個(gè)人的團(tuán)隊(duì)采用XP方法,隨著方法的熟練使用,團(tuán)隊(duì)的能力在不斷的增強(qiáng),能夠處理的問(wèn)題越越來(lái)越復(fù)雜,也許他們能夠處理采用重型方法的20個(gè)人團(tuán)隊(duì)能夠處理的問(wèn)題。可是如果團(tuán)隊(duì)的人數(shù)突然增加到12人,這支團(tuán)隊(duì)肯定就會(huì)出問(wèn)題,他的表現(xiàn)可能還不如那支20個(gè)人的團(tuán)隊(duì)了。人數(shù)增加的時(shí)候,原先的方法肯定還做適當(dāng)?shù)恼{(diào)整,比如說(shuō),在原先的敏捷方法上增加一些重型方法的技巧。我們不能夠要求一支6個(gè)人的團(tuán)隊(duì)和一支20個(gè)人的團(tuán)隊(duì)用同樣的方法,前者可能采用輕一些的敏捷方法,后者可能采用重一些的敏捷方法,關(guān)鍵的問(wèn)題在于,兩支團(tuán)隊(duì)都把重點(diǎn)放在溝通、反饋、頻繁交付軟件這些關(guān)鍵的因素上,也就是做到有效和靈活。
架構(gòu)設(shè)計(jì)
架構(gòu)(Architecture)(也有被稱(chēng)為體系結(jié)構(gòu)的)是軟件設(shè)計(jì)中非常重要的一個(gè)環(huán)節(jié)。軟件開(kāi)發(fā)的過(guò)程中只要需求和架構(gòu)確定之后,這個(gè)軟件就基本上可以定型了。這就好比骨骼確定了,這個(gè)人的體形就不會(huì)有很大的變化。因此我選擇了架構(gòu)設(shè)計(jì)來(lái)討論敏捷軟件開(kāi)發(fā)(需求我已經(jīng)寫(xiě)過(guò)了)。我們?cè)谇懊嬗懻撨^(guò)超集和子集的概念,因此我們接下去要討論的架構(gòu)設(shè)計(jì)也是一個(gè)很小的子集。方法論如果沒(méi)有經(jīng)歷過(guò)多個(gè)項(xiàng)目的檢驗(yàn)是不能稱(chēng)為成功的方法論的,我也并不認(rèn)為我的架構(gòu)設(shè)計(jì)就是一個(gè)好的方法論,但引玉還需拋磚,他的主要目的是為了傳播一種思想。因此,我采用了模式語(yǔ)言(PLOP)做為寫(xiě)作架構(gòu)設(shè)計(jì)的形式,主要的原因就是模式是一種很好的組織思想的方法。
因此,在我們接下去的歷程中,我們集中討論的東西就圍繞著架構(gòu)、方法學(xué)、敏捷這三個(gè)要素展開(kāi)。這篇文章并不是討論如何編碼實(shí)現(xiàn)軟件架構(gòu)的,也不要單純的把它看作架構(gòu)設(shè)計(jì)的指南,其實(shí)文中的很多思想來(lái)自于方法論,因此提到的很多架構(gòu)設(shè)計(jì)的思想也適用于其它工作,如果能夠了解這一點(diǎn),看這篇文章的收獲可能會(huì)更多一些。?
架構(gòu)設(shè)計(jì)中的方法學(xué)(3)——架構(gòu)源自需求
從需求到架構(gòu)
在需求階段,我們可以得到一些代表需求調(diào)研成果的中間產(chǎn)物。比如說(shuō),CRC卡片、基本用例模型、用戶(hù)素材、界面原型、界面原型流程圖
、非功能需求、變化案例等。我們?cè)诩軜?gòu)設(shè)計(jì)階段的主要工作就是要把這些需求階段的中間產(chǎn)物轉(zhuǎn)換為架構(gòu)設(shè)計(jì)階段的中間產(chǎn)物。?
其實(shí),架構(gòu)設(shè)計(jì)就是要完成兩項(xiàng)工作,一是分析,二是設(shè)計(jì)。分析是分析需求,設(shè)計(jì)則是設(shè)計(jì)軟件的大致結(jié)構(gòu)。很多的方法論把分析和設(shè)計(jì)兩種活動(dòng)分開(kāi)來(lái),但其實(shí)這兩者是很難區(qū)分的,做分析的時(shí)候會(huì)想到如何設(shè)計(jì),而思考如何設(shè)計(jì)反過(guò)來(lái)又會(huì)影響分析的效果。可以說(shuō),他們兩者之間是相互聯(lián)系和不斷迭代的。這種形態(tài)我們將會(huì)在后面的迭代設(shè)計(jì)模式中詳細(xì)的討論。?
在敏捷方法論中,需求最好是迭代進(jìn)行的,也就是說(shuō)一點(diǎn)一點(diǎn)的作需求。這種做法在那些需求變化快的項(xiàng)目中尤其適用。由于我們采用的流程是一種迭代式的流程,這里我們將會(huì)面臨著如何對(duì)待上一次迭代的中間產(chǎn)物的問(wèn)題。如果我們每一次迭代都需要修改已存在的中間產(chǎn)物,那么這種維護(hù)的成本未免過(guò)大。因此,敏捷方法論的基本做法是,扔掉那些已經(jīng)沒(méi)有用處的中間產(chǎn)物。還記得在第一章的時(shí)候,我們強(qiáng)調(diào)說(shuō)軟件要比文檔重要。我們生成中間產(chǎn)物的目的都是為了生成最終的程序,對(duì)于這些已經(jīng)完成作用的模型,沒(méi)有必要付出額外的維護(hù)成本。?
不要斷章取義的采用拋棄模型的做法。因?yàn)?#xff0c;拋棄模型的做法需要一個(gè)適合環(huán)境的支持。后面會(huì)針對(duì)這個(gè)話(huà)題開(kāi)展大范圍的討論。這里我們簡(jiǎn)單的做一個(gè)了解:?
簡(jiǎn)單化:簡(jiǎn)單的模型和簡(jiǎn)單的程序。模型和程序越復(fù)雜,就需要更多的精力來(lái)處理它們。因此,我們盡可能的簡(jiǎn)化它們,為的是更容易的處理它們。?
高效的溝通渠道:通過(guò)增強(qiáng)溝通的效果來(lái)減少對(duì)中間產(chǎn)物的需要。試想一下,如果我隨時(shí)能夠從客戶(hù)那里得到需求的細(xì)節(jié)資料,那前期的需求調(diào)研就沒(méi)有必要做的太細(xì)致。?
角色的交叉輪換:開(kāi)發(fā)人員之間建立起交換角色的機(jī)制,這樣,能夠盡量的避免各子系統(tǒng)諸侯割據(jù)的局面。?
清晰的流程:或者我們可以稱(chēng)之為明確的過(guò)程。過(guò)程在方法論中向來(lái)都是一個(gè)重點(diǎn),敏捷方法論也不例外。開(kāi)發(fā)人員能夠清楚的知道,今天做什么,明天做什么。過(guò)程不是給別人看的,而是給自己用的。?
工具:好用的工具能夠節(jié)省大量的時(shí)間,這里的工具并不僅僅指CASE工具,還包括了版本控制工具、自動(dòng)化測(cè)試工具、畫(huà)圖工具、文檔制作和管理工具。使用工具要注意成本和效益的問(wèn)題。?
標(biāo)準(zhǔn)和風(fēng)格:語(yǔ)言不通是溝通的一個(gè)很大的障礙。語(yǔ)言從某個(gè)角度來(lái)看屬于一種標(biāo)準(zhǔn)、一種風(fēng)格。因此,一個(gè)團(tuán)隊(duì)如果采用同樣的編碼標(biāo)準(zhǔn)、文檔標(biāo)準(zhǔn)、注釋風(fēng)格、制圖風(fēng)格,那么這個(gè)團(tuán)隊(duì)的溝通效率一定非常的高。?
如果上述的環(huán)境你都不具備,或是欠缺好幾項(xiàng),那你的文檔的模型還是留著的好。?
僅針對(duì)需求設(shè)計(jì)架構(gòu)?
僅針對(duì)需求設(shè)計(jì)架構(gòu)的含義就是說(shuō)不要做未來(lái)才有用的事情。有時(shí)候,我們會(huì)把架構(gòu)考慮的非常復(fù)雜,主要的原因就是我們把很多未來(lái)的因素放入到現(xiàn)在來(lái)考慮。或者,我們?cè)陂_(kāi)發(fā)第一個(gè)產(chǎn)品的時(shí)候就視圖把它做成一個(gè)完美的框架。以上的這兩種思路有沒(méi)有錯(cuò)呢?沒(méi)有錯(cuò),這只是如何看待投入的問(wèn)題,有人希望開(kāi)始的時(shí)候多投入一些,這樣后續(xù)的投入就會(huì)節(jié)省下來(lái)。但在現(xiàn)實(shí)中,由于需求的不確定性,希望通過(guò)增加開(kāi)始階段的投入來(lái)將降低未來(lái)的投入往往是難以做到的,框架的設(shè)計(jì)也絕對(duì)不是能夠一蹴而就的,此這種做法并不是一個(gè)好的做法。所以我們?cè)诤箢^會(huì)著重論述架構(gòu)設(shè)計(jì)的簡(jiǎn)單性和迭代過(guò)程,也就是因?yàn)檫@個(gè)理由。?
模式?
模式將可以幫助我們抓住重點(diǎn)。為了解決設(shè)計(jì)文檔編輯器引出的七個(gè)問(wèn)題,一共使用了8種不同的模式。這8種模式的組合其實(shí)就是架構(gòu),因?yàn)樗鼈兘鉀Q的,都是系統(tǒng)中最高層的問(wèn)題。
在實(shí)踐中,人們發(fā)現(xiàn)架構(gòu)也是存在模式的。比如,對(duì)于系統(tǒng)結(jié)構(gòu)設(shè)計(jì),我們使用層模式;對(duì)于分布式系統(tǒng),我們使用代理模式;對(duì)于交互系統(tǒng),我們使用MVC(模型-視圖-控制器)模式。模式本來(lái)就是針對(duì)特定問(wèn)題的解,因此,針對(duì)需求的特點(diǎn),我們也可以采用相應(yīng)的模式來(lái)設(shè)計(jì)架構(gòu)。
在sun網(wǎng)站上提供的寵物商店的范例中,就把MVC模式的思想擴(kuò)展成為架構(gòu)的思想,用于提供不同的界面視圖:
我們可以了解到在圖的背后隱藏著的需求:系統(tǒng)需要支持多種用戶(hù)界面,包括為普通用戶(hù)提供的HTML界面,為無(wú)線(xiàn)用戶(hù)提供的WML界面,為管理員提供的Swing界面,以及為B2B業(yè)務(wù)設(shè)計(jì)的WebService界面。這是系統(tǒng)最重要的需求,因此,系統(tǒng)的設(shè)計(jì)者就需要確定一個(gè)穩(wěn)定的架構(gòu),以解決多界面的問(wèn)題。相對(duì)于多界面的問(wèn)題,后端的業(yè)務(wù)處理邏輯都是一致的。比如HTML界面和WML界面的功能并沒(méi)有太大的差別。把處理邏輯和界面分離開(kāi)來(lái)還有額外的好處,可以在添加功能的同時(shí),不涉及界面的改動(dòng),反之亦然。這就是我們?cè)诘诙刑岬降鸟詈隙鹊膯?wèn)題。?
MVC模式正可以適用于解決該問(wèn)題。系統(tǒng)使用控制器來(lái)為業(yè)務(wù)邏輯選擇不同的界面,這就完成了MVC架構(gòu)的設(shè)計(jì)思路。在架構(gòu)設(shè)計(jì)的工作中,我們手頭上有模式這樣一張好牌,有什么理由不去使用它呢??
抓住重點(diǎn)?
在架構(gòu)設(shè)計(jì)一開(kāi)始,我們就說(shuō)架構(gòu)是一種抽象,那就是說(shuō),架構(gòu)設(shè)計(jì)摒棄了具體的細(xì)節(jié),僅僅抓住軟件最高層的概念,也就是最上層、優(yōu)先級(jí)最高、風(fēng)險(xiǎn)最大的那部分需求。?
我們考慮、分析、解決一個(gè)問(wèn)題,一定有一個(gè)漸進(jìn)的過(guò)程。架構(gòu)設(shè)計(jì)就是解決問(wèn)題其中比較早期的一個(gè)階段,我們不會(huì)在架構(gòu)設(shè)計(jì)這個(gè)階段投入過(guò)多的時(shí)間(具體的原因在下文會(huì)有討論),因此關(guān)鍵點(diǎn)在于我們要能夠在架構(gòu)設(shè)計(jì)中把握住需求的重點(diǎn)。比如,我們?cè)谀J揭还?jié)中提到了分布式系統(tǒng)和交互系統(tǒng),分布和交互就是這兩個(gè)系統(tǒng)的重點(diǎn)。那么,如果說(shuō)我們面對(duì)的是一個(gè)分布式的交互系統(tǒng),那么,我們就需要把這兩種特性做為重點(diǎn)來(lái)考慮,并以此為基礎(chǔ),設(shè)計(jì)架構(gòu)。而我們提到的寵物商店的范例也是類(lèi)似的,除了MVC的架構(gòu),還有很多的設(shè)計(jì)問(wèn)題需要解決,例如用于數(shù)據(jù)庫(kù)訪(fǎng)問(wèn)的數(shù)據(jù)對(duì)象,用于視圖管理的前端控制器,等等(具體使用到的架構(gòu)模式可以訪(fǎng)問(wèn)sun的網(wǎng)站)。但是這些相對(duì)于MVC模式來(lái)說(shuō),屬于局部的,優(yōu)先級(jí)較低的部分,可以在架構(gòu)確定后再來(lái)設(shè)計(jì)。?
架構(gòu)設(shè)計(jì)和領(lǐng)域?qū)<?
一個(gè)架構(gòu)要設(shè)計(jì)的好,和對(duì)需求的理解是分不開(kāi)的。因此在現(xiàn)實(shí)中,我們發(fā)現(xiàn)業(yè)務(wù)領(lǐng)域?qū)<覒{借著他對(duì)業(yè)務(wù)領(lǐng)域的了解,能夠幫助開(kāi)發(fā)人員設(shè)計(jì)出優(yōu)秀的架構(gòu)來(lái)。架構(gòu)是需要抽象的,它是現(xiàn)實(shí)社會(huì)活動(dòng)的一個(gè)基本模型,而業(yè)務(wù)領(lǐng)域的模型僅僅憑開(kāi)發(fā)人員是很難設(shè)計(jì)出來(lái)的。在ERP的發(fā)展史上,我們看到MRP發(fā)展為MRPII,在發(fā)展到閉環(huán)MRP,直到發(fā)展成為現(xiàn)在的ERP,主要的因素是管理思想的演化,也就是說(shuō),對(duì)業(yè)務(wù)領(lǐng)域的理解進(jìn)步了,架構(gòu)才有可能進(jìn)步。?
因此,敏捷型架構(gòu)設(shè)計(jì)的過(guò)程中,我們也非常強(qiáng)調(diào)領(lǐng)域?qū)<业淖饔?
架構(gòu)設(shè)計(jì)中的方法學(xué)(4)——團(tuán)隊(duì)設(shè)計(jì)?
團(tuán)隊(duì)設(shè)計(jì)是敏捷方法論中很重要的一項(xiàng)實(shí)踐。我們這里說(shuō)的團(tuán)隊(duì),指的并不是復(fù)數(shù)的人。一群人就是一群人,并沒(méi)有辦法構(gòu)成團(tuán)隊(duì)。要想成為團(tuán)隊(duì),有很多的工作要做。?
我們之所以考慮以團(tuán)隊(duì)
為單位來(lái)考慮架構(gòu)設(shè)計(jì),是因?yàn)檐浖_(kāi)發(fā)本身就不是一件個(gè)人的事情,架構(gòu)設(shè)計(jì)更是如此。單個(gè)人的思維不免有考慮欠妥之處,單個(gè)人的學(xué)識(shí)也不可能覆蓋所有的學(xué)科。而組織有效的團(tuán)隊(duì)卻能夠彌補(bǔ)這些缺憾。?
誰(shuí)來(lái)負(fù)責(zé)架構(gòu)的設(shè)計(jì)??
在我們的印象中,總認(rèn)為架構(gòu)設(shè)計(jì)是那些所謂架構(gòu)設(shè)計(jì)師的專(zhuān)屬工作,他們往往擁有豐富的設(shè)計(jì)經(jīng)驗(yàn)和相關(guān)的技能,他們不用編寫(xiě)代碼,就能夠設(shè)計(jì)出理論上盡善盡美的架構(gòu),配有精美的圖例。?
問(wèn)題1:理論上設(shè)計(jì)近乎完美的架構(gòu)缺乏程序的證明,在實(shí)際應(yīng)用中往往會(huì)出這樣那樣的問(wèn)題。?
問(wèn)題2:設(shè)計(jì)師設(shè)計(jì)架構(gòu)帶有很大的主觀(guān)性,往往會(huì)忽視客戶(hù)的需求,導(dǎo)致架構(gòu)無(wú)法滿(mǎn)足需求。?
問(wèn)題3:實(shí)現(xiàn)的程序員對(duì)這種架構(gòu)有抵觸的情緒,或是因?yàn)椴焕斫饧軜?gòu)而導(dǎo)致架構(gòu)實(shí)現(xiàn)的失敗。?
問(wèn)題4:架構(gòu)師設(shè)計(jì)架構(gòu)主要是依據(jù)自己的大量經(jīng)驗(yàn),設(shè)計(jì)出的架構(gòu)不能真實(shí)的反映目前的軟件需要。?
解決辦法?
團(tuán)隊(duì)設(shè)計(jì)的理論依據(jù)是群體決策。和個(gè)人決策相比,群體決策的最大好處就是其結(jié)論要更加的完整。而群體決策雖然有其優(yōu)點(diǎn),但其缺點(diǎn)也是很明顯的:需要額外付出溝通成本、決策效率低、責(zé)任不明確、等等。但是群體決策如果能夠組織得當(dāng)?shù)脑?huà),是能夠在架構(gòu)設(shè)計(jì)中發(fā)揮很大的優(yōu)勢(shì)的?
避免象牙塔式的架構(gòu)設(shè)計(jì)?
對(duì)軟件來(lái)說(shuō),架構(gòu)設(shè)計(jì)是一項(xiàng)至關(guān)重要的工作。這樣的工作交給某個(gè)人是非常危險(xiǎn)的。即便這個(gè)人再怎么聰明,他也可能會(huì)遺漏部分的細(xì)節(jié)。組織有效的團(tuán)隊(duì)的力量是大大超過(guò)個(gè)人的力量的,因此團(tuán)隊(duì)的成果較之個(gè)人的成果,在穩(wěn)定性和思考的周密程度上,都要更勝一籌。?
Scott W. Ambler在其著作中給出了象牙塔式架構(gòu)(ivory tower architecture)的概念:?
An ivory tower architecture is one that is often developed by an architect or architectural team in relative isolation to the day-to-day development activities of your project team(s).?
中國(guó)現(xiàn)在的軟件開(kāi)發(fā)行業(yè)中也逐漸出現(xiàn)了象牙塔式的架構(gòu)設(shè)計(jì)師。這些架構(gòu)師并不參與實(shí)際的程序編寫(xiě),他的工作就是為項(xiàng)目制作出精美的架構(gòu)模型,這種架構(gòu)模型在理論上是相當(dāng)完美的。?
例1:在XP中,我們基本上看不到架構(gòu)設(shè)計(jì)的影子。并不是說(shuō)采用XP技術(shù)的團(tuán)隊(duì)就不需要架構(gòu)設(shè)計(jì)。XP不存在專(zhuān)門(mén)的設(shè)計(jì)時(shí)期,它提倡使用一些簡(jiǎn)單的圖例、比喻的方式來(lái)表達(dá)軟件的架構(gòu),而這種的架構(gòu)設(shè)計(jì)是無(wú)時(shí)無(wú)刻不在進(jìn)行的。其實(shí),XP中的設(shè)計(jì)采用的就是團(tuán)隊(duì)設(shè)計(jì)的方式,結(jié)隊(duì)編程(Pair Programming)和代碼的集體所有制(Collective Ownership)是團(tuán)隊(duì)設(shè)計(jì)的基礎(chǔ),也就是基于口述的溝通方式。通過(guò)采用這樣的方式,XP幾乎不需要文檔來(lái)表達(dá)架構(gòu)的設(shè)計(jì)。?
優(yōu)秀的架構(gòu)師能夠充分的利用現(xiàn)有框架,減少軟件的投入,增強(qiáng)軟件的穩(wěn)定性。這些都沒(méi)有錯(cuò),但是問(wèn)題在于“過(guò)猶不及”。象牙塔式架構(gòu)師往往會(huì)出現(xiàn)文章開(kāi)始指出的那些問(wèn)題。架構(gòu)設(shè)計(jì)其實(shí)并不是非常復(fù)雜的工作,但它要求開(kāi)發(fā)人員具備相關(guān)的技能、經(jīng)驗(yàn)以及對(duì)問(wèn)題域有一定的了解。開(kāi)發(fā)人員往往都具有相關(guān)的技術(shù)技能(編程、數(shù)據(jù)庫(kù)設(shè)計(jì)、建模),而對(duì)問(wèn)題域的理解可以從用戶(hù)和行業(yè)專(zhuān)家那里獲得幫助。因此,在理論上,我們要實(shí)現(xiàn)架構(gòu)設(shè)計(jì)的團(tuán)隊(duì)化是完全可能的。?
在上面的象牙塔式架構(gòu)定義中,我們看到架構(gòu)師和日常的開(kāi)發(fā)工作是隔絕的。這樣設(shè)計(jì)出的架構(gòu)有很大的局限性。在現(xiàn)實(shí)中,我們還會(huì)發(fā)現(xiàn)另外一種角色,他來(lái)自于開(kāi)發(fā)團(tuán)隊(duì)外部,為開(kāi)發(fā)人員提供相關(guān)的技術(shù)或業(yè)務(wù)的培訓(xùn)。這種角色稱(chēng)為教練,在軟件開(kāi)發(fā)中是非常重要的角色,不能夠和象牙塔式架構(gòu)設(shè)計(jì)師之間畫(huà)等號(hào)。?
選擇你的設(shè)計(jì)團(tuán)隊(duì)?
軟件的架構(gòu)在軟件的生命周期的全過(guò)程中都很重要,也就是說(shuō),軟件開(kāi)發(fā)團(tuán)隊(duì)中的所有人員都需要和架構(gòu)打交道。因此,最好的團(tuán)隊(duì)組織方式是所有開(kāi)發(fā)人員都參與架構(gòu)的設(shè)計(jì),我們稱(chēng)這種方式為全員參與。全員參與的方式保證了所有開(kāi)發(fā)人員都能夠?qū)軜?gòu)設(shè)計(jì)提出自己的見(jiàn)解,綜合多方面的意見(jiàn),在全體開(kāi)發(fā)人員中達(dá)成一致。這種方式尤其適合于一些小的團(tuán)隊(duì)。?
還是會(huì)有很多的團(tuán)隊(duì)由于種種的原因不適合采用全員參與的方式。那么,組織優(yōu)秀的開(kāi)發(fā)人員組成設(shè)計(jì)組也是比較好的方式。一般,我們選擇那些在項(xiàng)目中比較重要的,有較多開(kāi)發(fā)經(jīng)驗(yàn),或是理論扎實(shí)的那些人來(lái)組成設(shè)計(jì)組。當(dāng)然,如果你考慮到為組織培養(yǎng)后續(xù)力量,你也可以讓一些新手加入設(shè)計(jì)組,或是你覺(jué)得自己的開(kāi)發(fā)力量不足,邀請(qǐng)外部的咨詢(xún)力量介入,這完全取決于具體的情況。?
設(shè)計(jì)組不同于我們之前提到的象牙塔式架構(gòu)設(shè)計(jì)師。設(shè)計(jì)組設(shè)計(jì)出來(lái)的架構(gòu)只能稱(chēng)為原始架構(gòu),它是需要不斷的反饋和改進(jìn)的。因此,在架構(gòu)實(shí)現(xiàn)中,設(shè)計(jì)組的成員將會(huì)分布到開(kāi)發(fā)團(tuán)隊(duì)的各個(gè)領(lǐng)域,把架構(gòu)的思想帶給所有開(kāi)發(fā)人員,編寫(xiě)代碼來(lái)檢驗(yàn)架構(gòu),并獲得具體的反饋,然后所有的成員再集中到設(shè)計(jì)組中討論架構(gòu)的演進(jìn)。?
團(tuán)隊(duì)設(shè)計(jì)中存在的問(wèn)題?
在團(tuán)隊(duì)設(shè)計(jì)的過(guò)程,我們會(huì)遇到各種各樣的問(wèn)題,首當(dāng)其沖的就是溝通成本的問(wèn)題。架構(gòu)設(shè)計(jì)時(shí),需求尚未被充分理解,軟件的設(shè)計(jì)思路還處于萌發(fā)的狀態(tài)。這樣的情況下,團(tuán)隊(duì)的每位成員對(duì)軟件都有獨(dú)特的見(jiàn)解,這些可能有些是相同的,有些是互斥的。就好比盲人摸象一樣,他們的觀(guān)點(diǎn)都代表了軟件的一部分或是一方面,但是沒(méi)有辦法代表軟件的全部。?
在敏捷方法論中,我們的每一個(gè)流程都是迅速進(jìn)行、不斷改進(jìn)的。架構(gòu)設(shè)計(jì)也是一樣,我們不可能在一次架構(gòu)設(shè)計(jì)上花費(fèi)更多的時(shí)間。而團(tuán)隊(duì)決策總是傾向于較長(zhǎng)的討論和權(quán)衡。?
例2中的問(wèn)題在架構(gòu)設(shè)計(jì)中時(shí)有發(fā)生,純技術(shù)的討論很容易上升稱(chēng)為爭(zhēng)吵。這種情況幾乎沒(méi)有辦法完全避免。團(tuán)隊(duì)型的決策必然會(huì)發(fā)生觀(guān)念的沖突。控制一定程度內(nèi)的觀(guān)念的沖突對(duì)團(tuán)隊(duì)的決策是有益,但是如果超出了這個(gè)程度就意味著失控了,需要團(tuán)隊(duì)領(lǐng)導(dǎo)者的調(diào)節(jié)。而更重要的,我們需要注意溝通的技巧?
團(tuán)隊(duì)溝通?
團(tuán)隊(duì)進(jìn)行架構(gòu)設(shè)計(jì)的時(shí)候溝通是一個(gè)非常需要注意的問(wèn)題,上述的情境在軟件組織中是經(jīng)常發(fā)生的,因?yàn)榧夹g(shù)人員很自然認(rèn)為自己的技術(shù)比別人的好,如果自己的技術(shù)受到質(zhì)疑,那怕對(duì)方是抱著討論的態(tài)度,也無(wú)異于自身的權(quán)威受到了挑戰(zhàn),面子是無(wú)論如何都需要捍衛(wèi)的。而溝通如果帶上了這樣一層主觀(guān)色彩,那么溝通信息的受眾就會(huì)潛意識(shí)的拒絕接受信息。相反,他會(huì)找出對(duì)方話(huà)語(yǔ)中的漏洞,準(zhǔn)備進(jìn)行反擊。因此,我們要注意培養(yǎng)一種良好的溝通氛圍。?
在實(shí)際的觀(guān)察中,我發(fā)現(xiàn)團(tuán)隊(duì)溝通中存在兩種角色,一種是建議者,他們經(jīng)常能夠提���建議。一種是質(zhì)疑者,他們對(duì)建議提出否定性的看法。這兩種角色是可能互換的,現(xiàn)在的建議者可能就是剛才的質(zhì)疑者。質(zhì)疑者的發(fā)言是很能打擊建議者的積極性的,而在一個(gè)腦力激蕩的會(huì)議中,最好是大家都能夠扮演建議者的角色,這就要求溝通會(huì)議的主持者能夠掌握好這一點(diǎn),對(duì)建議給予肯定的評(píng)價(jià),并鼓勵(lì)大家提出新的建議。?
例2:敏捷方法非常注重的就是團(tuán)隊(duì)的溝通。溝通是一個(gè)很有意思的話(huà)題,講起來(lái)會(huì)花費(fèi)大量的時(shí)間,我們這里只是針對(duì)架構(gòu)設(shè)計(jì)中可能存在的溝通問(wèn)題做一個(gè)簡(jiǎn)單的討論。我們這里假設(shè)一個(gè)討論情境,這個(gè)情境來(lái)源于真實(shí)的生活:項(xiàng)目主管徐輝、設(shè)計(jì)師李浩、設(shè)計(jì)師羅亦明正在討論一個(gè)新的軟件架構(gòu)。 “李浩你認(rèn)為這個(gè)軟件數(shù)據(jù)庫(kù)連接部分應(yīng)該如何考慮?”徐輝問(wèn)。李浩想了想,”我覺(jué)得方案A不錯(cuò)…” “方案A肯定有問(wèn)題!這個(gè)軟件和上一次的又不同。”羅亦明打斷了李浩的發(fā)言。 “你懂什么!你到公司才多久,方案A是經(jīng)過(guò)很長(zhǎng)時(shí)間的證明的!”發(fā)言被打斷,李浩有點(diǎn)惱火,羅亦明進(jìn)入公司沒(méi)有多久,但在一些事情上老是和他唱反調(diào)。 “我進(jìn)公司多久和方案A的錯(cuò)誤有什么關(guān)系!” 在這樣一種氛圍中,會(huì)議的結(jié)果可想而知。良好的溝通有助于架構(gòu)設(shè)計(jì)工作的開(kāi)展。一個(gè)成員的能力平平的團(tuán)隊(duì),可以藉由良好的溝通,設(shè)計(jì)出優(yōu)秀的架構(gòu),而一個(gè)擁有一個(gè)優(yōu)秀成員的團(tuán)隊(duì),如果缺乏溝通,最后可能連設(shè)計(jì)都出不來(lái)。這種例子現(xiàn)實(shí)中可以找到很多。?
標(biāo)準(zhǔn)和風(fēng)格?
我們總是在不知不覺(jué)之中使用各種各樣的標(biāo)準(zhǔn)和風(fēng)格。在團(tuán)隊(duì)設(shè)計(jì)中,我們?yōu)榱颂岣邲Q策的效率,可以考慮使用統(tǒng)一的標(biāo)準(zhǔn)和風(fēng)格。統(tǒng)一的標(biāo)準(zhǔn)和風(fēng)格并不是一朝一夕形成的。因?yàn)槊總€(gè)人都有自己不同的習(xí)慣和經(jīng)歷,強(qiáng)制性的要求開(kāi)發(fā)人員使用統(tǒng)一的標(biāo)準(zhǔn)(風(fēng)格)容易引起開(kāi)發(fā)人員的不滿(mǎn)。因此在操作上需要注意技巧。對(duì)架構(gòu)設(shè)計(jì)而言,比較重要的標(biāo)準(zhǔn)(風(fēng)格)包括界面設(shè)計(jì)、流程設(shè)計(jì)、建模規(guī)范、編碼規(guī)范、持久層設(shè)計(jì)、測(cè)試數(shù)據(jù)。?
在我的經(jīng)驗(yàn)中,有一些組織平時(shí)并不注意標(biāo)準(zhǔn)(風(fēng)格)的積累,認(rèn)為這種積累屬于雕蟲(chóng)小技,但正是這些小技,能夠非常有效的提高溝通的效率和降低開(kāi)發(fā)人員的學(xué)習(xí)曲線(xiàn)。試想一下,如果一個(gè)團(tuán)隊(duì)中所有人寫(xiě)出的代碼都是不同標(biāo)準(zhǔn)和風(fēng)格的,那么理解起來(lái)肯定會(huì)困難許多。當(dāng)然,我們沒(méi)有必要自己開(kāi)發(fā)一套標(biāo)準(zhǔn)(風(fēng)格)出來(lái),現(xiàn)實(shí)中有很多可以直接借用的資料。最好的標(biāo)準(zhǔn)是UML語(yǔ)言,我們可以從UML的官方網(wǎng)站下載到最新的規(guī)范,常用的編碼標(biāo)準(zhǔn)更是隨處可見(jiàn)。不過(guò)雖然有了統(tǒng)一的標(biāo)準(zhǔn),如果風(fēng)格不統(tǒng)一,同樣會(huì)造成溝通的障礙。例如下圖顯示的類(lèi)圖,雖然它們表示的是同一個(gè)類(lèi),但是由于版型、可視性、詳細(xì)程度的差別,看起來(lái)又很大的差別。而在其它的標(biāo)準(zhǔn)中,這種差別也是普遍存在的。因此,我們?cè)谑褂昧私y(tǒng)一的標(biāo)準(zhǔn)之后,還應(yīng)該使用同樣的風(fēng)格。Scott W. Ambler專(zhuān)門(mén)成立了一個(gè)網(wǎng)站討論UML的建模風(fēng)格的相關(guān)問(wèn)題,有興趣的讀者可以做額外的閱讀。
圖 4. 兩種風(fēng)格的類(lèi)圖?
在統(tǒng)一的風(fēng)格的基礎(chǔ)上更進(jìn)一步的是使用術(shù)語(yǔ)。使用溝通雙方都了解專(zhuān)門(mén)的術(shù)語(yǔ),可以代表大量的信息。最好的術(shù)語(yǔ)的范例就是設(shè)計(jì)模式的模式名。如果溝通的雙方都了解設(shè)計(jì)模式,那么一方只需要說(shuō)這部分的設(shè)計(jì)可以使用工廠(chǎng)模式,另一方就能夠理解,而不用再詳細(xì)的解釋設(shè)計(jì)的思路。這種的溝通方式是最高效的,但它所需要的學(xué)習(xí)曲線(xiàn)也會(huì)比較陡。?
團(tuán)隊(duì)設(shè)計(jì)的四明確?
為了最大程度的提高團(tuán)隊(duì)設(shè)計(jì)的高效性,可以從4個(gè)方面來(lái)考慮:?
1、明確目標(biāo)?
泛泛的召開(kāi)架構(gòu)討論會(huì)議是沒(méi)有什么意義的,一個(gè)沒(méi)有鮮明主題的會(huì)議也不會(huì)有什么結(jié)果。在源自需求的模式中,我們談到說(shuō)可以有非功能需求的架構(gòu),可以有功能需求的架構(gòu)。因此,在進(jìn)行團(tuán)隊(duì)設(shè)計(jì)之前,我們首先也需要確定,此次要解決什么問(wèn)題,是討論業(yè)務(wù)邏輯的架構(gòu),還是技術(shù)架構(gòu);是全局性的架構(gòu),還是各模塊的架構(gòu)。?
2、明確分工?
我們之所以重視團(tuán)隊(duì),很重要的額一個(gè)原因就是不同的成員有不同的擅長(zhǎng)的區(qū)域。有些成員可能擅長(zhǎng)于業(yè)務(wù)邏輯的建模,有的擅長(zhǎng)于原型設(shè)計(jì),有的擅長(zhǎng)于數(shù)據(jù)庫(kù)設(shè)計(jì),有的則擅長(zhǎng)于Web編程。你能夠想象一個(gè)軟件沒(méi)有界面嗎?(有些軟件可能是這種情況)你能夠想象一個(gè)軟件只有數(shù)據(jù)庫(kù),而沒(méi)有處理邏輯嗎?因此,架構(gòu)設(shè)計(jì)就需要綜合的考慮各個(gè)方面,充分利用成員的優(yōu)勢(shì)。這就要求團(tuán)隊(duì)的各個(gè)成員都能夠明確自己的分工。?
3、明確責(zé)權(quán)?
除了明確自己的分工,每位成員都需要清楚自己的責(zé)任。沒(méi)有責(zé)任,分工就不會(huì)有任何的效力。每位成員都需要明確自己要做些什么。當(dāng)然,和責(zé)任相對(duì)的,沒(méi)有成員還需要知道自己的權(quán)力是什么。這些清楚了,進(jìn)行高效的溝通的前提就具備了。每次架構(gòu)的討論下來(lái),每個(gè)人都清楚,自己要做些什么,自己需要要求其他人做些什么,自己該對(duì)誰(shuí)負(fù)責(zé)。如果這些問(wèn)題回答不了,那這次的討論就白費(fèi)了。?
4、明確溝通方式?
這里使用溝通方式可能有一點(diǎn)點(diǎn)不恰當(dāng),為了明確的表達(dá)意思,大家可以考慮信息流這個(gè)詞。一個(gè)完整架構(gòu)包括幾個(gè)方面,分別都由那些人負(fù)責(zé),如何產(chǎn)生,產(chǎn)生的整個(gè)過(guò)程應(yīng)該是什么樣的?這樣的一個(gè)信息流程,囊括了上面提到的三個(gè)明確。如果團(tuán)隊(duì)的每一個(gè)人都能夠?yàn)榧軜?gòu)的產(chǎn)生而努力,并順利的設(shè)計(jì)出架構(gòu),那么這樣的流程是完美的。如果你發(fā)現(xiàn)其中的一些人不知道做些什么,那么,這就是流程出問(wèn)題的現(xiàn)象了。完美的流程還會(huì)有一個(gè)額外的副產(chǎn)品,架構(gòu)產(chǎn)生之后,團(tuán)隊(duì)對(duì)于軟件的設(shè)計(jì)已經(jīng)是非常的清晰了。因?yàn)槲覀兲岢氖潜M可能多的開(kāi)發(fā)人員參與架構(gòu)的設(shè)計(jì)。?
不僅僅是架構(gòu) 討論到這里,其實(shí)有很多的內(nèi)容已經(jīng)脫離了架構(gòu)設(shè)計(jì)了。也就是說(shuō),很多的原則和技巧都是可以用于軟件開(kāi)發(fā)的其它活動(dòng)的。至于哪一些活動(dòng)能夠利用這些方法呢?大家可以結(jié)合自己的實(shí)際情況,來(lái)思考這個(gè)問(wèn)題。提示一點(diǎn),關(guān)鍵的入手處在于目前效率較低之處。?
架構(gòu)設(shè)計(jì)中的方法學(xué)(5)——簡(jiǎn)單設(shè)計(jì)
XP非常強(qiáng)調(diào)簡(jiǎn)單的設(shè)計(jì)原則:能夠用數(shù)組實(shí)現(xiàn)的功能決不用鏈表。在其它Agile方法中,簡(jiǎn)單的原則也被反復(fù)的強(qiáng)調(diào)。在這篇文章,我們就對(duì)簡(jiǎn)單性做一個(gè)全面的了解。?
架構(gòu)應(yīng)該設(shè)計(jì)到 什么程度?
- 1
在軟件開(kāi)發(fā)領(lǐng)域,最為常見(jiàn)的設(shè)計(jì)就是”Code and Fix”方式的設(shè)計(jì),設(shè)計(jì)隨著軟件開(kāi)���過(guò)程而增長(zhǎng)。或者,我們可以認(rèn)為這種方式根本就不能算是設(shè)計(jì),它抱著一種船到橋頭自然直的態(tài)度,可是在設(shè)計(jì)不斷改動(dòng)之后,代碼變得臃腫且難以理解,到處充滿(mǎn)著重復(fù)的代碼。這樣的情形下,架構(gòu)的設(shè)計(jì)也就無(wú)從談起,軟件就像是在風(fēng)雨中的破屋,瀕臨倒塌。
針對(duì)于這種情形,新的設(shè)計(jì)方式又出現(xiàn)了,Martin Fowler稱(chēng)這種方式為”P(pán)lanned Design”。和建筑的設(shè)計(jì)類(lèi)似,它強(qiáng)調(diào)在編碼之前進(jìn)行嚴(yán)格的設(shè)計(jì)。這也就是我們?cè)趫F(tuán)隊(duì)設(shè)計(jì)中談到的架構(gòu)設(shè)計(jì)師的典型做法。設(shè)計(jì)師們通常不會(huì)去編程,理由是在土木工程中,你不可能看到一位設(shè)計(jì)師還要砌磚頭。
“Planned Design”較之”Code and Fix”進(jìn)步了許多,但是還是會(huì)存在很多問(wèn)題。除了在團(tuán)隊(duì)設(shè)計(jì)中我們談的問(wèn)題之外,需求變更將會(huì)導(dǎo)致更大的麻煩。因此,我們理所當(dāng)然的想到進(jìn)行”彈性設(shè)計(jì)”:彈性的設(shè)計(jì)能夠滿(mǎn)足需求的變更。而彈性的設(shè)計(jì)所付出的代價(jià)就是復(fù)雜的設(shè)計(jì)。
題外話(huà):
這里我們談?wù)摗盤(pán)lanned Design”引出的一些問(wèn)題,并沒(méi)有任何排斥這種方式的意思。”P(pán)lanned Design”還是有很多可取之處的,但也有很多需要改進(jìn)的地方。事實(shí)上,本文中我們討論的架構(gòu)設(shè)計(jì)方式,本質(zhì)上也是屬于”P(pán)lanned Design”方式。和”P(pán)lanned Design”相對(duì)應(yīng)的方式是XP所主張的”Evolutionary Design”方式,但是這種方式還有待于實(shí)踐的檢驗(yàn),并不能簡(jiǎn)單的說(shuō)他就一定要比”P(pán)lanned Design”先進(jìn)或落后。但可以肯定的一點(diǎn)是:”Evolutionary Design”方式中有很多的思想和技巧是值得”P(pán)lanned Design”借鑒的。
解決方法:
XP中有兩個(gè)非常響亮的口號(hào):”Do The Simplest Thing that Could Possibly Work”和”You Aren’t Going to Need It”(通常稱(chēng)之為YAGNI)。他們的核心思想就是不要為了考慮將來(lái),把目前并不需要的功能加到軟件中來(lái)。
粗看之下,會(huì)有很多開(kāi)發(fā)人員認(rèn)為這是不切實(shí)際的口號(hào)。我能理解這種想法,其實(shí),在我熱衷于模式、可重用組件技術(shù)的時(shí)候,我對(duì)XP提倡的簡(jiǎn)單的口號(hào)嗤之以鼻。但在實(shí)際中,我的一些軟件因?yàn)閺?fù)雜設(shè)計(jì)導(dǎo)致開(kāi)發(fā)成本上升的時(shí)候,我重新思考這個(gè)問(wèn)題,發(fā)現(xiàn)簡(jiǎn)單的設(shè)計(jì)是有道理的。
降低開(kāi)發(fā)的成本
不論是模式,可重用組件,或是框架技術(shù),目的都是為了降低開(kāi)發(fā)的成本。但是他們的方式是先進(jìn)行大量的投入,然后再節(jié)省后續(xù)的開(kāi)發(fā)成本。因此,架構(gòu)設(shè)計(jì)方面的很多思路都是圍繞著這種想法展開(kāi)的,這可能也是導(dǎo)致開(kāi)發(fā)人員普遍認(rèn)為架構(gòu)設(shè)計(jì)高不可攀的原因。XP的方式恰恰相反,在處理第一個(gè)問(wèn)題的時(shí)候,不必要也不可能就設(shè)計(jì)出具有彈性、近乎完美的架構(gòu)來(lái)。這項(xiàng)工作應(yīng)該是隨著開(kāi)發(fā)的演進(jìn),慢慢成熟起來(lái)的。我不敢說(shuō)這種方式肯定正確,但是如果我們把生物的結(jié)構(gòu)視同為架構(gòu),這種方式不是很類(lèi)似于自然界中生物的進(jìn)化方式嗎?
在一開(kāi)始就制作出完美的架構(gòu)的設(shè)想并沒(méi)有錯(cuò),關(guān)鍵是很難做到這一點(diǎn)。總是會(huì)有很多的問(wèn)題是你在做設(shè)計(jì)時(shí)沒(méi)有考慮到的。這樣,當(dāng)一開(kāi)始花費(fèi)大量精力設(shè)計(jì)出的”完美無(wú)缺”的架構(gòu)必然會(huì)遇到意想不到的問(wèn)題,這時(shí)候,復(fù)雜的架構(gòu)反而會(huì)影響到設(shè)計(jì)的改進(jìn),導(dǎo)致開(kāi)發(fā)成本的上升。這就好比如果方向錯(cuò)了,交通工具再快,反而導(dǎo)致錯(cuò)誤的快速擴(kuò)大。Martin Fowler在他的論文中說(shuō),”Working on the wrong solution early is even more wasteful than working on the right solution early”(提前做一件錯(cuò)事要比提前做一件對(duì)的事更浪費(fèi)時(shí)間),相信也是這個(gè)道理。
更有意思的是,通常我們更有可能做錯(cuò)。在我們進(jìn)行架構(gòu)設(shè)計(jì)的時(shí)候,我們不可能完全取得詳細(xì)的需求。事實(shí)上,就算你已經(jīng)取得了完整的需求,也有可能發(fā)生變化。這種情況下做出的架構(gòu)設(shè)計(jì)是不可能不出錯(cuò)的。這樣,浪費(fèi)大量的時(shí)間在初始階段設(shè)計(jì)不可能達(dá)到的”完美架構(gòu)”,倒不如把時(shí)間花在后續(xù)的改進(jìn)上。
提升溝通的效率
我們?cè)趫F(tuán)隊(duì)設(shè)計(jì)中已經(jīng)談過(guò)了團(tuán)隊(duì)設(shè)計(jì)的目標(biāo)之一就是為了降低溝通的成本,以期讓所有人都能夠理解架構(gòu)。但是如果架構(gòu)如果過(guò)于復(fù)雜,將會(huì)重新導(dǎo)致溝通成本的上升,而且,這個(gè)成本并不會(huì)隨著項(xiàng)目進(jìn)行而降低,反而會(huì)因?yàn)樯厦嫖覀兲岬降挠龅叫碌膯?wèn)題導(dǎo)致溝通成本的持續(xù)上升。
簡(jiǎn)單的架構(gòu)設(shè)計(jì)可以加快開(kāi)發(fā)團(tuán)隊(duì)理解架構(gòu)的速度。我們可以通過(guò)兩種方式來(lái)理解簡(jiǎn)單的含義。首先,簡(jiǎn)單意味著問(wèn)題的解不會(huì)非常的復(fù)雜,架構(gòu)是解決需求的關(guān)鍵,無(wú)論需求再怎么復(fù)雜多變,總是可以找出簡(jiǎn)單穩(wěn)定的部分,我們可以把這個(gè)簡(jiǎn)單穩(wěn)定的部分做為基礎(chǔ),再根據(jù)需要進(jìn)行改進(jìn)擴(kuò)展,以解決復(fù)雜的問(wèn)題。在示例中,我們提到了measurement pattern,它就是按照這種想法來(lái)進(jìn)行設(shè)計(jì)的。
其次,簡(jiǎn)單性還體現(xiàn)在表示的簡(jiǎn)單上。一份5頁(yè)的文檔就能夠表達(dá)清楚的架構(gòu)設(shè)計(jì)為什么要花費(fèi)50頁(yè)呢?同樣的道理,能夠用一副簡(jiǎn)單的圖形就能夠表示的架構(gòu)設(shè)計(jì)也沒(méi)有必要使用文檔。畢竟,面對(duì)面的溝通才是最有效率的溝通,文檔不論如何的復(fù)雜,都不能被完全理解,而且,復(fù)雜的文檔,維護(hù)起來(lái)也需要花費(fèi)大量的時(shí)間。只有在兩種情況下,我們提倡使用復(fù)雜的文檔:一是開(kāi)發(fā)團(tuán)隊(duì)沒(méi)有辦法做到面對(duì)面溝通;二是開(kāi)發(fā)成果要作為團(tuán)隊(duì)的知識(shí)積累起來(lái),為下一次開(kāi)發(fā)所用。
考慮未來(lái)
我們之所以考慮未來(lái),主要的原因就是需求的不穩(wěn)定。因此,我們?nèi)绻紤]未來(lái)可能發(fā)生的需求變化,就會(huì)不知覺(jué)的在架構(gòu)設(shè)計(jì)中增加復(fù)雜的成分。這違背的簡(jiǎn)單的精神。但是,如果你
不考慮可能出現(xiàn)的情況,那些和目前設(shè)計(jì)格格不入的改變,將會(huì)導(dǎo)致大量的返工。?
還記得YAGNI嗎?原則上,我們?nèi)匀粓?jiān)持不要在現(xiàn)有的系統(tǒng)中為將來(lái)可能的情況進(jìn)行設(shè)計(jì)。但是,我們必須思考,必須要為將來(lái)可能出現(xiàn)的情況做一些準(zhǔn)備。其實(shí),軟件中了不起的接口的思想,不就是源于此嗎?因此,思考未來(lái),但等到需要時(shí)再實(shí)現(xiàn)。?
變更案例有助于我們思考未來(lái),變更案例就是你在將來(lái)可能要(或可能不要)滿(mǎn)足的,但現(xiàn)在不需要滿(mǎn)足的需求。當(dāng)我們?cè)谧黾軜?gòu)設(shè)計(jì)的時(shí)候,變更案例也將會(huì)成為設(shè)計(jì)的考慮因素之一,但它不可能成為進(jìn)行決策的唯一考慮因素。很多的時(shí)候,我們沉迷于設(shè)計(jì)通用系統(tǒng)給我們帶來(lái)的挑戰(zhàn)之中,其實(shí),我們所做的工作對(duì)用戶(hù)而言是毫無(wú)意義的。?
架構(gòu)的穩(wěn)定?
架構(gòu)簡(jiǎn)單化和架構(gòu)的穩(wěn)定性有什么關(guān)系嗎?我們說(shuō),架構(gòu)越簡(jiǎn)單,其穩(wěn)定性就越好。理由很簡(jiǎn)單,1個(gè)擁有4個(gè)方法和3個(gè)屬性的類(lèi),和1個(gè)擁有20個(gè)方法和30屬性的類(lèi)相比,哪一個(gè)更穩(wěn)定?當(dāng)然是前者。而架構(gòu)最終都是要映射到代碼級(jí)別上的,因此架構(gòu)的簡(jiǎn)單將會(huì)帶來(lái)架構(gòu)的穩(wěn)定。盡可能的讓你的類(lèi)小一些,盡可能的讓你的方法短一些,盡可能的讓類(lèi)之間的關(guān)系少一些。這并不是我的忠告,很多的設(shè)計(jì)類(lèi)的文章都是這么說(shuō)的。在這個(gè)話(huà)題上,我們可以進(jìn)一步的閱讀同類(lèi)的文章(關(guān)于 refactoring 的思考)。?
辨正的簡(jiǎn)單?
因此,對(duì)我們來(lái)說(shuō),簡(jiǎn)單的意義就是不要把未來(lái)的、或不需要實(shí)現(xiàn)的功能加入到目前的軟件中,相應(yīng)的架構(gòu)設(shè)計(jì)也不需要考慮這些額外的需求,只要?jiǎng)偤媚軌驖M(mǎn)足當(dāng)前的需求就好了。這就是簡(jiǎn)單的定義。可是在現(xiàn)實(shí)之中,總是有這樣或者那樣的原因,使得設(shè)計(jì)趨向復(fù)雜。一般來(lái)說(shuō),如果一個(gè)設(shè)計(jì)對(duì)團(tuán)隊(duì)而言是有價(jià)值的,那么,付出一定的成本來(lái)研究、驗(yàn)證、發(fā)展、文檔化這個(gè)設(shè)計(jì)是有意義的。反之,如果一個(gè)設(shè)計(jì)沒(méi)有很大的價(jià)值或是發(fā)展它的成本超過(guò)了其能夠提供的價(jià)值,那就不需要去考慮這個(gè)設(shè)計(jì)。?
價(jià)值對(duì)不同的團(tuán)隊(duì)來(lái)說(shuō)具有不同的含義。有時(shí)候可能是時(shí)間,有時(shí)候可能是用戶(hù)價(jià)值,有時(shí)候可能是為了團(tuán)隊(duì)的設(shè)計(jì)積累和代碼重用,有時(shí)候是為了獲得經(jīng)驗(yàn),有時(shí)候是為了研究出可重用的框架(FrameWork)。這些也可以稱(chēng)為目的,因此,你在設(shè)計(jì)架構(gòu)時(shí),請(qǐng)注意先確定好你的目的,對(duì)實(shí)現(xiàn)目的有幫助的事情才考慮。?
Scott W.Ambler在他的文章中提到一個(gè)他親身經(jīng)歷的故事,在軟件開(kāi)發(fā)的架構(gòu)設(shè)計(jì)過(guò)程中,花了很多的時(shí)間來(lái)設(shè)計(jì)數(shù)據(jù)庫(kù)到業(yè)務(wù)邏輯的映射架構(gòu),雖然這是一件任何開(kāi)發(fā)人員都樂(lè)意專(zhuān)研的事情(因?yàn)樗芸?#xff09;。但他不得不承認(rèn),對(duì)用戶(hù)來(lái)說(shuō),這種設(shè)計(jì)先進(jìn)的架構(gòu)是沒(méi)有太大的意義的,因?yàn)橛脩?hù)并不關(guān)心具體的技術(shù)。當(dāng)看到這個(gè)故事的時(shí)候,我的觸動(dòng)很大。一個(gè)開(kāi)發(fā)人員總是熱衷于新奇的技術(shù),但是如果這個(gè)新奇技術(shù)的成本由用戶(hù)來(lái)承擔(dān),是不是合理呢?雖然新技術(shù)的采用能夠?yàn)橛脩?hù)帶來(lái)效益,但是沒(méi)有人計(jì)算過(guò)效益背后的成本。就我開(kāi)發(fā)過(guò)的項(xiàng)目而言,這個(gè)成本往往是大于效益的。這個(gè)問(wèn)題可能并沒(méi)有確定的答案,只能是見(jiàn)仁見(jiàn)智了。?
簡(jiǎn)單并不等于實(shí)現(xiàn)簡(jiǎn)單?
說(shuō)到這里,如果大家有一個(gè)誤解,認(rèn)為一個(gè)簡(jiǎn)單的架構(gòu)也一定是容易設(shè)計(jì)的,那就錯(cuò)了。簡(jiǎn)單的架構(gòu)并不等于實(shí)現(xiàn)起來(lái)也簡(jiǎn)單。簡(jiǎn)單的架構(gòu)需要設(shè)計(jì)者花費(fèi)大量的心血,也要求設(shè)計(jì)者對(duì)技術(shù)有很深的造詣。在我們正在進(jìn)行的一個(gè)項(xiàng)目中,一開(kāi)始設(shè)計(jì)的基礎(chǔ)架構(gòu)在實(shí)現(xiàn)中被修改了幾次,但每修改一次,代碼量都減少一分,代碼的可讀性也就增強(qiáng)一分。從心理的角度上來(lái)說(shuō),對(duì)自己的架構(gòu)進(jìn)行不斷的修改,確實(shí)是需要一定的勇氣的。因?yàn)椴徽撌窃O(shè)計(jì)還是代碼,都是開(kāi)發(fā)人員的心血。但跨出這一步是值得的。?
下面的例子討論了Java的IO設(shè)計(jì),Java類(lèi)庫(kù)的設(shè)計(jì)應(yīng)該來(lái)說(shuō)是非常優(yōu)秀的,但是仍然避免不了重新的修改。實(shí)際上,在軟件開(kāi)發(fā)領(lǐng)域,由于原先的設(shè)計(jì)失誤而導(dǎo)致后來(lái)設(shè)計(jì)過(guò)于復(fù)雜的情況比比皆是(例如微軟的OLE)。同樣的,我們?cè)谠O(shè)計(jì)軟件的時(shí)候,也需要對(duì)設(shè)計(jì)進(jìn)行不斷的修改。能夠?qū)崿F(xiàn)復(fù)雜功能,同時(shí)自身又簡(jiǎn)單的設(shè)計(jì)并不是一件容易的事情。?
例1. Java的IO系統(tǒng)?
從Java的IO系統(tǒng)設(shè)計(jì)中,我們可以感受到簡(jiǎn)單設(shè)計(jì)的困難。?
例2. IO系統(tǒng)設(shè)計(jì)的困難性向來(lái)是公認(rèn)的。Java的IO設(shè)計(jì)的一個(gè)目的就是使IO的使用簡(jiǎn)單化。在Java的1.0中,Java的IO系統(tǒng)主要是把IO系統(tǒng)分為輸入輸出兩個(gè)大部分,并分別定義了抽象類(lèi)InputStream和OutputStream。從這兩個(gè)的抽象類(lèi)出發(fā),實(shí)現(xiàn)了一系列不同功能的輸入輸出類(lèi),同時(shí),Java的IO系統(tǒng)還在輸入輸出中實(shí)現(xiàn)了FilterInputStream和FilterOutputStream的抽象類(lèi)以及相關(guān)的一系列實(shí)現(xiàn),從而把不同的功能的輸入輸出函數(shù)連接在一起,實(shí)現(xiàn)復(fù)雜的功能。這個(gè)實(shí)現(xiàn)其實(shí)是Decorator模式(由于沒(méi)有看過(guò)源碼和相關(guān)的資料,這里僅僅是根據(jù)功能和使用技巧推測(cè),如果大家有不同的意見(jiàn),歡迎來(lái)信討論)。?
因此,我們可以把多個(gè)對(duì)象疊加在一起,提供復(fù)雜的功能:?
DataInpuStream in =?
new DataInputStream(?
new BufferedInputStream(?
new FileInputStream(“test.txt”);
上面的代碼使用了兩個(gè)FilterInputStream:DataInpuStream和BufferedInputStream,以實(shí)現(xiàn)讀數(shù)據(jù)和緩沖的功能,同時(shí)使用了一個(gè)InputStream:FileInputStream,從文件中讀取流數(shù)據(jù)。雖然使用起來(lái)不是很方便,但是應(yīng)該還是非常清晰的設(shè)計(jì)。?
令設(shè)計(jì)混亂的是既不屬于InputStream,也不屬于OutputStream的類(lèi),例如RandomAccessFile,這正表明,由于功能的復(fù)雜化,使得原先基于輸入輸出分類(lèi)的設(shè)計(jì)變得混亂,根據(jù)我們的經(jīng)驗(yàn),我們說(shuō)設(shè)計(jì)需要Refactoring了。因此,在Java1.1中,IO系統(tǒng)被重新設(shè)計(jì),采用了Reader和Writer位基礎(chǔ)的設(shè)計(jì),并增加了新的特性。但是目前的設(shè)計(jì)似乎更加混亂了,因?yàn)槲覀冃枰瑫r(shí)使用1.0和1.1兩種不同的IO設(shè)計(jì)?
架構(gòu)設(shè)計(jì)中的方法學(xué)(6)——迭代設(shè)計(jì)?
迭代是一種軟件開(kāi)發(fā)的生命周期模型,在設(shè)計(jì)中應(yīng)用迭代設(shè)計(jì),我們可以得到很多的好處。
在軟件生命周期中,我們?nèi)绾螌?duì)待架構(gòu)設(shè)計(jì)的發(fā)展?
架構(gòu)設(shè)計(jì)往往發(fā)生在細(xì)節(jié)需求尚未完成的時(shí)候進(jìn)行的。因此,隨著項(xiàng)目的進(jìn)行,需求還可能細(xì)化,可能變更。原先的架構(gòu)肯定會(huì)有不足或錯(cuò)誤的地方。那么,我們應(yīng)該如何對(duì)待原先的設(shè)計(jì)呢?
我們?cè)诤?jiǎn)單設(shè)計(jì)模式中簡(jiǎn)單提到了”P(pán)lanned Design”和”Evolutionary Design”的區(qū)別。XP社團(tuán)的人們推崇使用”Evolutionary Design”的方式,在外人看來(lái),似乎擁護(hù)者們從來(lái)不需要架構(gòu)的設(shè)計(jì),他們采用的方式是一開(kāi)始就進(jìn)入代碼的編寫(xiě),然后用Refactoring來(lái)改進(jìn)代碼的質(zhì)量,解決未經(jīng)設(shè)計(jì)導(dǎo)致的代碼質(zhì)量低下的功能。
從一定程度上來(lái)說(shuō),這個(gè)觀(guān)點(diǎn)并沒(méi)有錯(cuò),它強(qiáng)調(diào)了代碼對(duì)軟件的重要性,并通過(guò)一些技巧(如Refactoring)來(lái)解決缺乏設(shè)計(jì)的問(wèn)題。但我并不認(rèn)同”Evolutionary Design”的方式,在我看來(lái),一定程度上的”P(pán)lanned Design”是必須的,至少在中國(guó)的軟件行業(yè)中,”P(pán)lanned Design”還沒(méi)有成為主要的設(shè)計(jì)方向。借用一句明言,”凡事預(yù)則立,不預(yù)則廢”,在軟件設(shè)計(jì)初期,投入精力進(jìn)行架構(gòu)的設(shè)計(jì)是很有必要的,這個(gè)架構(gòu)是你在后續(xù)的設(shè)計(jì)、編碼過(guò)程中依賴(lài)的基礎(chǔ)。但是,一開(kāi)始我們提到的設(shè)計(jì)改進(jìn)的問(wèn)題依然存在,我們?nèi)绾谓鉀Q它呢?
在簡(jiǎn)單設(shè)計(jì)模式中,我們提到了設(shè)計(jì)改進(jìn)的必要性,但是,如果沒(méi)有一種方法去控制設(shè)計(jì)的改進(jìn)的話(huà),那么設(shè)計(jì)改進(jìn)本身就是一場(chǎng)噩夢(mèng)。因此,何時(shí)改進(jìn),怎么改進(jìn),如何控制,這都是我們需要面對(duì)的問(wèn)題。
解決方法
為了實(shí)現(xiàn)不斷的改進(jìn),我們將在開(kāi)發(fā)流程中引入迭代的概念。迭代的概念在《需求的實(shí)踐》中已經(jīng)提到,這里我們假設(shè)讀者已經(jīng)有了基本的迭代的概念。
軟件編碼之前的工作大致可以分為這樣一個(gè)工作流程:
上圖中的流程隱含著一個(gè)信息的損失的過(guò)程。來(lái)自于用戶(hù)的需求經(jīng)過(guò)整理之后,開(kāi)發(fā)人員就會(huì)從中去掉一些信息,同樣的事情發(fā)生在后面的過(guò)程中,信息丟失或變形的情況不斷的發(fā)生。這里發(fā)生了什么問(wèn)題?應(yīng)該說(shuō),需求信息的失真是非常普遍的,我們?nèi)鄙俚氖且环N有效的辦法來(lái)抑止失真,換句話(huà)說(shuō),就是缺少反饋。
如果把眼睛蒙上,那我們肯定沒(méi)有辦法走出一條很長(zhǎng)的直線(xiàn)。我們走路的時(shí)候都是針對(duì)目標(biāo)不斷的調(diào)整自己的方向的。同樣的,漫長(zhǎng)的軟件開(kāi)發(fā)過(guò)程如果沒(méi)有一種反饋機(jī)制來(lái)調(diào)整方向,那最后的軟件真是難以想象。
所以我們引入了迭代周期。?
初始設(shè)計(jì)和迭代設(shè)計(jì)?
在團(tuán)隊(duì)設(shè)計(jì)中,我們一直在強(qiáng)調(diào),設(shè)計(jì)組最開(kāi)始得到的設(shè)計(jì)一定只是一個(gè)原始架構(gòu),然后把這個(gè)原始架構(gòu)傳播到每一位開(kāi)發(fā)者的手中,從而在開(kāi)發(fā)團(tuán)隊(duì)中形成共同的愿景。(愿景(Vision):源自于管理學(xué),表示未來(lái)的愿望和景象。這里借用來(lái)表示軟件在開(kāi)發(fā)人員心中的樣子。在后面的文章中我們會(huì)有一個(gè)章節(jié)專(zhuān)門(mén)的討論架構(gòu)愿景。)
迭代(Iterate)設(shè)計(jì),或者我們稱(chēng)之為增量(Incremental)設(shè)計(jì)的思想和XP提倡的Evolutionary Design有異曲同工之妙。我們可以從XP、Crystal、RUP、ClearRoom等方法學(xué)中對(duì)比、體會(huì)迭代設(shè)計(jì)的精妙之處:每一次的迭代都是在上一次迭代的基礎(chǔ)上進(jìn)行的,迭代將致力于重用、修改、增強(qiáng)目前的架構(gòu),以使架構(gòu)越來(lái)越強(qiáng)壯。在軟件生命周期的最后,我們除了得到軟件,還得到了一個(gè)非常穩(wěn)定的架構(gòu)。對(duì)于一個(gè)軟件組織來(lái)說(shuō),這個(gè)架構(gòu)很有可能就是下一個(gè)軟件的投入或參考。
我們可以把早期的原始架構(gòu)當(dāng)作第一次迭代前的早期投入,也可以把它做為第一次迭代的重點(diǎn),這些都是無(wú)所謂的。關(guān)鍵在于,原始架構(gòu)對(duì)于后續(xù)的架構(gòu)設(shè)計(jì)而言是非常重要的,我們討論過(guò)架構(gòu)是來(lái)源于需求的,但是原始架構(gòu)應(yīng)該來(lái)源于那些比較穩(wěn)定的需求。
TIP:現(xiàn)實(shí)中迭代設(shè)計(jì)退化為”Code and Fix”的設(shè)計(jì)的情況屢見(jiàn)不鮮(”Code and Fix”參見(jiàn)簡(jiǎn)單設(shè)計(jì))。從表面上看,兩者的做法并沒(méi)有太大的差別,都是針對(duì)原有的設(shè)計(jì)進(jìn)行改進(jìn)。但是,二者效果的差別是明顯的:”Code and Fix”是混沌的,毫無(wú)方向感可言,每一次的改進(jìn)只是給原先就已搖搖欲墜的積木上再加一塊積木而已。而迭代設(shè)計(jì)的每一次改進(jìn)都朝著一個(gè)穩(wěn)定的目標(biāo)在前進(jìn),他給開(kāi)發(fā)人員帶來(lái)信心,而不是打擊。在過(guò)程上,我們說(shuō)迭代設(shè)計(jì)是在控制之下的。從實(shí)踐的經(jīng)驗(yàn)中,我們發(fā)現(xiàn),把原該在目前就該解決的問(wèn)題退后是造成這一問(wèn)題的主要原因之一。因此,請(qǐng)嚴(yán)格的對(duì)待每一次的迭代,確保計(jì)劃已經(jīng)完成、確保軟件的質(zhì)量、確保用戶(hù)的需求得到滿(mǎn)足,這樣才是正統(tǒng)的迭代之路。
單次的迭代?
我們說(shuō),每一次的迭代其實(shí)是一個(gè)完整的小過(guò)程。也就是說(shuō),它同樣要經(jīng)歷文章中討論的這些過(guò)程模式。只不過(guò),這些模式的工作量都不大,你甚至可以在很短的時(shí)間內(nèi)做完所有的事情。因此,我們好像又回到了文章的開(kāi)頭,重新討論架構(gòu)設(shè)計(jì)的過(guò)程。
單次迭代最令我們興奮的就是我們總是可以得到一個(gè)在當(dāng)前迭代中相當(dāng)穩(wěn)定的結(jié)果,而不像普通的架構(gòu)設(shè)計(jì)那樣,我們深怕架構(gòu)會(huì)出現(xiàn)問(wèn)題,但又不得不依賴(lài)這個(gè)架構(gòu)。從心理上來(lái)分析,我們是在持續(xù)的建設(shè)架構(gòu)中,不需要回避需求的變更,因?yàn)槲覀兿嘈?#xff0c;在需求相對(duì)應(yīng)的迭代中,會(huì)繼續(xù)對(duì)架構(gòu)進(jìn)行改進(jìn)。大家不要認(rèn)為這種心理的改變是無(wú)關(guān)緊要的,我起初并沒(méi)有意識(shí)到這個(gè)問(wèn)題,但是我很快發(fā)現(xiàn)新的架構(gòu)設(shè)計(jì)過(guò)程仍然籠罩在原先的懼怕改變的陰影之下的時(shí)候,迭代設(shè)計(jì)很容易就退化為”Code and Fix”的情形。開(kāi)發(fā)人員難以接受新方法的主要原因還是在心理上。因此,我不得不花了很多的時(shí)間來(lái)和開(kāi)發(fā)人員進(jìn)行溝通,這就是我現(xiàn)實(shí)的經(jīng)驗(yàn)。
迭代的交錯(cuò)?
基于我們對(duì)運(yùn)籌學(xué)的一點(diǎn)經(jīng)驗(yàn),迭代設(shè)計(jì)之間肯定不是線(xiàn)性的關(guān)系。這樣說(shuō)的一個(gè)原因架構(gòu)設(shè)計(jì)和后續(xù)的工作間還是時(shí)間差的。因此,我們不會(huì)傻到把時(shí)間浪費(fèi)在等待其它工作上。一般而言,當(dāng)下一次迭代的需求開(kāi)始之后,詳細(xì)需求開(kāi)始之前,我們就已經(jīng)可以開(kāi)始下一次迭代的架構(gòu)設(shè)計(jì)了。
各次迭代之間的時(shí)間距離要視項(xiàng)目的具體情況而定。比如,人員比較緊張的項(xiàng)目中,主要的架構(gòu)設(shè)計(jì)人員可能也要擔(dān)任編碼人員的角色,下一次迭代的架構(gòu)設(shè)計(jì)就可能要等到編碼工作的高峰期過(guò)了之后。可是,多次的交錯(cuò)迭代就可能產(chǎn)生版本的問(wèn)題。比如,本次的迭代的編碼中發(fā)現(xiàn)了架構(gòu)的一個(gè)問(wèn)題,反饋給架構(gòu)設(shè)計(jì)組,但是架構(gòu)設(shè)計(jì)組已經(jīng)根據(jù)偽修改的本次迭代的架構(gòu)開(kāi)始了下一次迭代的架構(gòu)設(shè)計(jì),這時(shí)候就會(huì)出現(xiàn)不同的設(shè)計(jì)之間的沖突問(wèn)題。這種情況當(dāng)然可以通過(guò)加強(qiáng)對(duì)設(shè)計(jì)模型的管理和引入版本控制機(jī)制來(lái)解決,但肯定會(huì)隨之帶來(lái)管理成本上升的問(wèn)題,而這是不符合敏捷的思想的。這時(shí)候,團(tuán)隊(duì)設(shè)計(jì)就體現(xiàn)了他的威力了,這也是我們?cè)趫F(tuán)隊(duì)設(shè)計(jì)中沒(méi)有提到的一個(gè)原因。團(tuán)隊(duì)設(shè)計(jì)通過(guò)完全的溝通,可以解決架構(gòu)設(shè)計(jì)中存在沖突的問(wèn)題。?
迭代頻率?
XP提倡迭代周期越短越好(XP建議為一到兩周),這是個(gè)不錯(cuò)的提議。在這么短的一個(gè)迭代周期內(nèi),我們花在架構(gòu)設(shè)計(jì)上的時(shí)間可能就只有一兩個(gè)小時(shí)到半天的時(shí)間。這時(shí)候,會(huì)有一個(gè)很有意思的現(xiàn)象,你很難去區(qū)分架構(gòu)設(shè)計(jì)和設(shè)計(jì)的概念了。因?yàn)樵谶@么短的一個(gè)周期之內(nèi),完成的需求數(shù)量是很少的,可能就只有一兩個(gè)用例或用戶(hù)素材。因此,這幾項(xiàng)需求的設(shè)計(jì)是不是屬于架構(gòu)設(shè)計(jì)呢?如果是的話(huà),由于開(kāi)發(fā)過(guò)程是由多次的迭代組成的,那么開(kāi)發(fā)過(guò)程中的設(shè)計(jì)不都屬于架構(gòu)設(shè)計(jì)了嗎?我們說(shuō),架構(gòu)是一個(gè)相對(duì)的概念,是針對(duì)范圍而言的,在傳統(tǒng)的瀑布模型中,我們可以很容易的區(qū)分出架構(gòu)設(shè)計(jì)和普通設(shè)計(jì),如果我們把一次迭代看作是一個(gè)單獨(dú)的生命周期,那么,普通的設(shè)計(jì)在這樣一個(gè)范圍之內(nèi)也就是架構(gòu)設(shè)計(jì),他們并沒(méi)有什么兩樣。但是,迭代周期中的架構(gòu)設(shè)計(jì)是要遵循一定的原則的,這我們?cè)谙旅孢€會(huì)提到。
我們希望迭代頻率越快越好,但是這還要根據(jù)現(xiàn)實(shí)的情況而定。比如數(shù)據(jù)倉(cāng)庫(kù)項(xiàng)目,在項(xiàng)目的初期階段,我們不得不花費(fèi)大量的時(shí)間來(lái)進(jìn)行數(shù)據(jù)建模的工作,這其實(shí)也是一項(xiàng)專(zhuān)門(mén)針對(duì)數(shù)據(jù)的架構(gòu)設(shè)計(jì),建立元數(shù)據(jù),制定維,整理數(shù)據(jù),這樣子的過(guò)程很難分為多次的迭代周期來(lái)實(shí)現(xiàn)。?
如何確定軟件的迭代周期?
可以說(shuō),如果一支開(kāi)發(fā)團(tuán)隊(duì)沒(méi)有相關(guān)迭代的概念,那么這支團(tuán)隊(duì)要立刻實(shí)現(xiàn)時(shí)隔兩周迭代周期是非常困難的,,同時(shí)也是毫無(wú)意義的。就像我們?cè)谏厦嬗懻摰?#xff0c;影響迭代周期的因素很多,以至于我們那無(wú)法對(duì)迭代周期進(jìn)行量化的定義。因此我們只能從定性的角度分析迭代周期的發(fā)展。
另一個(gè)了解迭代的方法是閱讀XP的相關(guān)資料,我認(rèn)為XP中關(guān)于迭代周期的使用是很不錯(cuò)的一種方法,只是他強(qiáng)調(diào)的如此短的迭代周期對(duì)于很多的軟件團(tuán)隊(duì)而言都是難以實(shí)現(xiàn)的。
迭代周期的引入一定是一個(gè)從粗糙到精確的過(guò)程。迭代的本質(zhì)其實(shí)是短周期的計(jì)劃,因此這也是迭代周期越短對(duì)我們?cè)接泻锰幍囊淮笤?#xff0c;因?yàn)闀r(shí)間縮短了,計(jì)劃的可預(yù)測(cè)性就增強(qiáng)了。我們知道,計(jì)劃的制定是依賴(lài)于已往的經(jīng)驗(yàn),如果原先我們沒(méi)有制定計(jì)劃或細(xì)節(jié)計(jì)劃的經(jīng)驗(yàn),那么我們的計(jì)劃就一定是非常粗糙,最后的誤差也一定很大。但是這沒(méi)有關(guān)系,每一次的計(jì)劃都會(huì)對(duì)下一次的計(jì)劃產(chǎn)生正面的影響,等到經(jīng)驗(yàn)足夠的時(shí)候,計(jì)劃將會(huì)非常的精確,最后的誤差也會(huì)很小。
迭代周期的確定需要依賴(lài)于單位工作量。單位工作量指的是一定時(shí)間內(nèi)你可以量化的最小的績(jī)效。最簡(jiǎn)單的單位工作量是每位程序員一天的編碼行數(shù)。可惜顯示往往比較殘酷,團(tuán)隊(duì)中不但有程序員的角色,還有設(shè)計(jì)師、測(cè)試人員、文檔制作人員等角色的存在,單純的編碼行數(shù)是不能夠作為唯一的統(tǒng)計(jì)依據(jù)的。同樣,只強(qiáng)調(diào)編碼行數(shù),也會(huì)導(dǎo)致其它的問(wèn)題,例如代碼質(zhì)量。為了保證統(tǒng)計(jì)的合理性,比較好的做法是一個(gè)團(tuán)隊(duì)實(shí)現(xiàn)某個(gè)功能所花費(fèi)的天數(shù)作為單位工作量。這里討論的內(nèi)容實(shí)際是軟件測(cè)量技術(shù),如果有機(jī)會(huì)的話(huà),再和大家探討這個(gè)問(wèn)題。?
迭代周期和軟件架構(gòu)的改進(jìn)
我們應(yīng)用迭代方法的最大的目的就是為了穩(wěn)步的改進(jìn)軟件架構(gòu)。因此,我們需要了解架構(gòu)是如何在軟件開(kāi)發(fā)的過(guò)程中不斷演進(jìn)的。在后面的文章中,我們會(huì)談到用Refactoring的方法來(lái)改進(jìn)軟件架構(gòu),但是Refactoring的定義中強(qiáng)調(diào),Refactoring必須在不修改代碼的外部功能的情況下進(jìn)行。對(duì)于架構(gòu)來(lái)說(shuō),我們可以近乎等價(jià)的認(rèn)為就是在外部接口不變的情況下對(duì)架構(gòu)進(jìn)行改進(jìn)。而在實(shí)際的開(kāi)發(fā)中,除非非常有經(jīng)驗(yàn),否則在軟件開(kāi)發(fā)全過(guò)程中保持所有的軟件接口不變是一件非常困難的事情。因此,我們這里談的架構(gòu)的改進(jìn)雖然和Refactoring有類(lèi)似之處,但還是有區(qū)別的。
軟件架構(gòu)的改進(jìn)在軟件開(kāi)發(fā)過(guò)程會(huì)經(jīng)歷一個(gè)振蕩期,這個(gè)振蕩期可能橫跨了數(shù)個(gè)迭代周期,其間架構(gòu)的設(shè)計(jì)將會(huì)經(jīng)歷劇烈的變化,但最后一定會(huì)取向于平穩(wěn)。(如果項(xiàng)目后期沒(méi)有出現(xiàn)設(shè)計(jì)平穩(wěn)化的情況,那么很不幸,你的項(xiàng)目注定要失敗了,要么是時(shí)間的問(wèn)題,要么就是需求的問(wèn)題)。關(guān)鍵的問(wèn)題在于,我們有沒(méi)有勇氣,在架構(gòu)需要改變的時(shí)候就毅然做出變化,而不是眼睜睜的看著問(wèn)題變得越來(lái)越嚴(yán)重。最后的例子中,我們討論三個(gè)迭代周期,假設(shè)我們?cè)诘诙€(gè)周期的時(shí)候拒絕對(duì)架構(gòu)進(jìn)行改變,那么第三個(gè)周期一定是有如噩夢(mèng)一般。變化,才有可能成功。
我們知道變化的重要性,但沒(méi)有辦法知道變化的確切時(shí)間。不過(guò)我們可以從開(kāi)發(fā)過(guò)程中嗅到架構(gòu)需要變化的氣味:當(dāng)程序中重復(fù)的代碼逐漸變多的時(shí)候,當(dāng)某些類(lèi)變得格外的臃腫的時(shí)候,當(dāng)編碼人員的編碼速度開(kāi)始下降的時(shí)候,當(dāng)需求出現(xiàn)大量的變動(dòng)的時(shí)候。?
實(shí)例?
從這一周開(kāi)始,我和我的小組將要負(fù)責(zé)對(duì)軟件項(xiàng)目中的表示層的設(shè)計(jì)。在這個(gè)迭代周期中,我們的任務(wù)是要為客戶(hù)端提供6到10個(gè)的視圖。由于視圖并不很多,表示層的架構(gòu)設(shè)計(jì)非常的簡(jiǎn)單:
準(zhǔn)確的說(shuō),這里談不上設(shè)計(jì),只是簡(jiǎn)單讓客戶(hù)端訪(fǎng)問(wèn)不同的視圖而已。當(dāng)然,在設(shè)計(jì)的示意圖中,我們并沒(méi)有必要畫(huà)出所有的視圖來(lái),只要能夠表達(dá)客戶(hù)端和視圖的關(guān)聯(lián)性就可以了。
(架構(gòu)設(shè)計(jì)需要和具體的實(shí)現(xiàn)綁定,但是在這個(gè)例子中,為了著重體現(xiàn)設(shè)計(jì)的演進(jìn),因此把不必要的信息都刪掉。在實(shí)際的設(shè)計(jì)中,視圖可能是JSP頁(yè)面,也可能是一個(gè)窗口。)
第一個(gè)迭代周的任務(wù)很快的完成了,小組負(fù)責(zé)的表示層模塊也很順利的和其它小組完成了對(duì)接,一個(gè)簡(jiǎn)陋但能夠運(yùn)轉(zhuǎn)的小系統(tǒng)順利的發(fā)布。客戶(hù)觀(guān)看了這個(gè)系統(tǒng)的演示,對(duì)系統(tǒng)提出了修改和補(bǔ)充。
第二���迭代周中,模塊要處理的視圖增加到了30個(gè),視圖之間存在相同的部分,并且,負(fù)責(zé)數(shù)據(jù)層的小組對(duì)我們說(shuō),由于客戶(hù)需求的改進(jìn),同一個(gè)視圖中將會(huì)出現(xiàn)不同的數(shù)據(jù)源。由于我們的視圖中直接使用了數(shù)據(jù)層小組提供給我們的數(shù)據(jù)源的函數(shù),這意味著我們的設(shè)計(jì)需要進(jìn)行較大的調(diào)整。
考慮到系統(tǒng)的視圖的量大大的增加,我們有必要對(duì)視圖進(jìn)行集中的管理。前端控制器(Front Control)模式將會(huì)是一個(gè)不錯(cuò)的技巧。對(duì)于視圖之間的普遍的重復(fù)部分,可以將視圖劃分為不同的子視圖,再把子視圖組合為各種各樣的視圖。這樣我們就可以使用組合(Composite)模式:
客戶(hù)的請(qǐng)求集中提交給控制器,控制器接受到客戶(hù)的請(qǐng)求之后,根據(jù)一定的規(guī)則,來(lái)提供不同的視圖來(lái)反饋給客戶(hù)。控制器是一個(gè)具有擴(kuò)展能力的設(shè)計(jì),目前的視圖數(shù)量并不多,因此仍然可以使用控制器來(lái)直接分配視圖。如果視圖的處理規(guī)則比較復(fù)雜,我們還可以使用創(chuàng)建工廠(chǎng)(Create Factory)模式來(lái)專(zhuān)門(mén)處理生成視圖的問(wèn)題。對(duì)于視圖來(lái)說(shuō),使用組合模式,把多個(gè)不同數(shù)據(jù)源的視圖組合為復(fù)雜的視圖。例如,一個(gè)JSP的頁(yè)面中,可能需要分為頭頁(yè)面和尾頁(yè)面。
項(xiàng)目進(jìn)入第三個(gè)迭代周期之后,表示層的需求進(jìn)一步復(fù)雜化。我們需要處理權(quán)限信息、需要處理數(shù)據(jù)的合法性判斷、還需要面對(duì)更多的視圖帶來(lái)的復(fù)雜程度上升的問(wèn)題。
表示層的權(quán)限處理比較簡(jiǎn)單,我們可以從前端控制器中增加權(quán)限控制的模塊。同時(shí),為了解決合法性判斷問(wèn)題,我們又增加了一個(gè)數(shù)據(jù)過(guò)濾鏈模塊,來(lái)完成數(shù)據(jù)的合法性判斷和轉(zhuǎn)換的工作。為了不使得控制器部分的功能過(guò)于復(fù)雜,我們把原先屬于控制器的視圖分發(fā)功能轉(zhuǎn)移到新的分發(fā)器模塊,而控制器專(zhuān)門(mén)負(fù)責(zé)用戶(hù)請(qǐng)求、視圖的控制。
我們來(lái)回顧這個(gè)例子,從迭代周期1中的需求最為簡(jiǎn)單,其實(shí),現(xiàn)實(shí)中的項(xiàng)目剛開(kāi)始的需求雖然未必會(huì)像例子中的那么簡(jiǎn)單,但一定不會(huì)過(guò)于復(fù)雜,因此迭代周期1的設(shè)計(jì)也非常的簡(jiǎn)單。到了迭代周期2的時(shí)候,需求開(kāi)始變得復(fù)雜,按照原先的架構(gòu)繼續(xù)設(shè)計(jì)的話(huà),必然會(huì)導(dǎo)致很多的問(wèn)題,因此對(duì)架構(gòu)進(jìn)行改進(jìn)是必要的。我們看到,新的設(shè)計(jì)能夠滿(mǎn)足新的需求。同樣的,迭代周期3的需求更加的復(fù)雜,因此設(shè)計(jì)也隨之演進(jìn)。這就是我們?cè)谖恼碌拈_(kāi)始提到的”Evolutionary Design”的演進(jìn)的思想。
架構(gòu)設(shè)計(jì)中的方法學(xué)(7)——組合使用模式
我們已經(jīng)討論了敏捷架構(gòu)設(shè)計(jì)的4種過(guò)程模式,在本文中,我們對(duì)這四種過(guò)程模式做一個(gè)小結(jié),并討論4者間的關(guān)系以及體現(xiàn)在模式中的敏捷方法論特色。通過(guò)這一章的描述,大家能夠?qū)η懊娴膬?nèi)容有更進(jìn)一步的了解。?
四種模式的著重點(diǎn) 我把源自需求、團(tuán)隊(duì)設(shè)計(jì)、簡(jiǎn)單設(shè)計(jì)、迭代設(shè)計(jì)這4種過(guò)程模式歸類(lèi)為架構(gòu)設(shè)計(jì)的第一層次,這4種模式能夠確定架構(gòu)設(shè)計(jì)過(guò)程的框架。這里需要對(duì)框架的含義進(jìn)行澄清:架構(gòu)設(shè)計(jì)的框架并不是說(shuō)你要嚴(yán)格的按照文中介紹的內(nèi)容來(lái)進(jìn)行架構(gòu)設(shè)計(jì),在文章的一開(kāi)始我們就指出,模式能夠激發(fā)思考。因此,這一框架是需要結(jié)合實(shí)際,進(jìn)行改造的。實(shí)際,我們?cè)谶@一個(gè)部分中介紹的,比較偏向于原則,我們花了很大的時(shí)間來(lái)討論原則的來(lái)龍去脈,而原則的度,則要大家自己去把握。為什么我們不討論原則的度呢?這里有兩個(gè)原因,一個(gè)是軟件開(kāi)發(fā)團(tuán)隊(duì)各有特色,很難定義出一個(gè)通用的度。第二個(gè)原因是我的水平不夠,實(shí)踐經(jīng)驗(yàn)也不夠豐富。 前面提到的四種模式其實(shí)是從四個(gè)側(cè)面討論了架構(gòu)設(shè)計(jì)中的方法問(wèn)題。源自需求提供了架構(gòu)設(shè)計(jì)的基礎(chǔ)。在軟件過(guò)程中,架構(gòu)設(shè)計(jì)是承接于需求分析的,如果沒(méi)有良好的需求分析活動(dòng)的支持,再好的架構(gòu)設(shè)計(jì)也沒(méi)有用。因此我們把這一模式放在首位,做為架構(gòu)設(shè)計(jì)的目標(biāo)。 有了確定的目標(biāo),還需有組織的保證,這也就是第二種模式――團(tuán)隊(duì)設(shè)計(jì)的由來(lái)。敏捷方法提倡優(yōu)秀的溝通,因此團(tuán)隊(duì)設(shè)計(jì)是必要且有效的。而團(tuán)隊(duì)設(shè)計(jì)的另一個(gè)意圖,是保證架構(gòu)設(shè)計(jì)的下游活動(dòng)得以順利的進(jìn)行,例如詳細(xì)設(shè)計(jì)、編碼、測(cè)試等。由于開(kāi)發(fā)團(tuán)隊(duì)中的人大都加入了架構(gòu)設(shè)計(jì),因此最大程度的減小了不同的活動(dòng)間的信息損耗和溝通效率低下的問(wèn)題。如果說(shuō)源自需求模式是起承上的作用,那么團(tuán)隊(duì)設(shè)計(jì)模式則是扮演了啟下的角色。 在軟件設(shè)計(jì)的過(guò)程中,溝通往往扮演著非常重要的角色。從團(tuán)隊(duì)設(shè)計(jì)開(kāi)始的幾種模式所要解決的都是溝通的問(wèn)題。團(tuán)隊(duì)設(shè)計(jì)對(duì)溝通的貢獻(xiàn)在于它能夠把設(shè)計(jì)意圖以最小的代價(jià)傳播到開(kāi)發(fā)團(tuán)隊(duì)的每個(gè)角落。這樣,設(shè)計(jì)和下游的活動(dòng)間由于溝通不暢產(chǎn)生的問(wèn)題就能夠得到緩解。一般而言,設(shè)計(jì)到編碼會(huì)經(jīng)歷一個(gè)信息損失的過(guò)程,編碼人員無(wú)法正確理解設(shè)計(jì)人員的意圖,設(shè)計(jì)人員卻往往無(wú)法考慮到一些編碼的細(xì)節(jié)。雖然我們可以通過(guò)共通的設(shè)計(jì)符號(hào)來(lái)提高溝通的質(zhì)量,例如UML。但是實(shí)踐證明,只要能夠保證暢通的溝通,即便沒(méi)有優(yōu)秀的開(kāi)發(fā)方法,項(xiàng)目成功的概率依然很高。因此對(duì)于單個(gè)的項(xiàng)目來(lái)說(shuō),最關(guān)鍵的問(wèn)題還是在于溝通。只要組織得當(dāng),團(tuán)隊(duì)設(shè)計(jì)是一個(gè)值得應(yīng)用的模式。當(dāng)然,配合以UML為代表的建模語(yǔ)言,更能夠提高溝通的效果。
在設(shè)計(jì)中,我們發(fā)現(xiàn),當(dāng)設(shè)計(jì)信息轉(zhuǎn)換為編碼信息需要一定的時(shí)間,這個(gè)時(shí)間包括設(shè)計(jì)的組織時(shí)間,設(shè)計(jì)被理解的時(shí)間。如果設(shè)計(jì)比較復(fù)雜,或者說(shuō)設(shè)計(jì)的文檔比較復(fù)雜,編碼人員花在理解上的時(shí)間就會(huì)大大增加。因此,權(quán)衡后的結(jié)果是,相對(duì)于詳細(xì)的設(shè)計(jì)說(shuō)明書(shū)而言,簡(jiǎn)單的設(shè)計(jì)說(shuō)明書(shū)再配合一定程度的面對(duì)面溝通能夠起到更好的效果。”簡(jiǎn)單要比復(fù)雜有效”,這就是簡(jiǎn)單設(shè)計(jì)模式的基本思路。?
同樣,簡(jiǎn)單的思路還會(huì)用在軟件開(kāi)發(fā)的各個(gè)方面,例如文檔、設(shè)計(jì)、流程。堅(jiān)持簡(jiǎn)單的原則,并不斷的加以改進(jìn),是降低軟件開(kāi)發(fā)成本的一種很有效的做法。?
在有了以上的思路之后,我們還需要面對(duì)兩個(gè)現(xiàn)實(shí)的問(wèn)題。需求的變化將會(huì)導(dǎo)致設(shè)計(jì)的不穩(wěn)定,而需求的復(fù)雜性又會(huì)導(dǎo)致簡(jiǎn)單架構(gòu)設(shè)計(jì)的困難。為了解決這個(gè)問(wèn)題,我們引入了迭代的方法,將問(wèn)題分割為多個(gè)子問(wèn)題(把一個(gè)復(fù)雜的問(wèn)題分解為多個(gè)較簡(jiǎn)單的子問(wèn)題是計(jì)算機(jī)領(lǐng)域最常見(jiàn)的處理方法)。這樣,問(wèn)題的范圍和難度都大大降低了。而更關(guān)鍵的是,由于對(duì)用戶(hù)需求理解不充分或用戶(hù)表達(dá)需求有錯(cuò)導(dǎo)致的設(shè)計(jì)風(fēng)險(xiǎn)被降到最低點(diǎn)。迭代和前面幾個(gè)模式都有關(guān)系。?
需求和迭代?
源自需求模式是架構(gòu)設(shè)計(jì)中的起手式,沒(méi)有這一模式的支持,架構(gòu)設(shè)計(jì)只能是空中樓閣。其實(shí),源自需求模式嚴(yán)格意義上并不能算是敏捷方法論的特色,而應(yīng)該算是軟件開(kāi)發(fā)的天然特性。不幸的是,就是這么一個(gè)基本的原則,卻沒(méi)能夠引起開(kāi)發(fā)者足夠的重視。?
敏捷方法論中把需求擺在一個(gè)非常重要的位置,我們把源自需求模式作為架構(gòu)設(shè)計(jì)的第一個(gè)模式,主要的目的是承接架構(gòu)設(shè)計(jì)的上游工作――需求。需求決定架構(gòu),因此,我們?cè)诮?jīng)典的瀑布模型中可以看到需求到設(shè)計(jì)的嚴(yán)格的分界線(xiàn),但是在實(shí)際的開(kāi)發(fā)中,按照瀑布模型的理論往往會(huì)遇到很多的問(wèn)題,所以,我們嘗試著把需求和(架構(gòu))設(shè)計(jì)之間的界限打破,形成一個(gè)重疊的地帶,從而提高軟件開(kāi)發(fā)的速度。因此,我們?cè)谠醋孕枨竽P椭兄赋?#xff0c;架構(gòu)設(shè)計(jì)是緊隨著需求開(kāi)始的。?
需求對(duì)軟件開(kāi)發(fā)最具影響就是需求的不穩(wěn)定性。我們都非常的清楚軟件開(kāi)發(fā)的曲線(xiàn),越到軟件開(kāi)發(fā)的后期,修改軟件的成本越高。因此,在軟件開(kāi)發(fā)上游的需求的變動(dòng)將會(huì)對(duì)軟件開(kāi)發(fā)的下游產(chǎn)生天翻地覆的影響。為了協(xié)調(diào)這一矛盾,軟工理論提出了螺旋開(kāi)發(fā)模型,這就是我們?cè)诘_(kāi)發(fā)模式中的討論的理論基礎(chǔ)。把軟件開(kāi)發(fā)過(guò)程分為多個(gè)的迭代周期,每一次的迭代周期最后都將生成一個(gè)可交付的軟件,用戶(hù)在每一次的迭代結(jié)束后,可以試用軟件,提出下一步的需求或是改變?cè)鹊男枨蟆Mㄟ^(guò)這樣的方式,把客戶(hù)、開(kāi)發(fā)商的風(fēng)險(xiǎn)降到一個(gè)可以接受的水平上。
請(qǐng)注意迭代的前提:需求的易變性。因此,對(duì)于那些需求容易發(fā)生變化的項(xiàng)目,我們就可以使用迭代式的開(kāi)發(fā)過(guò)程,雖然我們會(huì)付出一些額外的成本(剛開(kāi)始這個(gè)成本會(huì)比較大,但可以用較長(zhǎng)的迭代周期來(lái)降低這種成本),但是風(fēng)險(xiǎn)減小了。而對(duì)于需求比較固定的項(xiàng)目,
是不是有必要使用迭代的方法,就要看具體的環(huán)境了。因此,我們是根據(jù)實(shí)際的情況選用開(kāi)發(fā)方法,而不是因?yàn)橄冗M(jìn)或是流行的原因。
實(shí)際上,由于現(xiàn)代社會(huì)的特性,大部分的項(xiàng)目都是可以采用迭代方法。因此,我們的選擇就變成了了迭代周期應(yīng)該要多長(zhǎng)。迭代周期在理論上應(yīng)該是越短越好,但是并沒(méi)有一個(gè)絕對(duì)的數(shù)值,時(shí)間的跨度一般從幾周到幾個(gè)月。一般來(lái)說(shuō),迭代周期會(huì)受到幾個(gè)因素的影響:
各模塊的關(guān)聯(lián)程度。在軟件開(kāi)發(fā)中,我們有時(shí)候很難把一些模塊分離開(kāi)來(lái),要開(kāi)發(fā)模塊A,就需要模塊B,而模塊B又需要模塊C。各模塊的關(guān)聯(lián)程度越高,迭代周期越長(zhǎng)。當(dāng)然,也相應(yīng)的解決方法,我們可以在各模塊的功能中選取出一些關(guān)鍵點(diǎn),作為里程碑,以里程碑作為迭代完成點(diǎn)。
人員技能、經(jīng)驗(yàn)的平均程度。團(tuán)隊(duì)中成員的開(kāi)發(fā)能力、開(kāi)發(fā)經(jīng)驗(yàn)良莠不齊,這也是造成迭代周期延長(zhǎng)的一個(gè)原因。能力低、經(jīng)驗(yàn)少的開(kāi)發(fā)人員會(huì)拖后每一次迭代的時(shí)間。針對(duì)這種情況,做好統(tǒng)籌規(guī)劃就顯得非常的重要,可以通過(guò)一兩次的迭代,找出隊(duì)伍中的瓶頸人員,安排相應(yīng)的對(duì)策。
工具的缺乏。迭代周期越短,就意味著build、發(fā)布的次數(shù)越多,客戶(hù)也就有更多的機(jī)會(huì)來(lái)修改需求。這要求有相關(guān)的工具來(lái)幫助開(kāi)發(fā)人員控制軟件。最重要的工具是回歸測(cè)試工具。每一次迭代都需要增加新的功能,或是對(duì)原先的功能進(jìn)行改動(dòng),這就有可能引入新的bug,如果沒(méi)有回歸測(cè)試,開(kāi)發(fā)人員就需要花費(fèi)時(shí)間重新測(cè)試原先的功能。
計(jì)劃、控制的能力。迭代周期越短,所需要的計(jì)劃、控制的能力就越強(qiáng)。因?yàn)槎虝r(shí)間內(nèi)的計(jì)劃制定和實(shí)施需要高度的細(xì)分,這就要求開(kāi)發(fā)團(tuán)隊(duì)的管理者對(duì)開(kāi)發(fā)能力、工作量、任務(wù)分配有很強(qiáng)的認(rèn)識(shí),才能做好這項(xiàng)工作。不過(guò),迭代周期越短,同樣開(kāi)發(fā)時(shí)間的迭代次數(shù)就越多,而團(tuán)隊(duì)調(diào)整、改進(jìn)計(jì)劃控制的機(jī)會(huì)就越多。因此,后期的迭代一般都能夠做到比較精確的控制。而這樣的做法,要比問(wèn)題堆積到軟件交付日才爆發(fā)出來(lái)要好的多。沒(méi)有突然落后的軟件,只有每天都在落后的軟件。
簡(jiǎn)單和迭代
簡(jiǎn)單和迭代關(guān)系是雙向的。
在現(xiàn)實(shí)設(shè)計(jì)我們很難界定出簡(jiǎn)單設(shè)計(jì)的程度。怎樣的架構(gòu)設(shè)計(jì)才算是簡(jiǎn)單?按照我們?cè)诤?jiǎn)單設(shè)計(jì)模式中的討論,剛好滿(mǎn)足目前的需求的架構(gòu)設(shè)計(jì)就算是簡(jiǎn)單的設(shè)計(jì)。但是,從另外一個(gè)方面考慮,需求的易變性限制我們做出簡(jiǎn)單的設(shè)計(jì),因?yàn)槲覀儾荒軌蚩隙壳暗男枨髮?lái)會(huì)發(fā)生什么樣的變化。因此,為了克服對(duì)未知的恐懼,我們花了很大的力氣設(shè)計(jì)一些靈活的、能夠適應(yīng)變化的架構(gòu)。這是源自需求模式對(duì)簡(jiǎn)單設(shè)計(jì)模式的影響。
源自需求和迭代設(shè)計(jì)的關(guān)系的討論建議我們把需求分為多個(gè)迭代周期來(lái)實(shí)現(xiàn)。那么,相應(yīng)的架構(gòu)設(shè)計(jì)也被分在多個(gè)迭代周期中。這樣的方法可以降低架構(gòu)設(shè)計(jì)的復(fù)雜程度。因?yàn)樵O(shè)計(jì)人員不需要考慮軟件的全部需求,而只需要考慮當(dāng)前迭代周期的需求。復(fù)雜性的降低將會(huì)有助于架構(gòu)設(shè)計(jì)的簡(jiǎn)單化,從而達(dá)到簡(jiǎn)單設(shè)計(jì)的一系列的好處(參見(jiàn)簡(jiǎn)單設(shè)計(jì))。
我們從迭代設(shè)計(jì)中的最后一個(gè)例子可以清楚的看到迭代設(shè)計(jì)是如何把復(fù)雜的需求給簡(jiǎn)單化的。把握迭代設(shè)計(jì)有助于我們避免過(guò)分設(shè)計(jì)的毛病。這是個(gè)技術(shù)人員經(jīng)常犯的毛病。我所在的團(tuán)隊(duì)很多時(shí)候也無(wú)法避免。例如,在很多的項(xiàng)目中,我們都會(huì)花費(fèi)大量的時(shí)間來(lái)設(shè)計(jì)數(shù)據(jù)庫(kù)到業(yè)務(wù)實(shí)體的映射。諸如此類(lèi)的技術(shù)問(wèn)題對(duì)開(kāi)發(fā)人員的吸引程度是不言而喻的,但是必須看到,這種的設(shè)計(jì)會(huì)導(dǎo)致開(kāi)發(fā)成本的大幅度上升。更為糟糕的是,除非有豐富的經(jīng)驗(yàn),這種類(lèi)型的設(shè)計(jì)給開(kāi)發(fā)工作帶來(lái)的價(jià)值往往無(wú)法超過(guò)其成本。
因此,我們需要學(xué)會(huì)權(quán)衡利弊,是否有必要投入大量的資源來(lái)開(kāi)發(fā)其實(shí)并沒(méi)有那么有用的功能。因此,迭代設(shè)計(jì)和簡(jiǎn)單設(shè)計(jì)的結(jié)合有助于我們擺脫過(guò)度設(shè)計(jì)的困擾,把精力集中在真正重要的功能之上。
此外,簡(jiǎn)單的設(shè)計(jì)并不等同于較少的付出。簡(jiǎn)單的設(shè)計(jì)往往需要對(duì)現(xiàn)實(shí)世界的抽象,回憶我們?cè)诤?jiǎn)單設(shè)計(jì)中討論的測(cè)量模式的例子,它看似簡(jiǎn)單,但實(shí)現(xiàn)起來(lái)卻需要大量的業(yè)務(wù)知識(shí)、很強(qiáng)的設(shè)計(jì)能力。因此,做到簡(jiǎn)單是程序員不斷追尋的目標(biāo)之一。
在很多的方法論中,一般并不過(guò)分注意代碼重復(fù)的問(wèn)題,要么是不關(guān)注,要么認(rèn)為適當(dāng)?shù)拇a重復(fù)是允許的。而XP卻把代碼重復(fù)視為良好代碼的大敵。”只要存在重復(fù)代碼,就說(shuō)明代碼仍有Refactoring的可能。”這種觀(guān)點(diǎn)看起來(lái)非常的絕對(duì),這可能也正是其名字中Extreme的來(lái)歷(英文中的Extreme屬于語(yǔ)氣非常重的一個(gè)單詞)。從實(shí)踐的角度上來(lái)看,追求不重復(fù)的代碼雖然很難做到,但是其過(guò)程卻可以有效的提高開(kāi)發(fā)團(tuán)隊(duì)代碼的寫(xiě)作質(zhì)量,因?yàn)樗破戎阍诿看蔚貙?duì)代碼進(jìn)行改進(jìn),不能有絲毫的怠惰。而這種迭代的特性,促進(jìn)了簡(jiǎn)單的實(shí)現(xiàn)。
團(tuán)隊(duì)和簡(jiǎn)單
我們?cè)诤?jiǎn)單設(shè)計(jì)中提過(guò)簡(jiǎn)單設(shè)計(jì)需要全面的設(shè)計(jì)師。除此之外,它還需要團(tuán)隊(duì)的配合。簡(jiǎn)單意味著不同活動(dòng)間交付工件的簡(jiǎn)單化。也就是說(shuō),類(lèi)似于需求說(shuō)明書(shū)、設(shè)計(jì)文檔之類(lèi)的東西都將會(huì)比較簡(jiǎn)單。正因?yàn)槿绱?#xff0c;我們很難想象一個(gè)地理上分布在不同地點(diǎn)的開(kāi)發(fā)團(tuán)隊(duì)或一個(gè)超過(guò)50人的大團(tuán)隊(duì)能夠利用這種簡(jiǎn)單的文檔完成開(kāi)發(fā)任務(wù)。
因此,簡(jiǎn)單的設(shè)計(jì)是需要團(tuán)隊(duì)的組織結(jié)構(gòu)來(lái)保證的。簡(jiǎn)單的設(shè)計(jì)要求團(tuán)隊(duì)的相互溝通能夠快速的進(jìn)行。架構(gòu)設(shè)計(jì)完成后,架構(gòu)的設(shè)計(jì)思路傳達(dá)給所有的編碼人員的速度要塊,同樣,編碼中發(fā)現(xiàn)問(wèn)題,回饋給設(shè)計(jì)者,設(shè)計(jì)者經(jīng)過(guò)改進(jìn)之后再傳達(dá)給收到影響的編碼人員的速度也要快。象這樣高效率的傳播我們可以稱(chēng)之為”Hot Channel”。
為了保證”Hot Channel”的高溝通效率,最好的組織單位是開(kāi)發(fā)人員在3到6人之間,并處于同間工作室中。這樣的結(jié)構(gòu)可以保證訊息的交互速度達(dá)到最高,不需要付出額外的溝通成本,也不需要過(guò)于復(fù)雜的版本控制工具或權(quán)限分配。根據(jù)我的經(jīng)驗(yàn),一個(gè)共享式的小型版本控制工具、網(wǎng)絡(luò)共享、再加上一個(gè)簡(jiǎn)單的網(wǎng)絡(luò)數(shù)據(jù)庫(kù)就能夠解決大部分的問(wèn)題了。
在理論上,我們說(shuō)只要分配得當(dāng),大型的團(tuán)隊(duì)同樣可以組織為金字塔式的子團(tuán)隊(duì),以提高大型團(tuán)隊(duì)的工作效率。但是實(shí)際中,隨著團(tuán)隊(duì)的人數(shù)的增加,任務(wù)的正確分配的���度也隨之加大,溝通信息上傳下達(dá)的效率開(kāi)始下降,子團(tuán)隊(duì)間的隔閡開(kāi)始出現(xiàn),各種因素的累加導(dǎo)致敏捷方法并不一定適合于大型的團(tuán)隊(duì),因此我們討論的敏捷方法都將受到團(tuán)隊(duì)的特性的限制。
模式的源頭
如果你對(duì)XP有一定的了解的話(huà),那么你可能會(huì)感覺(jué)到我們討論的模式中應(yīng)用了XP的實(shí)踐。確實(shí)如此,XP中有很多優(yōu)秀的實(shí)踐,如果組織得當(dāng)?shù)脑?huà),這些微小的實(shí)踐將會(huì)組合成為一套了不起的開(kāi)發(fā)方法。不過(guò),目前的軟件開(kāi)發(fā)混亂的現(xiàn)狀阻止了先進(jìn)的軟件方法的應(yīng)用,對(duì)一個(gè)身體虛弱的病人施以補(bǔ)藥只會(huì)適得其反。因此,在前面討論的模式中,我們應(yīng)用了一些容易應(yīng)用、效果明顯的實(shí)踐方法。在實(shí)踐中適當(dāng)?shù)膽?yīng)用這些方法,并不需要額外的投入,卻能夠有很好的效果,同時(shí)還會(huì)為你的團(tuán)隊(duì)打下一個(gè)良好的基礎(chǔ)
架構(gòu)設(shè)計(jì)中的方法學(xué)(8)——架構(gòu)愿景(2)?
我們從源自需求模式中,學(xué)習(xí)到架構(gòu)的設(shè)計(jì)是來(lái)自于需求的,而應(yīng)用于軟件全局的架構(gòu)則來(lái)自于最重要的需求。還記得我們?cè)谀莻€(gè)模式中提到的網(wǎng)上寵物店的例子嗎?系統(tǒng)采用了MVC模式,sun的官方文檔一開(kāi)始說(shuō)明了為什么采用MVC模式,MVC模式解決了什么
問(wèn)題,然后開(kāi)始分析MVC模式的幾個(gè)組成部分:Model、View、和Controll。其實(shí),MVC中的每一個(gè)部分,在真正的代碼中,大都代表了一個(gè)子系統(tǒng),但是在目前,我們就非常的清楚系統(tǒng)大致上會(huì)是一個(gè)什么樣子,雖然這時(shí)候它還十分的朦朧。
不要視圖在全局的架構(gòu)愿景中就制定出非常細(xì)致的規(guī)劃,更不要視圖生成大量的實(shí)際代碼。因?yàn)?#xff0c;你的架構(gòu)愿景還沒(méi)有穩(wěn)定(我們?cè)谄浜蟮姆€(wěn)定化的模式中將會(huì)討論穩(wěn)定的問(wèn)題),還沒(méi)有獲得大家的同意,也沒(méi)有經(jīng)過(guò)證明。因此,從整個(gè)的開(kāi)發(fā)周期來(lái)看,全局架構(gòu)愿景是隨著迭代周期的進(jìn)行不斷發(fā)展、修改、完善的。
我們?nèi)绾未_定全局架構(gòu)愿景工作的完成?一般來(lái)說(shuō),你的架構(gòu)設(shè)計(jì)團(tuán)隊(duì)取得了一致的意見(jiàn)就可以結(jié)束了,如果問(wèn)題域是團(tuán)隊(duì)所熟悉的,一兩個(gè)小時(shí)就能夠解決問(wèn)題。接下來(lái)設(shè)計(jì)團(tuán)隊(duì)把架構(gòu)愿景傳播到整個(gè)的開(kāi)發(fā)團(tuán)隊(duì),大家形成一致的認(rèn)識(shí),不同的意見(jiàn)將會(huì)被反饋會(huì)來(lái),并在本次的迭代周期(如果時(shí)間比較緊迫)或下一次的迭代周期中(如果時(shí)間比較寬松)考慮。
子模塊級(jí)、或是子問(wèn)題級(jí)的架構(gòu)愿景
這時(shí)候的架構(gòu)愿景已經(jīng)是比較明確的了,因?yàn)橐呀?jīng)存在明確的問(wèn)題域。例如界面的設(shè)計(jì)、領(lǐng)域模型的設(shè)計(jì)、持久層的設(shè)計(jì)等。這里的愿景制定本質(zhì)上和全局的愿景制定差不多,具體的例子我們也不再舉了。但是要注意一點(diǎn),你不能夠和全局愿景所違背。在操作上,全局愿景是設(shè)計(jì)團(tuán)隊(duì)共同制定出來(lái)的,而子模塊級(jí)的架構(gòu)愿景就可以分給設(shè)計(jì)子團(tuán)隊(duì)來(lái)負(fù)責(zé),而其審核則還是要設(shè)計(jì)團(tuán)隊(duì)的共同參與。這有兩個(gè)好處,一是確保各個(gè)子模塊(子問(wèn)題)間不至于相互沖突或出現(xiàn)空白地帶,二是每個(gè)子設(shè)計(jì)團(tuán)隊(duì)可以從別人那里吸取設(shè)計(jì)經(jīng)驗(yàn)。
在設(shè)計(jì)時(shí),同樣我們可以參考其它的資料,例如相關(guān)的模式、或規(guī)范(界面設(shè)計(jì)指南)。在一個(gè)有開(kāi)發(fā)經(jīng)驗(yàn)的團(tuán)隊(duì),一般都會(huì)有開(kāi)發(fā)技術(shù)的積累,這些也是可供參考的重要資料。
我們?cè)谶@個(gè)層次的愿景中主要談一談子模塊(子問(wèn)題)間的耦合問(wèn)題。一般來(lái)說(shuō),各個(gè)子模塊間的耦合程度相對(duì)較小,例如一個(gè)MIS系統(tǒng)中,采購(gòu)和銷(xiāo)售模塊的耦合度就比較小,而子問(wèn)題間的耦合程度就比較大,例如權(quán)限設(shè)計(jì)、財(cái)務(wù),這些功能將會(huì)被每個(gè)模塊使用。那么,我們就需要為子模塊(子問(wèn)題)制定出合同接口(Contact Interface)。合同的意思就是說(shuō)這個(gè)接口是正式的,不能夠隨意的修改,因?yàn)檫@個(gè)結(jié)構(gòu)將會(huì)被其它的設(shè)計(jì)團(tuán)隊(duì)使用,如果修改,將會(huì)對(duì)其它的團(tuán)隊(duì)產(chǎn)生無(wú)法預(yù)計(jì)的影響。合同接口的制定、修改都需要設(shè)計(jì)團(tuán)隊(duì)的通過(guò)。此外,系統(tǒng)中的一些全局性的子問(wèn)題最好是提到全局愿景中考慮,例如在源自需求模式中提到的信貸帳務(wù)的例子中,我們就把一個(gè)利息計(jì)算方式的子問(wèn)題提到了全局愿景中。
代碼級(jí)的愿景
嚴(yán)格的說(shuō)這一層次的愿景已經(jīng)不是真正的愿景,而是具體設(shè)計(jì)了。但是我們?yōu)榱吮WC對(duì)架構(gòu)設(shè)計(jì)理解的完整性,還是簡(jiǎn)單的討論一下。這一個(gè)層次的愿景一般可以使用類(lèi)圖、接口來(lái)表示。但在類(lèi)圖中,你不需要標(biāo)記出具體的屬性、操作,你只需要規(guī)定出類(lèi)的職責(zé)以及類(lèi)之間的相互關(guān)系就可以了。該層次愿景的審核需要設(shè)計(jì)子團(tuán)隊(duì)的通過(guò)。
而設(shè)計(jì)細(xì)分到這個(gè)粒度上,執(zhí)行愿景設(shè)計(jì)的開(kāi)發(fā)人員可能就只有一兩個(gè)左右。但是比較重要的工作在于問(wèn)題如何分解和如何歸并。分解主要是從兩個(gè)維度來(lái)考慮,一個(gè)是問(wèn)題大小維,一個(gè)是時(shí)間長(zhǎng)短維。也就是說(shuō),你(設(shè)計(jì)子團(tuán)隊(duì)負(fù)責(zé)人)需要把問(wèn)題按大小和解決時(shí)間的長(zhǎng)短分解為更細(xì)的子問(wèn)題,交給不同的開(kāi)發(fā)人員。然后再把開(kāi)發(fā)人員提出的解決方法組合起來(lái)。
架構(gòu)愿景的形成過(guò)程
架構(gòu)愿景的形成的源頭是需求,需要特別指出的是,這里的需求主要是那些針對(duì)系統(tǒng)基本面的需求。比如說(shuō),系統(tǒng)的特點(diǎn)是一個(gè)交互式系統(tǒng),還是一個(gè)分布式系統(tǒng)。這些需求將會(huì)影響到架構(gòu)愿景的設(shè)計(jì)。在收集影響架構(gòu)愿景的各項(xiàng)需求之后,按照需求的重要性來(lái)設(shè)計(jì)架構(gòu)愿景。
架構(gòu)愿景的設(shè)計(jì)并不需要很復(fù)雜的過(guò)程,也不需要花費(fèi)很多的時(shí)間。我們已經(jīng)提過(guò),架構(gòu)遠(yuǎn)景的主要目的就是為了能夠在開(kāi)發(fā)團(tuán)隊(duì)中傳播設(shè)計(jì)思路,因此,架構(gòu)愿景包括基本的設(shè)計(jì)思路和基本的設(shè)計(jì)原則。
值得注意的是,架構(gòu)遠(yuǎn)景可能會(huì)有多種的視角,下文討論了一種設(shè)計(jì)模式的視角。但是實(shí)際設(shè)計(jì)中還可能會(huì)基于數(shù)據(jù)庫(kù)來(lái)設(shè)計(jì)架構(gòu)愿景。但在企業(yè)信息系統(tǒng)的設(shè)計(jì)中,我推薦使用領(lǐng)域類(lèi)的設(shè)計(jì),也就是下文中討論的例子。
架構(gòu)愿景設(shè)計(jì)好之后,問(wèn)題的焦點(diǎn)就轉(zhuǎn)到如何傳播架構(gòu)愿景上來(lái),為了達(dá)到在開(kāi)發(fā)團(tuán)隊(duì)中取得統(tǒng)一設(shè)計(jì)意圖的效果,可以考慮援引團(tuán)隊(duì)設(shè)計(jì)模式。除此之外,針對(duì)性的項(xiàng)目前期培訓(xùn)也會(huì)是一種有效的做法。
使用架構(gòu)模式
架構(gòu)模式也是一種很好的架構(gòu)愿景設(shè)計(jì)思路的來(lái)源。隨著對(duì)設(shè)計(jì)模式的研究的深入,人們發(fā)現(xiàn)其中的一些設(shè)計(jì)模式可以擴(kuò)展、或變化為軟件設(shè)計(jì)的基礎(chǔ)。在這個(gè)基礎(chǔ)上再實(shí)現(xiàn)更多的設(shè)計(jì),這些模式就形成了架構(gòu)模式。當(dāng)然,不同的軟件,它們的架構(gòu)模式也是不一樣的。在《Applying Pattern》一文中,有一個(gè)很典型的架構(gòu)愿景的例子:
假設(shè)我們需要設(shè)計(jì)分布式的交互式系統(tǒng)。分布式系統(tǒng)和交互式系統(tǒng)都有特定的架構(gòu)模式,前者為Broker模式,后者為MVC模式。首先我們先要根據(jù)系統(tǒng)的特點(diǎn)的重要程度來(lái)排列模式的順序。這里假設(shè)需求中分布式特性更重要一些。那么我們首先選擇Broker模式作為架構(gòu)的基本模式:
再考慮交互式的特點(diǎn),根據(jù)MVC模式的特點(diǎn),我們需要從目前的基本架構(gòu)中識(shí)別出Model、Controller、以及View。Model和View都很簡(jiǎn)單,分別分布在上圖中的Server和Client中。而Controller則有兩種的選擇,假設(shè)這里的Controller部署在客戶(hù)端,上圖則演化為下圖:
這樣,基礎(chǔ)的架構(gòu)愿景就已經(jīng)出現(xiàn)了。如果我們還有更多的需求,還可以繼續(xù)改進(jìn)。但是,記住一點(diǎn),架構(gòu)愿景不要過(guò)于復(fù)雜。正如我們?cè)谏弦还?jié)中所討論的,這里我們雖然是基于設(shè)計(jì)模式來(lái)討論架構(gòu)愿景,但是實(shí)際中還有很多從其它的視角來(lái)看待架構(gòu)愿景的。至于要如何選擇架構(gòu)愿景的視角,關(guān)鍵的還是在于需求的理解。
需求分析的20條法��?
我們討論的過(guò)程僅限于面向?qū)ο蟮能浖_(kāi)發(fā)過(guò)程。我們稱(chēng)之為OOSP(object-oriented software process )。因?yàn)槲覀兊倪^(guò)程需要面向?qū)ο筇匦缘闹С帧.?dāng)然,我們的很多做法一樣可以用在非OO的開(kāi)發(fā)過(guò)程中,但是為了達(dá)到最佳的效果,我建議您使用OO技術(shù)。對(duì)商業(yè)用戶(hù)來(lái)說(shuō),他們后面是成百上千個(gè)供應(yīng)商,前面是成千上萬(wàn)個(gè)消費(fèi)顧客。怎樣利用軟件管理錯(cuò)綜復(fù)雜的供應(yīng)商和消費(fèi)顧客,如何做好精細(xì)到一個(gè)小小調(diào)料包的進(jìn)、銷(xiāo)、調(diào)、存的商品流通工作,這些都是商業(yè)企業(yè)需要信息管理系統(tǒng)的理由。軟件開(kāi)發(fā)的意義也就在于此。而弄清商業(yè)用戶(hù)如此復(fù)雜需求的真面目,正是軟件開(kāi)發(fā)成功的關(guān)鍵所在。?
經(jīng)理:“我們要建立一套完整的商業(yè)管理軟件系統(tǒng),包括商品的進(jìn)、銷(xiāo)、調(diào)、存管理,是總部-門(mén)店的連鎖經(jīng)營(yíng)模式。通過(guò)通信手段門(mén)店自動(dòng)訂貨,供應(yīng)商自動(dòng)結(jié)算,賣(mài)場(chǎng)通過(guò)掃條碼實(shí)現(xiàn)銷(xiāo)售,管理人員能夠隨時(shí)查詢(xún)門(mén)店商品銷(xiāo)售和庫(kù)存情況。另外,我們也得為政府部門(mén)提供關(guān)于商品營(yíng)運(yùn)的報(bào)告。”?
分析員:“我已經(jīng)明白這個(gè)項(xiàng)目的大體結(jié)構(gòu)框架,這非常重要,但在制定計(jì)劃之前,我們必須收集一些需求。”?
經(jīng)理覺(jué)得奇怪:“我不是剛告訴你我的需求了嗎?”?
分析員:“實(shí)際上,您只說(shuō)明了整個(gè)項(xiàng)目的概念和目標(biāo)。這些高層次的業(yè)務(wù)需求不足以提供開(kāi)發(fā)的內(nèi)容和時(shí)間。我需要與實(shí)際將要使用系統(tǒng)的業(yè)務(wù)人員進(jìn)行討論,然后才能真正明白達(dá)到業(yè)務(wù)目標(biāo)所需功能和用戶(hù)要求,了解清楚后,才可以發(fā)現(xiàn)哪些是現(xiàn)有組件即可實(shí)現(xiàn)的,哪些是需要開(kāi)發(fā)的,這樣可節(jié)省很多時(shí)間。”?
經(jīng)理:“業(yè)務(wù)人員都在招商。他們非常忙,沒(méi)有時(shí)間與你們?cè)敿?xì)討論各種細(xì)節(jié)。你能不能說(shuō)明一下你們現(xiàn)有的系統(tǒng)?”?
分析員盡量解釋從用戶(hù)處收集需求的合理性:“如果我們只是憑空猜想用戶(hù)的要求,結(jié)果不會(huì)令人滿(mǎn)意。我們只是軟件開(kāi)發(fā)人員,而不是采購(gòu)專(zhuān)家、營(yíng)運(yùn)專(zhuān)家或是財(cái)務(wù)專(zhuān)家,我們并不真正明白您這個(gè)企業(yè)內(nèi)部運(yùn)營(yíng)需要做些什么。我曾經(jīng)嘗試過(guò),未真正明白這些問(wèn)題就開(kāi)始編碼,結(jié)果沒(méi)有人對(duì)產(chǎn)品滿(mǎn)意。”?
經(jīng)理堅(jiān)持道:“行了,行了,我們沒(méi)有那么多的時(shí)間。讓我來(lái)告訴您我們的需求。實(shí)際上我也很忙。請(qǐng)馬上開(kāi)始開(kāi)發(fā),并隨時(shí)將你們的進(jìn)展情況告訴我。”?
風(fēng)險(xiǎn)躲在需求的迷霧之后?
以上我們看到的是某客戶(hù)項(xiàng)目經(jīng)理與系統(tǒng)開(kāi)發(fā)小組的分析人員討論業(yè)務(wù)需求。在項(xiàng)目開(kāi)發(fā)中,所有的項(xiàng)目風(fēng)險(xiǎn)承擔(dān)者都對(duì)需求分析階段備感興趣。這里所指的風(fēng)險(xiǎn)承擔(dān)者包括客戶(hù)方面的項(xiàng)目負(fù)責(zé)人和用戶(hù),開(kāi)發(fā)方面的需求分析人員和項(xiàng)目管理者。這部分工作做得到位,能開(kāi)發(fā)出很優(yōu)秀的軟件產(chǎn)品,同時(shí)也會(huì)令客戶(hù)滿(mǎn)意。若處理不好,則會(huì)導(dǎo)致誤解、挫折、障礙以及潛在的質(zhì)量和業(yè)務(wù)價(jià)值上的威脅。因此可見(jiàn)——需求分析奠定了軟件工程和項(xiàng)目管理的基礎(chǔ)。?
撥開(kāi)需求分析的迷霧?
像這樣的對(duì)話(huà)經(jīng)常出現(xiàn)在軟件開(kāi)發(fā)的過(guò)程中。客戶(hù)項(xiàng)目經(jīng)理的需求對(duì)分析人員來(lái)講,像“霧里看花”般模糊并令開(kāi)發(fā)者感到困惑。那么,我們就撥開(kāi)霧影,分析一下需求的具體內(nèi)容:?
·業(yè)務(wù)需求——反映了組織機(jī)構(gòu)或客戶(hù)對(duì)系統(tǒng)、產(chǎn)品高層次的目標(biāo)要求,通常在項(xiàng)目定義與范圍文檔中予以說(shuō)明。?
·用戶(hù)需求——描述了用戶(hù)使用產(chǎn)品必須要完成的任務(wù),這在使用實(shí)例或方案腳本中予以說(shuō)明。?
·功能需求——定義了開(kāi)發(fā)人員必須實(shí)現(xiàn)的軟件功能,使用戶(hù)利用系統(tǒng)能夠完成他們的任務(wù),從而滿(mǎn)足了業(yè)務(wù)需求。?
·非功能性的需求——描述了系統(tǒng)展現(xiàn)給用戶(hù)的行為和執(zhí)行的操作等,它包括產(chǎn)品必須遵從的標(biāo)準(zhǔn)、規(guī)范和約束,操作界面的具體細(xì)節(jié)和構(gòu)造上的限制。?
·需求分析報(bào)告——報(bào)告所說(shuō)明的功能需求充分描述了軟件系統(tǒng)所應(yīng)具有的外部行為。“需求分析報(bào)告”在開(kāi)發(fā)、測(cè)試、質(zhì)量保證、項(xiàng)目管理以及相關(guān)項(xiàng)目功能中起著重要作用。?
前面提到的客戶(hù)項(xiàng)目經(jīng)理通常闡明產(chǎn)品的高層次概念和主要業(yè)務(wù)內(nèi)容,為后繼工作建立了一個(gè)指導(dǎo)性的框架。其他任何說(shuō)明都應(yīng)遵循“業(yè)務(wù)需求”的規(guī)定,然而“業(yè)務(wù)需求”并不能為開(kāi)發(fā)人員提供開(kāi)發(fā)所需的許多細(xì)節(jié)說(shuō)明。?
下一層次需求——用戶(hù)需求,必須從使用產(chǎn)品的用戶(hù)處收集。因此,這些用戶(hù)構(gòu)成了另一種軟件客戶(hù),他們清楚要使用該產(chǎn)品完成什么任務(wù)和一些非功能性的特性需求。例如:程序的易用性、健壯性和可靠性,而這些特性將會(huì)使用戶(hù)很好地接受具有該特點(diǎn)的軟件產(chǎn)品。?
經(jīng)理層有時(shí)試圖代替實(shí)際用戶(hù)說(shuō)話(huà),但通常他們無(wú)法準(zhǔn)確說(shuō)明“用戶(hù)需求”。用戶(hù)需求來(lái)自產(chǎn)品的真正使用者,必須讓實(shí)際用戶(hù)參與到收集需求的過(guò)程中。如果不這樣做,產(chǎn)品很可能會(huì)因缺乏足夠的信息而遺留不少隱患。?
在實(shí)際需求分析過(guò)程中,以上兩種客戶(hù)可能都覺(jué)得沒(méi)有時(shí)間與需求分析人員討論,有時(shí)客戶(hù)還希望分析人員無(wú)須討論和編寫(xiě)需求說(shuō)明就能說(shuō)出用戶(hù)的需求。除非遇到的需求極為簡(jiǎn)單;否則不能這樣做。如果您的組織希望軟件成功,那么必須要花上數(shù)天時(shí)間來(lái)消除需求中模糊不清的地方和一些使開(kāi)發(fā)者感到困惑的方面。?
優(yōu)秀的軟件產(chǎn)品建立在優(yōu)秀的需求基礎(chǔ)之上,而優(yōu)秀的需求源于客戶(hù)與開(kāi)發(fā)人員之間有效的交流和合作。只有雙方參與者都明白自己需要什么、成功的合作需要什么時(shí),才能建立起一種良好的合作關(guān)系。?
由于項(xiàng)目的壓力與日俱增,所有項(xiàng)目風(fēng)險(xiǎn)承擔(dān)者有著一個(gè)共同目標(biāo),那就是大家都想開(kāi)發(fā)出一個(gè)既能實(shí)現(xiàn)商業(yè)價(jià)值又能滿(mǎn)足用戶(hù)要求,還能使開(kāi)發(fā)者感到滿(mǎn)足的優(yōu)秀軟件產(chǎn)品。?
客戶(hù)的需求觀(guān)?
客戶(hù)與開(kāi)發(fā)人員交流需要好的方法。下面建議20條法則,客戶(hù)和開(kāi)發(fā)人員可以通過(guò)評(píng)審以下內(nèi)容并達(dá)成共識(shí)。如果遇到分歧,將通過(guò)協(xié)商達(dá)成對(duì)各自義務(wù)的相互理解,以便減少以后的磨擦(如一方要求而另一方不愿意或不能夠滿(mǎn)足要求)。?
1、 分析人員要使用符合客戶(hù)語(yǔ)言習(xí)慣的表達(dá)?
需求討論集中于業(yè)務(wù)需求和任務(wù),因此要使用術(shù)語(yǔ)。客戶(hù)應(yīng)將有關(guān)術(shù)語(yǔ)(例如:采價(jià)、印花商品等采購(gòu)術(shù)語(yǔ))教給分析人員,而客戶(hù)不一定要懂得計(jì)算機(jī)行業(yè)的術(shù)語(yǔ)。?
2、分析人員要了解客戶(hù)的業(yè)務(wù)及目標(biāo)?
只有分析人員更好地了解客戶(hù)的業(yè)務(wù),才能使產(chǎn)品更好地滿(mǎn)足需要。這將有助于開(kāi)發(fā)人員設(shè)計(jì)出真正滿(mǎn)足客戶(hù)需要并達(dá)到期望的優(yōu)秀軟件。為幫助開(kāi)發(fā)和分析人員,客戶(hù)可以考慮邀請(qǐng)他們觀(guān)察自己的工作流程。如果是切換新系統(tǒng),那么開(kāi)發(fā)和分析人員應(yīng)使用一下目前的舊系統(tǒng),有利于他們明白目前系統(tǒng)是怎樣工作的,其流程情況以及可供改進(jìn)之處。s 3、分析人員必須編寫(xiě)軟件需求報(bào)告?
分析人員應(yīng)將從客戶(hù)那里獲得的所有信息進(jìn)行整理,以區(qū)分業(yè)務(wù)需求及規(guī)范、功能需求、質(zhì)量目標(biāo)、解決方法和其他信息。通過(guò)這些分析,客戶(hù)就能得到一份“需求分析報(bào)告”,此份報(bào)告使開(kāi)發(fā)人員和客戶(hù)之間針對(duì)要開(kāi)發(fā)的產(chǎn)品內(nèi)容達(dá)成協(xié)議。報(bào)告應(yīng)以一種客戶(hù)認(rèn)為易于翻閱和理解的方式組織編寫(xiě)。客戶(hù)要評(píng)審此報(bào)告,以確保報(bào)告內(nèi)容準(zhǔn)確完整地表達(dá)其需求。一份高質(zhì)量的“需求分析報(bào)告”有助于開(kāi)發(fā)人員開(kāi)發(fā)出真正需要的產(chǎn)品。?
4、 要求得到需求工作結(jié)果的解釋說(shuō)明?
分析人員可能采用了多種圖表作為文字性“需求分析報(bào)告”的補(bǔ)充說(shuō)明,因?yàn)楣ぷ鲌D表能很清晰地描述出系統(tǒng)行為的某些方面,所以報(bào)告中各種圖表有著極高的價(jià)值;雖然它們不太難于理解,但是客戶(hù)可能對(duì)此并不熟悉,因此客戶(hù)可以要求分析人員解釋說(shuō)明每個(gè)圖表的作用、符號(hào)的意義和需求開(kāi)發(fā)工作的結(jié)果,以及怎樣檢查圖表有無(wú)錯(cuò)誤及不一致等。?
5、 開(kāi)發(fā)人員要尊重客戶(hù)的意見(jiàn)?
如果用戶(hù)與開(kāi)發(fā)人員之間不能相互理解,那關(guān)于需求的討論將會(huì)有障礙。共同合作能使大家“兼聽(tīng)則明”。參與需求開(kāi)發(fā)過(guò)程的客戶(hù)有權(quán)要求開(kāi)發(fā)人員尊重他們并珍惜他們?yōu)轫?xiàng)目成功所付出的時(shí)間,同樣,客戶(hù)也應(yīng)對(duì)開(kāi)發(fā)人員為項(xiàng)目成功這一共同目標(biāo)所做出的努力表示尊重。?
6、 開(kāi)發(fā)人員要對(duì)需求及產(chǎn)品實(shí)施提出建議和解決方案?
通常客戶(hù)所說(shuō)的“需求”已經(jīng)是一種實(shí)際可行的實(shí)施方案,分析人員應(yīng)盡力從這些解決方法中了解真正的業(yè)務(wù)需求,同時(shí)還應(yīng)找出已有系統(tǒng)與當(dāng)前業(yè)務(wù)不符之處,以確保產(chǎn)品不會(huì)無(wú)效或低效;在徹底弄清業(yè)務(wù)領(lǐng)域內(nèi)的事情后,分析人員就能提出相當(dāng)好的改進(jìn)方法,有經(jīng)驗(yàn)且有創(chuàng)造力的分析人員還能提出增加一些用戶(hù)沒(méi)有發(fā)現(xiàn)的很有價(jià)值的系統(tǒng)特性。?
7、 描述產(chǎn)品使用特性?
客戶(hù)可以要求分析人員在實(shí)現(xiàn)功能需求的同時(shí)還注意軟件的易用性,因?yàn)檫@些易用特性或質(zhì)量屬性能使客戶(hù)更準(zhǔn)確、高效地完成任務(wù)。例如:客戶(hù)有時(shí)要求產(chǎn)品要“界面友好”或“健壯”或“高效率”,但對(duì)于開(kāi)發(fā)人員來(lái)講,太主觀(guān)了并無(wú)實(shí)用價(jià)值。正確的做法是,分析人員通過(guò)詢(xún)問(wèn)和調(diào)查了解客戶(hù)所要的“友好、健壯、高效所包含的具體特性,具體分析哪些特性對(duì)哪些特性有負(fù)面影響,在性能代價(jià)和所提出解決方案的預(yù)期利益之間做出權(quán)衡,以確保做出合理的取舍。?
8、 允許重用已有的軟件組件?
需求通常有一定靈活性,分析人員可能發(fā)現(xiàn)已有的某個(gè)軟件組件與客戶(hù)描述的需求很相符,在這種情況下,分析人員應(yīng)提供一些修改需求的選擇以便開(kāi)發(fā)人員能夠降低新系統(tǒng)的開(kāi)發(fā)成本和節(jié)省時(shí)間,而不必嚴(yán)格按原有的需求說(shuō)明開(kāi)發(fā)。所以說(shuō),如果想在產(chǎn)品中使用一些已有的商業(yè)常用組件,而它們并不完全適合您所需的特性,這時(shí)一定程度上的需求靈活性就顯得極為重要了。?
9、 要求對(duì)變更的代價(jià)提供真實(shí)可靠的評(píng)估?
有時(shí),人們面臨更好、也更昂貴的方案時(shí),會(huì)做出不同的選擇。而這時(shí),對(duì)需求變更的影響進(jìn)行評(píng)估從而對(duì)業(yè)務(wù)決策提供幫助,是十分必要的。所以,客戶(hù)有權(quán)利要求開(kāi)發(fā)人員通過(guò)分析給出一個(gè)真實(shí)可信的評(píng)估,包括影響、成本和得失等。開(kāi)發(fā)人員不能由于不想實(shí)施變更而隨意夸大評(píng)估成本。?
10、 獲得滿(mǎn)足客戶(hù)功能和質(zhì)量要求的系統(tǒng)?
每個(gè)人都希望項(xiàng)目成功,但這不僅要求客戶(hù)要清晰地告知開(kāi)發(fā)人員關(guān)于系統(tǒng)“做什么”所需的所有信息,而且還要求開(kāi)發(fā)人員能通過(guò)交流了解清楚取舍與限制,一定要明確說(shuō)明您的假設(shè)和潛在的期望,否則,開(kāi)發(fā)人員開(kāi)發(fā)出的產(chǎn)品很可能無(wú)法讓您滿(mǎn)意。?
11、 給分析人員講解您的業(yè)務(wù)?
分析人員要依靠客戶(hù)講解業(yè)務(wù)概念及術(shù)語(yǔ),但客戶(hù)不能指望分析人員會(huì)成為該領(lǐng)域的專(zhuān)家,而只能讓他們明白您的問(wèn)題和目標(biāo);不要期望分析人員能把握客戶(hù)業(yè)務(wù)的細(xì)微潛在之處,他們可能不知道那些對(duì)于客戶(hù)來(lái)說(shuō)理所當(dāng)然的“常識(shí)”。?
12、 抽出時(shí)間清楚地說(shuō)明并完善需求?
客戶(hù)很忙,但無(wú)論如何客戶(hù)有必要抽出時(shí)間參與“頭腦高峰會(huì)議”的討論,接受采訪(fǎng)或其他獲取需求的活動(dòng)。有些分析人員可能先明白了您的觀(guān)點(diǎn),而過(guò)后發(fā)現(xiàn)還需要您的講解,這時(shí)請(qǐng)耐心對(duì)待一些需求和需求的精化工作過(guò)程中的反復(fù),因?yàn)樗侨藗兘涣髦泻茏匀坏默F(xiàn)象,何況這對(duì)軟件產(chǎn)品的成功極為重要。?
13、 準(zhǔn)確而詳細(xì)地說(shuō)明需求?
編寫(xiě)一份清晰、準(zhǔn)確的需求文檔是很困難的。由于處理細(xì)節(jié)問(wèn)題不但煩人而且耗時(shí),因此很容易留下模糊不清的需求。但是在開(kāi)發(fā)過(guò)程中,必須解決這種模糊性和不準(zhǔn)確性,而客戶(hù)恰恰是為解決這些問(wèn)題作出決定的最佳人選,否則,就只好靠開(kāi)發(fā)人員去正確猜測(cè)了。?
在需求分析中暫時(shí)加上“待定”標(biāo)志是個(gè)方法。用該標(biāo)志可指明哪些是需要進(jìn)一步討論、分析或增加信息的地方,有時(shí)也可能因?yàn)槟硞€(gè)特殊需求難以解決或沒(méi)有人愿意處理它而標(biāo)注上“待定”。客戶(hù)要盡量將每項(xiàng)需求的內(nèi)容都闡述清楚,以便分析人員能準(zhǔn)確地將它們寫(xiě)進(jìn)“軟件需求報(bào)告”中去。如果客戶(hù)一時(shí)不能準(zhǔn)確表達(dá),通常就要求用原型技術(shù),通過(guò)原型開(kāi)發(fā),客戶(hù)可以同開(kāi)發(fā)人員一起反復(fù)修改,不斷完善需求定義。?
14、 及時(shí)作出決定?
分析人員會(huì)要求客戶(hù)作出一些選擇和決定,這些決定包括來(lái)自多個(gè)用戶(hù)提出的處理方法或在質(zhì)量特性沖突和信息準(zhǔn)確度中選擇折衷方案等。有權(quán)作出決定的客戶(hù)必須積極地對(duì)待這一切,盡快做處理,做決定,因?yàn)殚_(kāi)發(fā)人員通常只有等客戶(hù)做出決定才能行動(dòng),而這種等待會(huì)延誤項(xiàng)目的進(jìn)展。?
15、 尊重開(kāi)發(fā)人員的需求可行性及成本評(píng)估?
所有的軟件功能都有其成本。客戶(hù)所希望的某些產(chǎn)品特性可能在技術(shù)上行不通,或者實(shí)現(xiàn)它要付出極高的代價(jià),而某些需求試圖達(dá)到在操作環(huán)境中不可能達(dá)到的性能,或試圖得到一些根本得不到的數(shù)據(jù)。開(kāi)發(fā)人員會(huì)對(duì)此作出負(fù)面的評(píng)價(jià),客戶(hù)應(yīng)該尊重他們的意見(jiàn)。?
16、 劃分需求的優(yōu)先級(jí)?
絕大多數(shù)項(xiàng)目沒(méi)有足夠的時(shí)間或資源實(shí)現(xiàn)功能性的每個(gè)細(xì)節(jié)。決定哪些特性是必要的,哪些是重要的,是需求開(kāi)發(fā)的主要部分,這只能由客戶(hù)負(fù)責(zé)設(shè)定需求優(yōu)先級(jí),因?yàn)殚_(kāi)發(fā)者不可能按照客戶(hù)的觀(guān)點(diǎn)決定需求優(yōu)先級(jí);開(kāi)發(fā)人員將為您確定優(yōu)先級(jí)提供有關(guān)每個(gè)需求的花費(fèi)和風(fēng)險(xiǎn)的信息。?
在時(shí)間和資源限制下,關(guān)于所需特性能否完成或完成多少應(yīng)尊重開(kāi)發(fā)人員的意見(jiàn)。盡管沒(méi)有人愿意看到自己所希望的需求在項(xiàng)目中未被實(shí)現(xiàn),但畢竟是要面對(duì)現(xiàn)實(shí),業(yè)務(wù)決策有時(shí)不得不依據(jù)優(yōu)先級(jí)來(lái)縮小項(xiàng)目范圍或延長(zhǎng)工期,或增加資源,或在質(zhì)量上尋找折衷。?
17、 評(píng)審需求文檔和原型?
客戶(hù)評(píng)審需求文檔,是給分析人員帶來(lái)反饋信息的一個(gè)機(jī)會(huì)。如果客戶(hù)認(rèn)為編寫(xiě)的“需求分析報(bào)告”不夠準(zhǔn)確,就有必要盡早告知分析人員并為改進(jìn)提供建議。?
更好的辦法是先為產(chǎn)品開(kāi)發(fā)一個(gè)原型。這樣客戶(hù)就能提供更有價(jià)值的反饋信息給開(kāi)發(fā)人員,使他們更好地理解您的需求;原型并非是一個(gè)實(shí)際應(yīng)用產(chǎn)品,但開(kāi)發(fā)人員能將其轉(zhuǎn)化、擴(kuò)充成功能齊全的系統(tǒng)。?
18、 需求變更要立即聯(lián)系?
不斷的需求變更,會(huì)給在預(yù)定計(jì)劃內(nèi)完成的質(zhì)量產(chǎn)品帶來(lái)嚴(yán)重的不利影響。變更是不可避免的,但在開(kāi)發(fā)周期中,變更越在晚期出現(xiàn),其影響越大;變更不僅會(huì)導(dǎo)致代價(jià)極高的返工,而且工期將被延誤,特別是在大體結(jié)構(gòu)已完成后又需要增加新特性時(shí)。所以,一旦客戶(hù)發(fā)現(xiàn)需要變更需求時(shí),請(qǐng)立即通知分析人員。?
19、 遵照開(kāi)發(fā)小組處理需求變更的過(guò)程?
為將變更帶來(lái)的負(fù)面影響減少到最低限度,所有參與者必須遵照項(xiàng)目變更控制過(guò)程。這要求不放棄所有提出的變更,對(duì)每項(xiàng)要求的變更進(jìn)行分析、綜合考慮,最后做出合適的決策,以確定應(yīng)將哪些變更引入項(xiàng)目中。?
20、 尊重開(kāi)發(fā)人員采用的需求分析過(guò)程?
軟件開(kāi)發(fā)中最具挑戰(zhàn)性的莫過(guò)于收集需求并確定其正確性,分析人員采用的方法有其合理性。也許客戶(hù)認(rèn)為收集需求的過(guò)程不太劃算,但請(qǐng)相信花在需求開(kāi)發(fā)上的時(shí)間是非常有價(jià)值的;如果您理解并支持分析人員為收集、編寫(xiě)需求文檔和確保其質(zhì)量所采用的技術(shù),那么整個(gè)過(guò)程將會(huì)更為順利。?
“需求確認(rèn)”意味著什么?
在“需求分析報(bào)告”上簽字確認(rèn),通常被認(rèn)為是客戶(hù)同意需求分析的標(biāo)志行為,然而實(shí)際操作中,客戶(hù)往往把“簽字”看作是毫無(wú)意義的事情。“他們要我在需求文檔的最后一行下面簽名,于是我就簽了,否則這些開(kāi)發(fā)人員不開(kāi)始編碼。”?
這種態(tài)度將帶來(lái)麻煩,譬如客戶(hù)想更改需求或?qū)Ξa(chǎn)品不滿(mǎn)時(shí)就會(huì)說(shuō):“不錯(cuò),我是在需求分析報(bào)告上簽了字,但我并沒(méi)有時(shí)間去讀完所有的內(nèi)容,我是相信你們的,是你們非讓我簽字的。”?
同樣問(wèn)題也會(huì)發(fā)生在僅把“簽字確認(rèn)”看作是完成任務(wù)的分析人員身上,一旦有需求變更出現(xiàn),他便指著“需求分析報(bào)告”說(shuō):“您已經(jīng)在需求上簽字了,所以這些就是我們所開(kāi)發(fā)的,如果您想要?jiǎng)e的什么,您應(yīng)早些告訴我們。”?
這兩種態(tài)度都是不對(duì)的。因?yàn)椴豢赡茉陧?xiàng)目的早期就了解所有的需求,而且毫無(wú)疑問(wèn)地需求將會(huì)出現(xiàn)變更,在“需求分析報(bào)告”上簽字確認(rèn)是終止需求分析過(guò)程的正確方法,所以我們必須明白簽字意味著什么。?
對(duì)“需求分析報(bào)告”的簽名是建立在一個(gè)需求協(xié)議的基線(xiàn)上,因此我們對(duì)簽名應(yīng)該這樣理解:“我同意這份需求文檔表述了我們對(duì)項(xiàng)目軟件需求的了解,進(jìn)一步的變更可在此基線(xiàn)上通過(guò)項(xiàng)目定義的變更過(guò)程來(lái)進(jìn)行。我知道變更可能會(huì)使我們重新協(xié)商成本、資源和項(xiàng)目階段任務(wù)等事宜。”對(duì)需求分析達(dá)成一定的共識(shí)會(huì)使雙方易于忍受將來(lái)的摩擦,這些摩擦來(lái)源于項(xiàng)目的改進(jìn)和需求的誤差或市場(chǎng)和業(yè)務(wù)的新要求等。?
需求確認(rèn)將迷霧撥散,顯現(xiàn)需求的真面目,給初步的需求開(kāi)發(fā)工作畫(huà)上了雙方都明確的句號(hào),并有助于形成一個(gè)持續(xù)良好的客戶(hù)與開(kāi)發(fā)人員的關(guān)系,為項(xiàng)目的成功奠定了堅(jiān)實(shí)的基礎(chǔ)。
專(zhuān)訪(fǎng)架構(gòu)師周愛(ài)民:談企業(yè)軟件架構(gòu)設(shè)計(jì)?
最近在網(wǎng)上讀到了“殺不死的人狼——我讀《人月神話(huà)》”系列文章。是周愛(ài)民關(guān)于《人月神化》的讀書(shū)心得。《人月神化》在軟件工程里一本很有分量的書(shū),講述了Brooks博士在IBM公司 System/360家族和OS/360中的項(xiàng)目管理經(jīng)驗(yàn)。周愛(ài)民在他的這一系列文章中用自己架構(gòu)師經(jīng)歷為基礎(chǔ),從他的視角重新品讀了這本書(shū)。而這也使我有了采訪(fǎng)下他的想法,從中我們也許可以了解到中國(guó)企業(yè)內(nèi)軟件架構(gòu)設(shè)計(jì)這個(gè)環(huán)節(jié)的現(xiàn)狀。目前周愛(ài)民是盛大網(wǎng)絡(luò)架構(gòu)師。在此特別感謝周愛(ài)民在百忙中抽出時(shí)間回復(fù)了這次訪(fǎng)談。
1, 您好,請(qǐng)先向我們的網(wǎng)友簡(jiǎn)單做一下自我介紹自己好嗎?
我94年開(kāi)始學(xué)習(xí)電腦,基本上從一開(kāi)始就學(xué)編程。從96年開(kāi)始涉及商業(yè)軟件開(kāi)發(fā),到現(xiàn)在約十一年了。其間我在鄭州的一家軟件公司呆了7年,歷經(jīng)了一家軟件公司的中興到消亡,因而也意識(shí)到工程、管理在軟件企業(yè)——當(dāng)然也包括其它類(lèi)型的企業(yè)——中的價(jià)值。后來(lái),從03年開(kāi)始的一年多時(shí)間,我在鄭州的另一家公司任軟件部經(jīng)理,也開(kāi)始實(shí)踐自己的工程和管理思想。很好,到現(xiàn)在我離開(kāi)這家公司一年多了,公司狀況依然很不錯(cuò)。我認(rèn)為,團(tuán)隊(duì)或公司并沒(méi)有因?yàn)槟愕娜毕兊迷愀?#xff0c;那便已經(jīng)是良性管理的表現(xiàn)了。關(guān)于“Borland Delphi產(chǎn)品專(zhuān)家”,其實(shí)更多的是一個(gè)圈子的認(rèn)可,而非行業(yè)的認(rèn)可。我在“大富翁論壇(delphibbs.com)”活動(dòng)了很長(zhǎng)的時(shí)間,得到了一些朋友們的認(rèn)可,后來(lái)Borland要評(píng)選這個(gè)專(zhuān)家的時(shí)候,大家推舉了我,于是就得了這個(gè)稱(chēng)號(hào)。其實(shí)在我看來(lái),優(yōu)秀的人才、專(zhuān)家很多,我大約是人緣好點(diǎn),運(yùn)氣好點(diǎn)罷。
我05年9月開(kāi)始到盛大網(wǎng)絡(luò),任架構(gòu)師一職。當(dāng)時(shí)Borland China也有offer,但在顧問(wèn)、軟件工程師與架構(gòu)師之間,我選擇了架構(gòu)師這個(gè)職務(wù),因?yàn)槲覍?duì)這個(gè)角色更加感興趣。我目前的工作,主要是盛大的軟件平臺(tái)方面的架構(gòu)、設(shè)計(jì)和一些實(shí)施方面的事務(wù)。雖然很多人認(rèn)為盛大是做游戲的公司,但我基本不涉及游戲產(chǎn)品的開(kāi)發(fā)。
在開(kāi)發(fā)技術(shù)方面,我03年出版過(guò)一本《Delphi源代碼分析》。在工程方面,《大道至簡(jiǎn)——軟件工程實(shí)踐者的思想》一書(shū)在下月初就應(yīng)出版了,它的第一版是以電子版的形式發(fā)布的。我在寫(xiě)的第三本書(shū)則是講計(jì)算機(jī)語(yǔ)言的,題材是“動(dòng)態(tài)函數(shù)式語(yǔ)言”。
2,您做為盛大網(wǎng)絡(luò)的架構(gòu)師,請(qǐng)介紹一下在軟件項(xiàng)目中平臺(tái)架構(gòu)師是一份怎樣的角色?主要處理哪些工作?
架構(gòu)師有很多種。很多人把體系架構(gòu)師與架構(gòu)師等同,其實(shí)不對(duì)。各類(lèi)架構(gòu)師基本素質(zhì)要求大抵一致,例如分析能力、設(shè)計(jì)的技術(shù)方法,以及對(duì)設(shè)計(jì)目標(biāo)的前瞻性。但是他們的專(zhuān)業(yè)素質(zhì)會(huì)有一些差別。舉個(gè)實(shí)例來(lái)說(shuō),如果讓我設(shè)計(jì)游戲引擎的架構(gòu),我就會(huì)做不好。但是,如果這個(gè)游戲引擎要設(shè)計(jì)成一個(gè)獨(dú)立的平臺(tái)層次,具有語(yǔ)言無(wú)關(guān)性、平臺(tái)整合能力,或是對(duì)不同類(lèi)型游戲的統(tǒng)一支撐,那么就是平臺(tái)架構(gòu)師的職責(zé)了。
具體來(lái)說(shuō),平臺(tái)架構(gòu)師會(huì)決策某個(gè)部分與其它部分的相互關(guān)系、界面的規(guī)約和檢測(cè)評(píng)估它們的方法。如果一個(gè)游戲引擎只為某個(gè)游戲而設(shè)計(jì),那么是用不到平臺(tái)架構(gòu)師的。但如果A游戲中的引擎要移植到B游戲,或者更多的游戲,甚至只是抽離它的部分,以作為某種體系中的一個(gè)數(shù)據(jù)交互層,那么就需要平臺(tái)架構(gòu)師來(lái)考量技術(shù)上的可行性、穩(wěn)定性以及它對(duì)于更大范圍內(nèi)的平臺(tái)建設(shè)的價(jià)值——當(dāng)然,如果沒(méi)有價(jià)值,架構(gòu)師也會(huì)否定它。
平臺(tái)是長(zhǎng)期建設(shè)的。平臺(tái)架構(gòu)師的重要職責(zé)之一,就是長(zhǎng)期的規(guī)劃和持續(xù)的推進(jìn)。所以平臺(tái)架構(gòu)師的工作總是伴隨客戶(hù)的戰(zhàn)略決策的。如果一個(gè)設(shè)計(jì)只是解決短期的技術(shù)問(wèn)題,那么也并不需要平臺(tái)架構(gòu)師,但如果是幾年或十幾年要在上面持續(xù)經(jīng)營(yíng)的一個(gè)整體方向,那么平臺(tái)架構(gòu)師就需要圍繞戰(zhàn)略來(lái)設(shè)計(jì)架構(gòu)的藍(lán)圖,并決定規(guī)劃的實(shí)施步驟。在這些方面,他可能需要協(xié)調(diào)很多團(tuán)隊(duì)一些來(lái)工作。不過(guò),這可不是跟項(xiàng)目經(jīng)理?yè)岋埻搿R驗(yàn)轫?xiàng)目經(jīng)理重在實(shí)施,而架構(gòu)師重在規(guī)劃。
當(dāng)然,事實(shí)上我也做一些其它類(lèi)型的架構(gòu)設(shè)計(jì)工作。例如設(shè)計(jì)一個(gè)小的模塊,或者一個(gè)業(yè)務(wù)工件。好的架構(gòu)師不會(huì)拒絕這些工作,而是從更多的、細(xì)節(jié)的工作中發(fā)現(xiàn)整體與局部的關(guān)系。也只有觸及到具體工作的細(xì)節(jié),架構(gòu)師才可能更早地發(fā)覺(jué)設(shè)計(jì)上的隱患或者與目標(biāo)的偏差。
3,《人月神話(huà)》這本書(shū)30多年來(lái)一直被認(rèn)為是項(xiàng)目管理者的必讀書(shū),最近也看到您的blog里寫(xiě)了一系列相關(guān)的書(shū)評(píng)。您是怎么看到書(shū)中“項(xiàng)目實(shí)施法則“和實(shí)際項(xiàng)目工作之間的關(guān)系。
這幾個(gè)問(wèn)題我基本上都在《殺不死的人狼》一文中講過(guò)了。概括來(lái)說(shuō),我認(rèn)為有以下三點(diǎn):
一、討論“有或沒(méi)有”銀彈這樣的話(huà)題沒(méi)有意義,因?yàn)椤度嗽律裨?huà)》所述的人狼根本殺不死,而且Brooks所設(shè)想的銀彈也過(guò)于學(xué)術(shù)。?
二、《人月神話(huà)》從廣義工程的角度設(shè)定了這個(gè)命題,這個(gè)命題的根本目標(biāo)與次要目標(biāo)正好與具體工程(狹義工程)相反。?
三、我承認(rèn)《人月神話(huà)》神話(huà)所述的答案以及建議在如今的軟件工程中得到了體現(xiàn)。但我們應(yīng)該更清醒地辨析出現(xiàn)象、答案與本質(zhì),并分析哪些是本質(zhì)的自然延伸,而哪些只是《人月神話(huà)》所帶來(lái)的影響——Brooks預(yù)言了未來(lái),也就改變了未來(lái),即使未來(lái)未必應(yīng)該如此。
與大多數(shù)人不一樣的是,我更多的是從與Brooks的預(yù)言不一致的那些現(xiàn)象是去發(fā)現(xiàn)一些東西。我所看到的是,正是在改變了Brooks的命題,或者認(rèn)識(shí)到他所述的“本質(zhì)”未必正確的時(shí)候,我們才找到了一些“不一樣的成功”。我提醒大家關(guān)注這些事例,以及它們與傳統(tǒng)工程、廣義工程的本質(zhì)差異。
我并不反對(duì)《人月神話(huà)》中的大多數(shù)工程觀(guān)點(diǎn),以及我們現(xiàn)在的軟件業(yè)中的工程實(shí)踐經(jīng)驗(yàn)。但是狹義工程沒(méi)有必要去追尋銀彈或那些看起來(lái)看銀彈的東西,我們應(yīng)該更加靈活。
4企業(yè)在進(jìn)行項(xiàng)目的軟件架構(gòu)設(shè)計(jì)時(shí),需要考慮哪些關(guān)鍵的問(wèn)題?
企業(yè)實(shí)施過(guò)程中的架構(gòu)問(wèn)題,可以分成兩個(gè)部分來(lái)考慮。一個(gè)是軟件企業(yè)自身,一個(gè)是工程的目標(biāo)客戶(hù)(有些時(shí)候它與前者一則)。基本上來(lái)說(shuō),架構(gòu)設(shè)計(jì)首先是面向客戶(hù)的,甚至在整個(gè)工程的絕大多數(shù)時(shí)候都面向客戶(hù)。因?yàn)槔斫鉀Q定設(shè)計(jì),所以讓架構(gòu)師盡可能早地、深入地了解工程目標(biāo)、應(yīng)用環(huán)境、戰(zhàn)略決策和發(fā)展方向,是至關(guān)重要的。否則,架構(gòu)師是不可能做出有效的設(shè)計(jì)來(lái)的。
架構(gòu)設(shè)計(jì)關(guān)注于三個(gè)方面:穩(wěn)定、持續(xù)和代價(jià)。
穩(wěn)定性由架構(gòu)師的設(shè)計(jì)能力決定。架構(gòu)的好壞是很難評(píng)判的,但基本的法則是“適用”。如果一個(gè)架構(gòu)不適用,那么再小或者再大都不可能穩(wěn)定。所因此進(jìn)一步推論是“架構(gòu)必須以工程的主體目標(biāo)為設(shè)計(jì)象”。看起來(lái)這是個(gè)簡(jiǎn)單的事,但事實(shí)上很多架構(gòu)設(shè)計(jì)中只是在做邊角功夫,例如為一兩處所謂的“精彩的局部”而叫好,全然不顧架構(gòu)是否為相應(yīng)的目標(biāo)而做。
持續(xù)性由架構(gòu)師的地位決定。如果不能認(rèn)識(shí)“設(shè)計(jì)的一致性”,以及架構(gòu)師對(duì)這種一致性的權(quán)威,那么再好的架構(gòu)也會(huì)面臨解體,再長(zhǎng)遠(yuǎn)的架構(gòu)也會(huì)在短期內(nèi)被廢棄。架構(gòu)的實(shí)施是要以犧牲
自由性為代價(jià)的,架構(gòu)師沒(méi)有足夠的地位(或權(quán)威),則不可能對(duì)抗實(shí)施者對(duì)自由的渴望。通常的失敗,并在于架構(gòu)的好或壞,而是架構(gòu)被架空,形同虛設(shè)。
代價(jià)的問(wèn)題上面有過(guò)一點(diǎn)討論,但方向不同。這里說(shuō)明的是,如果架構(gòu)師沒(méi)有充分的經(jīng)驗(yàn),不能準(zhǔn)確評(píng)估所設(shè)計(jì)的架構(gòu)的資源消耗,那么可能在項(xiàng)目初起便存在設(shè)計(jì)失誤;也可能在項(xiàng)目中困于枝節(jié),或疏離關(guān)鍵,從而徒耗了資源。這些都是架構(gòu)師應(yīng)該預(yù)見(jiàn)、預(yù)估的。
對(duì)于企業(yè)設(shè)計(jì)來(lái)說(shuō),上面三個(gè)方面沒(méi)有得到關(guān)注的結(jié)果就是:遲遲無(wú)法上線(xiàn)的工程、半拉子工程和不停追加投資的工程項(xiàng)目。我不否認(rèn)項(xiàng)目經(jīng)理對(duì)這些問(wèn)題的影響,但事實(shí)上可能從設(shè)計(jì)就開(kāi)始出了問(wèn)題,而項(xiàng)目經(jīng)理只是回天乏術(shù)罷了。
最后說(shuō)明一下,我認(rèn)為目前大多數(shù)的企業(yè)項(xiàng)目都缺乏架構(gòu)上的考量。大多數(shù)軟件公司只是出于自身的需要(例如組件化和規(guī)模開(kāi)發(fā))而進(jìn)行架構(gòu)設(shè)計(jì)。這樣的設(shè)計(jì)不是面向客戶(hù)的,事實(shí)上這增加了客戶(hù)投資,而未能給客戶(hù)項(xiàng)目產(chǎn)生價(jià)值。這也是我強(qiáng)調(diào)架構(gòu)面向客戶(hù)的原因之一。
5 目前,你的團(tuán)隊(duì)在使用什么樣的產(chǎn)品或者方法來(lái)進(jìn)行軟件架構(gòu)設(shè)計(jì)?
架構(gòu)設(shè)計(jì)的主要輸出是文檔,因而并沒(méi)有什么特別的工具來(lái)幫助你做架構(gòu)設(shè)計(jì)。很多工具是輔助分析的,例如MindMananger;另外一些則可能輔助你表述,例如Together和Rose。
大多數(shù)技術(shù)出身的架構(gòu)師會(huì)僅把“軟件編寫(xiě)的東西”才稱(chēng)為工具。其實(shí)不然,會(huì)議室里的那面白板也是我的工具之一。放開(kāi)思路,市場(chǎng)規(guī)劃圖、技術(shù)架構(gòu)路標(biāo)圖、特性/收益規(guī)劃圖等等這些圖表也是我們的工具。除開(kāi)這些之外,模式語(yǔ)言和建模語(yǔ)言也是主要的、形式化的工具。
我經(jīng)常按RUP的規(guī)范寫(xiě)文檔,也偶爾放棄其中的某些具體格式。這些既有的文檔模板也是工具。當(dāng)然,毋庸置疑的是這樣的工具也包括WORD和PowerPoint——很多人并不知道,我有1/4的設(shè)計(jì)是先用PowerPoint/Visio來(lái)完成的。
具體到方法,則非常多了,但應(yīng)用哪一種則與場(chǎng)景有關(guān)。不過(guò)最先做的則是分層,這與自頂向下的結(jié)構(gòu)分析很象——事實(shí)上在分析和設(shè)計(jì)的最初階段,這種方法幾乎是必須的。
6,您覺(jué)得國(guó)內(nèi)外軟件架構(gòu)設(shè)計(jì)這個(gè)環(huán)節(jié)的主要不同在哪里?
正如你這個(gè)問(wèn)題所表現(xiàn)出來(lái)的一樣:我們太注重于工程環(huán)節(jié)的某個(gè)局部。
國(guó)外軟件行業(yè)在工程實(shí)踐經(jīng)驗(yàn)上已豐富得多,因此大多數(shù)程序員、項(xiàng)目經(jīng)理或測(cè)試人員等等對(duì)工程的理解也深刻得多。他們并不自恃于當(dāng)前的環(huán)節(jié),也不否認(rèn)其它環(huán)節(jié)。這意味著在整體實(shí)施?
中大家更容易達(dá)成一致。然而國(guó)內(nèi)的軟件工程則很少?gòu)?qiáng)調(diào)這種合作,項(xiàng)目經(jīng)理強(qiáng)調(diào)管理,程序員強(qiáng)調(diào)技術(shù),架構(gòu)師強(qiáng)調(diào)一致性和持續(xù)性,測(cè)試人員則很開(kāi)心的看到每一個(gè)錯(cuò)誤并以及數(shù)量作為評(píng)核依據(jù)。
顯然這里出了問(wèn)題:我們的合作環(huán)節(jié)在各自為戰(zhàn)。大家都在強(qiáng)調(diào)自己的重要性,于是工程就沒(méi)法做了。解決的法子,還是讓大家都意識(shí)到對(duì)方工作的目標(biāo)與職責(zé),而不僅僅是了解自己的那個(gè)小圈子。
7,可以介紹一下你目前的Qomo項(xiàng)目嗎?我們的網(wǎng)友該如何參與?
Qomo(Qomolangma OpenProject)是一個(gè)JavaScript上的開(kāi)源項(xiàng)目。目前Qomo 1.0正式版已經(jīng)發(fā)布了。Qomo V1以語(yǔ)言補(bǔ)實(shí)為基本思想,在JavaScript上擴(kuò)展了AOP、OOP、IOP和GP等編程方法,基于它自身的完備的實(shí)現(xiàn),Qomo也提供了Builder和Profiler工具和相關(guān)的庫(kù)。
Qomo V1只是整個(gè)Qomolangma OpenProject構(gòu)想中的一很小一部分——盡管它重要。Qomo項(xiàng)目提出的整體目標(biāo)是:?
-Qomo內(nèi)核是足夠強(qiáng)大的能應(yīng)用在不同的JavaScript宿主環(huán)境下的通用擴(kuò)展。?
-Qomo有能力提供膠合不同的應(yīng)用環(huán)境下功能需求的中間代碼。?
-Qomo可以作為定制的宿主應(yīng)用的代碼包的一個(gè)部分以提升應(yīng)用的體驗(yàn)或局部性能。
所以Qomo V1并不完備。即便是我們正在展開(kāi)的Qomo V2,也并不完備。V2計(jì)劃提供組件庫(kù)、數(shù)據(jù)庫(kù)存取層和圖形表現(xiàn)層。此外,Qomo V2也打算啟用數(shù)個(gè)實(shí)踐項(xiàng)目,一方面作為Qomo的范例,另一方面也驗(yàn)證Qomo的設(shè)計(jì)。
Qomo已經(jīng)在sourceforge上注冊(cè)過(guò),但在那里表現(xiàn)并不活躍。你可以總是從我的blog上得到Qomo的最新消息,包括Qomo的計(jì)劃與每個(gè)版本發(fā)布。至于參與這個(gè)項(xiàng)目,請(qǐng)發(fā)mail給我。
C++之設(shè)計(jì)模式實(shí)現(xiàn)代碼?
———————– Page 1———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附 C++實(shí)現(xiàn)源碼目 錄- 1
- 2
- 3
0 引言…………………………………………………………………………………………………………………………….2?
0.1 設(shè)計(jì)模式解析(總序)………………………………………………………………………………………..2?
0.2 設(shè)計(jì)模式解析后記……………………………………………………………………………………………….2?
0.3 與作者聯(lián)系…………………………………………………………………………………………………………5?
1 創(chuàng)建型模式…………………………………………………………………………………………………………………..5?
1.1 Factory模式 …………………………………………………………………………………………………………5?
1.2 AbstactFactory模式 ……………………………………………………………………………………………. 11?
1.3 Singleton模式…………………………………………………………………………………………………….16?
1.4 Builder模式………………………………………………………………………………………………………..18?
1.5 Prototype模式…………………………………………………………………………………………………….23?
2 結(jié)構(gòu)型模式…………………………………………………………………………………………………………………26?
2.1 Bridge模式…………………………………………………………………………………………………………26?
2.2 Adapter模式……………………………………………………………………………………………………….31?
2.3 Decorator模式…………………………………………………………………………………………………….35?
2.4 Composite模式…………………………………………………………………………………………………..40?
2.5 Flyweight模式 ……………………………………………………………………………………………………44?
2.6 Facade模式………………………………………………………………………………………………………..49?
2.7 Proxy模式………………………………………………………………………………………………………….52?
3 行為模式…………………………………………………………………………………………………………………….55?
3.1 Template模式……………………………………………………………………………………………………..55?
3.2 Strategy模式 ………………………………………………………………………………………………………59?
3.3 State模式……………………………………………………………………………………………………………63?
3.4 Observer模式……………………………………………………………………………………………………..68?
3.5 Memento模式…………………………………………………………………………………………………….73?
3.6 Mediator模式……………………………………………………………………………………………………..76?
3.7 Command模式……………………………………………………………………………………………………81?
3.8 Visitor模式…………………………………………………………………………………………………………87?
3.9 Chain of Responsibility模式…………………………………………………………………………………92?
3.10 Iterator模式………………………………………………………………………………………………………96?
3.11 Interpreter模式………………………………………………………………………………………………..100?
4 說(shuō)明 …………………………………………………………………………………………………………………………105
- 1
———————– Page 2———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
0 引言
0.1 設(shè)計(jì)模式解析(總序)
“Next to My Life, Software Is My Passion”——Robert C.Martin.懂了設(shè)計(jì)模式,你就懂了面向?qū)ο蠓治龊驮O(shè)計(jì)(OOA/D )的精要。反之好像也可能成- 1
- 2
- 3
立。道可道,非常道。道不遠(yuǎn)人,設(shè)計(jì)模式亦然如此。
一直想把自己的學(xué)習(xí)經(jīng)驗(yàn)以及在項(xiàng)目中的應(yīng)用經(jīng)歷拿出來(lái)和大家共享,卻總是下不了這- 1
個(gè)決心:GoF 的23 種模式研讀、總結(jié)也總需要些時(shí)日,然而時(shí)間對(duì)于我來(lái)說(shuō)總是不可預(yù)計(jì)
的。
之所以下了這個(gè)決心,有兩個(gè)原因:一是Robert 的箴言,二是因?yàn)槲沂且粋€(gè)感恩的人,- 1
就像常說(shuō)的:長(zhǎng)懷感恩之心,人生便無(wú)遺憾。想想當(dāng)時(shí)讀 GoF 的那本圣經(jīng)時(shí)候的苦悶、實(shí)
現(xiàn)23 個(gè)模式時(shí)候的探索、悟道后的欣悅,我覺(jué)得還是有這個(gè)意義。
0.2 設(shè)計(jì)模式解析后記
寫(xiě)完了Interpreter模式之后,我習(xí)慣性的看看下一天的安排,卻陡然發(fā)現(xiàn)GoF的 23個(gè)- 1
設(shè)計(jì)模式的解析已經(jīng)在我不經(jīng)意間寫(xiě)完了。就像在一年前看GoF的《設(shè)計(jì)模式》一書(shū),和半
年前用C++模擬、實(shí)現(xiàn) 23種經(jīng)典的設(shè)計(jì)模式一般,透過(guò)這個(gè)寫(xiě)解析的過(guò)程,我又看到了另外
一個(gè)境界。一直認(rèn)為學(xué)習(xí)的過(guò)程很多時(shí)候可以這樣劃分:自己學(xué)會(huì)一門(mén)知識(shí)(技術(shù))、表達(dá)
出來(lái)、教會(huì)別人、記錄下來(lái),雖然這個(gè)排序未必對(duì)每個(gè)人都合適 (因?yàn)榭赡懿煌擞兄煌?/p>
的特點(diǎn)能力)。學(xué)一門(mén)知識(shí),經(jīng)過(guò)努力、加以時(shí)日,總是可以達(dá)到的,把自己學(xué)的用自己的
話(huà)表達(dá)出來(lái)就必須要將學(xué)到的知識(shí)加以消化、理解,而教會(huì)一個(gè)不懂這門(mén)知識(shí)的人則比表達(dá)
出來(lái)要難,因?yàn)閯e人可能并不是適應(yīng)你的表述方式,記錄下來(lái)則需要經(jīng)過(guò)沉淀、積累、思考,
最后厚積薄發(fā),方可小成。
設(shè)計(jì)模式之于面向?qū)ο笙到y(tǒng)的設(shè)計(jì)和開(kāi)發(fā)的作用就有如數(shù)據(jù)結(jié)構(gòu)之于面向過(guò)程開(kāi)發(fā)的- 1
作用一般,其重要性和必要性自然不需要我贅述。然而學(xué)習(xí)設(shè)計(jì)模式的過(guò)程卻是痛苦的,從
閱讀設(shè)計(jì)模式的圣經(jīng)——GoF 的《設(shè)計(jì)模式:可復(fù)用面向?qū)ο筌浖幕A(chǔ)》時(shí)的枯燥、苦悶、
茫無(wú)頭緒,到有一天突然有一種頓悟;自己去實(shí)現(xiàn)GoF 的23 中模式時(shí)候的知其然不知其所
以然,并且有一天在自己設(shè)計(jì)的系統(tǒng)種由于設(shè)計(jì)的原因讓自己苦不堪言,突然悟到了設(shè)計(jì)模
第 2 頁(yè) 共 105 頁(yè) k_eckel- 1
———————– Page 3———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
式種的某一個(gè)正好可以很好的解決問(wèn)題,到自己設(shè)計(jì)的 elegant 的系統(tǒng)時(shí)候的喜悅與思考;
一直到最后向別人去講解設(shè)計(jì)模式,別人向你咨詢(xún)?cè)O(shè)計(jì)模式,和別人討論設(shè)計(jì)模式。就如
GoF 在其前言中說(shuō)到:一旦你理解了設(shè)計(jì)并且有了一種 “Aha!” (而不是 “Huh?”)的應(yīng)
用經(jīng)驗(yàn)和體驗(yàn)后,你將用一種非同尋常的方式思考面向?qū)ο笤O(shè)計(jì)。這個(gè)過(guò)程我認(rèn)為是漫長(zhǎng)的,
painful,但是是非常必要的。經(jīng)過(guò)了的才是自己的,Scott Mayer 在其巨著《Effective C++》
就曾經(jīng)說(shuō)過(guò):C++老手和C++新手的區(qū)別就是前者手背上有很多傷疤。是的在軟件開(kāi)發(fā)和設(shè)
計(jì)的過(guò)程中,失敗、錯(cuò)誤是最好的老師,當(dāng)然在系統(tǒng)開(kāi)發(fā)中,失敗和錯(cuò)誤則是噩夢(mèng)的開(kāi)端和
結(jié)束,因?yàn)槟愫茈y有改正錯(cuò)誤的機(jī)會(huì)。因此,盡量讓自己多幾道疤痕是對(duì)的。
面向?qū)ο笙到y(tǒng)的分析和設(shè)計(jì)實(shí)際上追求的就是兩點(diǎn),一是高內(nèi)聚 (Cohesion),而是低- 1
耦合 (Coupling)。這也是我們軟件設(shè)計(jì)所準(zhǔn)求的,因此無(wú)論是OO 中的封裝、繼承、多態(tài),
還是我們的設(shè)計(jì)模式的原則和實(shí)例都是在為了這兩個(gè)目標(biāo)努力著、貢獻(xiàn)著。
道不遠(yuǎn)人,設(shè)計(jì)模式也是這般,正如我在 《設(shè)計(jì)模式探索(總序)》中提到的。設(shè)計(jì)模- 1
式并不是空的理論,并不是脫離實(shí)際的教條。就如我們?cè)谶M(jìn)行軟件開(kāi)發(fā)的過(guò)程會(huì)很自然用到
很多的算法和結(jié)構(gòu)來(lái)解決實(shí)際的問(wèn)題,那些其實(shí)也就是數(shù)據(jù)結(jié)構(gòu)中的重要概念和內(nèi)容。在面
向?qū)ο笙到y(tǒng)的設(shè)計(jì)和開(kāi)發(fā)中,我們已經(jīng)積累了很多的原則,比如面向?qū)ο笾械姆庋b、繼承和
多態(tài)、面向接口編程、優(yōu)先使用組合而不是繼承、將抽象和實(shí)現(xiàn)分離的思想等等,在設(shè)計(jì)模
式中你總是能看到他們的影子,特別是組合 (委托)和繼承的差異帶來(lái)系統(tǒng)在耦合性上的差
別,更是在設(shè)計(jì)模式多次涉及到。而一些設(shè)計(jì)模式的思想在我們做系統(tǒng)的設(shè)計(jì)和開(kāi)發(fā)中則是
經(jīng)常要用到的,比如說(shuō)Template、Strategy模式的思想,Singleton模式的思想,Factory
模式的思想等等,還有很多的模式已經(jīng)在我們的開(kāi)發(fā)平臺(tái)中扎根了,比如說(shuō)Observer (其實(shí)
例為Model-Control-View模式)是MFC和Struts中的基本框架,Iterator模式則在C++的STL
中有實(shí)現(xiàn)等。或許有的人會(huì)說(shuō),我們不需要設(shè)計(jì)模式,我們的系統(tǒng)很小,設(shè)計(jì)模式會(huì)束縛我
們的實(shí)現(xiàn)。我想說(shuō)的是,設(shè)計(jì)模式體現(xiàn)的是一種思想,而思想則是指導(dǎo)行為的一切,理解和
掌握了設(shè)計(jì)模式,并不是說(shuō)記住了23種(或更多)設(shè)計(jì)場(chǎng)景和解決策略(實(shí)際上這也是很
重要的一筆財(cái)富),實(shí)際接受的是一種思想的熏陶和洗禮,等這種思想融入到了你的思想中
后,你就會(huì)不自覺(jué)地使用這種思想去進(jìn)行你的設(shè)計(jì)和開(kāi)發(fā),這一切才是最重要的。
之于學(xué)習(xí)設(shè)計(jì)模式的過(guò)程我想應(yīng)該是一個(gè)迭代的過(guò)程,我向來(lái)學(xué)東西的時(shí)候不追求一遍- 1
就掌握、理解透徹 (很多情況也是不可能的),我喜歡用一種迭代的思想來(lái)指導(dǎo)我的學(xué)習(xí)過(guò)
程。看書(shū)看不懂、思想沒(méi)有理解,可以反復(fù)去讀、去思考,我認(rèn)為這樣一個(gè)過(guò)程是適合向我
們不是有一個(gè)很統(tǒng)一的時(shí)間去學(xué)習(xí)一種技術(shù)和知識(shí)(可能那樣有時(shí)候反而有些枯燥和郁悶)。
第 3 頁(yè) 共 105 頁(yè) k_eckel- 1
———————– Page 4———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
GoF 在 《設(shè)計(jì)模式》一書(shū)中也提到,如果不是一個(gè)有經(jīng)驗(yàn)的面向?qū)ο笤O(shè)計(jì)人員,建議從最簡(jiǎn)
單最常用的設(shè)計(jì)模式入門(mén),比如AbstractFactory 模式、Adapater模式、Composite 模式、
Decorator 模式、Factory模式、Observer模式、Strategy 模式、Template 模式等。我的
感觸是確實(shí)是這樣,至少GoF 列出的模式我都在開(kāi)發(fā)和設(shè)計(jì)有用到,如果需要我這里再加上
幾個(gè)我覺(jué)得在開(kāi)發(fā)中會(huì)很有用的模式:Singleton模式、Fa?ade模式和Bridge 模式。
寫(xiě)設(shè)計(jì)模式解析的目的其實(shí)是想把GoF 的《設(shè)計(jì)模式》進(jìn)行簡(jiǎn)化,變得容易理解和接受。- 1
GoF 的 《設(shè)計(jì)模式》是圣經(jīng),但是同時(shí)因?yàn)?《設(shè)計(jì)模式》一書(shū)是4 位博士的作品,并且主要
是基于Erich 的博士論文,博士的特色我覺(jué)得最大的就是抽象,將一個(gè)具體的問(wèn)題抽象到一
般,形成理論。因此GoF 的這本圣經(jīng)在很多地方用語(yǔ)都比較精簡(jiǎn)和抽象,讀過(guò)的可能都有一
種確實(shí)是博士寫(xiě)出來(lái)的東西的感覺(jué)。抽象的好處是能夠提供指導(dǎo)性的意見(jiàn)和建議,其瑕疵就
是不容易為新手所理解和掌握。我的本意是想為抽象描述和具體的實(shí)現(xiàn)提供一個(gè)橋接 (盡管
GoF 在書(shū)中給出了很多的代碼和實(shí)例,但是我覺(jué)得有兩個(gè)不足:一是不完整,結(jié)果是不好直
接看到演示,因此我給出的代碼都是完整的、可編譯運(yùn)行的;二是給出的都是一些比較大的
系統(tǒng)中一部分簡(jiǎn)單實(shí)現(xiàn),我想GoF 的原意可能是想說(shuō)明這些模式確實(shí)很管用,但是卻同時(shí)帶
來(lái)一個(gè)更大的不好的地方就是不容易為新手理解和掌握),然而這個(gè)過(guò)程是痛苦的,也可能
是不成功的 (可能會(huì)是這樣)。這里面就有一個(gè)取舍的問(wèn)題,一方面我想盡量去簡(jiǎn)化GoF
的描述,然而思考后的東西卻在很多的時(shí)候和GoF 的描述很相似,并且覺(jué)得將這些內(nèi)容再抽
象一下,書(shū)中的很多表達(dá)則是最為經(jīng)典的。當(dāng)然這里面也有些許的例外,Bruce Eckel 在其
大作《Thinking in Patterns》一書(shū)中提到:Bridge 模式是GoF 在描述其 23 中設(shè)計(jì)模式中
描述得最為糟糕得模式,于我心有戚戚焉!具體的內(nèi)容請(qǐng)參看我寫(xiě)的《設(shè)計(jì)模式解析——
Bridge 模式》一文。另外一方面,我又要盡量去避免走到了GoF 一起,因?yàn)槟菢泳褪チ?/p>
我寫(xiě)這個(gè)解析的本意了。這兩個(gè)方面的權(quán)衡是很痛苦,并且結(jié)果可能也還是沒(méi)有達(dá)到我的本
意要求。
4 月份是我最不忙的時(shí)候,也是我非常忙的時(shí)候。論文的查閱、思考、撰寫(xiě),幾個(gè)項(xiàng)目- 1
的前期準(zhǔn)備 (文檔、Demo等),俱樂(lè)部的諸多事宜,挑戰(zhàn)杯的準(zhǔn)備,學(xué)習(xí) (課業(yè)、專(zhuān)業(yè)等各
個(gè)方面)等等,更加重要的是Visual CMCS (Visual C_minus Compiler System)的設(shè)
計(jì)和開(kāi)發(fā)(Visual CMCS是筆者設(shè)計(jì)和開(kāi)發(fā)的C_minus語(yǔ)言(C的子集)的編譯系統(tǒng),系統(tǒng)操
作界面類(lèi)似VC,并且準(zhǔn)備代碼分發(fā)和共享,詳細(xì)信息請(qǐng)參考Visual CMCS的網(wǎng)站和Blog中的
相關(guān)信息的發(fā)布), Visual CMCS1.0(Beta)終于在4 月底發(fā)布了,也在別人的幫助下構(gòu)建
http://cs.whu.edu.cn/cmcs )。之所以提及這個(gè),一方面是在Visual CMCS- 1
了Visual CMCS的網(wǎng)站(
第 4 頁(yè) 共 105 頁(yè) k_eckel- 1
———————– Page 5———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
的設(shè)計(jì)和開(kāi)發(fā)體驗(yàn)了很多的設(shè)計(jì)模式,比如Factoty模式、Singleton模式、Strategy模式、
State模式等等(我有一篇Blog中有關(guān)于這個(gè)的不完全的描述);另外一方面是這個(gè)設(shè)計(jì)模
式解析實(shí)際上在這些工作的間隙中完成的,我一般會(huì)要求自己每天寫(xiě)一個(gè)模式,但是特殊的
時(shí)候可能沒(méi)有寫(xiě)或者一天寫(xiě)了不止一個(gè)。寫(xiě)這些文章,本身沒(méi)有任何功利的雜念,只是一個(gè)
原生態(tài)的沖動(dòng),反而很輕松的完成了。有心栽花未必發(fā),無(wú)心之事可成功,世間的事情可能
在很多的時(shí)候恰恰就是那樣了。
最后想用自己在閱讀、學(xué)習(xí)、理解、實(shí)現(xiàn)、應(yīng)用、思考設(shè)計(jì)模式后的一個(gè)感悟結(jié)束這個(gè)- 1
后記:只有真正理解了設(shè)計(jì)模式,才知道什么叫面向?qū)ο蠓治龊驮O(shè)計(jì)。
k_eckel 寫(xiě)畢于2005-05-04 (五四青年節(jié)) 1 :01- 1
0.3 與作者聯(lián)系
Author K_EckelState Candidate for Master’s Degree School of Computer Wuhan UniversityE_mail frwei@whu.edu.cn- 1
- 2
- 3
- 4
- 5
1 創(chuàng)建型模式
1.1 Factory 模式
問(wèn)題
在面向?qū)ο笙到y(tǒng)設(shè)計(jì)中經(jīng)常可以遇到以下的兩類(lèi)問(wèn)題:1 )為了提高內(nèi)聚(Cohesion)和松耦合(Coupling ),我們經(jīng)常會(huì)抽象出一些類(lèi)的公共- 1
- 2
- 3
接口以形成抽象基類(lèi)或者接口。這樣我們可以通過(guò)聲明一個(gè)指向基類(lèi)的指針來(lái)指向?qū)嶋H的子
類(lèi)實(shí)現(xiàn),達(dá)到了多態(tài)的目的。這里很容易出現(xiàn)的一個(gè)問(wèn)題n 多的子類(lèi)繼承自抽象基類(lèi),我們
不得不在每次要用到子類(lèi)的地方就編寫(xiě)諸如 new ×××;的代碼。這里帶來(lái)兩個(gè)問(wèn)題 1)客
戶(hù)程序員必須知道實(shí)際子類(lèi)的名稱(chēng) (當(dāng)系統(tǒng)復(fù)雜后,命名將是一個(gè)很不好處理的問(wèn)題,為了
處理可能的名字沖突,有的命名可能并不是具有很好的可讀性和可記憶性,就姑且不論不同
程序員千奇百怪的個(gè)人偏好了。),2)程序的擴(kuò)展性和維護(hù)變得越來(lái)越困難。
第 5 頁(yè) 共 105 頁(yè) k_eckel- 1
———————– Page 6———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
2 )還有一種情況就是在父類(lèi)中并不知道具體要實(shí)例化哪一個(gè)具體的子類(lèi)。這里的意思- 1
為:假設(shè)我們?cè)陬?lèi)A 中要使用到類(lèi)B,B 是一個(gè)抽象父類(lèi),在 A 中并不知道具體要實(shí)例化
那一個(gè)B 的子類(lèi),但是在類(lèi)A 的子類(lèi)D 中是可以知道的。在A(yíng) 中我們沒(méi)有辦法直接使用類(lèi)
似于new ×××的語(yǔ)句,因?yàn)楦揪筒恢馈痢痢潦鞘裁础?/p> 以上兩個(gè)問(wèn)題也就引出了Factory 模式的兩個(gè)最重要的功能:1 )定義創(chuàng)建對(duì)象的接口,封裝了對(duì)象的創(chuàng)建;2 )使得具體化類(lèi)的工作延遲到了子類(lèi)中。
- 1
- 2
- 3
- 4
- 5
模式選擇
我們通常使用Factory 模式來(lái)解決上面給出的兩個(gè)問(wèn)題。在第一個(gè)問(wèn)題中,我們經(jīng)常就- 1
是聲明一個(gè)創(chuàng)建對(duì)象的接口,并封裝了對(duì)象的創(chuàng)建過(guò)程。Factory 這里類(lèi)似于一個(gè)真正意義
上的工廠(chǎng)(生產(chǎn)對(duì)象)。在第二個(gè)問(wèn)題中,我們需要提供一個(gè)對(duì)象創(chuàng)建對(duì)象的接口,并在子
類(lèi)中提供其具體實(shí)現(xiàn)(因?yàn)橹挥性谧宇?lèi)中可以決定到底實(shí)例化哪一個(gè)類(lèi))。
第一中情況的Factory 的結(jié)構(gòu)示意圖為:圖1:Factory 模式結(jié)構(gòu)示意圖 1圖 1 所以的Factory 模式經(jīng)常在系統(tǒng)開(kāi)發(fā)中用到,但是這并不是 Factory 模式的最大威- 1
- 2
- 3
- 4
- 5
力所在 (因?yàn)檫@可以通過(guò)其他方式解決這個(gè)問(wèn)題)。Factory 模式不單是提供了創(chuàng)建對(duì)象的接
口,其最重要的是延遲了子類(lèi)的實(shí)例化(第二個(gè)問(wèn)題),以下是這種情況的一個(gè) Factory 的
結(jié)構(gòu)示意圖:
第 6 頁(yè) 共 105 頁(yè) k_eckel- 1
———————– Page 7———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
圖2:Factory 模式結(jié)構(gòu)示意圖 1圖2 中關(guān)鍵中Factory 模式的應(yīng)用并不是只是為了封裝對(duì)象的創(chuàng)建,而是要把對(duì)象的創(chuàng)- 1
- 2
- 3
建放到子類(lèi)中實(shí)現(xiàn):Factory 中只是提供了對(duì)象創(chuàng)建的接口,其實(shí)現(xiàn)將放在 Factory 的子類(lèi)
ConcreteFactory 中進(jìn)行。這是圖2 和圖 1 的區(qū)別所在。
實(shí)現(xiàn)
完整代碼示例(code)
Factory 模式的實(shí)現(xiàn)比較簡(jiǎn)單,這里為了方便初學(xué)者的學(xué)習(xí)和參考,將給出完整的實(shí)現(xiàn)- 1
代碼(所有代碼采用 C++實(shí)現(xiàn),并在VC 6.0 下測(cè)試運(yùn)行)。
第 7 頁(yè) 共 105 頁(yè) k_eckel- 1
———————– Page 8———————–
設(shè)計(jì)模式精解-GoF 23 種設(shè)計(jì)模式解析附C++實(shí)現(xiàn)源碼http://www.mscenter.edu.cn/blog/k_eckel
代碼片斷 1:Product.h 代碼片斷2:Product.cpp- 1
//Product.h //Product.cpp
#ifndef?PRODUCT_H?#include “Product.h”
#define?PRODUCT_H
#include <iostream>- 1
class Product using namespace std;
{
public: Product::Product()
virtual ~Product() = 0; {- 1
protected: }
Product();Product::~Product()- 1
- 2
- 3
private: {
}; }
class ConcreteProduct:public Product ConcreteProduct::ConcreteProduct()
{ {
public: cout<<”ConcreteProduct….”<
總結(jié)
- 上一篇: 基于VLC的本地视频播放器
- 下一篇: SSM框架,ajax实现登陆界面验证和登