首先,我们将简要介绍什么是清洁体系结构,包括域、用例和APP应用层等概念。 以及如何将清洁体系结构应用于前端,以及它们不值得这样做。
接下来,尝试使用干净体系结构原则设计并从头开始实施存储APP,以确定它是否正常工作。
此APP应用程序使用React作为UI框架。 这只是为了表明这种开发方法可以与React一起使用。 也可以选择其他UI库来实现它。
代码使用几种类型的脚本。 它只是为了演示如何使用类型和接口来描述实体。 其实所有代码都可以不使用TypeScript实现。 只是,代码看起来不那么富有表现力。
体系结构和设计
所谓设计,本质上就是把事物分解成可以重新组合起来的东西……把事物分割成可以重新组合起来的东西就是设计。 — Rich Hickey 《设计、重构和性能》
系统设计是系统划分,最重要的是可以不花时间再次分组。
我同意以上意见,但我认为系统体系结构的另一个主要目标是系统的可扩展性。 我们应用的需求在不断变化。 我们希望我们的计划能够非常容易地更新和修改,以适应不断变化的新需求。 清洁的体系结构有助于我们实现这个目标。
什么是清洁体系结构?
清洁体系结构是一种根据APP应用程序的域(域)相似度划分责任和功能的方法。
域(domain )是从现实世界中抽象出来的程序模型。 可以反映现实世界和程序中数据的映射。 例如,如果更新了产品的名称,则使用新名称替换旧名称就是域转换。
清洁体系结构的功能通常分为三个层次。 请看下图。
域层
中心是域层,这里介绍了APP应用程序主题区域的实体和数据,以及用于转换这些数据的代码。 领域是区分不同程序的核心。
请将区域理解为在我们从React迁移到Angular或修改某些用例时保持不变的部分。 商店这一APP应用程序涉及产品、订单、用户、购物车以及如何更新这些数据。
数据结构和他们之间的转换与外部世界隔离开来。 外部事件调用会引起域转换,但不确定如何执行。
例如,将商品添加到购物车的功能不关心如何将商品添加到购物车。用户单击“购买”按钮添加
用户使用优惠券自动添加了。
在这两种情况下,都将返回更新的购物车对象。
高速APP应用层
包围在区域之外的是APP应用层,该层描述了用例。
例如,“添加到购物车”场景是一个用例。 它描述了单击按钮后应该执行的具体操作,如“协调员”。
向服务器发送请求;
执行域转换;
使用响应的数据更新UI。
此外,APP应用层具有端口,用于描述APP应用层如何与外部进行通信。 端口通常是接口,行动合同。
也可以将端口视为现实世界与APP应用程序之间的“缓冲区”。 输入端口指示APP应用程序如何接受外部输入,而输出端口同样指示如何准备与外部通信。
适配器层
最外层包含外部服务适配器,通过适配器转换外部服务的不兼容API。
适配器可以减少我们的代码与外部第三方服务的耦合。 适配器一般分为以下几类
驱动-向我们的APP应用发送消息;
被动型-接受我们的APP应用程序发送的消息。
典型的用户往往与驱动程序适配器进行交互,例如,处理从UI框架发送的单击事件就是驱动程序适配器。 与浏览器API一起将事件转换为我们的APP应用程序可以理解的信号。
驱动型与我们的基础设施相互作用。 在前端,大多数基础设施都是后端服务器,但在某些情况下,它们可能与其他服务(如搜索引擎)直接交互。
请注意,距离中心越远,代码的功能就越“面向服务”,越远离APP应用程序的区域。 这在以后确定模块是哪个层时非常重要。
依赖于规则
三层结构有依赖规则。 只有外层可以依赖内层。 这意味着
领域必须独立
所述APP应用层可以依赖于区域
最外层可以依赖于任何东西
当然,有些特殊情况可能违反这个规则,但最好不要滥用它。 例如,即使不应该存在这种依赖关系,也可能在领域中使用第三方库。 看看代码就有这样的例子。
不控制依赖方向的代码可能会非常复杂,难以维护。 例如:
循环依赖,模块a依赖于b,b依赖于c,c依赖于a。
测试性差,即使测试了很少的功能也要模拟整个系统。
由于耦合度过高,模块之间的相互作用变得脆弱。
清洁体系结构的好处
独立领域
所有APP应用程序的核心功能都划分为一个位置—区域,并保持统一
区域内的功能是独立的,这意味着测试很容易。 模块依赖度越低,测试所需的基础架构就越少。独立领域也更容易根据业务期望进行测试。 这有助于初学者更容易理解。 独立的域还使您更容易消除从需求到代码实现的错误。
独立用例
的使用场景和用例是独立编写的。 确定所需的第三方服务。 我们让外部服务适应我们的需求,增加了选择合适第三方服务的空间。 例如,现在我们调用的支付系统涨价了。 马上就可以更换。
用例代码也是扁平的,容易测试,可扩展性强。 这在后面的例子中可以看到。
可更换的第三方服务
适配器可以方便地更换外部第三方服务。 只要我们不更改接口,任何第三方服务都可以实现这个接口。
这样别人更改代码不会直接影响我们。 适配器还减少了APP应用程序运行时错误的传播。
实现清洁体系结构的成本
首先,体系结构是一个工具。 和其他工具一样,干净的体系结构除了带来好处外还带来了额外的成本。
需要更多的时间
首先是时间。 设计、实施需要更多的时间。 因为直接调用第三方服务总是比写适配器更容易。
我们很难从一开始就很好地理解模块的所有交互和需求,在我们设计的时候需要经常注意哪些地方可能发生变化,所以必须考虑更多的可扩展性。
有时看起来多余
一般来说,清洁体系结构并不适用于所有场景,在某些情况下是有害的。 如果本身是一个小项目,就应该按照清洁体系结构进行设计。 这将大大提高获得的门槛。
变得更好更难
完全基于清洁体系结构来设计和实现对初学者来说更困难。 因为他首先需要了解APP应用程序是如何工作的。
代码量增加
这是前端特有的问题,清洁体系结构会增加最终包装的产品体积。 产物越大,下载和解释浏览器所需的时间越长,必须控制代码量,适当减少代码:
用例子更简单地说明;
直接从域与适配器交互,绕过用例;
进行代码分割
如何降低这些成本
通过牺牲适当的偷工减料和体系结构“清洁”,您可以减少实施时间和代码量。 如果放弃某事能获得更大的利益,我会毫不犹豫地去做。
所以,所有方面都不需要遵守清洁体系结构的设计标准,只要遵守核心标准就可以了。
抽象区域
领域抽象有助于理解总体设计及其工作方式,同时使其他开发人员更容易理解程序、实体及其之间的关系。
即使我们直接跳过其他层,抽象区域也更容易重建。 这些代码封装在一个位置,以便在需要其他层时轻松添加。遵守依存规则
第二条不应该放弃的规则是依赖规则,或者它们的依赖方向。 外部服务必须适合内部,而不是反向。
如果尝试直接调用外部API,这是有问题的,所以最好在还没有出现问题之前写适配器。
商店APP的设计
理论结束后,我们就可以开始实践了。 接下来,让我们实际设计一下商店APP。
商店出售各种类型的饼干,用户可以选择自己购买的饼干,通过三方支付服务支付。
用户可以在主页上查看所有cookie,但只能在登录后购买。 单击登录按钮可跳转到登录页面。