同步github:何構建一套出色的組件系統
同步cnblogs:組件化設計:如何構建一套出色的組件系統
同步知乎專欄:前端路上的摸索html
寫了好多年業務,想輸出一套前端的UI組件系統,可是對組件這個概念不是很深刻了解,因此參考了不少資料,以及結合本身的理解,作出概括和總結。因此纔有了這一篇,從什麼是組件,到什麼是軟件中的組件化設計,再到組件設計中有什麼優點和挑戰,到最後如何構建一套出色的組件系統。每一個人的想法都不是同樣的,因此這一套組件設計思想,可能也並不完善,僅做爲你們的參考,也歡迎你們補充。前端
這就是咱們現實生活中,最形象最貼切的物品了。git
圖一是一堆齒輪驅動的機器,每一個齒輪都是單獨存在的,若是一個齒輪壞了,咱們只要替換下來換一個好的就行了,這個機器同樣跑起來啦。程序員
圖二是我的PC的主板,你們也特別熟悉,對於插在主板上的每個單獨功能的組件,若是壞了一個,能夠換一個好的,經過插槽替換上去,也能夠跑起來了。github
因此生活中有不少組件的實體,咱們看看這些關於組件的定義:編程
1. 供裝配整臺機器、構件或元件的零件組合瀏覽器
2. 在電子或機械設備中組裝在一塊兒造成一個功能單元的一組元件安全
3. 組裝產品(如書櫥或碗櫥)時所組合的一般或多或少重複的部分模塊化
4. 可被組裝或被從新組裝的幾個部件之一組件化
這些都是咱們看獲得,摸獲得的,下面咱們再跳出現實表象,上升到一個更高的層面去看問題(這樣的高逼格的說法叫抽象)
圖三是一個完整的中國地圖,地圖上每一個省級的地域,咱們無論你在這片區域是平原、高山、仍是海島、仍是大海等,只要你屬於規劃範疇,那麼就屬於一個省級區域,由這些區域組成了咱們一個完整的國家,丟一塊都不行。咱們能夠把每一個省級抽象成一個組件,國家機器,就是由這些組件一塊兒跑起來的。
咱們將信息進行彙總和整理,得出以下結論:
1. 從外觀和功能上來說,他們都是一個獨立的部分,多是零件或者是原件
2. 從行爲上來說,他們擁有組裝這個屬性,能夠和其餘組件相互組合
3. 能夠被從新組裝,重複利用
固然咱們作軟件設計的,也是經過參考現實,抽象到軟件設計中,而後根據落地環境,去實現組件化設計思想,前人已經走在了路上,去摸索這塊土地,也得到了一些實用的理論,好比基於組件的軟件工程(Component-based software engineering,簡稱CBSE)或基於組件的開發(Component-Based Development,簡稱CBD)的軟件開發範型等等,有興趣的能夠本身去看下。
下面是前人對組件的定義:
1. 一個不透明的功能實體,可以被第三方組裝,且符合一個構件模型。 — 卡耐基梅隆大學
2. 是軟件系統中具備相對獨立功能、接口由契約指定、和語境有明顯依賴關係、可獨立部署、可組裝的軟件實體。 — 計算機百科全書
3. 是一個組裝單元,它具備約定式規範的接口,以及明確的依賴環境。構建能夠被獨立的部署,由第三方組裝。 — 軟件構件著做
4. 爲自包含的、可編程的、可重用的、與語言無關的軟件單元,軟件組件能夠很容易被用於組裝應用程序中。 — 百度百科
5. ......
每一個結論針對的都是各自穩定軟件領域的抽象,咱們還能夠看到更多對於組件的定義。因此咱們針對這些結論,作一個總結,組件具備什麼樣的特性?
1. 高度內聚,不透明 — 不須要關心這個東西怎麼搞出來的,知道怎麼用就行了
2. 對外以接口契約 — 有說明書,知道這個東西給了須要的就變成你想要的
3. 功能相對獨立 — 相對歸納的指明這個東西的使用途徑
4. 環境依賴 — 對環境的依賴比較重要
5. 可重用 — 能夠屢次使用
6. 可組裝 — 能夠和其餘東西組成其餘的玩意
原子組件:原子級別組件,單一功能,不能繼續拆分。
複合組件:多組件組合,組成的能完成某一功能的組件。
插槽組件:爲組件的組裝完成一個功能而提供的基礎設施。
拓展組件:在原有組件上派生出一個新的組件,爲原有組件增長新的性能或者更改原有組件的功能。
適配組件:經過適配組件去封裝不一樣組件,保證對外契約一致
將需求場景領域化,將場景領域模塊化,以符合系統需求爲衡量,以穩定領域最大複用爲目的,使其能夠經過組合拆分來構建整個系統的獨立解決方案
如圖:
案例:
好比咱們須要作一個簡單的前端的活動系統,需求要有登陸系統、查看活動、建立活動、修改活動、刪除活動。
將需求場景領域化:
登陸系統 --> 表單提交
查看活動 --> 數據展現
建立活動 --> 表單提交
修改活動 --> 表單提交
刪除活動 --> 行爲操做
==> 抽象出表單提交、數據展現和行爲操做這些穩定領域
場景領域模塊拆分:
表單領域拆分模塊(簡單拆分2個)
1.文本輸入模塊
2. 密碼輸入模塊
......
PS:其餘領域跟表單領域同樣,進行模塊拆分。
歸納共性:
好比表單領域的2個簡單模塊,咱們須要對其歸納共性,
1. 他們都是輸入的文本
2. 一個輸入文本可見,一個輸入文本不可見。
結論:咱們能夠設計一個輸入文本的組件,對外開放契約,若是你告訴我你須要把輸入不可見,我內部就作處理將這些東西遮住。
產出組件:
組件:輸入組件
契約:是否須要遮擋輸入
功能:輸入文本的
領域:表單輸入使用
設計意義:
以這樣的方式作組件設計,若是整個系統都有這樣的穩定領域,那麼這些組件的意義就是針對該系統是最好的,不只知足了需求,還能夠最大功能複用。
可重用,對於一個功能獨立且單一的組件,不須要花費其餘資源,能夠直接使用組件達到效果
拓展和替換,對於系統的維護和更新來講,能夠經過基礎組件進行拓展,而後能夠經過替換組件去爲系統進行更新
複雜合做可能性,獨立拆分模塊和組件,已組件拆分組合構建完整系統,使大型項目合做成爲可能。
提升效率,這包括對軟件複雜性更有效率的管理,快速地推向市場,以及更高的生產力(迭代效率),更高的質量等等
開發組件不是單獨完成一個功能或者一個頁面,若是開發成組件,所須要的時間和精力成本是遠遠大於只是純粹完成一個功能的成本的。
對於軟件的需求階段,在現實開發中,不多是全部需求都特別明確的,因此對於這些不定性,不可描述需求的開發,對於組件的挑戰是很大的,由於領域不穩定,最終可能抽象的組件也是不定且變化的,這樣致使的組件變化成本是急劇上升的。
對於系統中最後造成的組件的衡量,不是一個固定標準的。可能組件對於現階段的可用性已經徹底知足,可是對於將來變化和爆發是否須要前瞻性的作預留和拓展,以達到更高一層的可複用的衝突,須要開發者本身衡量的。
組件的維護在小型項目還能夠忽略,可是在大型項目中,若是維護須要本身一個代碼一個代碼的去尋找痕跡,那麼這樣的組件設計開發不理想,反而違背了組件設計最初的夢想。
由於組件內部是相對獨立的,咱們不知道內部的變化,因此衡量一個組件除了是否知足個人需求之外,是否可靠,以及組件不可靠,出現意外的反應機制是否可以準肯定位和降級容錯(損失一些功能,保證其餘功能完善)。
組件開發是爲了更高的減輕開發中的各類負擔,可是在組件持續的增加中,組件自己也會成爲一種負擔,對於自己的負擔是否有完善的處理機制,能夠在持續增加中hold住。
每一個攻城獅的開發風格都有各類差別,組件的規範,在這樣的合做中就是重中之重,減小多套理解成本。
對於核心大腦的健壯是整個系統的靈魂。這個很少說,掛了就直接game over!
有挑戰,是真實存在的,可是咱們能夠經過一系列的方法和規範去解決這些挑戰,讓組件化設計更好的服務咱們的系統。
構建組件系統有2個方向:
設計一套符合系統需求的組件
設計一套能夠通用的組件
羅列一些無論哪一個方向都要考慮的因素:
1.統一收口和管理組件
對於任何一個系統來講,快速迭代和增加中勢必會帶來組件的爆發式增加,若是不能將組件統一收口,可能會帶來組件的重複開發利用率低下(可能和一個組件功能80%相同,只須要拓展一個原子組件就能夠解決問題。或者無收口不知道其餘地方有個相似能夠知足的組件致使二次開發)。其次管理也同樣,好的管理能夠最大化發揮組件式開發的優點,不善的管理就會帶來這樣的疑問,"這樣的組件化開發,增長了更多的複雜度,還有什麼意義?"
2.組件升級和更新,乃至替換作到可控
忘本式迭代,拋棄舊包袱,迎接新時代這是一種很爽的開發體驗。可是也會帶來,開發一時爽,xxxxx(你們本身體會)。組件每次的升級,在沒有完整的方案前,勢必要考慮組件的兼容性,不然我每次迭代一個新的組件,使用的組件都不兼容,都須要從頭返工手把手替換使用的組件。那就呵呵了。可是有完整灰度方案之後能夠實施,好比組件總體升級2.0版本,才能使用新特性,且有足夠的組件升級遷移方案保證升級無影響。這樣的可控,能夠最大化組件開發的優點。
3.容錯,核心與非核心組件的容錯方案的處理。
容錯式,也分不少種方式,在傳統window大型系統中,對於核心組件的容錯式就特別的低,由於有些是核心組件,好比CPU,丟了這個就不能玩了。可是對於USB插槽,音頻輸出插槽等等這些容錯率就很高,你壞了無所謂,我係統能跑。只是我會斷掉你的組件提供的功能。因此組件的容錯,須要針對系統自己去評估,無統一方案。
4.安全性,除對外暴露契約影響,對內應自成沙盒
這個就跟瀏覽器同樣,我受影響的東西,只有我本身對外拋出的約定和契約,不然其餘東西都不能影響到我。這樣纔不會致使會有非自己的變更,而讓組件自身出現問題,解耦萬物,才能達到心裏的聚合和獨立。
5.文檔,組件的自描述,功能和對外契約
沒有文檔就是沒有自我介紹,誰知道你是誰,能幹什麼,能不能勝任個人解決方案。
6.可信,組件開發授於任何開發者,必須減小風險的可能,以及全面的測試。
組件設計最終的執行者是開發者,若是一個未受評估或者沒有全面測試的組件引入整個系統構建中,那麼就是引入了一個很大的風險,之後對於這個風險你可能會承受多餘自身的時間去把控這個問題。這也是一個合格的軟件開發工程師須要評估的問題。
7.適配器和膠水代碼:包裝更復雜複合通用組件,應經過適配器設計和膠水代碼組合,保證符合組件規範
組件的重複利用和組件之間的組裝,確定會帶來更多組件的出現和更復雜的組件出現,天然而然會獲得更高的複雜度。可是基於本系統的組件規範和開發規範,可使用更多的膠水代碼去適配成和本系統組件一致的模型,這樣你我都同樣,學習和使用成本都不高。業內不少都是建立一個組件的原始類,定義組件的基礎功能和契約,全部的組件都會去繼承這個原始類,達到組件的一致性。
8.友好,對開發者更友好,學習成本和使用成本更低廉
在軟件開發中,下游消費的是程序員,是將你建立的東西發揚光大的信教徒,你的佈道須要更多的友好。不然程序員心裏就會出現這樣粗俗的聲音,「你上來就給老子一棒子,寫着寫着又給老子一棒子,還玩個蛋!」
9.穩定,一切以穩定爲重,遠離危險代碼
相信每一個公司都會安利這樣的思惟,生產代碼是能經歷風吹雨打,是能扛得住大山的。你的組件同樣必須這樣,太多的問題,最終會致使沒法維護,成本過高,問題千奇百怪等等,而後你被幹掉了。
10.特點,獨特的系統有本身的特點和亮點
通常這個都是可選項,畢竟你想的輪子,可能前人都造了N個,你有什麼特點去讓別人去選擇你,使用你。是由於愛嗎?仍是由於愛嗎?
11.更符合使用者習慣
站在別人的角度去思考問題,才能知作別人須要什麼,才能讓別人離不開你。
第一要素:以需求爲中心,以知足需求爲衡量標準
1.挖掘符合本系統的組件作基礎組件和樣本組件。
一個系統的組件系統不多是本身從頭搭建,由於成本問題。在業務的快速迭代中,通常都會選擇一些提供原子組件的第三方的庫和包,經過包裝第三方的組件,造成符合本系統需求的組件系統。
2.構建需求組件,適應現有系統的組件模型和需求規範
不一樣組件定義了本身不一樣的對外接口契約,變幻無窮的契約會帶來雜、亂、差。無論哪一方的組件,乃至本身的組件,都須要遵照本系統的組件模型規範。
3.可選拓展,在需求可伸縮範圍支持拓展和收縮
在需求組件的開發中,對需求的發展,乃至回滾都有很清楚的認識。在這樣的基礎之上,能夠在組件開發中留有可選拓展項,需求伸縮和回滾都能把控。
4.適可而止,不過多設計
一切以需求爲準,知足便是最好。
5.自描述性更高,組件設計對需求的耦合性更高,須要更多的描述
因業務的複雜度耦合更多的獨特的規則,這樣的組件更須要更高的自描述性內容。
第一要素:以通用爲中心,以抽象共性解決同類問題爲衡量標準
1.關聯穩定的領域抽象
通用,便是穩定的,造成共識的領域。因此通用組件,也是穩定領域抽象出的組件
2.將組件通常化
通常組件都是爲了解決特定問題而產生的應用,將這個應用進行通常化,關聯更廣泛的業務對象
3.控制複雜度和可讀性
越通用的組件,可複用性越高,可是複雜度性對也越高,可讀性也越差
4.一致性
統一的接口和契約,乃至統一的對外異常暴露,只有你們越一致,更通用纔會成爲可能
5.適應性
爲組件增長一個配置接口,爲組件伸縮提供一種可能
針對組件設計的挑戰,咱們從未由於有挑戰就中止前進的步伐,因此結合前人探索和本身開發中的經驗和理解,對於想構建一套出色的組件系統的各位攻城獅提供一個指南和參考。
若是你感受對你有用,請點個star,繼續支持我更多的研究。
若是有任何問題,請到這裏提issues,一塊兒探討問題的可能性。