Author:Anders小明
以前寫過一篇《基於抽象的分層結構》,這裡補充一篇《基於業務模組組件的系統架構》
一些內容在《項目筆記:dao,web,模組邊界以及Model分類》以及《模組的介面設計》隨筆中已經提到,這裡補充總結一下。
任何一個有一定規模系統,通常會把系統做一定分解降低分析設計開發的難度,模組劃分是一個比較常見的方式。
而在模組的劃分及其分析設計的實踐中,包括了兩種層次的邊界。第一是互動行為層次,第二是對象層次。
首先說互動行為。
模組和模組的互動介面最為重要,通常我們認為這些介面應該通用穩定,然而如何設計每個模組對外提供的介面卻是一個不易的問題。
整合的兩種基本實現方式:
1. API方式。
這是常見的實踐方式。即每個模組公開數量不多的介面類(但擁有較多的介面方法)以及介面參數(都是普通的VO),每個介面的設計和實現都有該模組成員維護;實踐中:這些介面都獨立打包,形成多(模組)對一(介面)的依賴關係,方便編譯。
這樣的好處是:介面邊界清晰,開發編譯依賴比較簡單。
然而實踐中極有可能出現兩種狀況:介面維護失控或者過嚴而死板(而影響開發)。介面失控是因為介面的維護太過隨意,因為A模組的需要就輕易在B模組中添加一個介面(方法),導致該介面(方法)非獨立性(基本上只給模組A的這個功能點使用),或者是介面的控制過嚴,導致或者工作效率不高,或者介面的易用性不好。
原因在於:介面是兩個模組間的耦合,而發生的種種問題在於模組耦合太過緊密;同時實踐中,把模組對外提供的介面,與模組需要實現的外部模組的整合混為一談;換句話說,A模組需要整合的語義,和B模組提供介面的語義存在差距。
這樣的實踐優點:開發管理控製成本較低,模組編譯依賴簡單,模組物理邊界明確。
2. Adapter方式
這種的實踐可以一定程度上解決API方式面臨的問題:根據指導原則——為了降低耦合只有在中間加一層;即不輕易為模組設計對外提供的介面(方法),除非是通過重構得來的;模組對外提供兩種類:一個是需要外部模組實現的介面(介面設計從本模組需要出發,當然每個介面儘管是為某個功能點服務,但也要注意其在模組內通用性);另一個是其它模組要求本模組實現的介面的實作類別(這塊物理上獨立打包,獨立於模組之外)。
即:A模組擁有一些需要B模組實現的介面(A模組對B模組的要求),而B模組中也有要求A模組實現的介面,因而A有這些介面的實作類別。
處於編譯依賴的考慮,已有的實踐是把處理介面適配的代碼維護在模組外的,就是所謂的整合模組,這樣編譯上就形成了1(介面實現)對n(模組)的依賴關係。模組的邊界在這裡模糊了,當然在這之外模組的邊界是很清晰的。
這種實踐方式的好處在於:模組的介面就多了一層隔離降低了耦合,把介面的通用性和介面的適應性分離,又明確了模組的邊界,使得介面在日後的最佳化和調整有了緩衝。
這樣的實踐和API實踐的不同之處在於:介面的設計權利一分為二,需求方擁有了其應該有的權利,並且這個權利與提供方沒有衝突(舊的模式不行,一旦供應方改變了介面,就立刻導致編譯問題)。
兩種方式的對比:
1. 採用API方式整合,代價在於維護API本身,API面對眾多的用戶端,其面臨的設計維護成本較高,同時實施成本高;
2. 採用Adapter方式整合,由於沒有維護API,缺乏可複用介面,但可以做到為每個用戶端自由定製,其設計維護成本較低,實施上成本較高;
整合的演化方式:
1. 採用事件模式。
這也是完成互動處理的模式。通常事件模式在業務行為上也可以完成和介面相互的功能,不過由於其在介面簽名上無法明確提供其業務含義,建議謹慎應用。對於產品化項目,項目開始可以應用事件處理機制,在成熟時提取為更具體的介面。
事件模式中,Event的監聽類也面臨著模組的邊界問題。已知的成熟開源項目都在事件來源中暴露的模組內部對象,方便開發人員使用。
可以說這種方式的是Adapter方式的演化;
2. 採用架構回調方式
工作流程和頁面流也負責整合不同的模組.不過因為工作流程和頁面流架構都維護獨立的資料對象共用池,因而在這個層面上,模組間直接的互動並不存在。這種整合上的優勢,演化成通過ESB等整合架構完成.
這種方式是API方式的演化,但是把調用點以及調用方獨立出來,成為架構的一部分。
現在說說對象一級的邊界整合。
在保險中,benefit對象會關聯一個product對象,不過product對象是是屬於產品模組而非保單模組,對於保單模組只關心id而並不使用對象,但在RMS或者FMS或者UIC這樣的Integration Environment卻是需要product對象的。我們要採用代碼產生的方式,在benefit對象上加一個annotation,比如Integration的annotation標識,使用AspectJ在編譯上enhancement產生的class,使得benefit對象在Integration Environment上可以拿到product對象,這算是一個整合方面。
組件化管理
組件化管理組件含兩個含義:
1. 組件存取控制,依賴管理以及服務註冊;
現有的存取控制的辦法,只能通過代碼提交時或者編譯發布時檢查,但我們更期望支援運行時的能力,避免外部組件訪問組件未申明公開的內部結構和程式;同時維護方式應該簡單方便,成本低。
目前的組件依賴管理幾乎沒有,尤其是基於版本的依賴;而在實踐中,依賴維護管理尤其是多版本的通常花費大量的成本。
2. 組件依賴的綁定以及失效(故障)的隔離;
我們希望能夠為每個組件提供一個保護地區,當其依賴的一個組件因為種種原因(軟體錯誤的或者軟體升級)失效時,系統至少應該提供一種fail-fast機制,包括如下能力:
A.故障即停(Halt on failure)——當一個組件出錯時,應當立即停止下來,而不是繼續執行可能不正確的操作;
B.故障曝光性質(Failure status property)——當一個組件發生故障時,系統中的其他組件應該得到通知,故障的原因必須交代清楚;
同時,我們希望該組件,如果可能它應該可以繼續運行。完成這樣的目標需要很多的工作,但首先依賴於系統fail-fast能力,同時在故障消除服務恢複後,系統能夠提供相應的通知,並控制恢複的順序。
已知的支撐架構:SCA和OSGi
1. SCA考慮的是異構非同步環境,OSGi考慮同構同步環境;
2. OSGi規定了容器如何管理組件,組件依賴(版本)管理,組件邊界保護以及元件服務依賴運行時繫結原則和許可權控制;SCA對此沒有涉及;
3. SCA考慮的如何暴露服務,設計時用戶端如何使用服務;OSGi考慮的更加完善;