架構之路(五):忘記數據庫

摘要:面向對象或者領域驅動,最重要一點就是要忘記數據庫!我花了很長很長的時間,才理解了這一點,從而真正的邁向一個嶄新的天地;而後,我又花了很長很長的時間,才勉強做到這一點;我希望,有一天這將不再是一個問題。

本文爲他傾囊相授的第五篇:


前面寫了這麼多,很大程度上就是爲了這一章做準備。面向對象或者領域驅動,最重要的一點就是要忘記數據庫!我花了很長很長的時間,才理解了這一點,從而真正的邁向一個嶄新的天地;而後,我又花了很長很長的時間,才勉強做到這一點;我希望,有一天,這將不再是一個問題,我不需要考慮這一點……

爲什麼業務層這麼薄

三層架構流行起來之後,我們很清楚的知道UI層負責頁面交互並調用下一層,也知道DAL層就是和數據庫打交道。但BLL層?什麼纔算是“業務邏輯”?有各種各樣的解釋,但這些不都是SQL做的麼?對於絕大多數的應用系統而言,除了對數據庫進行“增刪改查”以外,實在不知道還能做些什麼?更何況,不是還有超級強大的存儲過程麼!

所以,很多系統,即使勉強弄出一個業務層,也“薄”得不像話,像一層塑料薄膜一樣,讓人有一種把它立即撕掉的強烈的衝動。

爲什麼會是這樣呢?

這得從.NET陣營從歷史說起。.NET陣營的同學知道三層架構,多半是從PetShop開始,這被奉爲三層架構的經典,很多項目甚至是直接複製其架構。在當時,它是一種了不起的進步。那時候,還是從ASP向ASP.NET轉型的過程,很多SAP項目,SQL代碼都還是寫在HTML裏面的!所以,UI和DAL的分離,無疑具有明細的示範效應。 

但微軟的步子,不大不小,剛好扯着蛋。

步子小一點,做成兩層架構,估計一點問題都沒有,大家都能接受;步子再大一點,就得上ORM,可惜微軟當時還沒條件支持。所以就搞出了這麼個不明不白稀裏糊塗的概念出來,折磨了我好久好久……

長期以來,.NET的陣營,在應用級層面,其實是“面向數據庫”的。從DataSet、DataGrid、DataSourceBinder之類的,都可以看出來。即使是Entity Framework,最開始也是從數據庫的表向.NET的類進行映射。這些,都極大的制約了.NET陣營同學面向對象的思維拓展。

好在我終於跳出來了。

面向數據庫

爲了說明,我們舉一個最簡單的例子。

需求是:記錄文章(Article)的瀏覽數(ViewCount)。每當文章被閱讀(View)一次,瀏覽數加一。

看到這個需求,你首先想到的是什麼?是不是:

Update Article set ViewCount = ViewCount + 1;
如果是這樣的話,恭喜你,你還牢牢的守住了“面向數據庫”的陣地。

/*
 
面向數據庫並不是不可接受的,面向對象也並不一定比面向數據庫“高級”。
這只是兩條道路的選擇,如果你願意看一看另外一條路的風景,就請繼續;否則,就此打住吧。
 
*/

面向對象

public void View()
{
    //從數據庫中取出Article
    Article article = session.Load<Article>(articleId);
     
    //改變Article的ViewCount屬性
    article.ViewCount += 1;
 
    //將改變後的Article再存入數據庫
    session.Save(article);
}

有什麼感覺?眼前一亮,還是不可思議?想得更深一點的,是不是覺得這是多此一舉,一句sql就能解決的問題,搞得這麼複雜?

我當年,考慮最多的,最不能接受的,是 性能問題。

  1. 這必須利用ORM,即使不考慮ORM生成的sql高不高效,就這生成sql的開銷,應該就不低吧?
  2. 這樣做,取數據,打開一次數據庫連接;存數據,又打開一次數據庫連接。就算有連接池,但能省一點就省一點不是更好?

所以,如果你也和我一樣,倒回去看我之前的博客吧!

這樣做,還有其他很多具體的技術問題,我們後續博客會逐一展開說明。

爲什麼

我們還是回到大方向上來,爲什麼要這麼做?換言之,“面向數據庫”有什麼問題,或者說“面向對象”有什麼好處?

我覺得,“抽象”、“解耦”、“複用”之類的說法,都還沒有觸及根本。最根本的原因,還在於我們的大腦,我們的大腦不適應於把這個世界抽象成一張一張的表,而更適應於一個一個的對象。隨着系統日趨複雜,這種現象就表現得越明顯。

