日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

架构设计方法学

發布時間:2023/12/14 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 架构设计方法学 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

架構設計的方法學

約公元前25年,古羅馬建筑師維特魯威說:“理想的建筑師應該既是文學家又是數字家,他還應通曉歷史,熱衷于哲學研究,精通音樂,懂得醫藥知識,具有法學造詣,深諳天文學及天文計算?!?#xff08;好難哪,軟件構架設計師的要求呢?大家好好想想吧。)?
本文目錄?
一、與構架有關的幾個基本概念;?
二、構架設計應考慮的因素概攬;?
三、程序的運行時結構方面的考慮;?
四、源代碼的組織結構方面的考慮;?
五、寫系統構架設計文檔應考慮的問題?
六、結語?
一、與構架有關的幾個基本概念:?
1、模塊(module):一組完成指定功能的語句,包括:輸入、輸出、邏輯處理功能、內部信息、運行環境(與功能對應但不是一對一關系)。?
2、組件(component):系統中相當重要的、幾乎是獨立的可替換部分,它在明確定義的構架環境中實現確切的功能。?
3、模式(pattern):指經過驗證,至少適用于一種實用環境(更多時候是好幾種環境)的解決方案模板(用于結構和行為。在 UML中:模式由參數化的協作來表示,但 UML 不直接對模式的其他方面(如使用結果列表、使用示例等,它們可由文本來表示)進行建模。存在各種范圍和抽象程度的模式,例如,構架模式、分析模式、設計模式和代碼模式或實施模式。模式將可以幫助我們抓住重點。構架也是存在模式的。比如,對于系統結構設計,我們使用層模式;對于分布式系統,我們使用代理模式(通過使用代理來替代實際的對象,使程序能夠控制對該對象的訪問);對于交互系統,我們使用MVC(M模型(對象)/V視圖(輸出管理)/C控制器(輸入處理))模式。模式是針對特定問題的解,因此,我們也可以針對需求的特點采用相應的模式來設計構架。?
4、構架模式(architectural pattern):表示軟件系統的基本結構組織方案。它提供了一組預定義的子系統、指定它們的職責,并且包括用于組織其間關系的規則和指導。?
5、層(layer):對模型中同一抽象層次上的包進行分組的一種特定方式。通過分層,從邏輯上將子系統劃分成許多集合,而層間關系的形成要遵循一定的規則。通過分層,可以限制子系統間的依賴關系,使系統以更松散的方式耦合,從而更易于維護。(層是對構架的橫向劃分,分區是對構架的縱向劃分)。?
6、系統分層的幾種常用方法:?
1) 常用三層服務:用戶層、業務邏輯層、數據層;?
2) 多層結構的技術組成模型:表現層、中間層、數據層;?
3) 網絡系統常用三層結構:核心層、匯聚層和接入層;?
4) RUP典型分層方法:應用層、專業業務層、中間件層、系統軟件層;?
5) 基于Java的B/S模式系統結構:瀏覽器端、服務器端、請求接收層、請求處理層;?
6) 某六層結構:功能層(用戶界面)、模塊層、組裝層(軟件總線)、服務層(數據處理)、數據層、核心層;?
7、構架(Architecture,愿意為建筑學設計和建筑物建造的藝術與科學): 在RUP中的定義:軟件系統的構架(在某一給定點)是指系統重要構件的組織或結構,這些重要構件通過接口與不斷減小的構件與接口所組成的構件進行交互;《軟件構架實踐》中的定義:某個軟件或者計算系統的軟件構架即組成該系統的一個或者多個結構,他們組成軟件的各個部分,形成這些組件的外部可見屬性及相互間的聯系;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,構架是系統在其所處環境中的最高層次的概念。軟件系統的構架是通過接口交互的重要構件(在特定時間點)的組織或結構,這些構件又由一些更小的構件和接口組成。(“構架”可以作為名詞,也可作為動詞,作為動詞的“構架”相當于“構架設計”)?
8、構架的描述方式:“4+1”視圖(用例視圖、設計視圖、實現視圖、過程視圖、配置視圖)是一個被廣為使用的構架描述的模型;RUP過程的構架描述模板在“4+1”視圖的基礎上增加了可選的數據視圖(從永久性數據存儲方面來對系統進行說明);HP公司的軟件描述模板也是基于“4+1”視圖。?
9、結構:軟件構架是多種結構的體現,結構是系統構架從不同角度觀察所產生的視圖。就像建筑物的結構會隨著觀察動機和出發點的不同而有多種含義一樣,軟件構架也表現為多種結構。常見的軟件結構有:模塊結構、邏輯或概念結構、進程或協調結構、物理結構、使用結構、調用結構、數據流、控制流、類結構等等。?
二、構架設計應考慮的因素概攬:?
模塊構架設計可以從程序的運行時結構和源代碼的組織結構方面考慮。?
1、程序的運行時結構方面的考慮:?
1) 需求的符合性:正確性、完整性;功能性需求、非功能性需求;?
2) 總體性能(內存管理、數據庫組織和內容、非數據庫信息、任務并行性、網絡多人操作、關鍵算法、與網絡、硬件和其他系統接口對性能的影響);?
3) 運行可管理性:便于控制系統運行、監視系統狀態、錯誤處理;模塊間通信的簡單性;與可維護性不同;?
4) 與其他系統接口兼容性;?
5) 與網絡、硬件接口兼容性及性能;?
6) 系統安全性;?
7) 系統可靠性;?
8) 業務流程的可調整性;?
9) 業務信息的可調整性?
10) 使用方便性?
11) 構架樣式的一致性?
注:運行時負載均衡可以從系統性能、系統可靠性方面考慮。?
2、源代碼的組織結構方面的考慮:?
1) 開發可管理性:便于人員分工(模塊獨立性、開發工作的負載均衡、進度安排優化、預防人員流動對開發的影響)、利于配置管理、大小的合理性與適度復雜性;?
2) 可維護性:與運行可管理性不同;?
3) 可擴充性:系統方案的升級、擴容、擴充性能;?
4) 可移植性:不同客戶端、應用服務器、數據庫管理系統;?
5) 需求的符合性(源代碼的組織結構方面的考慮)。?
三、程序的運行時結構方面的考慮:?
1、 需求的符合性:正確性、完整性;功能性需求、非功能性需求?
軟件項目最主要的目標是滿足客戶需求。在進行構架設計的時候,大家考慮更多的是使用哪個運行平臺、編成語言、開發環境、數據庫管理系統等問題,對于和客戶需求相關的問題考慮不足、不夠系統。如果無論怎么好的構架都無法滿足客戶明確的某個功能性需求或非功能性需求,就應該與客戶協調在項目范圍和需求規格說明書中刪除這一需求。否則,架構設計應以滿足客戶所有明確需求為最基本目標,盡量滿足其隱含的需求。(客戶的非功能性需求可能包括接口、系統安全性、可靠性、移植性、擴展性等等,在其他小節中細述)?
一般來說,功能需求決定業務構架、非功能需求決定技術構架,變化案例決定構架的范圍。需求方面的知識告訴我們,功能需求定義了軟件能夠做些什么。我們需要根據業務上的需求來設計業務構架,以使得未來的軟件能夠滿足客戶的需要。非功能需求定義了一些性能、效率上的一些約束、規則。而我們的技術構架要能夠滿足這些約束和規則。變化案例是對未來可能發生的變化的一個估計,結合功能需求和非功能需求,我們就可以確定一個需求的范圍,進而確定一個構架的范圍。(此段From林星)?
這里講一個前幾年因客戶某些需求錯誤造成構架設計問題而引起系統性能和可靠性問題的小小的例子:此系統的需求本身是比較簡單的,就是將某城市的某業務的全部歷史檔案卡片掃描存儲起來,以便可以按照姓名進行查詢。需求階段客戶說卡片大約有20萬張,需求調研者出于對客戶的信任沒有對數據的總量進行查證。由于是中小型數據量,并且今后數據不會增加,經過計算20萬張卡片總體容量之后,決定使用一種可以單機使用也可以聯網的中小型數據庫管理系統。等到系統完成開始錄入數據時,才發現數據至少有60萬,這樣使用那種中小型數據庫管理系統不但會造成系統性能的問題,而且其可靠性是非常脆弱的,不得不對系統進行重新設計。從這個小小的教訓可以看出,需求階段不僅對客戶的功能需求要調查清楚,對于一些隱含非功能需求的一些數據也應當調查清楚,并作為構架設計的依據。?
對于功能需求的正確性,在構架設計文檔中可能不好驗證(需要人工、費力)。對于功能需求完整性,就應當使用需求功能與對應模塊對照表來跟蹤追溯。對于非功能需求正確性和完整性,可以使用需求非功能與對應設計策略對照表來跟蹤追溯評估。?
“軟件設計工作只有基于用戶需求,立足于可行的技術才有可能成功。”?
2、 總體性能?
性能其實也是客戶需求的一部分,當然可能是明確的,也有很多是隱含的,這里把它單獨列出來在說明一次。性能是設計方案的重要標準,性能應考慮的不是單臺客戶端的性能,而是應該考慮系統總的綜合性能;?
性能設計應從以下幾個方面考慮:內存管理、數據庫組織和內容、非數據庫信息、任務并行性、網絡多人操作、關鍵算法、與網絡、硬件和其他系統接口對性能的影響;?
幾點提示:算法優化及負載均衡是性能優化的方向。經常要調用的模塊要特別注意優化。占用內存較多的變量在不用時要及時清理掉。需要下載的網頁主題文件過大時應當分解為若干部分,讓用戶先把主要部分顯示出來。?
3、 運行可管理性?
系統的構架設計應當為了使系統可以預測系統故障,防患于未然。現在的系統正逐步向復雜化、大型化發展,單靠一個人或幾個人來管理已顯得力不從心,況且對于某些突發事件的響應,人的反應明顯不夠。因此通過合理的系統構架規劃系統運行資源,便于控制系統運行、監視系統狀態、進行有效的錯誤處理;為了實現上述目標,模塊間通信應當盡可能簡單,同時建立合理詳盡的系統運行日志,系統通過自動審計運行日志,了解系統運行狀態、進行有效的錯誤處理;(運行可管理性與可���護性不同)?
4、 與其他系統接口兼容性(解釋略)?
5、 與網絡、硬件接口兼容性及性能(解釋略)?
6、 系統安全性?
隨著計算機應用的不斷深入和擴大,涉及的部門和信息也越來越多,其中有大量保密信息在網絡上傳輸,所以對系統安全性的考慮已經成為系統設計的關鍵,需要從各個方面和角度加以考慮,來保證數據資料的絕對安全。?
7、 系統可靠性?
系統的可靠性是現代信息系統應具有的重要特征,由于人們日常的工作對系統依賴程度越來越多,因此系統的必須可靠。系統構架設計可考慮系統的冗余度,盡可能地避免單點故障。系統可靠性是系統在給定的時間間隔及給定的環境條件下,按設計要求,成功地運行程序的概率。成功地運行不僅要保證系統能正確地運行,滿足功能需求,還要求當系統出現意外故障時能夠盡快恢復正常運行,數據不受破壞。?
8、 業務流程的可調整性?
應當考慮客戶業務流程可能出現的變化,所以在系統構架設計時要盡量排除業務流程的制約,即把流程中的各項業務結點工作作為獨立的對象,設計成獨立的模塊或組件,充分考慮他們與其他各種業務對象模塊或組件的接口,在流程之間通過業務對象模塊的相互調用實現各種業務,這樣,在業務流程發生有限的變化時(每個業務模塊本身的業務邏輯沒有變的情況下),就能夠比較方便地修改系統程序模塊或組件間的調用關系而實現新的需求。如果這種調用關系被設計成存儲在配置庫的數據字典里,則連程序代碼都不用修改,只需修改數據字典里的模塊或組件調用規則即可。?
9、 業務信息的可調整性?
應當考慮客戶業務信息可能出現的變化,所以在系統構架設計時必須盡可能減少因為業務信息的調整對于代碼模塊的影響范圍。?
10、 使用方便性?
使用方便性是不須提及的必然的需求,而使用方便性與系統構架是密切相關的。WinCE(1.0)的失敗和后來改進版本的成功就說明了這個問題。WinCE(1.0)有太多層次的視窗和菜單,而用戶則更喜歡簡單的界面和快捷的操作。失敗了應當及時糾正,但最好不要等到失敗了再來糾正,這樣會浪費巨大的財力物力,所以在系統構架階段最好能將需要考慮的因素都考慮到。當然使用方便性必須與系統安全性協調平衡統一,使用方便性也必須與業務流程的可調整性和業務信息的可調整性協調平衡統一?!皾M足用戶的需求,便于用戶使用,同時又使得操作流程盡可能簡單。這就是設計之本?!?
11、構架樣式的一致性?
軟件系統的構架樣式有些類似于建筑樣式(如中國式、哥特式、希臘復古式)。軟件構架樣式可分為數據流構架樣式、調用返回構架樣式、獨立組件構架樣式、以數據為中心的構架樣式和虛擬機構架樣式,每一種樣式還可以分為若干子樣式。構架樣式的一致性并不是要求一個軟件系統只能采用一種樣式,就像建筑樣式可以是中西結合的,軟件系統也可以有異質構架樣式(分為局部異質、層次異質、并行異質),即多種樣式的綜合,但這樣的綜合應該考慮其某些方面的一致性和協調性。每一種樣式都有其使用的時機,應當根據系統最強調的質量屬性來選擇。?
四、源代碼的組織結構方面的考慮:?
1、 開發可管理性?
便于人員分工(模塊獨立性、開發工作的負載均衡、進度安排優化、預防人員流動對開發的影響:一個好的構架同時應有助于減少項目組的壓力和緊張,提高軟件開發效率)、利于配置管理、大小的合理性、適度復雜性;?
1)便于人員分工-模塊獨立性、層次性?
模塊獨立性、層次性是為了保證項目開發成員工作之間的相對獨立性,模塊聯結方式應該是縱向而不是橫向, 模塊之間應該是樹狀結構而不是網狀結構或交叉結構,這樣就可以把開發人員之間的通信、模塊開發制約關系減到最少。同時模塊獨立性也比較利于配置管理工作的進行。現在有越來越多的的軟件開發是在異地進行,一個開發組的成員可能在不同城市甚至在不同國家,因此便于異地開發的人員分工與配置管理的源代碼組織結構是非常必要的。?
2)便于人員分工-開發工作的負載均衡?
不僅僅是開發出來的軟件系統需要負載均衡,在開發過程中開發小組各成員之間工作任務的負載均衡也是非重要的。所謂工作任務的負載均衡就是通過合理的任務劃分按照開發人員特點進行分配任務,盡量讓項目組中的每個人每段時間都有用武之地。這就需要在構架設計時應當充分考慮項目組手頭的人力資源,在實現客戶需求的基礎上實現開發工作的負載均衡,以提高整體開發效率。?
3)便于人員分工-進度安排優化;?
進度安排優化的前提是模塊獨立性并搞清楚模塊開發的先后制約關系。利用工作分解結構對所有程序編碼工作進行分解,得到每一項工作的輸入、輸出、所需資源、持續時間、前期應完成的工作、完成后可以進行的工作。然后預估各模塊需要時間,分析各模塊的并行與串行(順序制約),繪制出網絡圖,找出影響整體進度的關鍵模塊,算出關鍵路徑,最后對網絡圖進行調整,以使進度安排最優化。?
有個家喻戶曉的智力題叫烤肉片策略:約翰遜家戶外有一個可以同時烤兩塊肉片的烤肉架,烤每塊肉片的每一面需要10分鐘,現要烤三塊肉片給饑腸轆轆急不可耐的一家三口。問題是怎樣才能在最短的時間內烤完三片肉。一般的做法花20分鐘先烤完前兩片,再花20分鐘烤完第三片。有一種更好的方法可以節省10分鐘,大家想想。?
4)便于人員分工-預防員工人員流動對開發的影響?
人員流動在軟件行業是司空見慣的事情,已經是一個常見的風險。作為對這一風險的有效的防范對策之一,可以在構架設計中考慮到并預防員工人員流動對開發的影響。主要的思路還是在模塊的獨立性上(追求高內聚低耦合),組件化是目前流行的趨勢。?
5)利于配置管理(獨立性、層次性)?
利于配置管理與利于人員分工有一定的聯系。除了邏輯上的模塊組件要利于人員分工外,物理上的源代碼層次結構、目錄結構、各模塊所處源代碼文件的部署也應當利于人員分工和配置管理。(盡管現在配置管理工具有較強大的功能,但一個清楚的源碼分割和模塊分割是非常有好處的)。?
6)大小的合理性與適度復雜性?
大小的合理性與適度復雜性可以使開發工作的負載均衡,便于進度的安排,也可以使系統在運行時減少不必要的內存資源浪費。對于代碼的可閱讀性和系統的可維護性也有一定的好處。另外,過大的模塊常常是系統分解不充分,而過小的模塊有可能降低模塊的獨立性,造成系統接口的復雜。?
2、 可維護性?
便于在系統出現故障時及時方便地找到產生故障的原因和源代碼位置,并能方便地進行局部修改、切割;(可維護性與運行可管理性不同)?
3、 可擴充性:系統方案的升級、擴容、擴充性能?
系統在建成后會有一段很長的運行周期,在該周期內,應用在不斷增加,應用的層次在不斷升級,因此采用的構架設計等方案因充分考慮升級、擴容、擴充的可行性和便利?
4、 可移植性?
不同客戶端、應用服務器、數據庫管理系統:如果潛在的客戶使用的客戶端可能使用不同的操作系統或瀏覽器,其可移植性必須考慮客戶端程序的可移植性,或盡量不使業務邏輯放在客戶端;數據處理的業務邏輯放在數據庫管理系統中會有較好的性能,但如果客戶群中不能確定使用的是同一種數據庫管理系統,則業務邏輯就不能數據庫管理系統中;?
達到可移植性一定要注重標準化和開放性:只有廣泛采用遵循國際標準,開發出開放性強的產品,才可以保證各種類型的系統的充分互聯,從而使產品更具有市場競爭力,也為未來的系統移植和升級擴展提供了基礎。?
5、 需求的符合性?
從源代碼的組織結構看需求的符合型主要考慮針對用戶需求可能的變化的軟件代碼及構架的最小冗余(同時又要使得系統具有一定的可擴展性)。?
五、寫系統構架設計文檔應考慮的問題?
構架工作應該在需求開發完成約80%的時候開始進行,不必等到需求開發全部完成,需要項目經理以具體的判斷來評估此時是否足以開始構建軟件構架。?
給出一致的輪廓:系統概述。一個系統構架需要現有概括的描述,開發人員才能從上千個細節甚至數十個模塊或對象類中建立一致的輪廓。?
構架的目標應該能夠清楚說明系統概念,構架應盡可能簡化,最好的構架文件應該簡單、簡短,清晰而不雜亂,解決方案自然。?
構架應單先定義上層的主要子系統,應該描述各子系統的任務,并提供每個子系統中各模塊或對象類的的初步列表。?
構架應該描述不同子系統間相互通信的方式,而一個良好的構架應該將子系統間的通信關系降到最低。?
成功構架的一個重要特色,在于標明最可能變更的領域,應當列出程序中最可能變更的部分,說明構架的其他部分如何應變。?
復用分析、外購:縮短軟件開發周期、降低成本的有效方案未必是自行開發軟件,可以對現有軟件進行復用或進行外購。應考慮其對構架的影響。?
除了系統組織的問題,構架應重點考慮對于細節全面影響的設計決策,深入這些決策領域:外部軟件接口(兼容性、通信方式、傳遞數據結構)、用戶接口(用戶接口和系統層次劃分)、數據庫組織和內容、非數據庫信息、關鍵算法、內存管理(配置策略)、并行性、安全性、可移植性、網絡多人操作、錯誤處理。?
要保證需求的可追蹤性,即保證每個需求功能都有相應模塊去實現。?
構架不能只依據靜態的系統目標來設計,也應當考慮動態的開發過程,如人力資源的情況,進度要求的情況,開發環境的滿足情況。構架必須支持階段性規劃,應該能夠提供階段性規劃中如何開發與完成的方式。不應該依賴無法獨立運行的子系統構架。將系統各部分的、依賴關系找出來,形成一套開發計劃。?
六、結語?
系統構架設計和千差萬別的具體的開發平臺密切相關,因此在此無法給出通用的解決方案,主要是為了說明哪些因素是需要考慮的。對于每個因素的設計策略和本文未提到的因素需要軟件構架設計師在具體開發實踐中靈活把握。不同因素之間有時是矛盾的,構架設計時需要根據具體情況進行平衡。

