基础代码的复用往往比较简单,但是业务代码的复用通常是困难的,如果没有特殊的手段去治理项目会逐渐发展为难以维护的巨石应用,按照维基百科记载,代码的复用形式主要有三种,程序库,应用框架,设计模式
前端业务代码在程序库的体现主要是通过业务组件,稍微大点的团队都有自己的业务组件库,但是我去过的很多团队都有落地难的问题,其中有些是技术层面的,但是更多的是出现在跨职责协作上,其中,我认为影响最大的是 UI 设计师和前端开发之间的协作关系
UI 设计师作为前端的直接上游,生产前端工程师所需的设计资源,如果生产的设计资源本身就是不规范的,必然会极大影响前端团队组件化的发展
UI 设计师作为设计人员,和工程师的思维方式不同,对组件设计规范的意识并不强烈,大部分设计人员对规范的定义仅仅在主题色和主观意识强烈的 风格 上,UI 设计师的最终产出由少部分 视觉要素约定 +设计师个人 主观设计倾向 决定,也就是说,设计师的心情好坏和人员更替会直接影响每次产出设计稿的呈现,这对设计师来说很正常,但对前端工程师来说是致命的
基于此,我们需要在工具上对 UI 设计师的产出加以约束,使其在前端工程师可接受的范围内自由发挥,例如 figma,figma 的 component 概念与前端组件化概念高度吻合,我们可以要求设计稿中可复用的独立单元必须是一个 figma component,从而倒逼设计师建立业务的组件资产,进而确保组件设计的一致性
按照软件设计原则,找到程序中的变化内容并将其与不变的内容区分开,而在前端,按照代码改动频率依次排列,视图代码>视图逻辑>业务逻辑,相比业务逻辑,UI 代码属于高频变动的部分,尤其是是由 html+css 组成的视图代码
例如电商的商品卡片,不同节日下的商品卡片很可能有不同的 UI 样式,但是他们的业务逻辑是一样的,他们使用同样的业务数据和业务行为
在这种情况下大部分开发会选择两条路
前者会导致代码的大量冗余,后者违背了单一职责的设计原则,组件内部根据外部传入的节日类型写了一堆 if else,时间久了没人看得懂一堆 if else 里写的是什么
为了减少代码冗余和提升可维护性,我们可以按照职责将组件划为四部分
可以看到和 Flux 架构很像,但是又有些区别,更像是对 Flux 架构的补充完善
一条业务线往往会存在多个项目,不同项目之间通用业务代码的复用一直是个问题,在若干个项目上往往存在着多次复制黏贴的代码,经过项目的多次迭代,他们可能还会在各自的项目上衍生出不同的版本,长此以往维护成本会让开发人员痛苦不堪,我们当然知道抽离到 npm 私库是最佳实践,但是抽离模块的繁琐过程很大程度上提高了业务线上开发人员的心智成本,从而降低了将代码抽离到 npm 的意愿,在这种情况下,Monorepo 也许是更好的解决方案
lerna 提供了一个简易的 Monorepo 方案,利用 lerna 软链接项目作为依赖的特性,使得项目间的代码共享变得更加容易

