1. 程式人生 > >你真的瞭解分層架構嗎?——寫給被PetShop"毒害"的朋友們

你真的瞭解分層架構嗎?——寫給被PetShop"毒害"的朋友們

一葉障目

.NET平臺上的分層架構(很多朋友稱其為“三層架構”),似乎是一個長盛不衰的話題。經常看到許多朋友對其進行分析、探討、辯論甚至是抨擊。筆者在仔細閱讀了大量這方面文章後,認為許多朋友在分層架構的理解上存在兩個比較大的偏頗:

1.沒有從本質角度去理解分層的內涵,而只是瞭解其表象。

2.對分層架構的理解過於狹隘,只是少數概念,而又不夠深入。

許多朋友言“分層”則必稱“DAL”、“BLL”、“表示層”等概念,殊不知“DAL”的內部還有“Data Source 架構模式”、“Object-Relational Behavioral 模式”、“Object-Relational Structural 模式”等方面,而其中每個方面下下又有諸多具體模式,如“Data Source 架構模式”又有“Table Data Gateway”、“Row Data Gateway”、“Acitive Record”等等。再說“BLL”,大家都知道“BLL”是“業務邏輯層”,可是什麼是“業務邏輯”?“BLL”又可以構建為“Transaction Script”、“Domain Model”、“Table Module”三種模式,各是什麼意思?另外,分層也不僅只有“資料訪問層”+“業務邏輯層”+“表示層”這一種分法,諸如“服務層”、“持久化層”、“應用控制層”的概念朋友們是否真的熟悉呢。

造成這種現象,我想很大一部分原因是因為大多數.NET平臺的開發者(包括我在內)理解分層架構是從Microsoft的PetShop開始的。因為PetShop是官方的Demo,所以被眾多.NET開發者奉為聖經,甚至成了.NET平臺上分層架構的標準方案。我就曾看到許多朋友在我的部落格中留下“分層架構還是PetShop最經典”、“想學分層還是看PetShop吧”、“你這是跟PetShop學得吧”這樣的留言。朋友們太崇敬PetShop了,卻忽略了一個事實:它僅僅是一個Demo。退一步說,即使它是一個實際應用的專案,這樣通過一個具體專案去定義一個抽象概念的方式也是不科學的。

舉個例子,一個人不知道“牛”是什麼東西,於是請教一位奶牛場管理員,管理員遷出一頭奶牛,告訴他:“這就是牛”。從此以後,如果有人問他“牛”是什麼,他就會告訴別人“牛”是一種體型龐大,行動笨拙,性格溫順,身上有黑白斑塊圖案,還有一個好大的咪咪,可以擠奶供人喝。有一天,他聽說西班牙有鬥牛這項運動,他大驚道:“這怎麼可以!牛那麼溫順,怎麼能用來鬥呢!而且牛是用來擠奶喝的啊!”

故事中這個人犯了一個什麼錯誤呢?他把“具體的一頭奶牛”和“牛”這個抽象概念給劃等號了。他認為牛就是“體型龐大,行動笨拙,性格溫順,身上有黑白斑塊圖案,還有一個好大的咪咪,可以擠奶供人喝”。殊不知這世界上還有黃牛、水牛、犛牛、鬥牛、肉牛等各種牛。他沒能做到“透過想象看本質”從而形成抽象概念,而犯了“一葉障目”的錯誤。

其實,許多朋友之所以對分層架構理解片面或偏頗,是因為與故事中這個人犯了相同的錯誤。當初,我們不知道何為“分層架構”,於是微軟給了我們一個PetShop,說:“看!這就是.NET平臺下分層架構的產品。”於是我們“恍然大悟”:“噢!這就是分層架構啊!”。就這樣,我們把“分層架構”這樣一個內涵和外延都極大的抽象概念和一個具體的Demo劃了等號,從而也變成了故事中那個人——我們言分層架構必稱DAL、BLL,我們做專案必然依照PetShop方式架構……