架構設計中的方法學?
架構設計是一種權衡(trade-off)。一個問題總是有多種的解決方案。而我們要確定唯一的架構設計的解決方案,就意味著我們要在不同的矛盾體之間做出一個權衡。我們在設計的過程總是可以看到很多的矛盾體:開放和整合,一致性和特殊化,穩定性和延展性等等。任何一對矛盾體都源于我們對軟件的不同期望??墒?#xff0c;要滿足我們希望軟件穩定運行的要求,就必然會影響我們對軟件易于擴展的期望。我們希望軟件簡單明了,卻增加了我們設計的復雜度。沒有一個軟件能夠滿足所有的要求,因為這些要求之間帶有天生的互斥性。而我們評價架構設計的好壞的依據,就只能是根據不同要求的輕重緩急,在其間做出權衡的合理性。

  • 目標?
    我們希望一個好的架構能夠:
  • 重用:為了避免重復勞動,為了降低成本,我們希望能夠重用之前的代碼、之前的設計。重用是我們不斷追求的目標之一,但事實上,做到這一點可沒有那么容易。在現實中,人們已經在架構重用上做了很多的工作,工作的成果稱為框架(Framework),比如說Windows的窗口機制、J2EE平臺等。但是在企業商業建模方面,有效的框架還非常的少。?
    透明:有些時候,我們為了提高效率,把實現的細節隱藏起來,僅把客戶需求的接口呈現給客戶。這樣,具體的實現對客戶來說就是透明的。一個具體的例子是我們使用JSP的tag技術來代替JSP的嵌入代碼,因為我們的HTML界面人員更熟悉tag的方式。?
    延展:我們對延展的渴求源于需求的易變。因此我們需要架構具有一定的延展性,以適應未來可能的變化??墒?#xff0c;如上所說,延展性和穩定性,延展性和簡單性都是矛盾的。因此我們需要權衡我們的投入/產出比。以設計出具有適當和延展性的架構。?
    簡明:一個復雜的架構不論是測試還是維護都是困難的。我們希望架構能夠在滿足目的的情況下盡可能的簡單明了。但是簡單明了的含義究竟是什么好像并沒有一個明確的定義。使用模式能夠使設計變得簡單,但這是建立在我熟悉設計模式的基礎上。對于一個并不懂設計模式的人,他會認為這個架構很復雜。對于這種情況,我只能對他說,去看看設計模式。?
    高效:不論是什么系統,我們都希望架構是高效的。這一點對于一些特定的系統來說尤其重要。例如實時系統、高訪問量的網站。這些值的是技術上的高效,有時候我們指的高效是效益上的高效。例如,一個只有幾十到一百訪問量的信息系統,是不是有必要使用EJB技術,這就需要我們綜合的評估效益了。?
    安全:安全并不是我們文章討論的重點,卻是架構的一個很重要的方面。

    規則

    為了達到上述的目的,我們通常需要對架構設計制定一些簡單的規則:

    功能分解

    顧名思義,就是把功能分解開來。為什么呢?我們之所以很難達到重用目標就是因為我們編寫的程序經常處于一種好像是重復的功能,但又有輕微差別的狀態中。我們很多時候就會經不住誘惑,用拷貝粘貼再做少量修改的方式完成一個功能。這種行為在XP中是堅決不被允許的。XP提倡”Once and only once”,目的就是為了杜絕這種拷貝修改的現象。為了做到這一點,我們通常要把功能分解到細粒度。很多的設計思想都提倡小類,為的就是這個目的。

    所以,我們的程序中的類和方法的數目就會大大增長,而每個類和方法的平均代碼卻會大大的下降。可是,我們怎么知道這個度應該要如何把握呢,關于這個疑問,并沒有明確的答案,要看個人的功力和具體的要求,但是一般來說,我們可以用一個簡單的動詞短語來命名類或方法的,那就會是比較好的分類方法。

    我們使用功能分解的規則,有助于提高重用性,因為我們每個類和方法的精度都提高了。這是符合大自然的原則的,我們研究自然的主要的一個方向就是將物質分解。我們的思路同樣可以應用在軟件開發上。除了重用性,功能分解還能實現透明的目標,因為我們使用了功能分解的規則之后,每個類都有自己的單獨功能,這樣,我們對一個類的研究就可以集中在這個類本身,而不用牽涉到過多的類。

    根據實際情況決定不同類間的耦合度

    雖然我們總是希望類間的耦合度比較低,但是我們必須客觀的評價耦合度。系統之間不可能總是松耦合的,那樣肯定什么也做不了。而我們決定耦合的程度的依據何在呢?簡單的說,就是根據需求的穩定性,來決定耦合的程度。對于穩定性高的需求,不容易發生變化的需求,我們完全可以把各類設計成緊耦合的(我們雖然討論類之間的耦合度,但其實功能塊、模塊、包之間的耦合度也是一樣的),因為這樣可以提高效率,而且我們還可以使用一些更好的技術來提高效率或簡化代碼,例如Java中的內部類技術。可是,如果需求極有可能變化,我們就需要充分的考慮類之間的耦合問題,我們可以想出各種各樣的辦法來降低耦合程度,但是歸納起來,不外乎增加抽象的層次來隔離不同的類,這個抽象層次可以是具體的類,也可以是接口,或是一組的類(例如Beans)。我們可以借用Java中的一句話來概括降低耦合度的思想:”針對接口編程,而不是針對實現編程。

    設計不同的耦合度有利于實現透明和延展。對于類的客戶(調用者)來說,他不需要知道過多的細節(實現),他只關心他感興趣的(接口)。這樣,目標類對客戶來說就是一個黑盒子。如果接口是穩定的,那么,實現再怎么擴展,對客戶來說也不會有很大的影響。以前那種牽一發而動全身的問題完全可以緩解甚至避免。

    其實,我們仔細的觀察GOF的23種設計模式,沒有一種模式的思路不是從增加抽象層次入手來解決問題的。同樣,我們去觀察Java源碼的時候,我們也可以發現,Java源碼中存在著大量的抽象層次,初看之下,它們什么都不干,但是它們對系統的設計起著重大的作用。

    夠用就好 :?
    我們在上一章中就談過敏捷方法很看重剛好夠用的問題,現在我們結合架構設計來看:在同樣都能夠滿足需要的情況下,一項復雜的設計和一項簡單的設計,哪一個更好。從敏捷的觀點來看,一定是后者。因為目前的需求只有10項,而你的設計能夠滿足100項的需求,只能說這是種浪費。你在設計時完全沒有考慮成本問題,不考慮成本問題,你就是對開發組織的不負責,對客戶的不負責。

    應用模式

    這篇文章的寫作思路很多來源于對模式的研究。因此,文章中到處都可以看到模式思想的影子。模式是一種整理、傳播思想的非常優秀的途徑,我們可以通過模式的方式學習他人的經驗。一個好的模式代表了某個問題研究的成果,因此我們把模式應用在架構設計上,能夠大大增強架構的穩定性。

    抽象

    架構的本質在于其抽象性。它包括兩個方面的抽象:業務抽象和技術抽象。架構是現實世界的一個模型,所以我們首先需要對現實世界有一個很深的了解,然后我們還要能夠熟練的應用技術來實現現實世界到模型的映射。因此,我們在對業務或技術理解不夠深入的情況下,就很難設計出好的架構。當然,這時候我們發現一個問題:怎樣才能算是理解足夠深入呢。我認為這沒有一個絕對的準則。

    一次,一位朋友問我:他現在做的系統有很大的變化,原先設計的工作流架構不能滿足現在的要求。他很希望能夠設計出足夠好的工作流架構,以適應不同的變化。但是他發現這樣做無異于重新開發一個lotus notes。我聽了他的疑問之后覺得有兩點問題:

    首先,他的開發團隊中并沒有工作流領域的專家。他的客戶雖然了解自己的工作流程,但是缺乏足夠的理論知識把工作流提到抽象的地步。顯然,他本身雖然有技術方面的才能,但就工作流業務本身,他也沒有足夠的經驗。所以,設計出象notes那樣的系統的前提條件并不存在。

    其次,開發一個工作流系統的目的是什么。原先的工作流系統運作的不好,其原因是有變化發生。因此才有改進工作流系統的動機出現。可是,畢竟notes是為了滿足世界上所有的工作流系統而開發的,他目前的應用肯定達不到這個層次。

    因此,雖然做不到最優的業務抽象,但是我們完全可以在特定目的下,特定范圍內做到最優的業務抽象。比如說,我們工作流可能的變化是工組流路徑的變化。我們就完全可以把工作流的路徑做一個抽象,設計一個可以動態改變路徑的工作流架構。

    有些時候,我們雖然在技術上和業務上都有所欠缺,沒有辦法設計出好的架構。但是我們完全可以借鑒他人的經驗,看看類似的問題別人是如何解決的。這就是我們前面提到的模式。我們不要把模式看成是一個硬性的解決方法,它只是一種解決問題的思路。Martin Fowler曾說:”模式和業務組件的區別就在于模式會引發你的思考。

    在《分析模式》一書中,Martin Fowler提到了分析和設計的區別。分析并不僅僅只是用用例列出所有的需求,分析還應該深入到表面需求的的背后,以得到關于問題本質的Mental Model。然后,他引出了概念模型的概念。概念模型就類似于我們在討論的抽象。Martin Fowler提到了一個有趣的例子,如果要開發一套軟件來模擬桌球游戲,那么,用用例來描述各種的需求,可能會導致大量的運動軌跡的出現。如果你沒有了解表面現象之后隱藏的運動定律的本質,你可能永遠無法開發出這樣一個系統。

    關于架構和抽象的問題,在后面的文章中有一個測量模式的案例可以很形象的說明這個問題。

    架構的一些誤解

    我們花了一些篇幅來介紹架構的一些知識?,F在回到我們的另一個主題上來。對于一個敏捷開發過程,架構意味著什么,我們該如何面對架構。這里我們首先要澄清一些誤解:

    誤解1:架構設計需要很強的技術能力。從某種程度來說,這句話并沒有很大的錯誤。畢竟,你的能力越強,設計出優秀架構的幾率也會上升。但是能力和架構設計之間并沒有一個很強的聯系。即使是普通的編程人員,他一樣有能力設計出能實現目標的架構。

    誤解2:架構由專門的設計師來設計,設計出的藍圖交由程序員來實現。我們之所以會認為架構是設計師的工作,是因為我們喜歡把軟件開發和建筑工程做類比。但是,這兩者實際上是有著很大的區別的。關鍵之處在于,建筑設計已經有很長的歷史,已經發展出完善的理論,可以通過某些理論(如力學原理)來驗證設計藍圖??墒?#xff0c;對軟件開發而言,驗證架構設計的正確性,只能夠通過寫代碼來驗證。因此,很多看似完美的架構,往往在實現時會出現問題。

    誤解3:在一開始就要設計出完善的架構。這種方式是最傳統的前期設計方式。這也是為XP所摒棄的一種設計方式。主要的原因是,在一開始設計出完美的架構根本就是在自欺欺人。因為這樣做的基本假設就是需求的不變性。但需求是沒有不變的(關于需求的細節討論,請參看拙作『需求的實踐』)。這樣做的壞處是,我們一開始就限制了整個的軟件的形狀。而到實現時,我們雖然發現原來的設計有失誤之處,但卻不愿意面對現實。這使得軟件畸形的生長。原本一些簡單的問題,卻因為別扭的架構,變得非常的復雜。這種例子我們經常可以看到,例如為兼容前個版本而導致的軟件復雜性。而2000年問題,TCP/IP網絡的安全性問題也從一個側面反映了這個問題的嚴重性。

    誤解4:架構藍圖交給程序員之后,架構設計師的任務就完成了。和誤解2一樣,我們借鑒了建筑工程的經驗。我們看到建筑設計師把設計好的藍圖交給施工人員,施工人員就會按照圖紙建造出和圖紙一模一樣的大廈。于是,我們也企圖在軟件開發中使用這種模式。這是非常要命的。軟件開發中缺乏一種通用的語言,能夠充分的消除設計師和程序員的溝通隔閡。有人說,UML不可以嗎?UML的設計理念是好的,可以減輕溝通障礙問題。可是要想完全解決這個問題,UML還做不到。首先,程序員都具有個性化的思維,他會以自己的思維方式去理解設計,因為從設計到實現并不是一項機械的勞動,還是屬于一項知識性的勞動(這和施工人員的工作是不同的)。此外,對于程序員來說,他還極有可能按照自己的想法對設計圖進行一定的修改,這是非常正常的一項舉動。更糟的是,程序員往往都比較自負,他們會潛意識的排斥那些未經過自己認同的設計。

    架構設計的過程模式

    通常我們認為模式都是用在軟件開發、架構設計上的。其實,這只是模式的一個方面。模式的定義告訴我們,模式描述了一個特定環境的解決方法,這個特定環境往往重復出現,制定出一個較好的解決方法有利于我們在未來能有效的解決類似的問題。其實,在管理學上,也存在這種類似的這種思維。稱為結構性問題的程序化解決方法。所以呢,我們完全可以把模式的思想用在其它的方面,而目前最佳的運用就是過程模式和組織模式。在我們的文章中,我們僅限于討論過程模式。 方法論對軟件開發而言意味著什么?我們如何看待軟件開發中的方法論?方法論能夠成為軟件開發的救命稻草嗎?在讀過此文后,這些疑惑就會得到解答。?
    架構設計中的方法學(1)——方法源于恐懼

    方法論

    方法論的英文為Methodology,詞典中的解釋為:“A series of related methods or techniques”,我們可以把它定義為軟件開發(針對軟件開發)的一整套方法、過程、規則、實踐、技術。關于方法論出現的問題,我很贊同Alistair Cockburn的一句話,“方法論源于恐懼。”出于對項目的超期、成本失控等等因素的恐懼,項目經理們從以前的經驗出發,制定出了一些控制、監測項目的方法、技巧。這就是方法論產生的原因。

    在Agile Software Development一書中,作者提到了方法論的十三個要素,基本能夠函蓋方法論的各個方面:

    角色(Roles)、個性(Personality)、技能(Skills)、團隊(Teams)、技術(Techniques)、活動(Activities)、過程(Process)、工件(Work products)、里程碑(Milestones)、標準(Standards)、質量(Quality)、工具(Tools)、團隊價值(Team Values)。

    它們之間的關系可以用一幅圖來表示:

    圖 1. 方法論的十三個要素

    很多的方法論,都涉及了上面列舉的十三要素中的部分要素,因此,我們可以把方法論看作是一個抽象的、無窮的超集,而現實中的方法論都是指超集的一個有限的子集而已。它們之間的關系就好像有理數和1到100之間的整數的關系一樣。不論是XP,還是UI設計經驗之類,都屬于方法論的一個子集,只是這兩個子集之間有大小的差別而已。我們還應該看到,討論一個完備的方法論是沒有意義的,因此這種方法論鐵定不存在,就好像你視圖窮舉出所有的有理數一樣荒唐。因此,我們關于一個通用的方法論的說法也是無意義的。好的方法論,比如說XP、水晶系列,它們都有一個適合的范圍,因為它們了解一點,自己并不是一個無所不能的方法論。

    在現實中,我們其實不斷的在接觸方法論。比如說,為了控制項目的進度,項目經理要求所有的開發人員每周遞交一份詳細的進度報告,這就是一種方法、一種技巧。如果把開發過程中的這些技巧系統的組織起來,就能夠成為一種方法論。你可能會說,那一種方法論的產生也太容易了吧。不,這樣產生的方法論并沒有太大的實用價值,沒有實用價值的方法論根本就沒有存在的必要。因此,一個成功的方法論是要能夠為多個的項目所接受,并且能夠成功實現軟件的交付的方法論。

    我和我的同事在實踐中做了一些試驗,希望能夠把一些好的方法論應用于開發團隊。試驗的結果很無奈,方法論實施的效果并不理想,一開始我們認為是方法本身的原因,到后來,我們發現事情并不是這么簡單。在試驗的過程中,開發人員一致認同方法論的優勢所在,但是在實施過程中,鮮有堅持的下來的。在Agile Software Development中,我發現作者遇到了和我們一樣的問題。

    Alistair Cockburn在和大量的項目團隊的訪談之后,寫成了Agile Software Development一書。在訪談之前,他篤定自己將會發現高度精確的過程控制是成功的關鍵所在,結果他發現事實并非如此,他把他的發現歸結為7條定律。而我在實際中的發現也包含在這七條定律中,總結起來就只有兩點:溝通和反饋。

    只要能夠保證良好的溝通和即時的反饋,那么開發團隊即使并沒有采用先進的方法論,一樣可以成功。相反,那些“高質量”的團隊卻往往由于缺乏這兩個因素而導致失敗(我們這里指的失敗是用戶拒絕使用最終的軟件)。最有效,而成本也最低的溝通方法就是面對面(face to face)的溝通,而隨著項目團隊的變大,或是另外一些影響因素的加入(比如地理位置的隔絕),面對面的溝通越來越難實現,這導致溝通的成本逐漸加大,質量也慢慢下降。但這并不是說非面對面的溝通不可,重要的是我們需要知道不同的溝通方式的成本和質量并不相同。XP方法尤為強調面對面的溝通,通過現場客戶、站立會議、結對編程等方式來保證溝通的有效。在我的經驗中,一個開發團隊其實是需要多種溝通方式的結合的。完全的面對面的溝通對某些團隊來說是很難實現的,那么問題的關鍵就在于你如何應用溝通的方式來達到你希望的效果。在前不久結束的歐萊雅創業計劃大賽上,有一支團隊特別引人注目,他們彼此間素未謀面,僅僅憑借Internet和電話完成了高效的合作。他們雖然沒有使用面對面的溝通方式,但是仍然達成了既定的目標。軟件開發也是一樣的,面對面的溝通是非常有必要的,但其它的溝通方式也是需要的。

    再看反饋,不論是控制進度,還是保證客戶的滿意度,這些活動都需要管理成本。軟件開發中的管理成本的一個通性就是伴隨有中間產出物(intermediate delivery)。比如說我們的需求規約、分析文檔、設計文檔、測試計劃,這些都屬于中間產出物。中間產出物的增加將會帶來效率下降的問題,因為開發人員的時間都花在了完成中間產出物的工作上,花在給軟件新功能上的時間就減少了。而中間產出物的主要目的是兩個,一個是為了保證軟件如客戶所愿,例如需求規約;另一個是為了作為團隊中的其他成員工作的輸入,例如開發計劃、測試計劃等。因此,我們也可以針對這兩點來商討對策,一種是采用迭代的思想,提高軟件發布的頻率,以保證客戶的需求被確實的滿足,另一種就是縮小團隊的溝通范圍,保證成員能夠從其他人那里得到新的思路,而不是撰寫規范的內部文檔(內部文檔指那些僅為內部開發人員之間的溝通所需要的文檔)。

    因此,一個軟件項目的成功和你采用的開發方法論并沒有直接的關系。

    重量

    我們根據把擁有大量artifact(RUP官方翻譯為工件,意思是軟件開發過程中的中間產物,如需求規約、設計模型等)和復雜控制的軟件開發方法稱為重型(Heavy Weight)方法,相對的,我們稱artifact較少的方法為輕型(Light Weight)方法。在傳統的觀念中,我們認為重型方法要比輕型安全許多。因為我們之所以想出重型方法,就是由于在中大型的項目中,項目經理往往遠離代碼,他無法有效的了解目前的工程的進度、質量、成本等因素。為了克服未知的恐懼感,項目經理制定了大量的中間管理方法,希望能夠控制整個項目,最典型的莫過于要求開發人員頻繁的遞交各種表示項目目前狀態的報告。

    在Planning XP一書中有一段討論輕重型方法論的精辟論述,它把重型方法論歸結為一種防御性的姿態(defensive posture),而把輕型方法論歸結為一種渴望成功(Plan to win)的心態。如果你是采用了防御性姿態,那么你的工作就集中在防止和跟蹤錯誤上,大量的工作流程的制定,是為了保證項目不犯錯誤,而不是項目成功。而這種方法也不可謂不好,但前提是如果整個團隊能夠滿足前面所提到的兩個條件的話,項目也肯定會成功,但是重型方法論的一個弊端就在于,大家都在防止錯誤,都在懼怕錯誤,因此人和人之間的關系是很微妙的,要達到充分的溝通也是很難的。最終,連對人的評價也變成是以避免錯誤的多寡作為考評的依據,而不是成就。我們在做試驗的時候,一位項目經理開玩笑說,“方法論源自項目經理的恐懼,這沒錯。但最糟糕的是整個團隊只有項目經理一個人恐懼,如果能夠做到人人的恐懼,那大家也就沒有什么好恐懼的了?!边@句話提醒了我們,如果一個團隊的精神就是力求成功,那么這支團隊的心態就和其它的團隊不同了,尤其是對待錯誤的心態上。根本就沒有必要花費大量的精力來預防錯誤,錯誤犯了就犯了,即時改正就可以了。這其實就是渴望成功的心態。

    方法論的藝術

    管理,被稱為科學和藝術的融合體,而管理的藝術性部分很大程度的體現在人的管理上。我說,方法學,一樣是科學和藝術的融合體。這是有依據的,其實方法論和管理學是近親關系,管理學中有一門分支是項目管理,而在軟件組織中,項目管理是非常重要的,方法學就是一種針對軟件開發的一種特定的項目管理(或是項目管理的一個子集)。

    重型方法最大的一個問題就在于他不清楚或忽略了藝術這個層次,忽視了人的因素,把人做為一個計量單位,一種資源,一種線性元素。而人的要素在軟件開發中是非常重要的,軟件開發實際上是一種知識、智力的轉移過程,最終形成的產品是一種知識產品,它的成本取決于開發者的知識價值,因此,人是最重要的因素。而人這個要素是很難衡量的,每個人都有不同的個性、想法、經驗、經歷,這么多復雜的因素加在一起,就導致了人的不可預見性。因此,我們強調管人的藝術。

    最簡單的例子是,在重型方法中,我們的基本假設是對人的不信任。項目經理要控制項目。但不信任就會產生很多的問題,比如士氣不高,計劃趕不上變化,創新能力低下,跳槽率升高等等。人都是希望被尊重的,技術人員更看重這一點,而很多公司也口口聲聲說自己多么多么以人為本,可是采用的卻是以不信任人為前提的開發方法,言行不一。我們說敏捷方法的出發點是相互信任,做到這一點是很難的,但是一旦做到了,那這個團隊就是非常具有競爭力的。因此,這就產生了一個問題,在沒有做到完全的相互信任之前,我們到底相不相信他人呢,這就是我提到的藝術性的問題,什么時候你要相信人?什么時候你不相信人,這些都是需要權衡的問題,也都是表現你藝術性的問題。

    敏捷方法

    敏捷代表著有效和靈活。我們稱那些輕型的、有效的方法為敏捷方法。在重型方法中,我們在一些不必要、重復的中間環節上浪費了太多的精力,而敏捷則避免了這種浪費。我們的文章將會重點的討論敏捷(Agile)方法論的思想,敏捷這個名字的前身就是輕型。目前已經有了一個敏捷聯盟,他們制定了敏捷宣言:

    Individuals and interactions over processes and tools.

    Working software over comprehensive documentation.

    Customer collaboration over contract negotiation.

    Responding to change over following a plan.

    而我對敏捷的理解包括了幾個方面:

    較低的管理成本和高質量的產出。軟件開發存在兩個極端:一個是沒有任何的管理成本,所有的工作都是為了軟件的產出,但是這種方式卻往往導致軟件開發過程的混沌,產品的低質量,團隊士氣的低落。另一個是大量管理活動的加入,評審、變更管理,缺陷跟蹤,雖然管理活動的加入能夠在一定程度上提高開發過程的有序性,但是成本卻因此提高,更糟糕的是,很容易導致團隊的低效率,降低創新能力。因此,敏捷方法試圖尋找一個平衡點,用低成本的管理活動帶來最大的產出,即軟件的高質量。

    尊重人性。敏捷方法尊重人性,強調效率。軟件開發可以說是一種腦力的投入,如果不能保證開發人員的自愿投入,產品就肯定要打折扣。事實多次的證明,一個愿意投入的開發人員和一個不愿意投入的開發人員效率相差在三倍以上,對組織的貢獻更是在十倍以上。

    溝通和反饋是一切的基礎。我們已經討論過溝通的重要程度,而即時的反饋是擁抱變化的前提條件。

    客戶是上帝。沒有客戶就沒有一切,客戶的重要性可以用一句話來形容,就是以合理的成本建造合適的軟件(build the right system at the right cost)。

    敏捷其實也有輕重之分,關鍵在于是否能夠做到有效和靈活。因此,敏捷方法論提倡的一個思想是“剛好夠(barely sufficient)”。不過這個“剛好夠”可不是那么容易判斷的。一支8個人的團隊采用XP方法,隨著方法的熟練使用,團隊的能力在不斷的增強,能夠處理的問題越越來越復雜,也許他們能夠處理采用重型方法的20個人團隊能夠處理的問題。可是如果團隊的人數突然增加到12人,這支團隊肯定就會出問題,他的表現可能還不如那支20個人的團隊了。人數增加的時候,原先的方法肯定還做適當的調整,比如說,在原先的敏捷方法上增加一些重型方法的技巧。我們不能夠要求一支6個人的團隊和一支20個人的團隊用同樣的方法,前者可能采用輕一些的敏捷方法,后者可能采用重一些的敏捷方法,關鍵的問題在于,兩支團隊都把重點放在溝通、反饋、頻繁交付軟件這些關鍵的因素上,也就是做到有效和靈活。

    架構設計

    架構(Architecture)(也有被稱為體系結構的)是軟件設計中非常重要的一個環節。軟件開發的過程中只要需求和架構確定之后,這個軟件就基本上可以定型了。這就好比骨骼確定了,這個人的體形就不會有很大的變化。因此我選擇了架構設計來討論敏捷軟件開發(需求我已經寫過了)。我們在前面討論過超集和子集的概念,因此我們接下去要討論的架構設計也是一個很小的子集。方法論如果沒有經歷過多個項目的檢驗是不能稱為成功的方法論的,我也并不認為我的架構設計就是一個好的方法論,但引玉還需拋磚,他的主要目的是為了傳播一種思想。因此,我采用了模式語言(PLOP)做為寫作架構設計的形式,主要的原因就是模式是一種很好的組織思想的方法。

    因此,在我們接下去的歷程中,我們集中討論的東西就圍繞著架構、方法學、敏捷這三個要素展開。這篇文章并不是討論如何編碼實現軟件架構的,也不要單純的把它看作架構設計的指南,其實文中的很多思想來自于方法論,因此提到的很多架構設計的思想也適用于其它工作,如果能夠了解這一點,看這篇文章的收獲可能會更多一些。?
    架構設計中的方法學(3)——架構源自需求

    從需求到架構

    在需求階段,我們可以得到一些代表需求調研成果的中間產物。比如說,CRC卡片、基本用例模型、用戶素材、界面原型、界面原型流程圖

    、非功能需求、變化案例等。我們在架構設計階段的主要工作就是要把這些需求階段的中間產物轉換為架構設計階段的中間產物。?
    其實,架構設計就是要完成兩項工作,一是分析,二是設計。分析是分析需求,設計則是設計軟件的大致結構。很多的方法論把分析和設計兩種活動分開來,但其實這兩者是很難區分的,做分析的時候會想到如何設計,而思考如何設計反過來又會影響分析的效果??梢哉f,他們兩者之間是相互聯系和不斷迭代的。這種形態我們將會在后面的迭代設計模式中詳細的討論。?
    在敏捷方法論中,需求最好是迭代進行的,也就是說一點一點的作需求。這種做法在那些需求變化快的項目中尤其適用。由于我們采用的流程是一種迭代式的流程,這里我們將會面臨著如何對待上一次迭代的中間產物的問題。如果我們每一次迭代都需要修改已存在的中間產物,那么這種維護的成本未免過大。因此,敏捷方法論的基本做法是,扔掉那些已經沒有用處的中間產物。還記得在第一章的時候,我們強調說軟件要比文檔重要。我們生成中間產物的目的都是為了生成最終的程序,對于這些已經完成作用的模型,沒有必要付出額外的維護成本。?
    不要斷章取義的采用拋棄模型的做法。因為,拋棄模型的做法需要一個適合環境的支持。后面會針對這個話題開展大范圍的討論。這里我們簡單的做一個了解:?
    簡單化:簡單的模型和簡單的程序。模型和程序越復雜,就需要更多的精力來處理它們。因此,我們盡可能的簡化它們,為的是更容易的處理它們。?
    高效的溝通渠道:通過增強溝通的效果來減少對中間產物的需要。試想一下,如果我隨時能夠從客戶那里得到需求的細節資料,那前期的需求調研就沒有必要做的太細致。?
    角色的交叉輪換:開發人員之間建立起交換角色的機制,這樣,能夠盡量的避免各子系統諸侯割據的局面。?
    清晰的流程:或者我們可以稱之為明確的過程。過程在方法論中向來都是一個重點,敏捷方法論也不例外。開發人員能夠清楚的知道,今天做什么,明天做什么。過程不是給別人看的,而是給自己用的。?
    工具:好用的工具能夠節省大量的時間,這里的工具并不僅僅指CASE工具,還包括了版本控制工具、自動化測試工具、畫圖工具、文檔制作和管理工具。使用工具要注意成本和效益的問題。?
    標準和風格:語言不通是溝通的一個很大的障礙。語言從某個角度來看屬于一種標準、一種風格。因此,一個團隊如果采用同樣的編碼標準、文檔標準、注釋風格、制圖風格,那么這個團隊的溝通效率一定非常的高。?
    如果上述的環境你都不具備,或是欠缺好幾項,那你的文檔的模型還是留著的好。?
    僅針對需求設計架構?
    僅針對需求設計架構的含義就是說不要做未來才有用的事情。有時候,我們會把架構考慮的非常復雜,主要的原因就是我們把很多未來的因素放入到現在來考慮。或者,我們在開發第一個產品的時候就視圖把它做成一個完美的框架。以上的這兩種思路有沒有錯呢?沒有錯,這只是如何看待投入的問題,有人希望開始的時候多投入一些,這樣后續的投入就會節省下來。但在現實中,由于需求的不確定性,希望通過增加開始階段的投入來將降低未來的投入往往是難以做到的,框架的設計也絕對不是能夠一蹴而就的,此這種做法并不是一個好的做法。所以我們在后頭會著重論述架構設計的簡單性和迭代過程,也就是因為這個理由。?
    模式?
    模式將可以幫助我們抓住重點。為了解決設計文檔編輯器引出的七個問題,一共使用了8種不同的模式。這8種模式的組合其實就是架構,因為它們解決的,都是系統中最高層的問題。

    在實踐中,人們發現架構也是存在模式的。比如,對于系統結構設計,我們使用層模式;對于分布式系統,我們使用代理模式;對于交互系統,我們使用MVC(模型-視圖-控制器)模式。模式本來就是針對特定問題的解,因此,針對需求的特點,我們也可以采用相應的模式來設計架構。

    在sun網站上提供的寵物商店的范例中,就把MVC模式的思想擴展成為架構的思想,用于提供不同的界面視圖:

    我們可以了解到在圖的背后隱藏著的需求:系統需要支持多種用戶界面,包括為普通用戶提供的HTML界面,為無線用戶提供的WML界面,為管理員提供的Swing界面,以及為B2B業務設計的WebService界面。這是系統最重要的需求,因此,系統的設計者就需要確定一個穩定的架構,以解決多界面的問題。相對于多界面的問題,后端的業務處理邏輯都是一致的。比如HTML界面和WML界面的功能并沒有太大的差別。把處理邏輯和界面分離開來還有額外的好處,可以在添加功能的同時,不涉及界面的改動,反之亦然。這就是我們在第二篇中提到的耦合度的問題。?
    MVC模式正可以適用于解決該問題。系統使用控制器來為業務邏輯選擇不同的界面,這就完成了MVC架構的設計思路。在架構設計的工作中,我們手頭上有模式這樣一張好牌,有什么理由不去使用它呢??
    抓住重點?
    在架構設計一開始,我們就說架構是一種抽象,那就是說,架構設計摒棄了具體的細節,僅僅抓住軟件最高層的概念,也就是最上層、優先級最高、風險最大的那部分需求。?
    我們考慮、分析、解決一個問題,一定有一個漸進的過程。架構設計就是解決問題其中比較早期的一個階段,我們不會在架構設計這個階段投入過多的時間(具體的原因在下文會有討論),因此關鍵點在于我們要能夠在架構設計中把握住需求的重點。比如,我們在模式一節中提到了分布式系統和交互系統,分布和交互就是這兩個系統的重點。那么,如果說我們面對的是一個分布式的交互系統,那么,我們就需要把這兩種特性做為重點來考慮,并以此為基礎,設計架構。而我們提到的寵物商店的范例也是類似的,除了MVC的架構,還有很多的設計問題需要解決,例如用于數據庫訪問的數據對象,用于視圖管理的前端控制器,等等(具體使用到的架構模式可以訪問sun的網站)。但是這些相對于MVC模式來說,屬于局部的,優先級較低的部分,可以在架構確定后再來設計。?
    架構設計和領域專家?
    一個架構要設計的好,和對需求的理解是分不開的。因此在現實中,我們發現業務領域專家憑借著他對業務領域的了解,能夠幫助開發人員設計出優秀的架構來。架構是需要抽象的,它是現實社會活動的一個基本模型,而業務領域的模型僅僅憑開發人員是很難設計出來的。在ERP的發展史上,我們看到MRP發展為MRPII,在發展到閉環MRP,直到發展成為現在的ERP,主要的因素是管理思想的演化,也就是說,對業務領域的理解進步了,架構才有可能進步。?
    因此,敏捷型架構設計的過程中,我們也非常強調領域專家的作用?
    架構設計中的方法學(4)——團隊設計?
    團隊設計是敏捷方法論中很重要的一項實踐。我們這里說的團隊,指的并不是復數的人。一群人就是一群人,并沒有辦法構成團隊。要想成為團隊,有很多的工作要做。?
    我們之所以考慮以團隊

    為單位來考慮架構設計,是因為軟件開發本身就不是一件個人的事情,架構設計更是如此。單個人的思維不免有考慮欠妥之處,單個人的學識也不可能覆蓋所有的學科。而組織有效的團隊卻能夠彌補這些缺憾。?
    誰來負責架構的設計??
    在我們的印象中,總認為架構設計是那些所謂架構設計師的專屬工作,他們往往擁有豐富的設計經驗和相關的技能,他們不用編寫代碼,就能夠設計出理論上盡善盡美的架構,配有精美的圖例。?
    問題1:理論上設計近乎完美的架構缺乏程序的證明,在實際應用中往往會出這樣那樣的問題。?
    問題2:設計師設計架構帶有很大的主觀性,往往會忽視客戶的需求,導致架構無法滿足需求。?
    問題3:實現的程序員對這種架構有抵觸的情緒,或是因為不理解架構而導致架構實現的失敗。?
    問題4:架構師設計架構主要是依據自己的大量經驗,設計出的架構不能真實的反映目前的軟件需要。?
    解決辦法?
    團隊設計的理論依據是群體決策。和個人決策相比,群體決策的最大好處就是其結論要更加的完整。而群體決策雖然有其優點,但其缺點也是很明顯的:需要額外付出溝通成本、決策效率低、責任不明確、等等。但是群體決策如果能夠組織得當的話,是能夠在架構設計中發揮很大的優勢的?
    避免象牙塔式的架構設計?
    對軟件來說,架構設計是一項至關重要的工作。這樣的工作交給某個人是非常危險的。即便這個人再怎么聰明,他也可能會遺漏部分的細節。組織有效的團隊的力量是大大超過個人的力量的,因此團隊的成果較之個人的成果,在穩定性和思考的周密程度上,都要更勝一籌。?
    Scott W. Ambler在其著作中給出了象牙塔式架構(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).?
    中國現在的軟件開發行業中也逐漸出現了象牙塔式的架構設計師。這些架構師并不參與實際的程序編寫,他的工作就是為項目制作出精美的架構模型,這種架構模型在理論上是相當完美的。?
    例1:在XP中,我們基本上看不到架構設計的影子。并不是說采用XP技術的團隊就不需要架構設計。XP不存在專門的設計時期,它提倡使用一些簡單的圖例、比喻的方式來表達軟件的架構,而這種的架構設計是無時無刻不在進行的。其實,XP中的設計采用的就是團隊設計的方式,結隊編程(Pair Programming)和代碼的集體所有制(Collective Ownership)是團隊設計的基礎,也就是基于口述的溝通方式。通過采用這樣的方式,XP幾乎不需要文檔來表達架構的設計。?
    優秀的架構師能夠充分的利用現有框架,減少軟件的投入,增強軟件的穩定性。這些都沒有錯,但是問題在于“過猶不及”。象牙塔式架構師往往會出現文章開始指出的那些問題。架構設計其實并不是非常復雜的工作,但它要求開發人員具備相關的技能、經驗以及對問題域有一定的了解。開發人員往往都具有相關的技術技能(編程、數據庫設計、建模),而對問題域的理解可以從用戶和行業專家那里獲得幫助。因此,在理論上,我們要實現架構設計的團隊化是完全可能的。?
    在上面的象牙塔式架構定義中,我們看到架構師和日常的開發工作是隔絕的。這樣設計出的架構有很大的局限性。在現實中,我們還會發現另外一種角色,他來自于開發團隊外部,為開發人員提供相關的技術或業務的培訓。這種角色稱為教練,在軟件開發中是非常重要的角色,不能夠和象牙塔式架構設計師之間畫等號。?
    選擇你的設計團隊?
    軟件的架構在軟件的生命周期的全過程中都很重要,也就是說,軟件開發團隊中的所有人員都需要和架構打交道。因此,最好的團隊組織方式是所有開發人員都參與架構的設計,我們稱這種方式為全員參與。全員參與的方式保證了所有開發人員都能夠對架構設計提出自己的見解,綜合多方面的意見,在全體開發人員中達成一致。這種方式尤其適合于一些小的團隊。?
    還是會有很多的團隊由于種種的原因不適合采用全員參與的方式。那么,組織優秀的開發人員組成設計組也是比較好的方式。一般,我們選擇那些在項目中比較重要的,有較多開發經驗,或是理論扎實的那些人來組成設計組。當然,如果你考慮到為組織培養后續力量,你也可以讓一些新手加入設計組,或是你覺得自己的開發力量不足,邀請外部的咨詢力量介入,這完全取決于具體的情況。?
    設計組不同于我們之前提到的象牙塔式架構設計師。設計組設計出來的架構只能稱為原始架構,它是需要不斷的反饋和改進的。因此,在架構實現中,設計組的成員將會分布到開發團隊的各個領域,把架構的思想帶給所有開發人員,編寫代碼來檢驗架構,并獲得具體的反饋,然后所有的成員再集中到設計組中討論架構的演進。?
    團隊設計中存在的問題?
    在團隊設計的過程,我們會遇到各種各樣的問題,首當其沖的就是溝通成本的問題。架構設計時,需求尚未被充分理解,軟件的設計思路還處于萌發的狀態。這樣的情況下,團隊的每位成員對軟件都有獨特的見解,這些可能有些是相同的,有些是互斥的。就好比盲人摸象一樣,他們的觀點都代表了軟件的一部分或是一方面,但是沒有辦法代表軟件的全部。?
    在敏捷方法論中,我們的每一個流程都是迅速進行、不斷改進的。架構設計也是一樣,我們不可能在一次架構設計上花費更多的時間。而團隊決策總是傾向于較長的討論和權衡。?
    例2中的問題在架構設計中時有發生,純技術的討論很容易上升稱為爭吵。這種情況幾乎沒有辦法完全避免。團隊型的決策必然會發生觀念的沖突??刂埔欢ǔ潭葍鹊挠^念的沖突對團隊的決策是有益,但是如果超出了這個程度就意味著失控了,需要團隊領導者的調節。而更重要的,我們需要注意溝通的技巧?
    團隊溝通?
    團隊進行架構設計的時候溝通是一個非常需要注意的問題,上述的情境在軟件組織中是經常發生的,因為技術人員很自然認為自己的技術比別人的好,如果自己的技術受到質疑,那怕對方是抱著討論的態度,也無異于自身的權威受到了挑戰,面子是無論如何都需要捍衛的。而溝通如果帶上了這樣一層主觀色彩,那么溝通信息的受眾就會潛意識的拒絕接受信息。相反,他會找出對方話語中的漏洞,準備進行反擊。因此,我們要注意培養一種良好的溝通氛圍。?
    在實際的觀察中,我發現團隊溝通中存在兩種角色,一種是建議者,他們經常能夠提���建議。一種是質疑者,他們對建議提出否定性的看法。這兩種角色是可能互換的,現在的建議者可能就是剛才的質疑者。質疑者的發言是很能打擊建議者的積極性的,而在一個腦力激蕩的會議中,最好是大家都能夠扮演建議者的角色,這就要求溝通會議的主持者能夠掌握好這一點,對建議給予肯定的評價,并鼓勵大家提出新的建議。?
    例2:敏捷方法非常注重的就是團隊的溝通。溝通是一個很有意思的話題,講起來會花費大量的時間,我們這里只是針對架構設計中可能存在的溝通問題做一個簡單的討論。我們這里假設一個討論情境,這個情境來源于真實的生活:項目主管徐輝、設計師李浩、設計師羅亦明正在討論一個新的軟件架構。 “李浩你認為這個軟件數據庫連接部分應該如何考慮?”徐輝問。李浩想了想,”我覺得方案A不錯…” “方案A肯定有問題!這個軟件和上一次的又不同?!绷_亦明打斷了李浩的發言。 “你懂什么!你到公司才多久,方案A是經過很長時間的證明的!”發言被打斷,李浩有點惱火,羅亦明進入公司沒有多久,但在一些事情上老是和他唱反調。 “我進公司多久和方案A的錯誤有什么關系!” 在這樣一種氛圍中,會議的結果可想而知。良好的溝通有助于架構設計工作的開展。一個成員的能力平平的團隊,可以藉由良好的溝通,設計出優秀的架構,而一個擁有一個優秀成員的團隊,如果缺乏溝通,最后可能連設計都出不來。這種例子現實中可以找到很多。?
    標準和風格?
    我們總是在不知不覺之中使用各種各樣的標準和風格。在團隊設計中,我們為了提高決策的效率,可以考慮使用統一的標準和風格。統一的標準和風格并不是一朝一夕形成的。因為每個人都有自己不同的習慣和經歷,強制性的要求開發人員使用統一的標準(風格)容易引起開發人員的不滿。因此在操作上需要注意技巧。對架構設計而言,比較重要的標準(風格)包括界面設計、流程設計、建模規范、編碼規范、持久層設計、測試數據。?
    在我的經驗中,有一些組織平時并不注意標準(風格)的積累,認為這種積累屬于雕蟲小技,但正是這些小技,能夠非常有效的提高溝通的效率和降低開發人員的學習曲線。試想一下,如果一個團隊中所有人寫出的代碼都是不同標準和風格的,那么理解起來肯定會困難許多。當然,我們沒有必要自己開發一套標準(風格)出來,現實中有很多可以直接借用的資料。最好的標準是UML語言,我們可以從UML的官方網站下載到最新的規范,常用的編碼標準更是隨處可見。不過雖然有了統一的標準,如果風格不統一,同樣會造成溝通的障礙。例如下圖顯示的類圖,雖然它們表示的是同一個類,但是由于版型、可視性、詳細程度的差別,看起來又很大的差別。而在其它的標準中,這種差別也是普遍存在的。因此,我們在使用了統一的標準之后,還應該使用同樣的風格。Scott W. Ambler專門成立了一個網站討論UML的建模風格的相關問題,有興趣的讀者可以做額外的閱讀。

    圖 4. 兩種風格的類圖?
    在統一的風格的基礎上更進一步的是使用術語。使用溝通雙方都了解專門的術語,可以代表大量的信息。最好的術語的范例就是設計模式的模式名。如果溝通的雙方都了解設計模式,那么一方只需要說這部分的設計可以使用工廠模式,另一方就能夠理解,而不用再詳細的解釋設計的思路。這種的溝通方式是最高效的,但它所需要的學習曲線也會比較陡。?
    團隊設計的四明確?
    為了最大程度的提高團隊設計的高效性,可以從4個方面來考慮:?
    1、明確目標?
    泛泛的召開架構討論會議是沒有什么意義的,一個沒有鮮明主題的會議也不會有什么結果。在源自需求的模式中,我們談到說可以有非功能需求的架構,可以有功能需求的架構。因此,在進行團隊設計之前,我們首先也需要確定,此次要解決什么問題,是討論業務邏輯的架構,還是技術架構;是全局性的架構,還是各模塊的架構。?
    2、明確分工?
    我們之所以重視團隊,很重要的額一個原因就是不同的成員有不同的擅長的區域。有些成員可能擅長于業務邏輯的建模,有的擅長于原型設計,有的擅長于數據庫設計,有的則擅長于Web編程。你能夠想象一個軟件沒有界面嗎?(有些軟件可能是這種情況)你能夠想象一個軟件只有數據庫,而沒有處理邏輯嗎?因此,架構設計就需要綜合的考慮各個方面,充分利用成員的優勢。這就要求團隊的各個成員都能夠明確自己的分工。?
    3、明確責權?
    除了明確自己的分工,每位成員都需要清楚自己的責任。沒有責任,分工就不會有任何的效力。每位成員都需要明確自己要做些什么。當然,和責任相對的,沒有成員還需要知道自己的權力是什么。這些清楚了,進行高效的溝通的前提就具備了。每次架構的討論下來,每個人都清楚,自己要做些什么,自己需要要求其他人做些什么,自己該對誰負責。如果這些問題回答不了,那這次的討論就白費了。?
    4、明確溝通方式?
    這里使用溝通方式可能有一點點不恰當,為了明確的表達意思,大家可以考慮信息流這個詞。一個完整架構包括幾個方面,分別都由那些人負責,如何產生,產生的整個過程應該是什么樣的?這樣的一個信息流程,囊括了上面提到的三個明確。如果團隊的每一個人都能夠為架構的產生而努力,并順利的設計出架構,那么這樣的流程是完美的。如果你發現其中的一些人不知道做些什么,那么,這就是流程出問題的現象了。完美的流程還會有一個額外的副產品,架構產生之后,團隊對于軟件的設計已經是非常的清晰了。因為我們提倡的是盡可能多的開發人員參與架構的設計。?
    不僅僅是架構 討論到這里,其實有很多的內容已經脫離了架構設計了。也就是說,很多的原則和技巧都是可以用于軟件開發的其它活動的。至于哪一些活動能夠利用這些方法呢?大家可以結合自己的實際情況,來思考這個問題。提示一點,關鍵的入手處在于目前效率較低之處。?
    架構設計中的方法學(5)——簡單設計

    XP非常強調簡單的設計原則:能夠用數組實現的功能決不用鏈表。在其它Agile方法中,簡單的原則也被反復的強調。在這篇文章,我們就對簡單性做一個全面的了解。?
    架構應該設計到 什么程度?

    軟件的架構都是非常的復雜的,帶有大量的文檔和圖表。開發人員花在理解架構本身上的時間甚至超出了實現架構的時間。在前面的文章中,我們提到了一些反對象牙塔式架構的一個原因,而其中的一個原因就是象牙塔式架構的設計者往往在設計時參雜進過多的自身經驗,而不是嚴格的按照需求來進行設計。
    • 1

    在軟件開發領域,最為常見的設計就是”Code and Fix”方式的設計,設計隨著軟件開���過程而增長?;蛘?#xff0c;我們可以認為這種方式根本就不能算是設計,它抱著一種船到橋頭自然直的態度,可是在設計不斷改動之后,代碼變得臃腫且難以理解,到處充滿著重復的代碼。這樣的情形下,架構的設計也就無從談起,軟件就像是在風雨中的破屋,瀕臨倒塌。

    針對于這種情形,新的設計方式又出現了,Martin Fowler稱這種方式為”Planned Design”。和建筑的設計類似,它強調在編碼之前進行嚴格的設計。這也就是我們在團隊設計中談到的架構設計師的典型做法。設計師們通常不會去編程,理由是在土木工程中,你不可能看到一位設計師還要砌磚頭。

    “Planned Design”較之”Code and Fix”進步了許多,但是還是會存在很多問題。除了在團隊設計中我們談的問題之外,需求變更將會導致更大的麻煩。因此,我們理所當然的想到進行”彈性設計”:彈性的設計能夠滿足需求的變更。而彈性的設計所付出的代價就是復雜的設計。

    題外話:

    這里我們談論”Planned Design”引出的一些問題,并沒有任何排斥這種方式的意思?!盤lanned Design”還是有很多可取之處的,但也有很多需要改進的地方。事實上,本文中我們討論的架構設計方式,本質上也是屬于”Planned Design”方式。和”Planned Design”相對應的方式是XP所主張的”Evolutionary Design”方式,但是這種方式還有待于實踐的檢驗,并不能簡單的說他就一定要比”Planned Design”先進或落后。但可以肯定的一點是:”Evolutionary Design”方式中有很多的思想和技巧是值得”Planned Design”借鑒的。

    解決方法:

    XP中有兩個非常響亮的口號:”Do The Simplest Thing that Could Possibly Work”和”You Aren’t Going to Need It”(通常稱之為YAGNI)。他們的核心思想就是不要為了考慮將來,把目前并不需要的功能加到軟件中來。

    粗看之下,會有很多開發人員認為這是不切實際的口號。我能理解這種想法,其實,在我熱衷于模式、可重用組件技術的時候,我對XP提倡的簡單的口號嗤之以鼻。但在實際中,我的一些軟件因為復雜設計導致開發成本上升的時候,我重新思考這個問題,發現簡單的設計是有道理的。

    降低開發的成本

    不論是模式,可重用組件,或是框架技術,目的都是為了降低開發的成本。但是他們的方式是先進行大量的投入,然后再節省后續的開發成本。因此,架構設計方面的很多思路都是圍繞著這種想法展開的,這可能也是導致開發人員普遍認為架構設計高不可攀的原因。XP的方式恰恰相反,在處理第一個問題的時候,不必要也不可能就設計出具有彈性、近乎完美的架構來。這項工作應該是隨著開發的演進,慢慢成熟起來的。我不敢說這種方式肯定正確,但是如果我們把生物的結構視同為架構,這種方式不是很類似于自然界中生物的進化方式嗎?

    在一開始就制作出完美的架構的設想并沒有錯,關鍵是很難做到這一點。總是會有很多的問題是你在做設計時沒有考慮到的。這樣,當一開始花費大量精力設計出的”完美無缺”的架構必然會遇到意想不到的問題,這時候,復雜的架構反而會影響到設計的改進,導致開發成本的上升。這就好比如果方向錯了,交通工具再快,反而導致錯誤的快速擴大。Martin Fowler在他的論文中說,”Working on the wrong solution early is even more wasteful than working on the right solution early”(提前做一件錯事要比提前做一件對的事更浪費時間),相信也是這個道理。

    更有意思的是,通常我們更有可能做錯。在我們進行架構設計的時候,我們不可能完全取得詳細的需求。事實上,就算你已經取得了完整的需求,也有可能發生變化。這種情況下做出的架構設計是不可能不出錯的。這樣,浪費大量的時間在初始階段設計不可能達到的”完美架構”,倒不如把時間花在后續的改進上。

    提升溝通的效率

    我們在團隊設計中已經談過了團隊設計的目標之一就是為了降低溝通的成本,以期讓所有人都能夠理解架構。但是如果架構如果過于復雜,將會重新導致溝通成本的上升,而且,這個成本并不會隨著項目進行而降低,反而會因為上面我們提到的遇到新的問題導致溝通成本的持續上升。

    簡單的架構設計可以加快開發團隊理解架構的速度。我們可以通過兩種方式來理解簡單的含義。首先,簡單意味著問題的解不會非常的復雜,架構是解決需求的關鍵,無論需求再怎么復雜多變,總是可以找出簡單穩定的部分,我們可以把這個簡單穩定的部分做為基礎,再根據需要進行改進擴展,以解決復雜的問題。在示例中,我們提到了measurement pattern,它就是按照這種想法來進行設計的。

    其次,簡單性還體現在表示的簡單上。一份5頁的文檔就能夠表達清楚的架構設計為什么要花費50頁呢?同樣的道理,能夠用一副簡單的圖形就能夠表示的架構設計也沒有必要使用文檔。畢竟,面對面的溝通才是最有效率的溝通,文檔不論如何的復雜,都不能被完全理解,而且,復雜的文檔,維護起來也需要花費大量的時間。只有在兩種情況下,我們提倡使用復雜的文檔:一是開發團隊沒有辦法做到面對面溝通;二是開發成果要作為團隊的知識積累起來,為下一次開發所用。

    考慮未來

    我們之所以考慮未來,主要的原因就是需求的不穩定。因此,我們如果考慮未來可能發生的需求變化,就會不知覺的在架構設計中增加復雜的成分。這違背的簡單的精神。但是,如果你

    不考慮可能出現的情況,那些和目前設計格格不入的改變,將會導致大量的返工。?
    還記得YAGNI嗎?原則上,我們仍然堅持不要在現有的系統中為將來可能的情況進行設計。但是,我們必須思考,必須要為將來可能出現的情況做一些準備。其實,軟件中了不起的接口的思想,不就是源于此嗎?因此,思考未來,但等到需要時再實現。?
    變更案例有助于我們思考未來,變更案例就是你在將來可能要(或可能不要)滿足的,但現在不需要滿足的需求。當我們在做架構設計的時候,變更案例也將會成為設計的考慮因素之一,但它不可能成為進行決策的唯一考慮因素。很多的時候,我們沉迷于設計通用系統給我們帶來的挑戰之中,其實,我們所做的工作對用戶而言是毫無意義的。?
    架構的穩定?
    架構簡單化和架構的穩定性有什么關系嗎?我們說,架構越簡單,其穩定性就越好。理由很簡單,1個擁有4個方法和3個屬性的類,和1個擁有20個方法和30屬性的類相比,哪一個更穩定?當然是前者。而架構最終都是要映射到代碼級別上的,因此架構的簡單將會帶來架構的穩定。盡可能的讓你的類小一些,盡可能的讓你的方法短一些,盡可能的讓類之間的關系少一些。這并不是我的忠告,很多的設計類的文章都是這么說的。在這個話題上,我們可以進一步的閱讀同類的文章(關于 refactoring 的思考)。?
    辨正的簡單?
    因此,對我們來說,簡單的意義就是不要把未來的、或不需要實現的功能加入到目前的軟件中,相應的架構設計也不需要考慮這些額外的需求,只要剛好能夠滿足當前的需求就好了。這就是簡單的定義??墒窃诂F實之中,總是有這樣或者那樣的原因,使得設計趨向復雜。一般來說,如果一個設計對團隊而言是有價值的,那么,付出一定的成本來研究、驗證、發展、文檔化這個設計是有意義的。反之,如果一個設計沒有很大的價值或是發展它的成本超過了其能夠提供的價值,那就不需要去考慮這個設計。?
    價值對不同的團隊來說具有不同的含義。有時候可能是時間,有時候可能是用戶價值,有時候可能是為了團隊的設計積累和代碼重用,有時候是為了獲得經驗,有時候是為了研究出可重用的框架(FrameWork)。這些也可以稱為目的,因此,你在設計架構時,請注意先確定好你的目的,對實現目的有幫助的事情才考慮。?
    Scott W.Ambler在他的文章中提到一個他親身經歷的故事,在軟件開發的架構設計過程中,花了很多的時間來設計數據庫到業務邏輯的映射架構,雖然這是一件任何開發人員都樂意專研的事情(因為它很酷)。但他不得不承認,對用戶來說,這種設計先進的架構是沒有太大的意義的,因為用戶并不關心具體的技術。當看到這個故事的時候,我的觸動很大。一個開發人員總是熱衷于新奇的技術,但是如果這個新奇技術的成本由用戶來承擔,是不是合理呢?雖然新技術的采用能夠為用戶帶來效益,但是沒有人計算過效益背后的成本。就我開發過的項目而言,這個成本往往是大于效益的。這個問題可能并沒有確定的答案,只能是見仁見智了。?
    簡單并不等于實現簡單?
    說到這里,如果大家有一個誤解,認為一個簡單的架構也一定是容易設計的,那就錯了。簡單的架構并不等于實現起來也簡單。簡單的架構需要設計者花費大量的心血,也要求設計者對技術有很深的造詣。在我們正在進行的一個項目中,一開始設計的基礎架構在實現中被修改了幾次,但每修改一次,代碼量都減少一分,代碼的可讀性也就增強一分。從心理的角度上來說,對自己的架構進行不斷的修改,確實是需要一定的勇氣的。因為不論是設計還是代碼,都是開發人員的心血。但跨出這一步是值得的。?
    下面的例子討論了Java的IO設計,Java類庫的設計應該來說是非常優秀的,但是仍然避免不了重新的修改。實際上,在軟件開發領域,由于原先的設計失誤而導致后來設計過于復雜的情況比比皆是(例如微軟的OLE)。同樣的,我們在設計軟件的時候,也需要對設計進行不斷的修改。能夠實現復雜功能,同時自身又簡單的設計并不是一件容易的事情。?
    例1. Java的IO系統?
    從Java的IO系統設計中,我們可以感受到簡單設計的困難。?
    例2. IO系統設計的困難性向來是公認的。Java的IO設計的一個目的就是使IO的使用簡單化。在Java的1.0中,Java的IO系統主要是把IO系統分為輸入輸出兩個大部分,并分別定義了抽象類InputStream和OutputStream。從這兩個的抽象類出發,實現了一系列不同功能的輸入輸出類,同時,Java的IO系統還在輸入輸出中實現了FilterInputStream和FilterOutputStream的抽象類以及相關的一系列實現,從而把不同的功能的輸入輸出函數連接在一起,實現復雜的功能。這個實現其實是Decorator模式(由于沒有看過源碼和相關的資料,這里僅僅是根據功能和使用技巧推測,如果大家有不同的意見,歡迎來信討論)。?
    因此,我們可以把多個對象疊加在一起,提供復雜的功能:?
    DataInpuStream in =?
    new DataInputStream(?
    new BufferedInputStream(?
    new FileInputStream(“test.txt”);

    上面的代碼使用了兩個FilterInputStream:DataInpuStream和BufferedInputStream,以實現讀數據和緩沖的功能,同時使用了一個InputStream:FileInputStream,從文件中讀取流數據。雖然使用起來不是很方便,但是應該還是非常清晰的設計。?
    令設計混亂的是既不屬于InputStream,也不屬于OutputStream的類,例如RandomAccessFile,這正表明,由于功能的復雜化,使得原先基于輸入輸出分類的設計變得混亂,根據我們的經驗,我們說設計需要Refactoring了。因此,在Java1.1中,IO系統被重新設計,采用了Reader和Writer位基礎的設計,并增加了新的特性。但是目前的設計似乎更加混亂了,因為我們需要同時使用1.0和1.1兩種不同的IO設計?
    架構設計中的方法學(6)——迭代設計?
      迭代是一種軟件開發的生命周期模型,在設計中應用迭代設計,我們可以得到很多的好處。

      在軟件生命周期中,我們如何對待架構設計的發展?

      架構設計往往發生在細節需求尚未完成的時候進行的。因此,隨著項目的進行,需求還可能細化,可能變更。原先的架構肯定會有不足或錯誤的地方。那么,我們應該如何對待原先的設計呢?

      我們在簡單設計模式中簡單提到了”Planned Design”和”Evolutionary Design”的區別。XP社團的人們推崇使用”Evolutionary Design”的方式,在外人看來,似乎擁護者們從來不需要架構的設計,他們采用的方式是一開始就進入代碼的編寫,然后用Refactoring來改進代碼的質量,解決未經設計導致的代碼質量低下的功能。

      從一定程度上來說,這個觀點并沒有錯,它強調了代碼對軟件的重要性,并通過一些技巧(如Refactoring)來解決缺乏設計的問題。但我并不認同”Evolutionary Design”的方式,在我看來,一定程度上的”Planned Design”是必須的,至少在中國的軟件行業中,”Planned Design”還沒有成為主要的設計方向。借用一句明言,”凡事預則立,不預則廢”,在軟件設計初期,投入精力進行架構的設計是很有必要的,這個架構是你在后續的設計、編碼過程中依賴的基礎。但是,一開始我們提到的設計改進的問題依然存在,我們如何解決它呢?

      在簡單設計模式中,我們提到了設計改進的必要性,但是,如果沒有一種方法去控制設計的改進的話,那么設計改進本身就是一場噩夢。因此,何時改進,怎么改進,如何控制,這都是我們需要面對的問題。

      解決方法

      為了實現不斷的改進,我們將在開發流程中引入迭代的概念。迭代的概念在《需求的實踐》中已經提到,這里我們假設讀者已經有了基本的迭代的概念。

      軟件編碼之前的工作大致可以分為這樣一個工作流程:

      上圖中的流程隱含著一個信息的損失的過程。來自于用戶的需求經過整理之后,開發人員就會從中去掉一些信息,同樣的事情發生在后面的過程中,信息丟失或變形的情況不斷的發生。這里發生了什么問題?應該說,需求信息的失真是非常普遍的,我們缺少的是一種有效的辦法來抑止失真,換句話說,就是缺少反饋。

      如果把眼睛蒙上,那我們肯定沒有辦法走出一條很長的直線。我們走路的時候都是針對目標不斷的調整自己的方向的。同樣的,漫長的軟件開發過程如果沒有一種反饋機制來調整方向,那最后的軟件真是難以想象。

      所以我們引入了迭代周期。?
      初始設計和迭代設計?
      在團隊設計中,我們一直在強調,設計組最開始得到的設計一定只是一個原始架構,然后把這個原始架構傳播到每一位開發者的手中,從而在開發團隊中形成共同的愿景。(愿景(Vision):源自于管理學,表示未來的愿望和景象。這里借用來表示軟件在開發人員心中的樣子。在后面的文章中我們會有一個章節專門的討論架構愿景。)

      迭代(Iterate)設計,或者我們稱之為增量(Incremental)設計的思想和XP提倡的Evolutionary Design有異曲同工之妙。我們可以從XP、Crystal、RUP、ClearRoom等方法學中對比、體會迭代設計的精妙之處:每一次的迭代都是在上一次迭代的基礎上進行的,迭代將致力于重用、修改、增強目前的架構,以使架構越來越強壯。在軟件生命周期的最后,我們除了得到軟件,還得到了一個非常穩定的架構。對于一個軟件組織來說,這個架構很有可能就是下一個軟件的投入或參考。

      我們可以把早期的原始架構當作第一次迭代前的早期投入,也可以把它做為第一次迭代的重點,這些都是無所謂的。關鍵在于,原始架構對于后續的架構設計而言是非常重要的,我們討論過架構是來源于需求的,但是原始架構應該來源于那些比較穩定的需求。

      TIP:現實中迭代設計退化為”Code and Fix”的設計的情況屢見不鮮(”Code and Fix”參見簡單設計)。從表面上看,兩者的做法并沒有太大的差別,都是針對原有的設計進行改進。但是,二者效果的差別是明顯的:”Code and Fix”是混沌的,毫無方向感可言,每一次的改進只是給原先就已搖搖欲墜的積木上再加一塊積木而已。而迭代設計的每一次改進都朝著一個穩定的目標在前進,他給開發人員帶來信心,而不是打擊。在過程上,我們說迭代設計是在控制之下的。從實踐的經驗中,我們發現,把原該在目前就該解決的問題退后是造成這一問題的主要原因之一。因此,請嚴格的對待每一次的迭代,確保計劃已經完成、確保軟件的質量、確保用戶的需求得到滿足,這樣才是正統的迭代之路。

      單次的迭代?
      我們說,每一次的迭代其實是一個完整的小過程。也就是說,它同樣要經歷文章中討論的這些過程模式。只不過,這些模式的工作量都不大,你甚至可以在很短的時間內做完所有的事情。因此,我們好像又回到了文章的開頭,重新討論架構設計的過程。

      單次迭代最令我們興奮的就是我們總是可以得到一個在當前迭代中相當穩定的結果,而不像普通的架構設計那樣,我們深怕架構會出現問題,但又不得不依賴這個架構。從心理上來分析,我們是在持續的建設架構中,不需要回避需求的變更,因為我們相信,在需求相對應的迭代中,會繼續對架構進行改進。大家不要認為這種心理的改變是無關緊要的,我起初并沒有意識到這個問題,但是我很快發現新的架構設計過程仍然籠罩在原先的懼怕改變的陰影之下的時候,迭代設計很容易就退化為”Code and Fix”的情形。開發人員難以接受新方法的主要原因還是在心理上。因此,我不得不花了很多的時間來和開發人員進行溝通,這就是我現實的經驗。

      迭代的交錯?
      基于我們對運籌學的一點經驗,迭代設計之間肯定不是線性的關系。這樣說的一個原因架構設計和后續的工作間還是時間差的。因此,我們不會傻到把時間浪費在等待其它工作上。一般而言,當下一次迭代的需求開始之后,詳細需求開始之前,我們就已經可以開始下一次迭代的架構設計了。

      各次迭代之間的時間距離要視項目的具體情況而定。比如,人員比較緊張的項目中,主要的架構設計人員可能也要擔任編碼人員的角色,下一次迭代的架構設計就可能要等到編碼工作的高峰期過了之后。可是,多次的交錯迭代就可能產生版本的問題。比如,本次的迭代的編碼中發現了架構的一個問題,反饋給架構設計組,但是架構設計組已經根據偽修改的本次迭代的架構開始了下一次迭代的架構設計,這時候就會出現不同的設計之間的沖突問題。這種情況當然可以通過加強對設計模型的管理和引入版本控制機制來解決,但肯定會隨之帶來管理成本上升的問題,而這是不符合敏捷的思想的。這時候,團隊設計就體現了他的威力了,這也是我們在團隊設計中沒有提到的一個原因。團隊設計通過完全的溝通,可以解決架構設計中存在沖突的問題。?
      迭代頻率?
      XP提倡迭代周期越短越好(XP建議為一到兩周),這是個不錯的提議。在這么短的一個迭代周期內,我們花在架構設計上的時間可能就只有一兩個小時到半天的時間。這時候,會有一個很有意思的現象,你很難去區分架構設計和設計的概念了。因為在這么短的一個周期之內,完成的需求數量是很少的,可能就只有一兩個用例或用戶素材。因此,這幾項需求的設計是不是屬于架構設計呢?如果是的話,由于開發過程是由多次的迭代組成的,那么開發過程中的設計不都屬于架構設計了嗎?我們說,架構是一個相對的概念,是針對范圍而言的,在傳統的瀑布模型中,我們可以很容易的區分出架構設計和普通設計,如果我們把一次迭代看作是一個單獨的生命周期,那么,普通的設計在這樣一個范圍之內也就是架構設計,他們并沒有什么兩樣。但是,迭代周期中的架構設計是要遵循一定的原則的,這我們在下面還會提到。

      我們希望迭代頻率越快越好,但是這還要根據現實的情況而定。比如數據倉庫項目,在項目的初期階段,我們不得不花費大量的時間來進行數據建模的工作,這其實也是一項專門針對數據的架構設計,建立元數據,制定維,整理數據,這樣子的過程很難分為多次的迭代周期來實現。?
      如何確定軟件的迭代周期?
      可以說,如果一支開發團隊沒有相關迭代的概念,那么這支團隊要立刻實現時隔兩周迭代周期是非常困難的,,同時也是毫無意義的。就像我們在上面討論的,影響迭代周期的因素很多,以至于我們那無法對迭代周期進行量化的定義。因此我們只能從定性的角度分析迭代周期的發展。

      另一個了解迭代的方法是閱讀XP的相關資料,我認為XP中關于迭代周期的使用是很不錯的一種方法,只是他強調的如此短的迭代周期對于很多的軟件團隊而言都是難以實現的。

      迭代周期的引入一定是一個從粗糙到精確的過程。迭代的本質其實是短周期的計劃,因此這也是迭代周期越短對我們越有好處的一大原因,因為時間縮短了,計劃的可預測性就增強了。我們知道,計劃的制定是依賴于已往的經驗,如果原先我們沒有制定計劃或細節計劃的經驗,那么我們的計劃就一定是非常粗糙,最后的誤差也一定很大。但是這沒有關系,每一次的計劃都會對下一次的計劃產生正面的影響,等到經驗足夠的時候,計劃將會非常的精確,最后的誤差也會很小。

      迭代周期的確定需要依賴于單位工作量。單位工作量指的是一定時間內你可以量化的最小的績效。最簡單的單位工作量是每位程序員一天的編碼行數??上э@示往往比較殘酷,團隊中不但有程序員的角色,還有設計師、測試人員、文檔制作人員等角色的存在,單純的編碼行數是不能夠作為唯一的統計依據的。同樣,只強調編碼行數,也會導致其它的問題,例如代碼質量。為了保證統計的合理性,比較好的做法是一個團隊實現某個功能所花費的天數作為單位工作量。這里討論的內容實際是軟件測量技術,如果有機會的話,再和大家探討這個問題。?
      迭代周期和軟件架構的改進

      我們應用迭代方法的最大的目的就是為了穩步的改進軟件架構。因此,我們需要了解架構是如何在軟件開發的過程中不斷演進的。在后面的文章中,我們會談到用Refactoring的方法來改進軟件架構,但是Refactoring的定義中強調,Refactoring必須在不修改代碼的外部功能的情況下進行。對于架構來說,我們可以近乎等價的認為就是在外部接口不變的情況下對架構進行改進。而在實際的開發中,除非非常有經驗,否則在軟件開發全過程中保持所有的軟件接口不變是一件非常困難的事情。因此,我們這里談的架構的改進雖然和Refactoring有類似之處,但還是有區別的。

      軟件架構的改進在軟件開發過程會經歷一個振蕩期,這個振蕩期可能橫跨了數個迭代周期,其間架構的設計將會經歷劇烈的變化,但最后一定會取向于平穩。(如果項目后期沒有出現設計平穩化的情況,那么很不幸,你的項目注定要失敗了,要么是時間的問題,要么就是需求的問題)。關鍵的問題在于,我們有沒有勇氣,在架構需要改變的時候就毅然做出變化,而不是眼睜睜的看著問題變得越來越嚴重。最后的例子中,我們討論三個迭代周期,假設我們在第二個周期的時候拒絕對架構進行改變,那么第三個周期一定是有如噩夢一般。變化,才有可能成功。

      我們知道變化的重要性,但沒有辦法知道變化的確切時間。不過我們可以從開發過程中嗅到架構需要變化的氣味:當程序中重復的代碼逐漸變多的時候,當某些類變得格外的臃腫的時候,當編碼人員的編碼速度開始下降的時候,當需求出現大量的變動的時候。?
      實例?
      從這一周開始,我和我的小組將要負責對軟件項目中的表示層的設計。在這個迭代周期中,我們的任務是要為客戶端提供6到10個的視圖。由于視圖并不很多,表示層的架構設計非常的簡單:

      準確的說,這里談不上設計,只是簡單讓客戶端訪問不同的視圖而已。當然,在設計的示意圖中,我們并沒有必要畫出所有的視圖來,只要能夠表達客戶端和視圖的關聯性就可以了。

      (架構設計需要和具體的實現綁定,但是在這個例子中,為了著重體現設計的演進,因此把不必要的信息都刪掉。在實際的設計中,視圖可能是JSP頁面,也可能是一個窗口。)

      第一個迭代周的任務很快的完成了,小組負責的表示層模塊也很順利的和其它小組完成了對接,一個簡陋但能夠運轉的小系統順利的發布??蛻粲^看了這個系統的演示,對系統提出了修改和補充。

      第二���迭代周中,模塊要處理的視圖增加到了30個,視圖之間存在相同的部分,并且,負責數據層的小組對我們說,由于客戶需求的改進,同一個視圖中將會出現不同的數據源。由于我們的視圖中直接使用了數據層小組提供給我們的數據源的函數,這意味著我們的設計需要進行較大的調整。

      考慮到系統的視圖的量大大的增加,我們有必要對視圖進行集中的管理。前端控制器(Front Control)模式將會是一個不錯的技巧。對于視圖之間的普遍的重復部分,可以將視圖劃分為不同的子視圖,再把子視圖組合為各種各樣的視圖。這樣我們就可以使用組合(Composite)模式:

    客戶的請求集中提交給控制器,控制器接受到客戶的請求之后,根據一定的規則,來提供不同的視圖來反饋給客戶??刂破魇且粋€具有擴展能力的設計,目前的視圖數量并不多,因此仍然可以使用控制器來直接分配視圖。如果視圖的處理規則比較復雜,我們還可以使用創建工廠(Create Factory)模式來專門處理生成視圖的問題。對于視圖來說,使用組合模式,把多個不同數據源的視圖組合為復雜的視圖。例如,一個JSP的頁面中,可能需要分為頭頁面和尾頁面。

    項目進入第三個迭代周期之后,表示層的需求進一步復雜化。我們需要處理權限信息、需要處理數據的合法性判斷、還需要面對更多的視圖帶來的復雜程度上升的問題。

      表示層的權限處理比較簡單,我們可以從前端控制器中增加權限控制的模塊。同時,為了解決合法性判斷問題,我們又增加了一個數據過濾鏈模塊,來完成數據的合法性判斷和轉換的工作。為了不使得控制器部分的功能過于復雜,我們把原先屬于控制器的視圖分發功能轉移到新的分發器模塊,而控制器專門負責用戶請求、視圖的控制。

    我們來回顧這個例子,從迭代周期1中的需求最為簡單,其實,現實中的項目剛開始的需求雖然未必會像例子中的那么簡單,但一定不會過于復雜,因此迭代周期1的設計也非常的簡單。到了迭代周期2的時候,需求開始變得復雜,按照原先的架構繼續設計的話,必然會導致很多的問題,因此對架構進行改進是必要的。我們看到,新的設計能夠滿足新的需求。同樣的,迭代周期3的需求更加的復雜,因此設計也隨之演進。這就是我們在文章的開始提到的”Evolutionary Design”的演進的思想。

    架構設計中的方法學(7)——組合使用模式

    我們已經討論了敏捷架構設計的4種過程模式,在本文中,我們對這四種過程模式做一個小結,并討論4者間的關系以及體現在模式中的敏捷方法論特色。通過這一章的描述,大家能夠對前面的內容有更進一步的了解。?
    四種模式的著重點 我把源自需求、團隊設計、簡單設計、迭代設計這4種過程模式歸類為架構設計的第一層次,這4種模式能夠確定架構設計過程的框架。這里需要對框架的含義進行澄清:架構設計的框架并不是說你要嚴格的按照文中介紹的內容來進行架構設計,在文章的一開始我們就指出,模式能夠激發思考。因此,這一框架是需要結合實際,進行改造的。實際,我們在這一個部分中介紹的,比較偏向于原則,我們花了很大的時間來討論原則的來龍去脈,而原則的度,則要大家自己去把握。為什么我們不討論原則的度呢?這里有兩個原因,一個是軟件開發團隊各有特色,很難定義出一個通用的度。第二個原因是我的水平不夠,實踐經驗也不夠豐富。 前面提到的四種模式其實是從四個側面討論了架構設計中的方法問題。源自需求提供了架構設計的基礎。在軟件過程中,架構設計是承接于需求分析的,如果沒有良好的需求分析活動的支持,再好的架構設計也沒有用。因此我們把這一模式放在首位,做為架構設計的目標。 有了確定的目標,還需有組織的保證,這也就是第二種模式――團隊設計的由來。敏捷方法提倡優秀的溝通,因此團隊設計是必要且有效的。而團隊設計的另一個意圖,是保證架構設計的下游活動得以順利的進行,例如詳細設計、編碼、測試等。由于開發團隊中的人大都加入了架構設計,因此最大程度的減小了不同的活動間的信息損耗和溝通效率低下的問題。如果說源自需求模式是起承上的作用,那么團隊設計模式則是扮演了啟下的角色。 在軟件設計的過程中,溝通往往扮演著非常重要的角色。從團隊設計開始的幾種模式所要解決的都是溝通的問題。團隊設計對溝通的貢獻在于它能夠把設計意圖以最小的代價傳播到開發團隊的每個角落。這樣,設計和下游的活動間由于溝通不暢產生的問題就能夠得到緩解。一般而言,設計到編碼會經歷一個信息損失的過程,編碼人員無法正確理解設計人員的意圖,設計人員卻往往無法考慮到一些編碼的細節。雖然我們可以通過共通的設計符號來提高溝通的質量,例如UML。但是實踐證明,只要能夠保證暢通的溝通,即便沒有優秀的開發方法,項目成功的概率依然很高。因此對于單個的項目來說,最關鍵的問題還是在于溝通。只要組織得當,團隊設計是一個值得應用的模式。當然,配合以UML為代表的建模語言,更能夠提高溝通的效果。

    在設計中,我們發現,當設計信息轉換為編碼信息需要一定的時間,這個時間包括設計的組織時間,設計被理解的時間。如果設計比較復雜,或者說設計的文檔比較復雜,編碼人員花在理解上的時間就會大大增加。因此,權衡后的結果是,相對于詳細的設計說明書而言,簡單的設計說明書再配合一定程度的面對面溝通能夠起到更好的效果。”簡單要比復雜有效”,這就是簡單設計模式的基本思路。?
    同樣,簡單的思路還會用在軟件開發的各個方面,例如文檔、設計、流程。堅持簡單的原則,并不斷的加以改進,是降低軟件開發成本的一種很有效的做法。?
    在有了以上的思路之后,我們還需要面對兩個現實的問題。需求的變化將會導致設計的不穩定,而需求的復雜性又會導致簡單架構設計的困難。為了解決這個問題,我們引入了迭代的方法,將問題分割為多個子問題(把一個復雜的問題分解為多個較簡單的子問題是計算機領域最常見的處理方法)。這樣,問題的范圍和難度都大大降低了。而更關鍵的是,由于對用戶需求理解不充分或用戶表達需求有錯導致的設計風險被降到最低點。迭代和前面幾個模式都有關系。?
    需求和迭代?
    源自需求模式是架構設計中的起手式,沒有這一模式的支持,架構設計只能是空中樓閣。其實,源自需求模式嚴格意義上并不能算是敏捷方法論的特色,而應該算是軟件開發的天然特性。不幸的是,就是這么一個基本的原則,卻沒能夠引起開發者足夠的重視。?
    敏捷方法論中把需求擺在一個非常重要的位置,我們把源自需求模式作為架構設計的第一個模式,主要的目的是承接架構設計的上游工作――需求。需求決定架構,因此,我們在經典的瀑布模型中可以看到需求到設計的嚴格的分界線,但是在實際的開發中,按照瀑布模型的理論往往會遇到很多的問題,所以,我們嘗試著把需求和(架構)設計之間的界限打破,形成一個重疊的地帶,從而提高軟件開發的速度。因此,我們在源自需求模型中指出,架構設計是緊隨著需求開始的。?
    需求對軟件開發最具影響就是需求的不穩定性。我們都非常的清楚軟件開發的曲線,越到軟件開發的后期,修改軟件的成本越高。因此,在軟件開發上游的需求的變動將會對軟件開發的下游產生天翻地覆的影響。為了協調這一矛盾,軟工理論提出了螺旋開發模型,這就是我們在迭代開發模式中的討論的理論基礎。把軟件開發過程分為多個的迭代周期,每一次的迭代周期最后都將生成一個可交付的軟件,用戶在每一次的迭代結束后,可以試用軟件,提出下一步的需求或是改變原先的需求。通過這樣的方式,把客戶、開發商的風險降到一個可以接受的水平上。

    請注意迭代的前提:需求的易變性。因此,對于那些需求容易發生變化的項目,我們就可以使用迭代式的開發過程,雖然我們會付出一些額外的成本(剛開始這個成本會比較大,但可以用較長的迭代周期來降低這種成本),但是風險減小了。而對于需求比較固定的項目,

    是不是有必要使用迭代的方法,就要看具體的環境了。因此,我們是根據實際的情況選用開發方法,而不是因為先進或是流行的原因。

    實際上,由于現代社會的特性,大部分的項目都是可以采用迭代方法。因此,我們的選擇就變成了了迭代周期應該要多長。迭代周期在理論上應該是越短越好,但是并沒有一個絕對的數值,時間的跨度一般從幾周到幾個月。一般來說,迭代周期會受到幾個因素的影響:

    各模塊的關聯程度。在軟件開發中,我們有時候很難把一些模塊分離開來,要開發模塊A,就需要模塊B,而模塊B又需要模塊C。各模塊的關聯程度越高,迭代周期越長。當然,也相應的解決方法,我們可以在各模塊的功能中選取出一些關鍵點,作為里程碑,以里程碑作為迭代完成點。

    人員技能、經驗的平均程度。團隊中成員的開發能力、開發經驗良莠不齊,這也是造成迭代周期延長的一個原因。能力低、經驗少的開發人員會拖后每一次迭代的時間。針對這種情況,做好統籌規劃就顯得非常的重要,可以通過一兩次的迭代,找出隊伍中的瓶頸人員,安排相應的對策。

    工具的缺乏。迭代周期越短,就意味著build、發布的次數越多,客戶也就有更多的機會來修改需求。這要求有相關的工具來幫助開發人員控制軟件。最重要的工具是回歸測試工具。每一次迭代都需要增加新的功能,或是對原先的功能進行改動,這就有可能引入新的bug,如果沒有回歸測試,開發人員就需要花費時間重新測試原先的功能。

    計劃、控制的能力。迭代周期越短,所需要的計劃、控制的能力就越強。因為短時間內的計劃制定和實施需要高度的細分,這就要求開發團隊的管理者對開發能力、工作量、任務分配有很強的認識,才能做好這項工作。不過,迭代周期越短,同樣開發時間的迭代次數就越多,而團隊調整、改進計劃控制的機會就越多。因此,后期的迭代一般都能夠做到比較精確的控制。而這樣的做法,要比問題堆積到軟件交付日才爆發出來要好的多。沒有突然落后的軟件,只有每天都在落后的軟件。

    簡單和迭代

    簡單和迭代關系是雙向的。

    在現實設計我們很難界定出簡單設計的程度。怎樣的架構設計才算是簡單?按照我們在簡單設計模式中的討論,剛好滿足目前的需求的架構設計就算是簡單的設計。但是,從另外一個方面考慮,需求的易變性限制我們做出簡單的設計,因為我們不能夠肯定目前的需求將來會發生什么樣的變化。因此,為了克服對未知的恐懼,我們花了很大的力氣設計一些靈活的、能夠適應變化的架構。這是源自需求模式對簡單設計模式的影響。

    源自需求和迭代設計的關系的討論建議我們把需求分為多個迭代周期來實現。那么,相應的架構設計也被分在多個迭代周期中。這樣的方法可以降低架構設計的復雜程度。因為設計人員不需要考慮軟件的全部需求,而只需要考慮當前迭代周期的需求。復雜性的降低將會有助于架構設計的簡單化,從而達到簡單設計的一系列的好處(參見簡單設計)。

    我們從迭代設計中的最后一個例子可以清楚的看到迭代設計是如何把復雜的需求給簡單化的。把握迭代設計有助于我們避免過分設計的毛病。這是個技術人員經常犯的毛病。我所在的團隊很多時候也無法避免。例如,在很多的項目中,我們都會花費大量的時間來設計數據庫到業務實體的映射。諸如此類的技術問題對開發人員的吸引程度是不言而喻的,但是必須看到,這種的設計會導致開發成本的大幅度上升。更為糟糕的是,除非有豐富的經驗,這種類型的設計給開發工作帶來的價值往往無法超過其成本。

    因此,我們需要學會權衡利弊,是否有必要投入大量的資源來開發其實并沒有那么有用的功能。因此,迭代設計和簡單設計的結合有助于我們擺脫過度設計的困擾,把精力集中在真正重要的功能之上。

    此外,簡單的設計并不等同于較少的付出。簡單的設計往往需要對現實世界的抽象,回憶我們在簡單設計中討論的測量模式的例子,它看似簡單,但實現起來卻需要大量的業務知識、很強的設計能力。因此,做到簡單是程序員不斷追尋的目標之一。

    在很多的方法論中,一般并不過分注意代碼重復的問題,要么是不關注,要么認為適當的代碼重復是允許的。而XP卻把代碼重復視為良好代碼的大敵?!敝灰嬖谥貜痛a,就說明代碼仍有Refactoring的可能?!边@種觀點看起來非常的絕對,這可能也正是其名字中Extreme的來歷(英文中的Extreme屬于語氣非常重的一個單詞)。從實踐的角度上來看,追求不重復的代碼雖然很難做到,但是其過程卻可以有效的提高開發團隊代碼的寫作質量,因為它逼迫著你在每次迭代重對代碼進行改進,不能有絲毫的怠惰。而這種迭代的特性,促進了簡單的實現。

    團隊和簡單

    我們在簡單設計中提過簡單設計需要全面的設計師。除此之外,它還需要團隊的配合。簡單意味著不同活動間交付工件的簡單化。也就是說,類似于需求說明書、設計文檔之類的東西都將會比較簡單。正因為如此,我們很難想象一個地理上分布在不同地點的開發團隊或一個超過50人的大團隊能夠利用這種簡單的文檔完成開發任務。

    因此,簡單的設計是需要團隊的組織結構來保證的。簡單的設計要求團隊的相互溝通能夠快速的進行。架構設計完成后,架構的設計思路傳達給所有的編碼人員的速度要塊,同樣,編碼中發現問題,回饋給設計者,設計者經過改進之后再傳達給收到影響的編碼人員的速度也要快。象這樣高效率的傳播我們可以稱之為”Hot Channel”。

    為了保證”Hot Channel”的高溝通效率,最好的組織單位是開發人員在3到6人之間,并處于同間工作室中。這樣的結構可以保證訊息的交互速度達到最高,不需要付出額外的溝通成本,也不需要過于復雜的版本控制工具或權限分配。根據我的經驗,一個共享式的小型版本控制工具、網絡共享、再加上一個簡單的網絡數據庫就能夠解決大部分的問題了。

    在理論上,我們說只要分配得當,大型的團隊同樣可以組織為金字塔式的子團隊,以提高大型團隊的工作效率。但是實際中,隨著團隊的人數的增加,任務的正確分配的���度也隨之加大,溝通信息上傳下達的效率開始下降,子團隊間的隔閡開始出現,各種因素的累加導致敏捷方法并不一定適合于大型的團隊,因此我們討論的敏捷方法都將受到團隊的特性的限制。

    模式的源頭

    如果你對XP有一定的了解的話,那么你可能會感覺到我們討論的模式中應用了XP的實踐。確實如此,XP中有很多優秀的實踐,如果組織得當的話,這些微小的實踐將會組合成為一套了不起的開發方法。不過,目前的軟件開發混亂的現狀阻止了先進的軟件方法的應用,對一個身體虛弱的病人施以補藥只會適得其反。因此,在前面討論的模式中,我們應用了一些容易應用、效果明顯的實踐方法。在實踐中適當的應用這些方法,并不需要額外的投入,卻能夠有很好的效果,同時還會為你的團隊打下一個良好的基礎

    架構設計中的方法學(8)——架構愿景(2)?
    我們從源自需求模式中,學習到架構的設計是來自于需求的,而應用于軟件全局的架構則來自于最重要的需求。還記得我們在那個模式中提到的網上寵物店的例子嗎?系統采用了MVC模式,sun的官方文檔一開始說明了為什么采用MVC模式,MVC模式解決了什么

    問題,然后開始分析MVC模式的幾個組成部分:Model、View、和Controll。其實,MVC中的每一個部分,在真正的代碼中,大都代表了一個子系統,但是在目前,我們就非常的清楚系統大致上會是一個什么樣子,雖然這時候它還十分的朦朧。

    不要視圖在全局的架構愿景中就制定出非常細致的規劃,更不要視圖生成大量的實際代碼。因為,你的架構愿景還沒有穩定(我們在其后的穩定化的模式中將會討論穩定的問題),還沒有獲得大家的同意,也沒有經過證明。因此,從整個的開發周期來看,全局架構愿景是隨著迭代周期的進行不斷發展、修改、完善的。

    我們如何確定全局架構愿景工作的完成?一般來說,你的架構設計團隊取得了一致的意見就可以結束了,如果問題域是團隊所熟悉的,一兩個小時就能夠解決問題。接下來設計團隊把架構愿景傳播到整個的開發團隊,大家形成一致的認識,不同的意見將會被反饋會來,并在本次的迭代周期(如果時間比較緊迫)或下一次的迭代周期中(如果時間比較寬松)考慮。

    子模塊級、或是子問題級的架構愿景

    這時候的架構愿景已經是比較明確的了,因為已經存在明確的問題域。例如界面的設計、領域模型的設計、持久層的設計等。這里的愿景制定本質上和全局的愿景制定差不多,具體的例子我們也不再舉了。但是要注意一點,你不能夠和全局愿景所違背。在操作上,全局愿景是設計團隊共同制定出來的,而子模塊級的架構愿景就可以分給設計子團隊來負責,而其審核則還是要設計團隊的共同參與。這有兩個好處,一是確保各個子模塊(子問題)間不至于相互沖突或出現空白地帶,二是每個子設計團隊可以從別人那里吸取設計經驗。

    在設計時,同樣我們可以參考其它的資料,例如相關的模式、或規范(界面設計指南)。在一個有開發經驗的團隊,一般都會有開發技術的積累,這些也是可供參考的重要資料。

    我們在這個層次的愿景中主要談一談子模塊(子問題)間的耦合問題。一般來說,各個子模塊間的耦合程度相對較小,例如一個MIS系統中,采購和銷售模塊的耦合度就比較小,而子問題間的耦合程度就比較大,例如權限設計、財務,這些功能將會被每個模塊使用。那么,我們就需要為子模塊(子問題)制定出合同接口(Contact Interface)。合同的意思就是說這個接口是正式的,不能夠隨意的修改,因為這個結構將會被其它的設計團隊使用,如果修改,將會對其它的團隊產生無法預計的影響。合同接口的制定、修改都需要設計團隊的通過。此外,系統中的一些全局性的子問題最好是提到全局愿景中考慮,例如在源自需求模式中提到的信貸帳務的例子中,我們就把一個利息計算方式的子問題提到了全局愿景中。

    代碼級的愿景

    嚴格的說這一層次的愿景已經不是真正的愿景,而是具體設計了。但是我們為了保證對架構設計理解的完整性,還是簡單的討論一下。這一個層次的愿景一般可以使用類圖、接口來表示。但在類圖中,你不需要標記出具體的屬性、操作,你只需要規定出類的職責以及類之間的相互關系就可以了。該層次愿景的審核需要設計子團隊的通過。

    而設計細分到這個粒度上,執行愿景設計的開發人員可能就只有一兩個左右。但是比較重要的工作在于問題如何分解和如何歸并。分解主要是從兩個維度來考慮,一個是問題大小維,一個是時間長短維。也就是說,你(設計子團隊負責人)需要把問題按大小和解決時間的長短分解為更細的子問題,交給不同的開發人員。然后再把開發人員提出的解決方法組合起來。

    架構愿景的形成過程

    架構愿景的形成的源頭是需求,需要特別指出的是,這里的需求主要是那些針對系統基本面的需求。比如說,系統的特點是一個交互式系統,還是一個分布式系統。這些需求將會影響到架構愿景的設計。在收集影響架構愿景的各項需求之后,按照需求的重要性來設計架構愿景。

    架構愿景的設計并不需要很復雜的過程,也不需要花費很多的時間。我們已經提過,架構遠景的主要目的就是為了能夠在開發團隊中傳播設計思路,因此,架構愿景包括基本的設計思路和基本的設計原則。

    值得注意的是,架構遠景可能會有多種的視角,下文討論了一種設計模式的視角。但是實際設計中還可能會基于數據庫來設計架構愿景。但在企業信息系統的設計中,我推薦使用領域類的設計,也就是下文中討論的例子。

    架構愿景設計好之后,問題的焦點就轉到如何傳播架構愿景上來,為了達到在開發團隊中取得統一設計意圖的效果,可以考慮援引團隊設計模式。除此之外,針對性的項目前期培訓也會是一種有效的做法。

    使用架構模式

    架構模式也是一種很好的架構愿景設計思路的來源。隨著對設計模式的研究的深入,人們發現其中的一些設計模式可以擴展、或變化為軟件設計的基礎。在這個基礎上再實現更多的設計,這些模式就形成了架構模式。當然,不同的軟件,它們的架構模式也是不一樣的。在《Applying Pattern》一文中,有一個很典型的架構愿景的例子:

    假設我們需要設計分布式的交互式系統。分布式系統和交互式系統都有特定的架構模式,前者為Broker模式,后者為MVC模式。首先我們先要根據系統的特點的重要程度來排列模式的順序。這里假設需求中分布式特性更重要一些。那么我們首先選擇Broker模式作為架構的基本模式:

    再考慮交互式的特點,根據MVC模式的特點,我們需要從目前的基本架構中識別出Model、Controller、以及View。Model和View都很簡單,分別分布在上圖中的Server和Client中。而Controller則有兩種的選擇,假設這里的Controller部署在客戶端,上圖則演化為下圖:

    這樣,基礎的架構愿景就已經出現了。如果我們還有更多的需求,還可以繼續改進。但是,記住一點,架構愿景不要過于復雜。正如我們在上一節中所討論的,這里我們雖然是基于設計模式來討論架構愿景,但是實際中還有很多從其它的視角來看待架構愿景的。至于要如何選擇架構愿景的視角,關鍵的還是在于需求的理解。

    需求分析的20條法��?
    我們討論的過程僅限于面向對象的軟件開發過程。我們稱之為OOSP(object-oriented software process )。因為我們的過程需要面向對象特性的支持。當然,我們的很多做法一樣可以用在非OO的開發過程中,但是為了達到最佳的效果,我建議您使用OO技術。對商業用戶來說,他們后面是成百上千個供應商,前面是成千上萬個消費顧客。怎樣利用軟件管理錯綜復雜的供應商和消費顧客,如何做好精細到一個小小調料包的進、銷、調、存的商品流通工作,這些都是商業企業需要信息管理系統的理由。軟件開發的意義也就在于此。而弄清商業用戶如此復雜需求的真面目,正是軟件開發成功的關鍵所在。?
      經理:“我們要建立一套完整的商業管理軟件系統,包括商品的進、銷、調、存管理,是總部-門店的連鎖經營模式。通過通信手段門店自動訂貨,供應商自動結算,賣場通過掃條碼實現銷售,管理人員能夠隨時查詢門店商品銷售和庫存情況。另外,我們也得為政府部門提供關于商品營運的報告?!?
      分析員:“我已經明白這個項目的大體結構框架,這非常重要,但在制定計劃之前,我們必須收集一些需求?!?
      經理覺得奇怪:“我不是剛告訴你我的需求了嗎?”?
      分析員:“實際上,您只說明了整個項目的概念和目標。這些高層次的業務需求不足以提供開發的內容和時間。我需要與實際將要使用系統的業務人員進行討論,然后才能真正明白達到業務目標所需功能和用戶要求,了解清楚后,才可以發現哪些是現有組件即可實現的,哪些是需要開發的,這樣可節省很多時間?!?
      經理:“業務人員都在招商。他們非常忙,沒有時間與你們詳細討論各種細節。你能不能說明一下你們現有的系統?”?
      分析員盡量解釋從用戶處收集需求的合理性:“如果我們只是憑空猜想用戶的要求,結果不會令人滿意。我們只是軟件開發人員,而不是采購專家、營運專家或是財務專家,我們并不真正明白您這個企業內部運營需要做些什么。我曾經嘗試過,未真正明白這些問題就開始編碼,結果沒有人對產品滿意?!?
      經理堅持道:“行了,行了,我們沒有那么多的時間。讓我來告訴您我們的需求。實際上我也很忙。請馬上開始開發,并隨時將你們的進展情況告訴我?!?
    風險躲在需求的迷霧之后?
      以上我們看到的是某客戶項目經理與系統開發小組的分析人員討論業務需求。在項目開發中,所有的項目風險承擔者都對需求分析階段備感興趣。這里所指的風險承擔者包括客戶方面的項目負責人和用戶,開發方面的需求分析人員和項目管理者。這部分工作做得到位,能開發出很優秀的軟件產品,同時也會令客戶滿意。若處理不好,則會導致誤解、挫折、障礙以及潛在的質量和業務價值上的威脅。因此可見——需求分析奠定了軟件工程和項目管理的基礎。?
    撥開需求分析的迷霧?
      像這樣的對話經常出現在軟件開發的過程中。客戶項目經理的需求對分析人員來講,像“霧里看花”般模糊并令開發者感到困惑。那么,我們就撥開霧影,分析一下需求的具體內容:?
      ·業務需求——反映了組織機構或客戶對系統、產品高層次的目標要求,通常在項目定義與范圍文檔中予以說明。?
      ·用戶需求——描述了用戶使用產品必須要完成的任務,這在使用實例或方案腳本中予以說明。?
      ·功能需求——定義了開發人員必須實現的軟件功能,使用戶利用系統能夠完成他們的任務,從而滿足了業務需求。?
      ·非功能性的需求——描述了系統展現給用戶的行為和執行的操作等,它包括產品必須遵從的標準、規范和約束,操作界面的具體細節和構造上的限制。?
      ·需求分析報告——報告所說明的功能需求充分描述了軟件系統所應具有的外部行為。“需求分析報告”在開發、測試、質量保證、項目管理以及相關項目功能中起著重要作用。?
      前面提到的客戶項目經理通常闡明產品的高層次概念和主要業務內容,為后繼工作建立了一個指導性的框架。其他任何說明都應遵循“業務需求”的規定,然而“業務需求”并不能為開發人員提供開發所需的許多細節說明。?
      下一層次需求——用戶需求,必須從使用產品的用戶處收集。因此,這些用戶構成了另一種軟件客戶,他們清楚要使用該產品完成什么任務和一些非功能性的特性需求。例如:程序的易用性、健壯性和可靠性,而這些特性將會使用戶很好地接受具有該特點的軟件產品。?
      經理層有時試圖代替實際用戶說話,但通常他們無法準確說明“用戶需求”。用戶需求來自產品的真正使用者,必須讓實際用戶參與到收集需求的過程中。如果不這樣做,產品很可能會因缺乏足夠的信息而遺留不少隱患。?
      在實際需求分析過程中,以上兩種客戶可能都覺得沒有時間與需求分析人員討論,有時客戶還希望分析人員無須討論和編寫需求說明就能說出用戶的需求。除非遇到的需求極為簡單;否則不能這樣做。如果您的組織希望軟件成功,那么必須要花上數天時間來消除需求中模糊不清的地方和一些使開發者感到困惑的方面。?
      優秀的軟件產品建立在優秀的需求基礎之上,而優秀的需求源于客戶與開發人員之間有效的交流和合作。只有雙方參與者都明白自己需要什么、成功的合作需要什么時,才能建立起一種良好的合作關系。?
      由于項目的壓力與日俱增,所有項目風險承擔者有著一個共同目標,那就是大家都想開發出一個既能實現商業價值又能滿足用戶要求,還能使開發者感到滿足的優秀軟件產品。?
    客戶的需求觀?
      客戶與開發人員交流需要好的方法。下面建議20條法則,客戶和開發人員可以通過評審以下內容并達成共識。如果遇到分歧,將通過協商達成對各自義務的相互理解,以便減少以后的磨擦(如一方要求而另一方不愿意或不能夠滿足要求)。?
    1、 分析人員要使用符合客戶語言習慣的表達?
      需求討論集中于業務需求和任務,因此要使用術語??蛻魬獙⒂嘘P術語(例如:采價、印花商品等采購術語)教給分析人員,而客戶不一定要懂得計算機行業的術語。?
    2、分析人員要了解客戶的業務及目標?
      只有分析人員更好地了解客戶的業務,才能使產品更好地滿足需要。這將有助于開發人員設計出真正滿足客戶需要并達到期望的優秀軟件。為幫助開發和分析人員,客戶可以考慮邀請他們觀察自己的工作流程。如果是切換新系統,那么開發和分析人員應使用一下目前的舊系統,有利于他們明白目前系統是怎樣工作的,其流程情況以及可供改進之處。s 3、分析人員必須編寫軟件需求報告?
      分析人員應將從客戶那里獲得的所有信息進行整理,以區分業務需求及規范、功能需求、質量目標、解決方法和其他信息。通過這些分析,客戶就能得到一份“需求分析報告”,此份報告使開發人員和客戶之間針對要開發的產品內容達成協議。報告應以一種客戶認為易于翻閱和理解的方式組織編寫??蛻粢u審此報告,以確保報告內容準確完整地表達其需求。一份高質量的“需求分析報告”有助于開發人員開發出真正需要的產品。?
    4、 要求得到需求工作結果的解釋說明?
      分析人員可能采用了多種圖表作為文字性“需求分析報告”的補充說明,因為工作圖表能很清晰地描述出系統行為的某些方面,所以報告中各種圖表有著極高的價值;雖然它們不太難于理解,但是客戶可能對此并不熟悉,因此客戶可以要求分析人員解釋說明每個圖表的作用、符號的意義和需求開發工作的結果,以及怎樣檢查圖表有無錯誤及不一致等。?
    5、 開發人員要尊重客戶的意見?
      如果用戶與開發人員之間不能相互理解,那關于需求的討論將會有障礙。共同合作能使大家“兼聽則明”。參與需求開發過程的客戶有權要求開發人員尊重他們并珍惜他們為項目成功所付出的時間,同樣,客戶也應對開發人員為項目成功這一共同目標所做出的努力表示尊重。?
    6、 開發人員要對需求及產品實施提出建議和解決方案?
      通常客戶所說的“需求”已經是一種實際可行的實施方案,分析人員應盡力從這些解決方法中了解真正的業務需求,同時還應找出已有系統與當前業務不符之處,以確保產品不會無效或低效;在徹底弄清業務領域內的事情后,分析人員就能提出相當好的改進方法,有經驗且有創造力的分析人員還能提出增加一些用戶沒有發現的很有價值的系統特性。?
    7、 描述產品使用特性?
      客戶可以要求分析人員在實現功能需求的同時還注意軟件的易用性,因為這些易用特性或質量屬性能使客戶更準確、高效地完成任務。例如:客戶有時要求產品要“界面友好”或“健壯”或“高效率”,但對于開發人員來講,太主觀了并無實用價值。正確的做法是,分析人員通過詢問和調查了解客戶所要的“友好、健壯、高效所包含的具體特性,具體分析哪些特性對哪些特性有負面影響,在性能代價和所提出解決方案的預期利益之間做出權衡,以確保做出合理的取舍。?
    8、 允許重用已有的軟件組件?
      需求通常有一定靈活性,分析人員可能發現已有的某個軟件組件與客戶描述的需求很相符,在這種情況下,分析人員應提供一些修改需求的選擇以便開發人員能夠降低新系統的開發成本和節省時間,而不必嚴格按原有的需求說明開發。所以說,如果想在產品中使用一些已有的商業常用組件,而它們并不完全適合您所需的特性,這時一定程度上的需求靈活性就顯得極為重要了。?
    9、 要求對變更的代價提供真實可靠的評估?
      有時,人們面臨更好、也更昂貴的方案時,會做出不同的選擇。而這時,對需求變更的影響進行評估從而對業務決策提供幫助,是十分必要的。所以,客戶有權利要求開發人員通過分析給出一個真實可信的評估,包括影響、成本和得失等。開發人員不能由于不想實施變更而隨意夸大評估成本。?
    10、 獲得滿足客戶功能和質量要求的系統?
      每個人都希望項目成功,但這不僅要求客戶要清晰地告知開發人員關于系統“做什么”所需的所有信息,而且還要求開發人員能通過交流了解清楚取舍與限制,一定要明確說明您的假設和潛在的期望,否則,開發人員開發出的產品很可能無法讓您滿意。?
    11、 給分析人員講解您的業務?
      分析人員要依靠客戶講解業務概念及術語,但客戶不能指望分析人員會成為該領域的專家,而只能讓他們明白您的問題和目標;不要期望分析人員能把握客戶業務的細微潛在之處,他們可能不知道那些對于客戶來說理所當然的“常識”。?
    12、 抽出時間清楚地說明并完善需求?
      客戶很忙,但無論如何客戶有必要抽出時間參與“頭腦高峰會議”的討論,接受采訪或其他獲取需求的活動。有些分析人員可能先明白了您的觀點,而過后發現還需要您的講解,這時請耐心對待一些需求和需求的精化工作過程中的反復,因為它是人們交流中很自然的現象,何況這對軟件產品的成功極為重要。?
    13、 準確而詳細地說明需求?
      編寫一份清晰、準確的需求文檔是很困難的。由于處理細節問題不但煩人而且耗時,因此很容易留下模糊不清的需求。但是在開發過程中,必須解決這種模糊性和不準確性,而客戶恰恰是為解決這些問題作出決定的最佳人選,否則,就只好靠開發人員去正確猜測了。?
      在需求分析中暫時加上“待定”標志是個方法。用該標志可指明哪些是需要進一步討論、分析或增加信息的地方,有時也可能因為某個特殊需求難以解決或沒有人愿意處理它而標注上“待定”??蛻粢M量將每項需求的內容都闡述清楚,以便分析人員能準確地將它們寫進“軟件需求報告”中去。如果客戶一時不能準確表達,通常就要求用原型技術,通過原型開發,客戶可以同開發人員一起反復修改,不斷完善需求定義。?
    14、 及時作出決定?
      分析人員會要求客戶作出一些選擇和決定,這些決定包括來自多個用戶提出的處理方法或在質量特性沖突和信息準確度中選擇折衷方案等。有權作出決定的客戶必須積極地對待這一切,盡快做處理,做決定,因為開發人員通常只有等客戶做出決定才能行動,而這種等待會延誤項目的進展。?
    15、 尊重開發人員的需求可行性及成本評估?
      所有的軟件功能都有其成本??蛻羲M哪承┊a品特性可能在技術上行不通,或者實現它要付出極高的代價,而某些需求試圖達到在操作環境中不可能達到的性能,或試圖得到一些根本得不到的數據。開發人員會對此作出負面的評價,客戶應該尊重他們的意見。?
    16、 劃分需求的優先級?
      絕大多數項目沒有足夠的時間或資源實現功能性的每個細節。決定哪些特性是必要的,哪些是重要的,是需求開發的主要部分,這只能由客戶負責設定需求優先級,因為開發者不可能按照客戶的觀點決定需求優先級;開發人員將為您確定優先級提供有關每個需求的花費和風險的信息。?
      在時間和資源限制下,關于所需特性能否完成或完成多少應尊重開發人員的意見。盡管沒有人愿意看到自己所希望的需求在項目中未被實現,但畢竟是要面對現實,業務決策有時不得不依據優先級來縮小項目范圍或延長工期,或增加資源,或在質量上尋找折衷。?
    17、 評審需求文檔和原型?
      客戶評審需求文檔,是給分析人員帶來反饋信息的一個機會。如果客戶認為編寫的“需求分析報告”不夠準確,就有必要盡早告知分析人員并為改進提供建議。?
      更好的辦法是先為產品開發一個原型。這樣客戶就能提供更有價值的反饋信息給開發人員,使他們更好地理解您的需求;原型并非是一個實際應用產品,但開發人員能將其轉化、擴充成功能齊全的系統。?
    18、 需求變更要立即聯系?
      不斷的需求變更,會給在預定計劃內完成的質量產品帶來嚴重的不利影響。變更是不可避免的,但在開發周期中,變更越在晚期出現,其影響越大;變更不僅會導致代價極高的返工,而且工期將被延誤,特別是在大體結構已完成后又需要增加新特性時。所以,一旦客戶發現需要變更需求時,請立即通知分析人員。?
    19、 遵照開發小組處理需求變更的過程?
      為將變更帶來的負面影響減少到最低限度,所有參與者必須遵照項目變更控制過程。這要求不放棄所有提出的變更,對每項要求的變更進行分析、綜合考慮,最后做出合適的決策,以確定應將哪些變更引入項目中。?
    20、 尊重開發人員采用的需求分析過程?
      軟件開發中最具挑戰性的莫過于收集需求并確定其正確性,分析人員采用的方法有其合理性。也許客戶認為收集需求的過程不太劃算,但請相信花在需求開發上的時間是非常有價值的;如果您理解并支持分析人員為收集、編寫需求文檔和確保其質量所采用的技術,那么整個過程將會更為順利。?
    “需求確認”意味著什么?
      在“需求分析報告”上簽字確認,通常被認為是客戶同意需求分析的標志行為,然而實際操作中,客戶往往把“簽字”看作是毫無意義的事情?!八麄円以谛枨笪臋n的最后一行下面簽名,于是我就簽了,否則這些開發人員不開始編碼?!?
      這種態度將帶來麻煩,譬如客戶想更改需求或對產品不滿時就會說:“不錯,我是在需求分析報告上簽了字,但我并沒有時間去讀完所有的內容,我是相信你們的,是你們非讓我簽字的?!?
      同樣問題也會發生在僅把“簽字確認”看作是完成任務的分析人員身上,一旦有需求變更出現,他便指著“需求分析報告”說:“您已經在需求上簽字了,所以這些就是我們所開發的,如果您想要別的什么,您應早些告訴我們?!?
      這兩種態度都是不對的。因為不可能在項目的早期就了解所有的需求,而且毫無疑問地需求將會出現變更,在“需求分析報告”上簽字確認是終止需求分析過程的正確方法,所以我們必須明白簽字意味著什么。?
      對“需求分析報告”的簽名是建立在一個需求協議的基線上,因此我們對簽名應該這樣理解:“我同意這份需求文檔表述了我們對項目軟件需求的了解,進一步的變更可在此基線上通過項目定義的變更過程來進行。我知道變更可能會使我們重新協商成本、資源和項目階段任務等事宜。”對需求分析達成一定的共識會使雙方易于忍受將來的摩擦,這些摩擦來源于項目的改進和需求的誤差或市場和業務的新要求等。?
      需求確認將迷霧撥散,顯現需求的真面目,給初步的需求開發工作畫上了雙方都明確的句號,并有助于形成一個持續良好的客戶與開發人員的關系,為項目的成功奠定了堅實的基礎。

    專訪架構師周愛民:談企業軟件架構設計?
    最近在網上讀到了“殺不死的人狼——我讀《人月神話》”系列文章。是周愛民關于《人月神化》的讀書心得。《人月神化》在軟件工程里一本很有分量的書,講述了Brooks博士在IBM公司 System/360家族和OS/360中的項目管理經驗。周愛民在他的這一系列文章中用自己架構師經歷為基礎,從他的視角重新品讀了這本書。而這也使我有了采訪下他的想法,從中我們也許可以了解到中國企業內軟件架構設計這個環節的現狀。目前周愛民是盛大網絡架構師。在此特別感謝周愛民在百忙中抽出時間回復了這次訪談。

    1, 您好,請先向我們的網友簡單做一下自我介紹自己好嗎?

    我94年開始學習電腦,基本上從一開始就學編程。從96年開始涉及商業軟件開發,到現在約十一年了。其間我在鄭州的一家軟件公司呆了7年,歷經了一家軟件公司的中興到消亡,因而也意識到工程、管理在軟件企業——當然也包括其它類型的企業——中的價值。后來,從03年開始的一年多時間,我在鄭州的另一家公司任軟件部經理,也開始實踐自己的工程和管理思想。很好,到現在我離開這家公司一年多了,公司狀況依然很不錯。我認為,團隊或公司并沒有因為你的缺席而變得糟糕,那便已經是良性管理的表現了。關于“Borland Delphi產品專家”,其實更多的是一個圈子的認可,而非行業的認可。我在“大富翁論壇(delphibbs.com)”活動了很長的時間,得到了一些朋友們的認可,后來Borland要評選這個專家的時候,大家推舉了我,于是就得了這個稱號。其實在我看來,優秀的人才、專家很多,我大約是人緣好點,運氣好點罷。

    我05年9月開始到盛大網絡,任架構師一職。當時Borland China也有offer,但在顧問、軟件工程師與架構師之間,我選擇了架構師這個職務,因為我對這個角色更加感興趣。我目前的工作,主要是盛大的軟件平臺方面的架構、設計和一些實施方面的事務。雖然很多人認為盛大是做游戲的公司,但我基本不涉及游戲產品的開發。

    在開發技術方面,我03年出版過一本《Delphi源代碼分析》。在工程方面,《大道至簡——軟件工程實踐者的思想》一書在下月初就應出版了,它的第一版是以電子版的形式發布的。我在寫的第三本書則是講計算機語言的,題材是“動態函數式語言”。

    2,您做為盛大網絡的架構師,請介紹一下在軟件項目中平臺架構師是一份怎樣的角色?主要處理哪些工作?

    架構師有很多種。很多人把體系架構師與架構師等同,其實不對。各類架構師基本素質要求大抵一致,例如分析能力、設計的技術方法,以及對設計目標的前瞻性。但是他們的專業素質會有一些差別。舉個實例來說,如果讓我設計游戲引擎的架構,我就會做不好。但是,如果這個游戲引擎要設計成一個獨立的平臺層次,具有語言無關性、平臺整合能力,或是對不同類型游戲的統一支撐,那么就是平臺架構師的職責了。

    具體來說,平臺架構師會決策某個部分與其它部分的相互關系、界面的規約和檢測評估它們的方法。如果一個游戲引擎只為某個游戲而設計,那么是用不到平臺架構師的。但如果A游戲中的引擎要移植到B游戲,或者更多的游戲,甚至只是抽離它的部分,以作為某種體系中的一個數據交互層,那么就需要平臺架構師來考量技術上的可行性、穩定性以及它對于更大范圍內的平臺建設的價值——當然,如果沒有價值,架構師也會否定它。

    平臺是長期建設的。平臺架構師的重要職責之一,就是長期的規劃和持續的推進。所以平臺架構師的工作總是伴隨客戶的戰略決策的。如果一個設計只是解決短期的技術問題,那么也并不需要平臺架構師,但如果是幾年或十幾年要在上面持續經營的一個整體方向,那么平臺架構師就需要圍繞戰略來設計架構的藍圖,并決定規劃的實施步驟。在這些方面,他可能需要協調很多團隊一些來工作。不過,這可不是跟項目經理搶飯碗。因為項目經理重在實施,而架構師重在規劃。

    當然,事實上我也做一些其它類型的架構設計工作。例如設計一個小的模塊,或者一個業務工件。好的架構師不會拒絕這些工作,而是從更多的、細節的工作中發現整體與局部的關系。也只有觸及到具體工作的細節,架構師才可能更早地發覺設計上的隱患或者與目標的偏差。

    3,《人月神話》這本書30多年來一直被認為是項目管理者的必讀書,最近也看到您的blog里寫了一系列相關的書評。您是怎么看到書中“項目實施法則“和實際項目工作之間的關系。

    這幾個問題我基本上都在《殺不死的人狼》一文中講過了。概括來說,我認為有以下三點:

    一、討論“有或沒有”銀彈這樣的話題沒有意義,因為《人月神話》所述的人狼根本殺不死,而且Brooks所設想的銀彈也過于學術。?
    二、《人月神話》從廣義工程的角度設定了這個命題,這個命題的根本目標與次要目標正好與具體工程(狹義工程)相反。?
    三、我承認《人月神話》神話所述的答案以及建議在如今的軟件工程中得到了體現。但我們應該更清醒地辨析出現象、答案與本質,并分析哪些是本質的自然延伸,而哪些只是《人月神話》所帶來的影響——Brooks預言了未來,也就改變了未來,即使未來未必應該如此。

    與大多數人不一樣的是,我更多的是從與Brooks的預言不一致的那些現象是去發現一些東西。我所看到的是,正是在改變了Brooks的命題,或者認識到他所述的“本質”未必正確的時候,我們才找到了一些“不一樣的成功”。我提醒大家關注這些事例,以及它們與傳統工程、廣義工程的本質差異。

    我并不反對《人月神話》中的大多數工程觀點,以及我們現在的軟件業中的工程實踐經驗。但是狹義工程沒有必要去追尋銀彈或那些看起來看銀彈的東西,我們應該更加靈活。

    4企業在進行項目的軟件架構設計時,需要考慮哪些關鍵的問題?

    企業實施過程中的架構問題,可以分成兩個部分來考慮。一個是軟件企業自身,一個是工程的目標客戶(有些時候它與前者一則)。基本上來說,架構設計首先是面向客戶的,甚至在整個工程的絕大多數時候都面向客戶。因為理解決定設計,所以讓架構師盡可能早地、深入地了解工程目標、應用環境、戰略決策和發展方向,是至關重要的。否則,架構師是不可能做出有效的設計來的。

    架構設計關注于三個方面:穩定、持續和代價。

    穩定性由架構師的設計能力決定。架構的好壞是很難評判的,但基本的法則是“適用”。如果一個架構不適用,那么再小或者再大都不可能穩定。所因此進一步推論是“架構必須以工程的主體目標為設計象”??雌饋磉@是個簡單的事,但事實上很多架構設計中只是在做邊角功夫,例如為一兩處所謂的“精彩的局部”而叫好,全然不顧架構是否為相應的目標而做。

    持續性由架構師的地位決定。如果不能認識“設計的一致性”,以及架構師對這種一致性的權威,那么再好的架構也會面臨解體,再長遠的架構也會在短期內被廢棄。架構的實施是要以犧牲

    自由性為代價的,架構師沒有足夠的地位(或權威),則不可能對抗實施者對自由的渴望。通常的失敗,并在于架構的好或壞,而是架構被架空,形同虛設。

    代價的問題上面有過一點討論,但方向不同。這里說明的是,如果架構師沒有充分的經驗,不能準確評估所設計的架構的資源消耗,那么可能在項目初起便存在設計失誤;也可能在項目中困于枝節,或疏離關鍵,從而徒耗了資源。這些都是架構師應該預見、預估的。

    對于企業設計來說,上面三個方面沒有得到關注的結果就是:遲遲無法上線的工程、半拉子工程和不停追加投資的工程項目。我不否認項目經理對這些問題的影響,但事實上可能從設計就開始出了問題,而項目經理只是回天乏術罷了。

    最后說明一下,我認為目前大多數的企業項目都缺乏架構上的考量。大多數軟件公司只是出于自身的需要(例如組件化和規模開發)而進行架構設計。這樣的設計不是面向客戶的,事實上這增加了客戶投資,而未能給客戶項目產生價值。這也是我強調架構面向客戶的原因之一。

    5 目前,你的團隊在使用什么樣的產品或者方法來進行軟件架構設計?

    架構設計的主要輸出是文檔,因而并沒有什么特別的工具來幫助你做架構設計。很多工具是輔助分析的,例如MindMananger;另外一些則可能輔助你表述,例如Together和Rose。

    大多數技術出身的架構師會僅把“軟件編寫的東西”才稱為工具。其實不然,會議室里的那面白板也是我的工具之一。放開思路,市場規劃圖、技術架構路標圖、特性/收益規劃圖等等這些圖表也是我們的工具。除開這些之外,模式語言和建模語言也是主要的、形式化的工具。

    我經常按RUP的規范寫文檔,也偶爾放棄其中的某些具體格式。這些既有的文檔模板也是工具。當然,毋庸置疑的是這樣的工具也包括WORD和PowerPoint——很多人并不知道,我有1/4的設計是先用PowerPoint/Visio來完成的。

    具體到方法,則非常多了,但應用哪一種則與場景有關。不過最先做的則是分層,這與自頂向下的結構分析很象——事實上在分析和設計的最初階段,這種方法幾乎是必須的。

    6,您覺得國內外軟件架構設計這個環節的主要不同在哪里?

    正如你這個問題所表現出來的一樣:我們太注重于工程環節的某個局部。

    國外軟件行業在工程實踐經驗上已豐富得多,因此大多數程序員、項目經理或測試人員等等對工程的理解也深刻得多。他們并不自恃于當前的環節,也不否認其它環節。這意味著在整體實施?
    中大家更容易達成一致。然而國內的軟件工程則很少強調這種合作,項目經理強調管理,程序員強調技術,架構師強調一致性和持續性,測試人員則很開心的看到每一個錯誤并以及數量作為評核依據。

    顯然這里出了問題:我們的合作環節在各自為戰。大家都在強調自己的重要性,于是工程就沒法做了。解決的法子,還是讓大家都意識到對方工作的目標與職責,而不僅僅是了解自己的那個小圈子。

    7,可以介紹一下你目前的Qomo項目嗎?我們的網友該如何參與?

    Qomo(Qomolangma OpenProject)是一個JavaScript上的開源項目。目前Qomo 1.0正式版已經發布了。Qomo V1以語言補實為基本思想,在JavaScript上擴展了AOP、OOP、IOP和GP等編程方法,基于它自身的完備的實現,Qomo也提供了Builder和Profiler工具和相關的庫。

    Qomo V1只是整個Qomolangma OpenProject構想中的一很小一部分——盡管它重要。Qomo項目提出的整體目標是:?
     -Qomo內核是足夠強大的能應用在不同的JavaScript宿主環境下的通用擴展。?
     -Qomo有能力提供膠合不同的應用環境下功能需求的中間代碼。?
     -Qomo可以作為定制的宿主應用的代碼包的一個部分以提升應用的體驗或局部性能。

    所以Qomo V1并不完備。即便是我們正在展開的Qomo V2,也并不完備。V2計劃提供組件庫、數據庫存取層和圖形表現層。此外,Qomo V2也打算啟用數個實踐項目,一方面作為Qomo的范例,另一方面也驗證Qomo的設計。

    Qomo已經在sourceforge上注冊過,但在那里表現并不活躍。你可以總是從我的blog上得到Qomo的最新消息,包括Qomo的計劃與每個版本發布。至于參與這個項目,請發mail給我。

    C++之設計模式實現代碼?
    ———————– Page 1———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    設計模式精解-GoF 23 種設計模式解析附 C++實現源碼目 錄
    • 1
    • 2
    • 3

    0 引言…………………………………………………………………………………………………………………………….2?
    0.1 設計模式解析(總序)………………………………………………………………………………………..2?
    0.2 設計模式解析后記……………………………………………………………………………………………….2?
    0.3 與作者聯系…………………………………………………………………………………………………………5?
    1 創建型模式…………………………………………………………………………………………………………………..5?
    1.1 Factory模式 …………………………………………………………………………………………………………5?
    1.2 AbstactFactory模式 ……………………………………………………………………………………………. 11?
    1.3 Singleton模式…………………………………………………………………………………………………….16?
    1.4 Builder模式………………………………………………………………………………………………………..18?
    1.5 Prototype模式…………………………………………………………………………………………………….23?
    2 結構型模式…………………………………………………………………………………………………………………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 說明 …………………………………………………………………………………………………………………………105

    第 1 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 2———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    0 引言

    0.1 設計模式解析(總序)

    “Next to My Life, Software Is My Passion”——Robert C.Martin.懂了設計模式,你就懂了面向對象分析和設計(OOA/D )的精要。反之好像也可能成
    • 1
    • 2
    • 3

    立。道可道,非常道。道不遠人,設計模式亦然如此。

    一直想把自己的學習經驗以及在項目中的應用經歷拿出來和大家共享,卻總是下不了這
    • 1

    個決心:GoF 的23 種模式研讀、總結也總需要些時日,然而時間對于我來說總是不可預計

    的。

    之所以下了這個決心,有兩個原因:一是Robert 的箴言,二是因為我是一個感恩的人,
    • 1

    就像常說的:長懷感恩之心,人生便無遺憾。想想當時讀 GoF 的那本圣經時候的苦悶、實

    現23 個模式時候的探索、悟道后的欣悅,我覺得還是有這個意義。

    0.2 設計模式解析后記

    寫完了Interpreter模式之后,我習慣性的看看下一天的安排,卻陡然發現GoF的 23個
    • 1

    設計模式的解析已經在我不經意間寫完了。就像在一年前看GoF的《設計模式》一書,和半

    年前用C++模擬、實現 23種經典的設計模式一般,透過這個寫解析的過程,我又看到了另外

    一個境界。一直認為學習的過程很多時候可以這樣劃分:自己學會一門知識(技術)、表達

    出來、教會別人、記錄下來,雖然這個排序未必對每個人都合適 (因為可能不同人有著不同

    的特點能力)。學一門知識,經過努力、加以時日,總是可以達到的,把自己學的用自己的

    話表達出來就必須要將學到的知識加以消化、理解,而教會一個不懂這門知識的人則比表達

    出來要難,因為別人可能并不是適應你的表述方式,記錄下來則需要經過沉淀、積累、思考,

    最后厚積薄發,方可小成。

    設計模式之于面向對象系統的設計和開發的作用就有如數據結構之于面向過程開發的
    • 1

    作用一般,其重要性和必要性自然不需要我贅述。然而學習設計模式的過程卻是痛苦的,從

    閱讀設計模式的圣經——GoF 的《設計模式:可復用面向對象軟件的基礎》時的枯燥、苦悶、

    茫無頭緒,到有一天突然有一種頓悟;自己去實現GoF 的23 中模式時候的知其然不知其所

    以然,并且有一天在自己設計的系統種由于設計的原因讓自己苦不堪言,突然悟到了設計模

    第 2 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 3———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    式種的某一個正好可以很好的解決問題,到自己設計的 elegant 的系統時候的喜悅與思考;

    一直到最后向別人去講解設計模式,別人向你咨詢設計模式,和別人討論設計模式。就如

    GoF 在其前言中說到:一旦你理解了設計并且有了一種 “Aha!” (而不是 “Huh?”)的應

    用經驗和體驗后,你將用一種非同尋常的方式思考面向對象設計。這個過程我認為是漫長的,

    painful,但是是非常必要的。經過了的才是自己的,Scott Mayer 在其巨著《Effective C++》

    就曾經說過:C++老手和C++新手的區別就是前者手背上有很多傷疤。是的在軟件開發和設

    計的過程中,失敗、錯誤是最好的老師,當然在系統開發中,失敗和錯誤則是噩夢的開端和

    結束,因為你很難有改正錯誤的機會。因此,盡量讓自己多幾道疤痕是對的。

    面向對象系統的分析和設計實際上追求的就是兩點,一是高內聚 (Cohesion),而是低
    • 1

    耦合 (Coupling)。這也是我們軟件設計所準求的,因此無論是OO 中的封裝、繼承、多態,

    還是我們的設計模式的原則和實例都是在為了這兩個目標努力著、貢獻著。

    道不遠人,設計模式也是這般,正如我在 《設計模式探索(總序)》中提到的。設計模
    • 1

    式并不是空的理論,并不是脫離實際的教條。就如我們在進行軟件開發的過程會很自然用到

    很多的算法和結構來解決實際的問題,那些其實也就是數據結構中的重要概念和內容。在面

    向對象系統的設計和開發中,我們已經積累了很多的原則,比如面向對象中的封裝、繼承和

    多態、面向接口編程、優先使用組合而不是繼承、將抽象和實現分離的思想等等,在設計模

    式中你總是能看到他們的影子,特別是組合 (委托)和繼承的差異帶來系統在耦合性上的差

    別,更是在設計模式多次涉及到。而一些設計模式的思想在我們做系統的設計和開發中則是

    經常要用到的,比如說Template、Strategy模式的思想,Singleton模式的思想,Factory

    模式的思想等等,還有很多的模式已經在我們的開發平臺中扎根了,比如說Observer (其實

    例為Model-Control-View模式)是MFC和Struts中的基本框架,Iterator模式則在C++的STL

    中有實現等?;蛟S有的人會說,我們不需要設計模式,我們的系統很小,設計模式會束縛我

    們的實現。我想說的是,設計模式體現的是一種思想,而思想則是指導行為的一切,理解和

    掌握了設計模式,并不是說記住了23種(或更多)設計場景和解決策略(實際上這也是很

    重要的一筆財富),實際接受的是一種思想的熏陶和洗禮,等這種思想融入到了你的思想中

    后,你就會不自覺地使用這種思想去進行你的設計和開發,這一切才是最重要的。

    之于學習設計模式的過程我想應該是一個迭代的過程,我向來學東西的時候不追求一遍
    • 1

    就掌握、理解透徹 (很多情況也是不可能的),我喜歡用一種迭代的思想來指導我的學習過

    程??磿床欢?、思想沒有理解,可以反復去讀、去思考,我認為這樣一個過程是適合向我

    們不是有一個很統一的時間去學習一種技術和知識(可能那樣有時候反而有些枯燥和郁悶)。

    第 3 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 4———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    GoF 在 《設計模式》一書中也提到,如果不是一個有經驗的面向對象設計人員,建議從最簡

    單最常用的設計模式入門,比如AbstractFactory 模式、Adapater模式、Composite 模式、

    Decorator 模式、Factory模式、Observer模式、Strategy 模式、Template 模式等。我的

    感觸是確實是這樣,至少GoF 列出的模式我都在開發和設計有用到,如果需要我這里再加上

    幾個我覺得在開發中會很有用的模式:Singleton模式、Fa?ade模式和Bridge 模式。

    寫設計模式解析的目的其實是想把GoF 的《設計模式》進行簡化,變得容易理解和接受。
    • 1

    GoF 的 《設計模式》是圣經,但是同時因為 《設計模式》一書是4 位博士的作品,并且主要

    是基于Erich 的博士論文,博士的特色我覺得最大的就是抽象,將一個具體的問題抽象到一

    般,形成理論。因此GoF 的這本圣經在很多地方用語都比較精簡和抽象,讀過的可能都有一

    種確實是博士寫出來的東西的感覺。抽象的好處是能夠提供指導性的意見和建議,其瑕疵就

    是不容易為新手所理解和掌握。我的本意是想為抽象描述和具體的實現提供一個橋接 (盡管

    GoF 在書中給出了很多的代碼和實例,但是我覺得有兩個不足:一是不完整,結果是不好直

    接看到演示,因此我給出的代碼都是完整的、可編譯運行的;二是給出的都是一些比較大的

    系統中一部分簡單實現,我想GoF 的原意可能是想說明這些模式確實很管用,但是卻同時帶

    來一個更大的不好的地方就是不容易為新手理解和掌握),然而這個過程是痛苦的,也可能

    是不成功的 (可能會是這樣)。這里面就有一個取舍的問題,一方面我想盡量去簡化GoF

    的描述,然而思考后的東西卻在很多的時候和GoF 的描述很相似,并且覺得將這些內容再抽

    象一下,書中的很多表達則是最為經典的。當然這里面也有些許的例外,Bruce Eckel 在其

    大作《Thinking in Patterns》一書中提到:Bridge 模式是GoF 在描述其 23 中設計模式中

    描述得最為糟糕得模式,于我心有戚戚焉!具體的內容請參看我寫的《設計模式解析——

    Bridge 模式》一文。另外一方面,我又要盡量去避免走到了GoF 一起,因為那樣就失去了

    我寫這個解析的本意了。這兩個方面的權衡是很痛苦,并且結果可能也還是沒有達到我的本

    意要求。

    4 月份是我最不忙的時候,也是我非常忙的時候。論文的查閱、思考、撰寫,幾個項目
    • 1

    的前期準備 (文檔、Demo等),俱樂部的諸多事宜,挑戰杯的準備,學習 (課業、專業等各

    個方面)等等,更加重要的是Visual CMCS (Visual C_minus Compiler System)的設

    計和開發(Visual CMCS是筆者設計和開發的C_minus語言(C的子集)的編譯系統,系統操

    作界面類似VC,并且準備代碼分發和共享,詳細信息請參考Visual CMCS的網站和Blog中的

    相關信息的發布), Visual CMCS1.0(Beta)終于在4 月底發布了,也在別人的幫助下構建

    http://cs.whu.edu.cn/cmcs )。之所以提及這個,一方面是在Visual CMCS
    • 1

    了Visual CMCS的網站(

    第 4 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 5———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    的設計和開發體驗了很多的設計模式,比如Factoty模式、Singleton模式、Strategy模式、

    State模式等等(我有一篇Blog中有關于這個的不完全的描述);另外一方面是這個設計模

    式解析實際上在這些工作的間隙中完成的,我一般會要求自己每天寫一個模式,但是特殊的

    時候可能沒有寫或者一天寫了不止一個。寫這些文章,本身沒有任何功利的雜念,只是一個

    原生態的沖動,反而很輕松的完成了。有心栽花未必發,無心之事可成功,世間的事情可能

    在很多的時候恰恰就是那樣了。

    最后想用自己在閱讀、學習、理解、實現、應用、思考設計模式后的一個感悟結束這個
    • 1

    后記:只有真正理解了設計模式,才知道什么叫面向對象分析和設計。

    k_eckel 寫畢于2005-05-04 (五四青年節) 1 :01
    • 1

    0.3 與作者聯系

    Author K_EckelState Candidate for Master’s Degree School of Computer Wuhan UniversityE_mail frwei@whu.edu.cn
    • 1
    • 2
    • 3
    • 4
    • 5

    1 創建型模式

    1.1 Factory 模式

    問題

    在面向對象系統設計中經??梢杂龅揭韵碌膬深悊栴}:1 )為了提高內聚(Cohesion)和松耦合(Coupling ),我們經常會抽象出一些類的公共
    • 1
    • 2
    • 3

    接口以形成抽象基類或者接口。這樣我們可以通過聲明一個指向基類的指針來指向實際的子

    類實現,達到了多態的目的。這里很容易出現的一個問題n 多的子類繼承自抽象基類,我們

    不得不在每次要用到子類的地方就編寫諸如 new ×××;的代碼。這里帶來兩個問題 1)客

    戶程序員必須知道實際子類的名稱 (當系統復雜后,命名將是一個很不好處理的問題,為了

    處理可能的名字沖突,有的命名可能并不是具有很好的可讀性和可記憶性,就姑且不論不同

    程序員千奇百怪的個人偏好了。),2)程序的擴展性和維護變得越來越困難。

    第 5 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 6———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    2 )還有一種情況就是在父類中并不知道具體要實例化哪一個具體的子類。這里的意思
    • 1

    為:假設我們在類A 中要使用到類B,B 是一個抽象父類,在 A 中并不知道具體要實例化

    那一個B 的子類,但是在類A 的子類D 中是可以知道的。在A 中我們沒有辦法直接使用類

    似于new ×××的語句,因為根本就不知道×××是什么。

    以上兩個問題也就引出了Factory 模式的兩個最重要的功能:1 )定義創建對象的接口,封裝了對象的創建;2 )使得具體化類的工作延遲到了子類中。
    • 1
    • 2
    • 3
    • 4
    • 5

    模式選擇

    我們通常使用Factory 模式來解決上面給出的兩個問題。在第一個問題中,我們經常就
    • 1

    是聲明一個創建對象的接口,并封裝了對象的創建過程。Factory 這里類似于一個真正意義

    上的工廠(生產對象)。在第二個問題中,我們需要提供一個對象創建對象的接口,并在子

    類中提供其具體實現(因為只有在子類中可以決定到底實例化哪一個類)。

    第一中情況的Factory 的結構示意圖為:圖1:Factory 模式結構示意圖 1圖 1 所以的Factory 模式經常在系統開發中用到,但是這并不是 Factory 模式的最大威
    • 1
    • 2
    • 3
    • 4
    • 5

    力所在 (因為這可以通過其他方式解決這個問題)。Factory 模式不單是提供了創建對象的接

    口,其最重要的是延遲了子類的實例化(第二個問題),以下是這種情況的一個 Factory 的

    結構示意圖:

    第 6 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 7———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼http://www.mscenter.edu.cn/blog/k_eckel

    圖2:Factory 模式結構示意圖 1圖2 中關鍵中Factory 模式的應用并不是只是為了封裝對象的創建,而是要把對象的創
    • 1
    • 2
    • 3

    建放到子類中實現:Factory 中只是提供了對象創建的接口,其實現將放在 Factory 的子類

    ConcreteFactory 中進行。這是圖2 和圖 1 的區別所在。

    實現

    完整代碼示例(code)

    Factory 模式的實現比較簡單,這里為了方便初學者的學習和參考,將給出完整的實現
    • 1

    代碼(所有代碼采用 C++實現,并在VC 6.0 下測試運行)。

    第 7 頁 共 105 頁 k_eckel
    • 1

    ———————– Page 8———————–

    設計模式精解-GoF 23 種設計模式解析附C++實現源碼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….”<

    總結

    以上是生活随笔為你收集整理的架构设计方法学的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。