項目地址:http://github.com/honovation/veil
設計理念
做為框架:改不改得動是檢驗一切架構的唯一標準
我們認為框架不僅僅是為了節省開發人員的時間,能夠讓你五分鐘寫一個博客系統。更重要的是給應用程序的邏輯提供一個組織的方式。因為我們知道,軟件開發就是管理復雜度的藝術。管理好軟件業務邏輯的復雜度,就需要代碼有一個良好的組織。這么多年來,人們總結出來的金玉良言就是“高內聚,低耦合”的模塊化設計方式。Veil框架僅僅是我們對于踐行模塊化設計的一個努力和嘗試。
模塊化設計并不是一個新概念。甚至C的module也可以稱自己為模塊化。Veil的特點在于徹底的模塊化,比如有的時候我們會把東西放到不同的地方
- 安裝程序如果是集中管理的,那么每個模塊的一部分實現還是要外泄到安裝程序里
- 運行腳本如果時集中管理的,那么集中的運行腳本還需要知道每個模塊是如何運行的
- 代碼如果是分層管理的,每個模塊實現的功能需要跨越多個層次,被割裂在幾個分開的目錄內
- 頁面和代碼如果不是擱一塊的,那么模塊還是要分為代碼和頁面兩塊
- javascript和css如果是單獨存放的,那么模塊的改動還要不停地在相關的javascript和頁面之間跳來跳去
而有的時候我們又不把東西分開來
- 使用相同表的方法和實現哪怕是為了完成不同功能,我們也會把這些代碼放到同一個“Model”,不管它已經有多大了
- 同一層的代碼可以肆無忌憚的彼此引用,哪怕有的時cms有的是交易代碼,風馬牛不相及
- 調用web service等外部服務的代碼散落到代碼的各個角落,可以隨意引用
所以Veil從某種意義上來說是對傳統”秩序“的反思。我們把很多應該放在一起的東西出于種種困難沒有能夠放在一起,并且已經視之為理所當然。而有些完全不該放在一起的東西,打著”分層“,”OO“等旗號被堆砌到了一起,使得代碼龐雜而難以管理。Veil無視我們已經習慣的秩序,單純地從”高內聚,低耦合“的角度出發,來評判什么應該被放在一起,而什么又不應該放在一起。
最終的目標不是為了OO,不是為了達成什么架構上的理想,甚至實現“高內聚,低耦合”也不能稱之為目標。最終一個框架,以及其背后的架構設計思想的檢驗標準只能是響應變化的能力。也就是說,同樣堆砌功能,用架構A和架構B當然都可以實現。而實現的質量除了靜態的檢驗(功能性需求和非功能性需求是否滿足),更重要的時動態的檢驗,就是“動”的能力。當我們需要對功能進行增刪,把模塊的職責互相移動的時候,代碼能不能改,怕不怕改亂來,才是真正體現功力的地方。沒有任何設計能夠在一開時預見所有的需有,好的架構就是要讓設計需要改動的時候,改得動不怕改。而在我們看來,要實現這一目標就是一個很簡單的原則,就是要分而治之,同時保證被分治的部分之間保持“高內聚,低耦合”的關系。在Veil的設計過程中,就是秉著這樣的目標,把模塊化追求到極致。至于是否能夠幫到你,是否真的能夠達到前面所說的幫助你提高響應需求變化的能力,還有待實際使用中的檢驗。
做為庫:出來混遲早是要還的
框架與應用的關系是,框架提供骨骼(所謂架構),應用提供肉(所謂業務邏輯)。但是不管是什么框架,最終還是會提供一些庫來給以用使用,作者總是會期待能夠把“公共”的“重復性“的勞動幫助應用完成了。而這種簡便性,往往成了一個框架宣傳時候的所謂亮點。但是我們知道物質是守恒的,代碼的復雜度也是守恒的。實現同樣的功能,不是應用程序多寫一點代碼,就是使用的庫的多實現一些功能。從長遠的角度來看,出來混遲早是要還的。所有庫幫應用實現的功能,最終仍然是應用的一部分,從依賴的角度來看,你使用的語言的運行時(比如python的標準庫),再下面的c運行時環境,操作系統的api,硬件驅動,乃至cpu指令都是你應用的一部分。一旦一個功能出錯了,它可能是cpu出錯了,也可能是你代碼寫錯了,也可能是從你的代碼到cpu中的每一個環節。
既然認識到庫也是應用的一部分,那么我們就需要思考什么時候需要用庫,我們需要什么樣的庫。Veil自身需要提供什么樣的庫api給應用使用。我們認為影響庫的設計與使用取舍有三條:
- 問題域本身的復雜度。 如果問題本身過于復雜,無法讓庫的用戶安心使用庫提供的api,那么這樣的場合可能就不適合封裝成庫。比如說SQL就一個很復雜的問題域,經過ORM的封裝,它事實上重新發明了一種查詢語言。帶來的結果是,做為ORM的用戶,不但要了解ORM封裝之后提供的新的查詢語言,還要知道SQL(事關執行效率),而且還要知道ORM封裝后的查詢語言與SQL之間的翻譯關系(要不然我怎么讓在性能出問題的時候,讓ORM翻譯出想要的SQL呢)。
- 庫自身api設計是否良好,有沒有泄漏內部實現。 如果問題本身不復雜,比如計算一個字符串的md5值之類的。那么就只需要api設計良好,一般用戶都不用去關心起內部實現了。
- 庫的代碼質量。 但是有的時候我們還是被迫去了解一些庫的內部實現。比如曾經用過的一版.net的hibernate,其處理并發情況下的lazy load list的時候,從連接池有取到不同連接的問題。在徹底檢查了自己的代碼之后悲慘地發現是庫的代碼有bug。
對于以上三條,無論是哪條有問題,都會讓我們進入一個還債的狀態,以十倍地時間去了解我們不甚了解而又往往過于復雜的代碼。因為庫面對的用戶是千千萬萬的,解決的問題也是形形色色的。比如說linux的進程調度有林林總總的實現,滿足不同計算場合的要求。如果哪天我們被迫需要知道我們的進程是如何被linux調度的,那需要耗費的時間可想而知。即便是庫解決的是一個明確而又小的問題,設計有良好的api,而且自身代碼也不出什么問題,我們仍然會有可能遇到,問題可能稍微發生了一些變化,庫不完全能解決我們的問題,而又不失完全不能解決的時候。遇到這樣的場合,不少人可能都會選擇與修改使用的庫,要么fork,要么提交回去。
總之,就是那句話,出來混遲早是要還的。Veil的原則也很直白,就是簡單粗暴。如果要封裝,也盡量處理明確而又小的問題,api不泄漏實現,同時要保證質量。不要在應用的代碼和最終實現之間插入太多的magic。
浙公網安備 33010602011771號