鍵值對在架構設計里的應用
1. 談談我對程序的理解
作為程序員你對程序是如何理解的?寫這篇文章的時候,我認真思考了下,發現我對程序的理解不是和教科書一樣的,我每次聽到程序二字我想到的只有兩個東西:代碼和數據,而每次寫程序的時候也就是寫代碼操作數據的過程。
做程序開發和做菜很像,數據就是食材,代碼就是廚藝,做出的軟件就是一道菜了,至于這個菜好不好吃,到底是看食材還是看廚藝了?呵呵,當我拋出這個問題的時候,我的第一反應是菜不好吃當然是手藝不好了,不知道其他童鞋是不是這么想的。認真想下,一道好菜一般都是二者必須兼備,當然不排除某一項突出也可以達到同樣的效果,但這種情況畢竟不是大眾化,而是屬于少數精英的,做軟件也是如此,代碼與數據是不可偏廢的。這里我要提的是數據。
根據我的經驗和知識(分類標準我一直想不太好,所以說是自己的經驗和知識),我把數據分為兩類:落地數據和不落地數據。
- 落地數據:就是被持久化的數據,這種數據一般放在硬盤或是其他的持久化存儲設備里,例如:圖片、系統日志、在頁面上顯示的數據以及保存在關系數據庫里的數據等等,落地數據一定會有一個固定的載體,他們不會瞬時消失的。
- 不落地數據:一般指存儲在內存或者是網絡傳輸里的數據,這些數據是瞬時,使用完畢就會消失,例如:我們在瀏覽器發送給服務器的請求;從數據庫讀取出來的一直到頁面展示前的數據等等。
寫過程序的人都知道,程序里對這兩種類型數據操作是有很大的不同的。
2. 由Java EE的MVC設計模式談起
Java一個很重要的貢獻就是推出了MVC設計模式,MVC其實應該按VCM順序讀最好。V及View,主要是前臺展示的頁面;C及Controller,控制層主要作用是接受前臺頁面數據,根據數據的不同調用后臺不同的業務模型,同時業務模型處理好的數據也要發送到Controller,Controller再分配給相應的前臺頁面;M及Model,模型層專門負責操作業務模型。下圖很好的表達了MVC的理念:
隨著MVC模式的發展,現在流行的架構:View(視圖層)+ Controller(也叫Action,控制層)+ Service(業務模型層)+ DAO(數據訪問對象層)+ 數據庫的多層結構,如下圖:
紅線是用戶的請求;藍線是服務器響應用戶的請求。紅色和藍線也代表各層數據傳輸的流向。
不管是傳統的MVC模式還是現在流行的多層架構,各個邏輯層傳輸的數據都是不落地數據。
在Java項目里,一般我們都是傳輸JavaBean,而這些JavaBean都是程序員根據實際業務需求自己定義的,例如下面一個典型的JavaBean:
public class User { private String name = ""; private String sex = ""; private String age = ""; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }
各個邏輯層傳輸JavaBean對象的觀念一定會深入很多Java程序員的人心,當一個項目開始,程序員都會吭哧吭哧的創建JavaBean對象,比如數據庫表映射的JavaBean,在Struts 1.2里還有頁面表達對應的JavaBean,做了這么多年這樣的JavaBean,現在我就思考,使用JavaBean真是最好的選擇嗎?
3. NoJavaBean
我這里借用現在很流行的NoSQL的定義作為我文章第三部分的標題。JavaBean已經深入很多Java程序員心里,甚至是很多程序員的習慣,其實它真的那么好用嗎?真的那么包治百病嗎?其實不盡然,下面我要列舉它的缺點:
1. JavaBean的文件太多。一個Java企業項目,都會使用ORM, 將數據庫映射為Java對象,一般一張表對應一個JavaBean,甚至有些特殊情況還會歸并一些表做一個統一的JavaBean,如果這個系統有1000張表也就會有不少于1000個JavaBean,在原始的Struts 1.2里面還有和頁面表單字段一一對應的JavaBean,大伙可以想象下,這些毫無技術含量的Java類也許會像病毒一樣去繁殖。
2. JavaBean會增強各層之間的耦合度。每個層里運算結束,業務數據大多會被封裝成JavaBean對象,不同的業務封裝的JavaBean是不同的,MVC本來就是為邏輯層解耦做的設計,而傳輸介質卻是包含業務邏輯,如果碰到業務層級的修改,各個層之間都會有相應的結構性修改,增加了維護的成本。
3. 我們至少會多維護一份數據字典。數據庫里的某張表一個字段叫USER_NAME, 那么到了JavaBean里可能就變成了userName,當然我們在ORM會有一個映射模型,但是隨著數據一層層傳遞,離數據庫越遠的數據,數據的本質也就越模糊,特別會給新手產生一定誤解,增加了軟件開發和維護成本。
4. 這個是缺點是我的在實際項目里碰到的一個難題,我還沒把它總結成一個概括性的缺陷,但我相信會有童鞋碰到類似的問題。我在一個項目里做權限管理,因為某些數據的敏感性我們要做數據集的權限,比如某些人只能查看當天的數據,還有些人只能看當天數據前10條,另一些人只能看最近一個星期的數據,而且只有三個字段能讓他查看。由于權限管理是在該項目三期的任務,我們的權限設計是在原有的系統上進行開發,而且包含兩個不同項目,其中一個項目是使用JavaBean做傳輸介質,另一個我們用了另外的方式,最后這個JavaBean成了我們的夢魘,為了做一個通用解決方案,我們將用JavaBean作為傳輸介質的項目重構了一下,增加了不少工作量。
5. MVC分層思想,其實是為了讓專業的人做專業的事,擅長做頁面的做頁面,擅長邏輯的做邏輯,按MVC思想項目開發往往是橫向分組的,但是實際開發中,沒人敢這么分配工作,究其原因就是層與層直接傳輸的介質并不統一。
既然我的標題是NoJavaBean, Not Only JavaBean,那么就像NoSQL能彌足SQL數據庫的不足,以上的不足我們用什么技術來彌補了?
答案就是:鍵值對。
4. 萬能的MAP(鍵值對)
Google的三篇論文帶來了云時代,用博大的胸懷改變了世界,而這里面最關鍵的東西就是map(鍵值對),Key-Value模式(后面簡稱KV)+ 數組我個人覺得基本可以表述這個世界的90%了。而且基本所有的語言都支持KV的數據結構,可見KV是多么強大的數據結構,世界就是被這個簡單方式而改變的。(本來我想談談KV在云計算存儲和計算的作用,作為本文主題的補充,但是時間限制,大伙可以自己查閱下相關資料)。
我的替代數據模型就是用map作為數據傳輸介質,讓我產生這個想法的源頭是三個技術:MapReduce,iBATIS和json;我們中心很重視Hadoop技術,我們這里經常做Hadoop相關技術分享,聽來聽去都有什么MapReduce,都是map, map;而我們現在公司的項目都是用iBATIS做ORM, 當時表很多,我一時偷懶不是所有的iBATIS配置文件都和JavaBean一一對應,只是返回一個map對象,如果是列表查詢就是List<Map>,沒想這么做居然有意外的收獲,因為頁面數據我們都是封裝成json對象,json其實也是一個鍵值對的模型,數據到了action也是被傳化成了map,所有返回值一樣,居然提升了整個開發的效率,而且項目里面少了JavaBean對象,顯的清爽多了。
下面我總結下map的好處,在文章第三部分寫到了JavaBean的缺點,這些缺點倒過來看就是map的優點了,我這里就不再復述了:
1. 不管什么技術從map取值的方式是統一的:例如在Javascript里面json:
obj.XXX 或者 obj[XXX]
Java里的map:
map.get(XXX) 或 map.put(XXX)
map取值方式是用key,key是字符串,是可以隨時定義,而JavaBean是通過定義的方法讀取,如果使用map會將傳輸數據的業務屬性封閉在map內部,這樣帶來了操作的方便。
2. map技術幾乎在所有的主流技術里面都有,那么用這種數據結構作為傳輸介質是跨平臺的。
3. map數據結構算法很成熟,做復雜計算是十分方便。
ok,寫道這里吧,還有很多東西沒講清楚,寫的太累了,明天還要起早趕火車,我的這個想法拋出來就是想聽聽大伙的意見,現在有點著迷map了,不知道將我們把各個邏輯層用map這種數據結構做傳輸是不是會帶來更多的開發便利,很希望聽到大家的意見。