我們確實被PetShop“毒害”了。但這不是微軟的錯,更不是PetShop的錯,就像在故事中,我們不能把罪責歸咎於奶牛場管理員或那頭奶牛。錯在我們自己!當微軟給我們PetShop時,我們應該在腦中清醒認識到:這是一個分層架構的Demo。而不是理解成了“這就是分層架構”。我們應該鑽研、思考,從而抓住分層架構的本質,可是我們沒有。與其說我們是被PetShop“毒害”了,倒不如說我們是被自己、被自己那種不良的學習習慣毒害了。我們僅看錶象,還是隻看了一個表象,然後就冒然對分層架構蓋棺定論。而沒能透過想象看本質。所以,我們同樣犯了“一葉障目”的錯誤。

以上的錯誤,筆者也曾經犯過!所以,在下文中,我想和朋友們一起分享一下我在反省自己的過程中,悟出的一些心得體會,希望能借此幫助更多朋友儘快走出“一葉障目”。

洞悉分層的本質

我們可以討論如何分層,可以討論分層的利弊,可以討論分層有沒有價值……但在這一切一切討論之前,我們要先弄清楚一件事:分層的本質是什麼?或者說:分層是怎麼來的?如果這個問題不明晰,那麼我們其他的討論猶如“浮沙之上築高臺”,再精闢的言辭,如果沒有一個牢固的基礎,也是站不住腳的。

想要了解分層的本質,就不得不說說分工。分工可以說是勞動生產力上最大的改良,最初分工的好處體現在“比較優勢”上,由於各司其職,每個人可以從事其最擅長的勞動,再加上單純勞動所帶來的勞動熟練度提升和減少了更換勞動時的損失,使得勞動生產率大幅提升。然而,隨著社會的發展,我們發現某些特殊形式的分工不但可以提高生產力,還有另一些好處!為了理解這些好處,我們舉個實際的例子。

今天是六一國際兒童節,一位母親想給她的女兒買一個奶油蛋糕作為禮物。我們知道,蛋糕需要麵粉、需要雞蛋、需要牛奶等等,還需呀經過一系列複雜的加工和包裝過程,但是這位母親不需要關心這些,她只要去附近的超市直接買就行了。而超市裡既沒有養雞場,也沒有奶牛場,更沒有種小麥的農民伯伯和烘焙蛋糕的工人師傅。這個簡單的“買蛋糕”場景,大約可以用下圖表示。

圖1、製作蛋糕的分工

圖1大約說明了一個蛋糕是如何從到達顧客手裡的。可以看到,製作蛋糕不是一個單一的勞動,需要許多的分工,如果自底向上看,主要的分工包括:基礎物質資料的種植生產、原料加工、蛋糕加工、商業銷售。並不是所有分工都如上圖這樣,上圖所示的分工,有一些特點,下面總結一下。

1.下層不知道上層的存在。例如奶牛廠生產牛奶,它不必知道牛奶被拿去做什麼,可能被奶油廠收購去做奶油,也可能被雪糕廠收購了做雪糕,也可能被收購去做奶糖,總之,它只管完成自己的職責——生產牛奶,而對於它的上層一無所知。同樣,奶油加工廠只管生產奶油,它不必知道奶油被拿去做蛋糕還是做摩卡咖啡。

2.每一層僅僅知道它的下一層(最後一層除外,因為最後一層沒有下一層),而不知道另外的下層。例如,蛋糕廠只需知道從麵粉廠、奶油廠和雞蛋廠提取麵粉、奶油、雞蛋就行了,而不必關心麵粉是怎麼來了、奶油是怎麼來的這些問題。

可以說,符合以上兩點的分工就是分層架構的思想來源。下面說的稍微正式一點。所謂分層思想,就是這樣一種分工:它將系統按不同的職責組織成有序的層次。其中,除最上層外,每一層僅提供若干服務供其相鄰的上層使用,但不知道上層的存在;除最下層外,每一層僅呼叫其臨近下層的服務。

所以,所謂“分層思想”,不過是一種特殊的分工形式。而計算機軟體架構中的分層思想,是將這一思想應用於軟體開發中的特例,而PetShop所使用的“DAL+BLL+PL”的方式,又不過是將這一思想應用於軟體開發中的特例的特例。例如,如果某個系統的業務很簡單,僅僅是增刪改查,那麼BLL就沒有作用,“DAL+PL”的方式就可以很好完成,這也是很好的分層架構。再如,如果某個系統的業務很複雜,需要先規格化,再做運算,再做整理,那麼“DAL+規格化層+計算層+整理層+PL”這種五層架構也是很合理的啊。如果某個系統BLL所暴露的介面太繁雜,那麼使用Facade模式在BLL和PL之間加一個“Facade Service Layer”也是很正常的。再者,如果某個系統不需要資料存取功能,例如計算器程式,我們只是想把表示和業務(計算功能)分開,那麼就沒有DAL了,“BLL+PL”就是合理的。所以,用分層的思想進行架構,本質是“將系統按不同職責組織成有序層次……”這一段話描述的,而不是簡單“將系統分成DAL+BLL+PL”,更不是“按PetShop的方式進行架構”。

