以前寫過一篇《基于抽象的分層結(jié)構(gòu)》,這里補(bǔ)充一篇《基于業(yè)務(wù)模塊組件的系統(tǒng)架構(gòu)》
一些內(nèi)容在《項(xiàng)目筆記:dao,web,模塊邊界以及Model分類》以及《模塊的接口設(shè)計(jì)》隨筆中已經(jīng)提到,這里補(bǔ)充總結(jié)一下。
任何一個有一定規(guī)模系統(tǒng),通常會把系統(tǒng)做一定分解降低分析設(shè)計(jì)開發(fā)的難度,模塊劃分是一個比較常見的方式。
而在模塊的劃分及其分析設(shè)計(jì)的實(shí)踐中,包括了兩種層次的邊界。第一是交互行為層次,第二是對象層次。
首先說交互行為。
模塊和模塊的交互接口最為重要,通常我們認(rèn)為這些接口應(yīng)該通用穩(wěn)定,然而如何設(shè)計(jì)每個模塊對外提供的接口卻是一個不易的問題。
集成的兩種基本實(shí)現(xiàn)方式:
1. API方式。
這是常見的實(shí)踐方式。即每個模塊公開數(shù)量不多的接口類(但擁有較多的接口方法)以及接口參數(shù)(都是普通的VO),每個接口的設(shè)計(jì)和實(shí)現(xiàn)都有該模塊成員維護(hù);實(shí)踐中:這些接口都獨(dú)立打包,形成多(模塊)對一(接口)的依賴關(guān)系,方便編譯。
這樣的好處是:接口邊界清晰,開發(fā)編譯依賴比較簡單。
然而實(shí)踐中極有可能出現(xiàn)兩種狀況:接口維護(hù)失控或者過嚴(yán)而死板(而影響開發(fā))。接口失控是因?yàn)榻涌诘木S護(hù)太過隨意,因?yàn)锳模塊的需要就輕易在B模塊中添加一個接口(方法),導(dǎo)致該接口(方法)非獨(dú)立性(基本上只給模塊A的這個功能點(diǎn)使用),或者是接口的控制過嚴(yán),導(dǎo)致或者工作效率不高,或者接口的易用性不好。
原因在于:接口是兩個模塊間的耦合,而發(fā)生的種種問題在于模塊耦合太過緊密;同時實(shí)踐中,把模塊對外提供的接口,與模塊需要實(shí)現(xiàn)的外部模塊的集成混為一談;換句話說,A模塊需要集成的語義,和B模塊提供接口的語義存在差距。
這樣的實(shí)踐優(yōu)點(diǎn):開發(fā)管理控制成本較低,模塊編譯依賴簡單,模塊物理邊界明確。
2. Adapter方式
這種的實(shí)踐可以一定程度上解決API方式面臨的問題:根據(jù)指導(dǎo)原則——為了降低耦合只有在中間加一層;即不輕易為模塊設(shè)計(jì)對外提供的接口(方法),除非是通過重構(gòu)得來的;模塊對外提供兩種類:一個是需要外部模塊實(shí)現(xiàn)的接口(接口設(shè)計(jì)從本模塊需要出發(fā),當(dāng)然每個接口盡管是為某個功能點(diǎn)服務(wù),但也要注意其在模塊內(nèi)通用性);另一個是其它模塊要求本模塊實(shí)現(xiàn)的接口的實(shí)現(xiàn)類(這塊物理上獨(dú)立打包,獨(dú)立于模塊之外)。
即:A模塊擁有一些需要B模塊實(shí)現(xiàn)的接口(A模塊對B模塊的要求),而B模塊中也有要求A模塊實(shí)現(xiàn)的接口,因而A有這些接口的實(shí)現(xiàn)類。
處于編譯依賴的考慮,已有的實(shí)踐是把處理接口適配的代碼維護(hù)在模塊外的,就是所謂的集成模塊,這樣編譯上就形成了1(接口實(shí)現(xiàn))對n(模塊)的依賴關(guān)系。模塊的邊界在這里模糊了,當(dāng)然在這之外模塊的邊界是很清晰的。
這種實(shí)踐方式的好處在于:模塊的接口就多了一層隔離降低了耦合,把接口的通用性和接口的適應(yīng)性分離,又明確了模塊的邊界,使得接口在日后的優(yōu)化和調(diào)整有了緩沖。
這樣的實(shí)踐和API實(shí)踐的不同之處在于:接口的設(shè)計(jì)權(quán)利一分為二,需求方擁有了其應(yīng)該有的權(quán)利,并且這個權(quán)利與提供方?jīng)]有沖突(舊的模式不行,一旦供應(yīng)方改變了接口,就立刻導(dǎo)致編譯問題)。
兩種方式的對比:
1. 采用API方式集成,代價在于維護(hù)API本身,API面對眾多的客戶端,其面臨的設(shè)計(jì)維護(hù)成本較高,同時實(shí)施成本高;
2. 采用Adapter方式集成,由于沒有維護(hù)API,缺乏可復(fù)用接口,但可以做到為每個客戶端自由定制,其設(shè)計(jì)維護(hù)成本較低,實(shí)施上成本較高;
集成的演進(jìn)方式:
1. 采用事件模式。
這也是完成交互處理的模式。通常事件模式在業(yè)務(wù)行為上也可以完成和接口相互的功能,不過由于其在接口簽名上無法明確提供其業(yè)務(wù)含義,建議謹(jǐn)慎應(yīng)用。對于產(chǎn)品化項(xiàng)目,項(xiàng)目開始可以應(yīng)用事件處理機(jī)制,在成熟時提取為更具體的接口。
事件模式中,Event的監(jiān)聽類也面臨著模塊的邊界問題。已知的成熟開源項(xiàng)目都在事件源中暴露的模塊內(nèi)部對象,方便開發(fā)者使用。
可以說這種方式的是Adapter方式的演進(jìn);
2. 采用框架回調(diào)方式
工作流和頁面流也負(fù)責(zé)集成不同的模塊.不過因?yàn)楣ぷ髁骱晚撁媪骺蚣芏季S護(hù)獨(dú)立的數(shù)據(jù)對象共享池,因而在這個層面上,模塊間直接的交互并不存在。這種集成上的優(yōu)勢,演化成通過ESB等集成框架完成.
這種方式是API方式的演進(jìn),但是把調(diào)用點(diǎn)以及調(diào)用方獨(dú)立出來,成為框架的一部分。
現(xiàn)在說說對象一級的邊界集成。
在保險中,benefit對象會關(guān)聯(lián)一個product對象,不過product對象是是屬于產(chǎn)品模塊而非保單模塊,對于保單模塊只關(guān)心id而并不使用對象,但在RMS或者FMS或者UIC這樣的集成環(huán)境卻是需要product對象的。我們要采用代碼生成的方式,在benefit對象上加一個annotation,比如Integration的annotation標(biāo)識,使用AspectJ在編譯上enhancement生成的class,使得benefit對象在集成環(huán)境上可以拿到product對象,這算是一個集成方面。
組件化管理
組件化管理包含兩個含義:
1. 組件訪問控制,依賴管理以及服務(wù)注冊;
現(xiàn)有的訪問控制的辦法,只能通過代碼提交時或者編譯發(fā)布時檢查,但我們更期望支持運(yùn)行時的能力,避免外部組件訪問組件未申明公開的內(nèi)部結(jié)構(gòu)和程序;同時維護(hù)方式應(yīng)該簡單方便,成本低。
目前的組件依賴管理幾乎沒有,尤其是基于版本的依賴;而在實(shí)踐中,依賴維護(hù)管理尤其是多版本的通常花費(fèi)大量的成本。
2. 組件依賴的綁定以及失效(故障)的隔離;
我們希望能夠?yàn)槊總€組件提供一個保護(hù)區(qū)域,當(dāng)其依賴的一個組件因?yàn)榉N種原因(軟件錯誤的或者軟件升級)失效時,系統(tǒng)至少應(yīng)該提供一種fail-fast機(jī)制,包括如下能力:
A.故障即停(Halt on failure)——當(dāng)一個組件出錯時,應(yīng)當(dāng)立即停止下來,而不是繼續(xù)執(zhí)行可能不正確的操作;
B.故障曝光性質(zhì)(Failure status property)——當(dāng)一個組件發(fā)生故障時,系統(tǒng)中的其他組件應(yīng)該得到通知,故障的原因必須交代清楚;
同時,我們希望該組件,如果可能它應(yīng)該可以繼續(xù)運(yùn)行。完成這樣的目標(biāo)需要很多的工作,但首先依賴于系統(tǒng)fail-fast能力,同時在故障消除服務(wù)恢復(fù)后,系統(tǒng)能夠提供相應(yīng)的通知,并控制恢復(fù)的順序。
已知的支撐框架:SCA和OSGi
1. SCA考慮的是異構(gòu)異步環(huán)境,OSGi考慮同構(gòu)同步環(huán)境;
2. OSGi規(guī)定了容器如何管理組件,組件依賴(版本)管理,組件邊界保護(hù)以及組件服務(wù)依賴運(yùn)行時綁定策略和權(quán)限控制;SCA對此沒有涉及;
3. SCA考慮的如何暴露服務(wù),設(shè)計(jì)時客戶端如何使用服務(wù);OSGi考慮的更加完善;