上面我们用 lerna 管理了三个项目,其中 shared 属于其他两个项目的共享代码,wap-app 和 web-app 可以通过依赖的方式直接消费 shared 项目中的组件,工具函数和业务服务,极大优化我们的工作流程
很多时候我们提到代码复用第一时间想到的组件,但是组件有组件的局限性,它是和 UI 框架 强耦合 的,而有一些场景需要需要实现 ==跨平台跨框架的代码复用== ,例如一个产品它既有 PC 网页,也有 RN 开发的 App,还有小程序
他们存在完全迥异的视图层或者框架体系,与之强耦合的组件没办法实现复用,但它们背后的业务逻辑都是一样的,所以为了复用我们的业务逻辑,需要实现业务逻辑的 ==框架无关,环境无关==
设计本质上就是以一种可以将它们重新组合在一起的方式将事物拆开…… 将事物拆分成可以重新组合的事物,这就是设计。 — Rich Hickey《设计、重构和性能》
系统设计其实就是系统的拆分,最重要的是我们可以在不耗费太多时间的情况下重新把它们组起来。
我同意上面这个观点,但我认为系统架构的另一个主要目标是系统的可扩展性。我们应用的需求是不断变化的。我们希望我们的程序可以非常易于更新和修改以满足持续变化的新需求。干净的架构就可以帮助我们实现这一目标。
了解干净架构,可以阅读《前端领域的 “干净架构” https://juejin.cn/post/7054888223830441991》
《架构整洁之道》中提出的整洁架构就是解决这个问题的,腾讯文档团队也有对整洁架构的相关实践 让 JS 摆脱框架的束缚
我们可以将 react 的代码快速的迁移到一个类 react 框架,但是我们很难将他迁移到 Vue 框架和 Angular 框架。可能在代码迁移合并升级的时候,我们能做的可能只有重构。 我们可能会想到使用 Web Components 或者是微服务,但是带来的可能会是,更多的浏览器限定,要看更多的框架文档去遵循更多的规范。 无论框架如何的迭代,我们 JS 是永远不会太大的变化的,所有框架都是基于 JS 去写的,如何让我们通用 JS 代码被不同的框架去应用,让我们的通用代码去框架化,是我们应该思考的问题。 既然我们要去框架化,那架构就不去用了,直接用 JS 就好了呀,那就是一种技术的倒退,我们要做的不是不用框架,而是用一种更巧妙的方式去可以适配更多的框架。 例如,目前前端的类 MVVM 架构,ViewModel 层可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。我们要去用我们不变的 JS 代码去适配更多框架的 VM。
Clean Architecture 是由 Robert C. Martin 在 2012 年提出的,最早只是在 Android,Android 应用有很重的 View 层。今天,前端应用走向了 MV* 的架构方案,也有了一层很重的 View 层。
《DDD中常提到的应用架构总结(六边形、洋葱、整洁、清晰) https://blog.csdn.net/luo15242208310/article/details/124708008》 架构随时间的演进可参见下图:

Robert C. Martin 总结了六边形架构(即端口与适配器架构):DCI (Data-Context-Interactions,数据-场景-交互)架构BCI(Boundary Control Entity,Boundary Control Entity)架构等多种架构,归纳出了这些架构的基本特点:
如你所见,作为一个普通(不分前后端)的开发人员,我们关注于业务逻辑的抽离,让业务逻辑独立于框架。而在前端的实化,则是让前端的业务逻辑,可以独立于框架,只让 UI(即表现层)与框架绑定。一旦,我们更换框架的时候,只需要替换这部分的业务逻辑即可。


这种架构使得,框架和一切外部相关的实现细节被隔离在框架与驱动层,业务逻辑层只负责业务本身,与外部的联系由接口适配器层控制,假设我们需要从 Vue 迁移到 React,或者从 Vue2 升级到 Vue3,我们只需要变动接口适配器层和框架与驱动层,业务逻辑层可以继续复用
如图所示 Clean Architecture 一共分为四个环,四个层级。环与环之间,存在一个依赖关系原则:源代码中的依赖关系,必须只指向同心圆的内层,即由低层机制指向高级策略。其类似于 SOLID 中的依赖倒置原则:
与此同时,四个环都存在各自核心的概念: 实体 Entities (又称领域对象或业务对象,实体用于封装企业范围的业务规则)
这个介绍可能有些简单,让我复制/粘贴一下更详细的解释:
从某种意义上来说,Clean Architectute 是一种规范化和模板化的实施方案。与此同时,它在数据层的三层机制,使得它存在两层防腐层,usecase 可以作为业务的缓冲层,repository 层可以隔离后端服务与模型。
2017年Herberto Graca在其《软件架构编年》史系列文章中提出清晰架构Explicit Architecture,即将DDD, Hexagonal, Onion, Clean, CQRS等进行融合后的架构。

采用按组件分包Package By Component,即整合传统按层分包Package By Layer和按特性分包Package By Feature,组件Component可以理解为专属于特定一个领域内的业务逻辑服务和数据访问逻辑的组合,也可以理解为特定领域,如账单、用户、评论或帐号等。
在清晰架构中可以理解为:
参考文章:
前端业务代码如何复用 https://zhuanlan.zhihu.com/p/406182932
让 JS 摆脱框架的束缚 https://mp.weixin.qq.com/s/n65x3duoeQAtQU_fH_dJDw
DDD中常提到的应用架构总结(六边形、洋葱、整洁、清晰) https://blog.csdn.net/luo15242208310/article/details/124708008
Clean Frontend Architecture:整洁前端架构 https://phodal.github.io/clean-frontend/
微模块-前端业务模块化探索# https://eluxjs.com/designed/micro-module.html
“整洁架构” 和商家前端的重构之路 https://my.oschina.net/u/5783135/blog/5562550
转载本站文章《前端代码复用学习笔记:整洁架构与清晰架构》, 请注明出处:https://www.zhoulujun.cn/html/webfront/engineer/Architecture/8910.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。