下面,摘錄一段Fowler在《Patterns of Enterprise Application Architecture》中對分層的定義:

When thinking of a system in terms of layers, you imagine the principal subsystem in the software arranged in some form of layer cake,where each layer rests on lower layer. In this scheme the higher layer uses various services defined by lower layer,but lower layer is unaware of the higher layer. Furthemore, each layer usally hides its lower layers from the layers above.

——Martin Fowler, 《Patterns of Enterprise Application Architecture》, P17

大致譯文如下:

當我們說一個系統是分層架構的時候,你可以把這個軟體想象成一個有很多層的蛋糕的樣子,其中每一層放在它的下一層上。較高層使用諸多較低層定義和提供的服務,但較低層並沒有察覺較高層的存在。另外,每一層都會對其上層隱藏更低的層。

——馬丁 福勒, 《企業應用架構模式》, P17

但是,這裡有一點需要宣告:雖然說“DAL+BLL+PL”不等價於分層架構,而僅僅是一種例項。但同時我們要清楚的認識到,這個方式之所以如此流行,以至於微軟的官方示例都這樣架構,是因為對於許多系統,特別是大中型MIS系統,這種架構方式是應該優先考慮的。在這一節中,筆者絕對沒有對“DAL+BLL+PL”進行批判的意思,相反,當開發系統時,這種方式可以優先考慮,然後可以根據系統的特點,進行一定得改良。筆者在本節所強調的是:不能把“DAL+BLL+PL”看做分層架構的本質,更不能和“分層架構”這個思想概念劃等號。

分層架構的利弊分析

在理解了分層架構的本質的基礎上,我們才可以放心大膽的對分層架構進行利弊分析。廢話少講,這一節我們直接切入正題。

分層架構的優點如下:

1.分離開發人員的關注。

由於某一層僅僅呼叫其相鄰下一層所提供的服務,所以,只要本層的API和相鄰下一層的API定義完整,開發人員在開發某一層時就可以像關注集中於這一層所用的思想、模式、技術,這樣,就等同於將分工帶來的生產力提高優勢引入軟體開發。又如買蛋糕的例子,作為超市,只要知道下層API(如何從蛋糕廠獲取蛋糕)和本層需要實現的API(把蛋糕銷售給客戶),就可以制定自己的業務模式很策略計劃了,而不必關心如何種小麥、如何磨麵粉、如何做奶油、如何做蛋糕等。這樣,超市只需進行商業運作,而不必進行產業運作,如此專一,必然提高業務水平。

2.無損替換。

想象一下,如果某家奶牛場倒閉了,奶油加工廠也要跟著倒閉嗎?當然不會,它可以迅速更換一家奶牛場,因為各個奶牛場都可以實現“提供牛奶”這項服務。再譬如,如果某天國家出臺政策,要求所有奶油廠必須從審查合格的奶牛場引進原料,恰好某奶油廠的合作牛奶供應商沒能通過審查,那麼,只要換一家通過審查的合作就行了。而且奶油廠內部的各個環節一動不用動,因為不同的奶牛場都可以提供“供應牛奶”這個服務。而如果奶油廠自己養牛生產牛奶,一旦遇到這個政策,還得自己去有關部門進行審查,調整相應業務流程,牽一髮而動全身。程式中同樣的道理,最常聽說的可能就是遷移資料庫了。

3.降低了系統間的依賴。

還是蛋糕那個例子,如果某天蛋糕廠內部換機器了,或業務流程調整了,請問顧客需要關心嗎?顯然不用,因為顧客只調用超市提供的服務。而超市為顧客隱藏了下面所有產業細節。如果每一個顧客買一樣商品,都要了解這個商品從原料生產到成型再到銷售的一系列細節,豈不累死了。換做程式中,就如表示層只管呼叫業務層的服務,至於業務層下還有幾層?各種資料是怎麼來的?怎麼存的?是真實的還是捏造的?都不需要了解,這大大降低了系統各職責之間的依賴。

