分層在英文里面有Tier和Layer兩方面的含義。Tier主要是只硬件上的分層,如客戶端,應(yīng)用服務(wù)器和數(shù)據(jù)庫服務(wù)器。而Layer主要是指軟件系統(tǒng)結(jié)構(gòu)下的分層。而這里談的主要還是軟件體系結(jié)構(gòu)上的分層。
??
??
最近經(jīng)常看到的DotNet多層架構(gòu),七層架構(gòu)等詞語。歸根到底其核心還是數(shù)據(jù)資源層,邏輯層和表現(xiàn)層三個層次。其它層次基本上都是基于這三個層次所做的擴展。在做一個軟件系統(tǒng)的時候,具體如何分層跟要采用的系統(tǒng)架構(gòu)有密切關(guān)系,而要采用何種系統(tǒng)架構(gòu)又和業(yè)務(wù)需求密切相關(guān)。因此,是業(yè)務(wù)需求在驅(qū)動具體解決方案的分層,分層和獨立新的子項目都絕對不是越多越好,而應(yīng)該有充足的需求來支持。
??
1.高效開發(fā)的分層方案(數(shù)據(jù)庫存儲過程+DA數(shù)據(jù)訪問層+UI層)
是否應(yīng)該使用存儲過程或者說業(yè)務(wù)邏輯是否應(yīng)該放在存儲過程中一直是爭論的一個焦點問題。但不可否認(rèn)的是使用存儲過程,并將業(yè)務(wù)邏輯放在存儲過程中是一種值得推薦的高效開發(fā)模式。存儲過程的可移植性和可維護性一直是一個問題,但只要我們注意了包,函數(shù)和子存儲過程的劃分,存儲過程一樣是很容易維護的。
??
是否應(yīng)該使用存儲過程或者說業(yè)務(wù)邏輯是否應(yīng)該放在存儲過程中一直是爭論的一個焦點問題。但不可否認(rèn)的是使用存儲過程,并將業(yè)務(wù)邏輯放在存儲過程中是一種值得推薦的高效開發(fā)模式。存儲過程的可移植性和可維護性一直是一個問題,但只要我們注意了包,函數(shù)和子存儲過程的劃分,存儲過程一樣是很容易維護的。
??
從2001年開始使用DotNet開始,我們就一直借鑒了IBuySpy的案例采用這種開發(fā)模式,開發(fā)的僅存儲過程代碼可能就超過50萬行,2003年后臺數(shù)據(jù)庫要移植到Oracle數(shù)據(jù)庫是遇到的最大一次挑戰(zhàn),整個項目組花了3個多月的時間完成了遷移。但經(jīng)過實踐證明,這種簡潔的開發(fā)模式和分層方式是完全值得中小型項目推廣和使用,以獲得最大化的開發(fā)效率。
??
??
由于業(yè)務(wù)邏輯放在存儲過程中,因此沒有專門的業(yè)務(wù)邏輯層,僅僅保留了數(shù)據(jù)訪問層,而且采用存儲過程這種方式的時候整個DA層都完全通過代碼生成器或數(shù)據(jù)訪問組件來實現(xiàn)。對于數(shù)據(jù)處理和傳輸也沒有使用專門的DTO對象,而直接使用DataSet和DataTable等來實現(xiàn),因此也沒有專門的數(shù)據(jù)實體層。UI層除了處理UI操作和數(shù)據(jù)展現(xiàn)外,還做簡單的數(shù)據(jù)完整性等方面的校驗。
??
??
開發(fā)的公用類,公用組件或異常日志的處理仍然需要單獨建立一個公用項目來實現(xiàn)。
??
??
這種分層方案最大的缺點就是可移植性,當(dāng)出現(xiàn)數(shù)據(jù)庫需要遷移或移植,或需要支持多數(shù)據(jù)庫的時候往往造成極大的麻煩。
??
2.是否獨立專門的DataEntity層存放數(shù)據(jù)實體
在微軟的Duwamish或PetShop等范例程序種都有專門的DataEntity層來存放數(shù)據(jù)實體。這里首先要討論的是否要使用數(shù)據(jù)實體,當(dāng)我們使用DataSet或DataTable來作為數(shù)據(jù)傳輸對象的時候,DataSet其實已經(jīng)起到了數(shù)據(jù)實體的作用,但當(dāng)這個DataSet是非類型化的DataSet的時候完全沒有必要建立單獨的DataEntity項目。
??
在微軟的Duwamish或PetShop等范例程序種都有專門的DataEntity層來存放數(shù)據(jù)實體。這里首先要討論的是否要使用數(shù)據(jù)實體,當(dāng)我們使用DataSet或DataTable來作為數(shù)據(jù)傳輸對象的時候,DataSet其實已經(jīng)起到了數(shù)據(jù)實體的作用,但當(dāng)這個DataSet是非類型化的DataSet的時候完全沒有必要建立單獨的DataEntity項目。
??
當(dāng)使用Typed DataSet或Custom Entity來做數(shù)據(jù)實體的時候,一般就需要考慮建立單獨的DataEntity項目,這個項目基本上完全獨立的項目而不會依賴于其它項目,但DataEntity項目卻會被DA層,邏輯層或UI層的多個項目引用。將數(shù)據(jù)實體獨立為項目的時候就解決了項目間由于要訪問數(shù)據(jù)實體而引起的循環(huán)項目依賴問題。
??
??
我們經(jīng)常因為性能問題而拋棄了采用Typed DataSet作為DTO的這種高效的模式,而自己建立相關(guān)的對象類和類集合來處理這些記錄集。到了客戶端又要進行相關(guān)的轉(zhuǎn)換以滿足數(shù)據(jù)綁定的需要。DataSet決定可以算得上是ADO.net中的一個值得稱道的對象,有了DataSet后可以大大的簡化我們對記錄集的處理和綁定。如果我們老把Java或J2EE中的一些架構(gòu)和分層思路生搬硬套的往DotNet上使用,而不去考慮DotNet和ADO.net自身的很多優(yōu)質(zhì)特性,那就很難真正得到一個高效的分層架構(gòu)。
???
3.業(yè)務(wù)邏輯層
如果不在存儲過程中存儲業(yè)務(wù)邏輯,則建立獨立的業(yè)務(wù)邏輯層是完全有必要的。在這里談到的業(yè)務(wù)邏輯層更多是業(yè)務(wù)控制類,因為業(yè)務(wù)實體類已經(jīng)單獨分離為DataEntity項目。這和RUP里面談到的實體類和控制類個人認(rèn)為是有點類似的。
???
如果不在存儲過程中存儲業(yè)務(wù)邏輯,則建立獨立的業(yè)務(wù)邏輯層是完全有必要的。在這里談到的業(yè)務(wù)邏輯層更多是業(yè)務(wù)控制類,因為業(yè)務(wù)實體類已經(jīng)單獨分離為DataEntity項目。這和RUP里面談到的實體類和控制類個人認(rèn)為是有點類似的。
???
對業(yè)務(wù)邏輯層的錯誤使用主要來自兩方面的內(nèi)容。一方面是將對數(shù)據(jù)表的裝載或保存等數(shù)據(jù)操作做為業(yè)務(wù)邏輯,而這個應(yīng)該是放到數(shù)據(jù)層的內(nèi)容;另外是將本身屬于業(yè)務(wù)邏輯的內(nèi)容放置到了UI層。所以我們觀察很多實際的軟件項目的時候會發(fā)現(xiàn)業(yè)務(wù)邏輯層往往形同虛設(shè),里面基本都是一個簡單的Wrapp和轉(zhuǎn)發(fā)代碼,而無實際的業(yè)務(wù)邏輯代碼。UI層僅僅是將獲取的數(shù)據(jù)顯示到界面上,或者將界面數(shù)據(jù)整理后傳遞到邏輯層,以及界面流程的跳轉(zhuǎn),簡單的數(shù)據(jù)完整性校驗等,跟這些無關(guān)的都應(yīng)該放到邏輯層進行處理。
???
???
試想一下對于將某一類別產(chǎn)品的最近兩個月銷售量差別>10%的數(shù)據(jù)顯示為紅色的業(yè)務(wù)邏輯是什么呢?
???
4.關(guān)于需要同時支持BS和CS兩種模式的問題
應(yīng)用系統(tǒng)往往有需要同時提供Web和CS的兩種訪問模式。對于BS應(yīng)用而言一般不存在分布式部署的問題,而對于CS模式則一般要實現(xiàn)為分布式的應(yīng)用,需要考慮分布式部署的問題。對于分布式的考慮將在后面進一步描述。
???
應(yīng)用系統(tǒng)往往有需要同時提供Web和CS的兩種訪問模式。對于BS應(yīng)用而言一般不存在分布式部署的問題,而對于CS模式則一般要實現(xiàn)為分布式的應(yīng)用,需要考慮分布式部署的問題。對于分布式的考慮將在后面進一步描述。
???
當(dāng)同時支持BS和CS兩種客戶端的時候,我們的期望是僅僅是WinUI和WebUI兩個項目存在不同,而其它各層的相關(guān)項目都可以實現(xiàn)完全的重用。為了最大化的實現(xiàn)這種重用,原來放在UI層中做的UI數(shù)據(jù)完整性校驗等內(nèi)容也需要抽取出來做為單獨的Facade層,這樣UI層僅僅處理完全跟UI相關(guān)的操作,當(dāng)一個功能要由CS轉(zhuǎn)BS的時候僅僅編寫最小化的WebUI層代碼即可。
????
5.對系統(tǒng)支持分布式應(yīng)用和部署的考慮
為了讓系統(tǒng)支持分布式部署,我們一般需要增加服務(wù)代理,服務(wù)接口,WebService的相關(guān)層和子項目。一個系統(tǒng)為了實現(xiàn)對分布式的支持往往多增加了2,3個子項目而增加了系統(tǒng)的復(fù)雜性。在2004年開始的一個應(yīng)用系統(tǒng)架構(gòu)設(shè)計中,經(jīng)過充分的考慮決定了采用Remoting+http+Binary來實現(xiàn)分布式應(yīng)用,但整個系統(tǒng)的分布式不增加任何的子項目和分層,僅僅是在客戶端和服務(wù)器端增加相應(yīng)的配置文件,所有的分布式都是通過分布式部署來自動實現(xiàn)的。
???
????
5.對系統(tǒng)支持分布式應(yīng)用和部署的考慮
為了讓系統(tǒng)支持分布式部署,我們一般需要增加服務(wù)代理,服務(wù)接口,WebService的相關(guān)層和子項目。一個系統(tǒng)為了實現(xiàn)對分布式的支持往往多增加了2,3個子項目而增加了系統(tǒng)的復(fù)雜性。在2004年開始的一個應(yīng)用系統(tǒng)架構(gòu)設(shè)計中,經(jīng)過充分的考慮決定了采用Remoting+http+Binary來實現(xiàn)分布式應(yīng)用,但整個系統(tǒng)的分布式不增加任何的子項目和分層,僅僅是在客戶端和服務(wù)器端增加相應(yīng)的配置文件,所有的分布式都是通過分布式部署來自動實現(xiàn)的。
???
采用配置文件來實現(xiàn)分布式的方法很好了解決了應(yīng)用要同時支持BS和CS兩種模式的問題。因為在整個解決方案中不會存在僅僅CS才會使用的服務(wù)代理或服務(wù)接口層的問題。所有的代碼除了UI層外BS和CS都是公用的,實現(xiàn)了很好的復(fù)用。從實際運行效果和開發(fā)效率來看這都不失為一種好方法,至少不會出現(xiàn)為了增加一個簡單的功能都要修改7,8個項目,增加相關(guān)的代碼才能夠?qū)崿F(xiàn)的問題。
???
6.對系統(tǒng)復(fù)用而建立的公用項目和公用組件
這是無論采用哪種分層架構(gòu)下都必須考慮的問題。對于公用類和組件必須建立單獨的項目來進行管理,這樣公用項目既可以實現(xiàn)很好的專人管理,也可以方便被其它各層的項目引用。
???
這是無論采用哪種分層架構(gòu)下都必須考慮的問題。對于公用類和組件必須建立單獨的項目來進行管理,這樣公用項目既可以實現(xiàn)很好的專人管理,也可以方便被其它各層的項目引用。
???
公用項目應(yīng)該保護常用的字符串,日期和集合的處理,對DataSet的輔助處理,常用的算法,常用的基礎(chǔ)數(shù)據(jù)的獲取等相關(guān)內(nèi)容。而對于公用的組件更建議以黑盒dll的形式來實現(xiàn)復(fù)用。對于嚴(yán)格基于組件和構(gòu)件開發(fā)的系統(tǒng),復(fù)用率可以達(dá)到70-80%。因此對于一般的軟件系統(tǒng)至少應(yīng)該達(dá)到40%以上的軟件復(fù)用。
???
7..架構(gòu)對異常,日志,安全,緩存,異步等方面內(nèi)容考慮而增加的獨立項目
異常,日志和安全等都是一個系統(tǒng)必須要考慮的非功能性需求。但具體的每個系統(tǒng)要實現(xiàn)到哪個程度,控制到哪個級別則完全是跟具體的業(yè)務(wù)需求相關(guān)的。例如對于異常日志我們可能僅僅需要的是能夠捕獲內(nèi)部異常而給用戶提供友好的提示信息但又能夠記錄在相關(guān)異常信息方便分析錯誤,我們的異常日志功能能夠有針對性的滿足到此就足夠了。
???
異常,日志和安全等都是一個系統(tǒng)必須要考慮的非功能性需求。但具體的每個系統(tǒng)要實現(xiàn)到哪個程度,控制到哪個級別則完全是跟具體的業(yè)務(wù)需求相關(guān)的。例如對于異常日志我們可能僅僅需要的是能夠捕獲內(nèi)部異常而給用戶提供友好的提示信息但又能夠記錄在相關(guān)異常信息方便分析錯誤,我們的異常日志功能能夠有針對性的滿足到此就足夠了。
???
當(dāng)我們實現(xiàn)一個軟件系統(tǒng)不加思索的將微軟的Enterprise Library的10多個dll一股腦的全部加入到項目中去后并不一定會給項目帶來多少好處,為了實現(xiàn)一個小需求而用這些面面俱到的工具只會增加整個系統(tǒng)的復(fù)雜度。我們?yōu)楹我欢ㄒビ梦④浀腢pdater App Block呢?獲取我們需要的僅僅是自己手寫的不超過100行的一個簡單的Loader程序。
???
???
我們完全可以僅僅建立一個獨立的項目就可以實現(xiàn)關(guān)于異常,日志和安全等所有的項目需要的非功能性需求。一個解決方案下的項目過多只會增加系統(tǒng)的復(fù)雜性和管理上的困難。做軟件系統(tǒng)需要考慮系統(tǒng)的可擴展性,但我們絕不應(yīng)該要那種項目根本不需要的擴展作為系統(tǒng)的裝飾品。