同步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,一块儿探讨问题的可能性。