我曾經參與過一個項目,它的數據庫結構打印出來,得用地圖那麼大一張紙(我不知道算A幾了),密密麻麻的全是表,各種線條交錯其中,我看着就頭皮發麻。部門裏面像個寶貝一樣把這張表供着,因爲公司沒法打印也沒法複印啊!(我不知道他們最開始是怎麼得來的,估計肯定麻煩)

如果你一邊讀一邊在想,就會發現,“不對呀,有多少表就有多少類,類圖不是一樣複雜嗎?”

是的,而且由於抽象,類很可能比表還要多。但是,有於抽象,在我們進行架構、設計、溝通的時候,可以暫時的拋棄很多細節。比如,我們可以說,“文章 被評論之後,文章作者的積分加10分”,這個時候,我們就不考慮文章有很多種:博客、新聞、問答、評論……,也不考慮積分增加是直接改積分總分呢,還是添 加一條積分記錄,或者還要同步……。如果只有表,你怎麼說?

當然,表的結構也可以設計成類似於繼承的樣子(類的繼承關係也最終會映射成表結構),但是,在交流溝通中,你如何表明這種抽象關係呢?

單純從程序的角度上說,使用ORM,面向對象,還增加了系統的複雜性。畢竟多了一道工作,而且把對象映射到數據庫不是一件簡單的工作,尤其是你還要考慮性能問題的時候。

那爲什麼我們還要這樣做?委託,換言之,把複雜性往其他地方推。我記得我反覆講過這一點,架構的一個重要工作,就是把複雜性進行拆分和推諉。拆分估計大家好理解,但“推諉”是個什麼意思,推給誰呢?管它呢,我只做我分類的事,其他的,UI推給BLL,BLL推給DAL,DAL推給DBA,DBA推給採購部……

寫在這裏很搞笑,但事實就是這樣的。在 性能篇,我說,你要寫高性能的代碼,你就是搶了人家的飯碗,就這個意思。UI都把DBA的活兒幹了,人家吃什麼?你代碼都寫成01001010101010二進制了,別說做彙編的,估計做CPU的都活不下去了。

我們這裏,就是把複雜度推給了Map團隊、ORM工具開發商和DBA。

因爲我們要和客戶談需求啊,典型的是領域驅動,要和客戶/領域專家找到“共同的語言”,這共同的語言是什麼?是表結構?估計如果開發的是一個財務會 計系統,這還是可行的——估計早期的系統大多就是財務報表類系統?說不定還真是這樣。爲什麼面向對象從Java開始流行,Java是虛擬機,可以用在微波 爐報警器之類上面的,底層數據結構可以完全脫離數據庫啊!.NET做什麼起家的,就報表啊!呵呵。

總之,發展到今天,隨着系統複雜性的增加。在系統的架構設計中,我們不得不將現實世界首先映射成一個一個可以封裝、具有繼承多態特性的對象,並且將重心放在這些對象關係功能的維護上。

數據庫?就先不管它吧。

只有脫離了數據庫的束縛,我們才能自由的翱翔在面向對象的世界裏!

忘不掉

“問題是我忘不掉啊!”

“我只要看到需求,腦子裏馬上就是數據庫就是表。”

“沒有數據庫,我都不知道怎麼開始寫代碼了。”

……

是的,忘掉數據庫是很難很難——尤其是對於我們這些老人來說。已經浸淫sql數十年的高手,你讓我忘掉它?你以爲寫小說啊,張無忌學太極啊?

我只能說說我是怎麼做到的,希望能給你一些參考。

我就假設我的系統不是用“關係數據庫”存儲數據,不是mysql,不是oracle;我用nosql,我用xml文件存儲,行不行?nosql,怎 麼用?不知道啊,我十竅通了九竅。但我就要在我還不知道nosql怎麼用的時候,就開始構建我的BLL/領域層。而且我只設定幾個最簡單的假設:

  1. 所有的對象都可以直接從硬盤Load()出來
  2. 所有的對象都可以直接Save()到硬盤
  3. 對象之間用1:1、1:n、n:n建立關聯即可
究竟怎麼從硬盤裏存取(所謂的“持久化”),以後再說。我連用什麼進行持久化都不知道,現在怎麼考慮?但有一條,反正不會用關係數據庫,估計是用NoSQL吧…… 

最終的期望

真正的對象數據庫!快出來啊,求你了…… 

慣例說我的項目進展: 
1、寫文檔寫到吐…… 
2、重構累成了狗…… 
本計劃發佈了新版本再寫這篇博客的,但實在不能再拖了。博客系列接下來,就進入項目的具體開發了,代碼還亂成一堆,啊…… 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章