三、架構的開發成本以及品質問題解決討論
架構一個重要的關注點在於控制開發成本,這點很重要,因為通常講維護成本是開發成本的3倍。降低開發成本核心,在於提高效率,這也意味著提高了開發對需求的回應時間,而時間對公司來說是重要的。
1. 問題域
問題域可分解為兩種類型,業務上和技術上。(又見分解,分而治之真是老祖宗傳下的靈丹妙藥啊)
1. 業務上。問題域分解為,邏輯的縱向抽象層次,以及邏輯的橫向模組分解和整合。
2. 技術上。問題域分解為,縱向的技術主題,以及橫向的技術職責的分解和整合。
A. 領域基本問題
所以通常而言,領域模型設計中,模組分解,抽象分層和職責分層都是重要手段。問題域為:流程,業務實體和計算(包括規則)。
- 對象的抽象分解和整合
- 對象的依賴分解和整合(模組內和模組外)
- 流程的分解和整合(頁面流,工作流程以及計算流程)
- 進程邊界:使用者請求重新導向,以及業務資料持久化等。
B. 領域組件問題
物件導向語言本身沒有提供的組件層級的依賴關係整合能力。語言不提供,因為領域組件的粒度太大,超越了語言的範疇。但我們可以通過架構提供,在Java體系中,目前已經有一個較好的解決方案:OSGi(JSR291)。可以完美的解決元件服務依賴關係管理,包括熱替換。
同時另一個問題——邏輯分層的問題:保險產品面臨的核心層,國家層以及公司層三個邏輯層次分解和整合能力。這點的解決方案可以通過OSGi + Spring來解決,包括了靜態差異性替換和動態差異性替換。
還有組件邊界保護問題,我們希望限制別的組件訪問本組件內部實現,有兩種手段可以完成,1是提交部署時,通過在代碼提交時的代碼檢查工具,或者發布時編譯工具完成;2是通過OSGi的邊界限制能力。
C. 邏輯替換問題
邏輯的替換根據開發方式不同,有兩種類型:基於介面和基於繼承;
A. 基於介面(包括了靜態替換和動態替換)
1. 靜態替換是override,在OSGi中只要停止原有服務,啟用新服務即可,而在Spring中更改相應設定檔即可;
2. 動態替換,其實是指運行時Condition Service Locator,在OSGi中可以利用Extension Point(Plug-in)解決,而Spring中只要提供一個類似Service Locator就可以。
B. 基於繼承(或者靜態類)
1.開發時,直接修改原始碼編譯;
2.編譯時間,採用AspectJ,在編譯時間提供替換;
3.載入時,開發一個新邏輯的同名類,但其載入路徑優先於原有類;
2. 基本手段
提高開發效率和品質的基本手段是分解——即充分的分離系統中不同的關注點,好處不用說了,可以並發的工作,每個人面對的問題都簡單而容易操作。而與分解對應的整合,只有提供了好的整合能力,分解才成為現實,而只有分解了,才能清晰的提供業務更多適應性。
分解和整合的手段分為程式設計語言和技術架構兩個層面。所謂語言就是強架構,而架構就是弱語言。
A. 語言
現代物件導向的語言提供如下能力:抽象和派生能力,以及介面隔離能力。實際提供兩種分解和整合能力:
1. 把邏輯分解在兩個層次中,而通過繼承的方式把兩個部分整合在一起。
2. 把邏輯的外觀和實現分解在兩個地方,而通過介面實現的方式把兩部分整合在一起。
另一種語言AspectJ或者C#語言2.0之後提供的特性:把流程邏輯,分解在不同的地方,而通過簽名匹配,利用代碼產生的方式來把幾部分整合在一起。
B. 架構
然而語言提供的整合能力,畢竟底層,而且有限,擴充起來也格外小心。因而技術架構提供另外的整合能力就格外重要:
1. 對象關聯關係的分解和整合,如Spring提供容器管理能力
2. 模組間關聯關係的分解和整合,如OSGi,ESB等
3. 不同系統的類型分解和整合,如Spring利用動態代理提供的Exporter模式。
4. 流程邏輯的分解和整合,如Spring Web Flow以及jBPM。
C. 設計
說起整合,就不得不提到一種類型的對象存在——VO對象。VO對象是為了整合而存在的;其意義是:1. 保護系統的資訊邊界,提供一種結構可以使其它系統或者組件通過編碼方式擷取系統內資訊的方式;2. 保護系統的事務邊界,領域對象技術上攜帶著持久化資訊,通過VO可以屏蔽得以屏蔽。常見的VO對象存在於Web層和Domain層。
因此,VO對象的存在只是為了整合而存在,其是否存在的取決於架構的兩個方面:物件路徑訪問能力以及事務邊界管理。
Web層VO對象,以SWF為例,早在SWF 1.x時代,架構就提供了豐富的物件路徑訪問能力,但其Web互動是典型的MVC2方式,事務邊界在view的render前關閉,因而導致需要特定的VO對象來避免持久化資訊問題;而SWF 2.x時代,view的render是在事務邊界內,VO不在需要。
Domain層VO對象,通常是用於不同領域組件間的互動,但隨著架構的改進,整合代碼獨立存在而不再嵌入到組件內部,組件的邊界問題保護不複存在;更進一步的是,架構提供自動化的介面適配映射能力的增強。因而VO對象也失去存在的意義。
BTW:通常語言作為架構的基礎引入和更換是有巨大風險的;而通過提供強大的架構能力,架構儘可能多的完成技術問題,並通過中繼資料,模式以及約定降低業務和架構的耦合。避免因為架構升級帶來不必要的成本。
3. 其它手段
從技術手段上,提高開發效率的另外兩個手段是代碼產生和類庫引用。但代碼產生和類庫引用,都只解決了邏輯的分解能力,沒有提供整合能力,所以一般情況下需要提供框架組成,尤其代碼產生需要在系統的最外層,避免整合帶來的問題。
4. 學習成本
對於Team Dev來說,額外面臨一個問題,組織內部的學習成本問題。
1. 需要保持分解以及整合能力本身的簡約性
這個……其實是一個culture問題,不再羅唆!
2. 採用模式和約定是減少學習成本的另一種手段。ROR的興起就是最好的例證。
成本還表現在組織的劃分上,應用開發/架構開發,而在每個層面又劃分為橫向模組劃分。
總結一下,解決架構面臨開發成本問題需要如下幾個方面:
0. 問題域
1. 分解與分層
2. 架構與類庫,Spring,Hibernate。起支撐性作用。
3. 模式和技巧
4. 領域模型
5. 方法論
5.1.開發方法:OO(設計模式),FP(函數式編程)。
5.2.設計方法:Domain Model Prototype和業務行為的分析模式。
5. 品質問題
架構面臨的品質問題,則通過自動化測試,代碼偵查工具來完成。
必須大量應用自動化測試,減少人工硬調試的複雜性,重複性和不確定性。
自動化測試包括單元測試和整合測試。無論是單元測試還是整合測試對面臨需要脫離隔離依賴關係並保證開發的並行性。
單元測試面臨的項目執行問題:
5.1. 設計的粒度問題。設計的粒度大小將直接決定單元測試的難易程度。開發分工如果是設計和開發兩種角色集一體的,問題自我消化;但如果是分開,就會帶來一些分工認識問題。
5.2. 遺留系統風險。遺留系統通常依賴關係複雜,設計結構以及粒度也不好,同時缺乏既有測試案例。在遺留系統維護成本很高,為了滿足測試案例,通常需要對遺留系統重構,風險很高。
5.3. 測試案例評估與考核。測試案例不是越多越好,通常系統重構也會導致一些測試案例被拋棄,過多非核心用例反而是在重構中帶來成本。因此對於測試案例進行評估成為一種必要,評估的標準較難確定。
5.4. 工作量評估。寫測試案例技術上並非難題,但不代表沒有工作量。如果評估工作量也是一個問題。
5.5. 測試案例的簡易度。雖然技術上非難題,但是業務開發面臨的種種問題,還是需要項目做一定的封裝,以便提高測試案例的開發和啟動並執行效率。
以上幾點都是直接影響項目的進度,因此如果不能有效處理好,很難說服專案經理在專案計劃中執行單元測試。
6. 文檔的思考
6.1. 文檔的分類
架構文檔,high level設計文檔和detail設計文檔
6.2. Detail設計文檔面臨的問題
A. 維護成本高。開發過程中設計到的具體而維的細節變化較頻繁,導致維護成本偏高;而開發成本和維護成本1:3的比例,導致這些文檔在後期維護的成本也很高;
B. 驗收成本高。目前缺乏自動化的驗收工作;ST是黑箱測試,驗收的是系統,而非文檔;獨立驗收人員的學習曲線太高;而開發人員自我驗收的效果不好,即便是交叉驗收也容易達成私下協議;
C. 收益低。文檔的維護人員,工作缺乏成就感;這些文檔的閱讀者通常是IT人員,使用代碼閱讀無疑具有更好的閱讀效果;
本文地址http://www.chengxuyuans.com/software_design/176.html