4.複用。

例如,你可以去這個超市買東西,我也可以去這個超市買東西。蛋糕廠可以從麵粉廠提取麵粉,饅頭廠也可以。這樣,同樣的層就可以為不同的上層提供服務,達到了複用的目的。具體到程式中,例如氣象局製作釋出了一個“Service Layer”,用於提供天氣預告資訊。這樣新浪、搜狐這些網站可以利用這個服務層提供的服務,製作天氣預告頁面,QQ也可以利用這個服務在它的聊天工具上新增天氣預告,你自己做一個軟體需要用到天氣預告功能,也可以呼叫氣象臺的“Service Layer”。

說罷優點,再來談談分層架構的弊端:

1.級聯修改問題。

這個問題在現實中不好比喻,但在程式中相信很多朋友都明白。例如,一個人事管理系統,本來檢視人員資訊只能分頁檢視,而現在,需要增加一個功能:在分頁的同時還能分部門。例如,可以檢視“銷售部的前50個人”,這樣,為了這個功能所有層都需要修改。

2.效能問題。

本來直來直去的操作,現在要層層傳遞,勢必造成效能的下降。就如在購買蛋糕的例子中。顧客在享受分工帶來的便利時,也要承受由於不同層的部門分佈各地而造成的蛋糕價格上升,這是因為分層增加了成本,如運輸、不同層間部門的協調管理成本等。

縱觀以上分析,分層架構有利有弊。這是一定得,世上任何事物都有利弊,所以,把“分層架構捧上天”和“一棍子打死”這兩種做法都是不明智也是不科學的。

對待分層架構,我們的態度應當是明晰其本質和利弊,然後根據具體情況做出理性的分析和抉擇。

從上面的分析可以看出,分層架構可以降低層內變化的成本,而對於API的變化非常敏感。如在級聯修改中提到的“在分頁的同時還能分部門”的新需求,就是對API進行的變動。API的變動對於分層架構是致命的,修改起來難度非常大。

所以,一個簡單的判斷法則就是:如果您的系統層內頻繁變動(甚至整層替換)可能性很大,而API變動可能性很小,就使用分層;而如果API可能會頻繁變動,那就要謹慎使用分層架構了。

後面的話

其實,我想說的主要內容,就是前面三節了。不過還是有些話,想和大家嘮叨嘮叨。

這篇文章,不是一篇技術文章,所以通篇不提技術細節,而只是想幫大家澄清對分層的誤解。最近看了很多對分層架構(或三層架構)的探討,其中以批判居多,有的甚至認為分層就是個沒用的垃圾東西。我想,產生這種想法的人,大致經過了以下階段:聽說分層,粗略學習分層、模仿使用分層、用得十分不爽、出來批判。

其實,任何技術都是客觀的,都沒有錯誤,錯誤在人,是人沒有正確使用,或沒有用到合適的地方。就像我們不能批判刀片不適合劈叉,也不能批判柴刀不適合刮鬍子。一項技術想要發揮威力,關鍵要正確運用,而要正確運用,就需要有深厚的功底,需要我們努力學習,勤于思考。這不是一朝一夕的事情,要有持久的毅力。我們要爭取做一個善於用功、善於把握事物本質的人,而不是一個用刀片劈柴、用柴刀刮鬍子,然後大罵刀片和柴刀都是垃圾的人。

分層思想從來就不是軟體架構中首先提出來的,我們天天上網用到的網路,都遵循OSI七層協議,網路結構的設計是分層思想合理應用的一個典範。另外,在許多其他工程技術領域,分層思想也是很普遍的。所以,不要把分層當成計算機人士甚至軟體開發人士獨有的能力,相對那些領域,將分層應用於軟體架構的技術還很不成熟,還有許多事情等待我們去做。

最後強烈推薦一本書:Martin Fowler的《Patterns of Enterprise Application Architecture》,相信看完這本書,對於分層思想的理解和分層中具體模式的運用決策都會有大幅提高。你會明白,原來分層不是隻有“DAL”、“BLL”,原來分層還有怎麼多內在的東西。

最後祝大家六一快樂!:)