655
技術社區[雲棲]
Arale 背後的一些設計理念
作者:玉伯
緣由
拔赤提到的一些問題,不少是在做 Arale 的過程中,反複糾結過的。在 QCon 的分享上,因為考慮聽眾更多的是想了解 Arale 和 spm,因此有些地方省略或簡單帶過了。這篇博文嚐試講講 Arale 背後的一些故事和設計理念。
開放
就如拔赤所說,看到 Arale 的 Widget 繼承圖時,咋一看,和 KISSY 沒什麼本質區別。為什麼有了 KISSY,還要開發 Arale 呢?兩者的區別究竟在哪?
首先,Arale、KISSY,包括著名的 YUI 等類庫,都是前端組件庫,通過一定的方式,對外提供了一套組件集。在 UI 組件(Widgets)層麵,這些類庫要解決的問題,以及解決問題的方式都是類似,表麵上看沒什麼區別。
但在工具組件(Utilities)層麵,Arale 與 KISSY、YUI 有著很大的不一樣。Arale 裏的工具組件,比如 jQuery、Handlebars、Moment 等,都直接來自業界,並且一定程度上是可替換的,比如在移動端,jQuery 可以被替換成 Zepto 庫。
除了工具組件,部分 UI 組件,比如編輯器、日曆等,Arale 裏也可以直接來自業界,甚至可以直接移植部分成熟的 jQuery 插件過來。這在 YUI 和 KISSY 裏,是不怎麼被考慮的。
Arale 是真心開放的一個組件解決方案,這種開放性,我相信會是 Arale 的最大活力。
簡單、易用
這個的確如拔赤所說,幾乎所有類庫都會這麼標榜自己,但是有些隻是標榜,並未真正做到。比如 KISSY 最開始很推崇 KISS 原則。但隨著後續的發展,個人覺得目前其實已經背離 KISS 原則,沒有做到保持簡單。就如拔赤說的 switchable 組件,裏麵超細的分層和功能點是否真的有必要?前不久在群裏還討論過延遲加載組件的一個 bug,在某種特殊場景下,該組件存在一個 bug,作為程序員,好像會毫不猶豫的把 bug 就修複掉了,覺得天經地義,但我直覺裏卻覺得是否值得?即便也許隻需要增加幾行代碼。
在簡單麵前,還有一個比 KISSY 更明顯的反例是 YUI3。拔赤已經說了自定義事件搞那麼複雜,理論上看起來很完美,但實際上卻什麼人去用。YUI3 是個典型的學院派風格類庫,不光自定義事件,很多其他組件的設計上,都存在學院派式的完美主義情節。這個不多說,喜歡 YUI3 的可以繼續用,但我的感覺和拔赤一樣,類 YUI3 的類庫路子隻會越來越窄,最後自己把自己幹掉。(當然,所有預言都是不靠譜的。)
回到 KISS 原則上來,回到經常提起的簡單之美上來。對於 KISS,自從概念提出來就一直存在理解上的分歧,下麵是一篇我讀到過多次每次讀都感慨的一篇文章:
文字比較多,還是不貼過來,請移步閱讀:簡單之美——係統設計黃金法則
中間有個故事很有意思:
一位 MIT 的教授一直困惱於 Syscall 處理時間過長出現中斷時如何保護用戶進程某些狀態,從而讓用戶進程能繼續執行。他問新澤西人,Unix 是怎麼處理這個問題。新澤西人說,Unix 隻支持大多數 Syscall 處理時間較短的情況,如果時間太長出現中斷 Syscall 不能完成,那就會返回一個錯誤碼,讓用戶重新調用 Syscall。但 MIT 人不喜歡這個解決方案,因為這不是“正確的做法”。
這兩個流派非常典型,我還是忍不住再摘抄過來:
1)MIT Approach
簡單性:設計必須簡單,這既是對實現的要求,也是對接口的要求。接口的簡單要比實現的簡單更加重要。
正確性:設計在任何值得注意的方麵都要保證正確。不正確是絕對不允許的。
一致性:設計必須保持一致兼容。設計可以允許輕微少量的不簡單和不完整,來避免不一致。一致性和正確性同等重要。
完整性:設計必須覆蓋到實際應用的各種重要場景。所有可預料到的情況都必須覆蓋到。簡單性不能過度的損害完整性。
我相信 MIT 的這套理念,是絕大部分程序員的默認意識。這這套哲學裏,簡單性不能破壞正確性、一致性和完整性。很多程序員見 bug 就改的習慣,潛意識裏感覺是受完整性的影響。
來看另一種理解:
2)New Jersey Approach
簡單性:設計必須簡單,這既是對實現的要求,也是對接口的要求。實現的簡單要比接口的簡單更加重要。簡單是設計中需要第一重視的因素。
正確性:設計在任何值得注意的方麵都要求正確。為了簡單性,正確性可以做輕微的讓步。
一致性:設計不能過度不兼容一致。為了簡單,一致性可以在某些方麵做些犧牲,但與其允許設計中的這些處理不常見情況的部分去增加實現的複雜性和不一致性,不如丟掉它們。
完整性:設計必須覆蓋到實際應用的各種重要場景。所有可預料到的情況都應該覆蓋到。為了保證其它幾種特征的品質,完整性可以作出犧牲。事實上,一旦簡單性受到危害,完整性必須做出犧牲。一致性可以為實現的完整性作出犧牲;最不重要的是接口上的一致性。
上麵這套理念,剛接觸時,簡直有點邪教的感覺。比如實現的簡單比接口簡單重要,以及正確性居然可以讓步於簡單性,還有最不重要的是接口的一致性。
New Jersey Approach 初看有點 naive,但我個人的感覺,通過 KISSY 的開發、SeaJS 的開發,越來越覺得 New Jersey Approach 可貴性。
可以說,YUI3、KISSY 等類庫,遵循的都是 MIT 哲學,但 SeaJS、Arale 嚐試的是 New Jersey 哲學。
這會帶來很多不同。舉一個例子簡單說下,比如 Overlay 組件,在 Old IE 下需要增加 iframe 墊片,在傳統的組件設計裏,會允許在 config 裏關閉或打開 shim 配置。但在 Arale 裏,直接沒這個配置,發現是 Old IE 時,默認就打開,否則則關閉。不給用戶這層選擇,用戶也就不用去操心還有這麼回事。這個設計,在內部討論時,曾經被挑戰過,比如用戶有可能為了性能優化,希望在 IE6 下也不創建這個 iframe,因為用戶很明確知道沒墊片也不會出問題。Arale Overlay 的設計看起來是無法滿足這個需求的,對完整性是種破壞,但是我們最後還是決定不添加這個配置,因為這樣更簡單。完整性可以為簡單性做出犧牲。
這隻是其中一個小例子,Arale 的組件配置與 YUI3 等相比,都會偏少,很多都是出於簡單性考慮。但在 KISSY 和 YUI3 裏,很多時候是恨不得把所有配置都暴露出來。
在簡單性上,我們甚至會優先考慮實現上的簡單性,比如 Mask 組件,就全局單例,因為這樣實現最簡單。
開放、簡單,我個人覺得這在 Arale 裏,是非常非常實在的東西。
支付寶的業務特征是,需要穩定、高效、靈活。我們的理解是,因為開放,所以穩定,比如 jQuery 的穩定性比自己折騰一個 DOM 操作類庫會更靠譜,高效來自簡單、易用,用起來爽,效率自然就高了。
至於靈活,更多時候也是通過開放來解決的,因此開放,同一類型的組件可以有多個不同定製版本,這一點,和 KISSY 通過 component 實現的靈活有很大不同。在 Arale 裏更追求組件的獨立性,下麵細說下。
適度
這個在 PPT 裏沒說,在 Arale 組件開發裏,是時時被強調的:
- 適度靈活
- 適量重複
適度靈活不多解釋,Arale 裏不會去構建萬能組件,隻會讓組件適當的具備一定的可擴展性。比如 Arale 的 Switchable 組件,肯定不會去增加新建 Tab 的功能。需要複雜功能時,去使用另一個 TabView 組件就好。
第二個適度法則是適量重複。這個是我的切身體會,有悖於傳統的軟件開發思想,但我覺得在前端界,適量重複比 DRY 更實用。
是個程序員可能都聽過 DRY (Don’t Repeat Yourself),這條法則非常好,在大部分情況下都是對的。
然後在構建前端類庫時,我覺得遵守 DRY 會很危險。
如果你追求代碼的不重複,那麼你在寫 a 和 b 組件時,會把公用部分抽取為 c,不斷重複這個追求,最後就會得到一個非常龐大的依賴結構圖,比如 YUI3 就是這樣。YUI3 追求顆粒化,表麵上看顆粒化可以讓自定義打包更靈活更優秀,但實際上,顆粒化的粒度非常關鍵,像目前 YUI3 的粒度太小,導致的問題是,實際上你若真去把 dom / event / node 等模塊打包出來,其實會比 jQuery 大出不少,不光達不到實際的期望效果,還牽三掛四,開發起來並不方便。(雖然 combo 服務可以緩解一點)
對於 DRY 法則,我的理解是,必須要非常小心的把握好兩點:
- 究竟不應該重複的是什麼?
- 粒度如何?
在 Arale 裏的答案是,不應該重複的是組件的職責,而不是組件的代碼。 比如:
- jQuery 的職責是 DOM 操作類庫,那麼在 Arale 裏就不會再有第二個 DOM 操作類庫。
- Underscore 的職責是語言增強,那麼在 Arale 裏就不會有第二個語言增強組件。
- jQuery 和 Underscore 是不重複的,他們的職責不同,主體功能不同。
- 但 jQuery 和 Underscore 兩個組件,可以存在部分相同的輔助功能,比如 each 等方法。
在這種對 DRY 的理解下,Arale 裏的組件寧可 copy 一些代碼,也會保持組件的獨立性,而不會特意去追求代碼級別的不重複。
這一點我們糾結過不少時間,但目前來看,適量重複帶來的簡單性是很不錯的。
粒度的問題,在 Arale 裏,實踐的是粗粒度法則。 如果要複用某些代碼,那麼會以獨立工具組件的形式提供,比如 position 工具組件,就提供一個靜態定位方法,其他 UI 組件想用時,直接采用引用的方式調用靜態方法就好,而不會像 YUI3 或 KISSY 一樣,采用 mixin 的方式去做。Arale 的工具組件,推崇:
組合 > 混入 > 繼承
這篇博客有點長了,回到拔赤的幾個問題。大部分問題已經回答了,再來回答這個問題:到底誰才會開發出真正高質量的組件?這引出了本篇博客想談論的最後一個議題。
生態圈
在《支付寶前端技術之路》裏,無論 Arale 部分,還是 spm 工具部分,都非常強調生態圈的概念。對於組件的開發、貢獻、篩選,在 CMD 模塊生態圈裏,就如 NodeJS 社區一樣,是開放自由的,同時又是非常殘忍自然的。
殘忍自然是因為我們想打造的是生態圈, 生態圈是自然的,同時也是物競天擇、適者生存。 一個組件是否優秀,完全取決於它能否被生態圈認可。這和 GitHub 也是一樣的,GitHub 上這麼多項目,但通過一些簡單的維度,我們還是可以比較容易的篩選出一套精品組件。
Arale 隻是 CMD 生態圈裏的一套模塊精選集,並且這個精選集,目前是基於支付寶的需求去選擇的。其他公司完全可以從 CMD 生態圈裏,選取另一套模塊精選集,比如叫做 CoolLib 什麼的。
CMD 生態圈目前還沒正式對外運作起來,目前隻在支付寶和 B2B 初步嚐試,等時機成熟後,會徹底開放出來。
我相信生態圈是解決組件質量的不錯選擇。
小結
在 Arale 裏, 開放、簡單、易用、適度靈活、適量重複、生態圈 ,這些概念是實實在在的,也正是這些理念,使得 Arale 與 YUI3、KISSY 等類庫不同,我相信這份嚐試會成功,並期待你的加入,一起為夢遠航。
最後更新:2017-04-03 07:57:04