敲打干净的建筑

  > Clean Architecture? :)

  干净的建筑,六角形的建筑,洋葱的建筑,尖叫的建筑! 这么多名字,那么短时间! 围绕这些提出的理论的概念有些相似,我认为尝试破解其中一种也会使您对其他理论有所了解。 

  看起来很多东西,不是吗? 不过,这个想法很聪明,我不会说那么复杂。 目的是将很少更改的内容与消耗性内容分开。 您可能想知道在软件开发领域很少发生变化是什么,您认为正确是正确的。 我要说的是,至少在应用程序的生命周期中,不会经常改变的事情是域,即应用程序本身的核心概念。 举例来说,如果您要建立会计应用程式,客户就不太可能在两周后要求您提供电子游戏。 对应用程序的固有概念进行建模通常可以在设计的初始阶段完成。 当然,您永远不会做所有的设计,这并不意味着您的核心实体永远不会改变。 但是,只要您保持井井有条并尽量减少影响,就可以了。

  还有框架的问题。 框架是工具,它们不应驱动应用程序的内部运行。 起初,这听起来有点怪异,因为我当时做了一些Java EE开发,并且非常习惯在表实体上添加注释,在我看来,这始终是推荐的方法。 但是,如果您考虑一下,所有这些类型的操作就是将域对象绑定到某种类型的数据库和某种框架。 如果您以后决定更改,则可能需要来到这里,对以前所做的事情进行很好的了解,然后再开始研究应用程序的核心。 我们都知道,这种风险通常是利益相关者不准备承担的,因为它可能会影响生产,甚至阻碍发展。 因此,一旦通过了最初的决策过程,框架灵活性就不会在软件工程界经常遇到。

  对于我想向您展示的示例,我选择了一个称为NestJs的东西,作者将其描述为:"……用于构建高效,可扩展的Node.js服务器端应用程序的框架。" 由于它对Typescript提供了一流的支持,近几个月来我对它有了越来越多的支持,所以我决定深入研究并准备一个小型应用程序来支持本文。 它始于锻造大戒指….等等,对不起,错误的宇宙:)始于我设计一些核心领域对象,我打算在"奇幻世界中的集市集"应用程序中使用这些对象。 自启动NestJs应用程序(主要是为了完成一些准备好的项目"骨架")后,我开始从基础开始缓慢地黑客入侵。

  

  正是领域模型! 这些看起来像什么? 嗯,这是纯Typescript代码。 没有实现框架方法,没有花哨的装饰器,没有在框架超类中重写该特殊方法。 正是Sigmar的意图! :)

  您可能会争辩说语言本身就是一个框架。 可能是这样,但是我仍然认为它具有一定的纯度。 如果我们需要在此处使用异常,则可能还可以将一些与业务相关的异常定义为域的一部分,这些异常可以在基础结构级别重新抛出。 为了简单起见,我使用了一些NestJs异常,但这不是必须的(并且可能也不建议:P)。

  虽然该域代表"洋葱"的核心,但下一层属于DDD所称的用例。 这些用例表示应用程序可以做什么,以及用户希望它做什么。 业务规则和实现属于此处。 同样,请确保仅使用核心语言来实现这些目标。 这里的巨大优势是可测试性。 如果无需框架设置或其他仪式就可以测试核心功能,则容易得多。

  

  这些元素的依赖关系指向内部,因为干净架构中的所有模块都必须如此! 在此,我们仅使用模型内容,其余为纯Typescript代码。 同样,请忽略框架异常:)

  这里需要进一步的解释。 我们如何使依赖点指向内部? 在没有依赖项注入容器,没有连接到数据库或没有与外部系统对话的情况下,用例如何进行相关工作? 答案是端口。 我们通过迫使利用用例的外部层实现缺少的功能来逆转依赖关系。 这里的if子句是业务规则,但是sellItemService需要由某些框架填充。 在此级别上,我们不应该在乎如何使用或使用哪个框架,因为这是外层的责任。 这里的关键要点是:与纯业务功能无关的所有操作都将被外部化到适当的级别。

  在我的小应用程序架构中,向外扩展一层将使我们进入基础架构级别。 这是所有接线的地方。 如果我们稍后决定这样做,则可以完全替换此级别,而不会对业务规则或域对象造成太大的麻烦。 在现实世界的项目中,这可以证明是一个巨大的优势。

  

  这是我们需要实际交互的地方。 通过HTTP调用Web服务,与数据库对话并对其进行配置,通过管道传输事件或我们需要做的其他任何事情。 在我们的案例中,NestJs与Mongoose完美集成,Mongoose是用于MongoDB的优雅建模工具。 我的数据库在Docker本地运行,但这又是一个纯粹的选择。 它可能就像是Postgres服务器一样,可以远程运行。

  我们实现用例中定义的端口,在此进行实际的数据库操作。 看似更多的代码,但是从长远来看,去耦很可能会得到回报。 与外界的接口,即控制器,也将属于基础架构级别。

  如您所见,这里使用的是用例,因此,依赖关系再次向内指向。 依赖注入是在此处手动完成的,以使框架装饰器远离内层。 这些控制器的唯一职责是通过HTTP与外部客户端进行通信。 我们的业务规则是孤立的。 可以通过cURL添加一些数据进行测试:

  curl -d '{"race": { "mainRaceName": "MANKIND", "subrace": "Empire" }, "name": "Karl Franz", "itemsOwned": [{"name": "Ghal Maraz", "itemKind": "HAMMER", "worthInGold": 999999}], "friends": [], "goldOwned": 0}' -H "Content-Type: application/json" -X POST localhost:3000/

  然后,导航到http:// localhost:3000将向我们显示所有保存的字符:

  [{"_id":"5d18678e59e031da82880ced","race":{"_id":"5d18678e59e031da82880cee","mainRaceName":"MANKIND","subrace":"Empire"},"name":"Saltzpyre","itemsOwned":[],"friends":[],"goldOwned":50,"__v":0},{"_id":"5d187eb48e139bdd93fcde28","race":{"_id":"5d187eb48e139bdd93fcde29","mainRaceName":"MANKIND","subrace":"Empire"},"name":"Karl Franz","itemsOwned":[{"_id":"5d187eb48e139bdd93fcde2a","name":"Ghal Maraz","itemKind":"HAMMER","worthInGold":999999}],"friends":[],"goldOwned":0,"__v":0}]

  在这个小练习中,看到干净架构的一些优点对我来说非常有用。 我希望这也将对其他人有用。 总之,在设计大型应用程序时,您可能会考虑几个优点:

  · 框架独立性:不再需要将我们的内部业务逻辑与任何特定于库的功能混合在一起。

  · 可测试性:我们的业务逻辑变得更容易测试。

  · 基础架构的独立性:替换数据库层,HTTP层,异步队列系统或我们可能需要的其他任何东西都容易得多,因为它们位于外层。

  · 灵活性:向这种架构添加新的业务逻辑要容易得多。 只需添加更多用例,或在客户需要新的或不同的东西时更改现有的用例。 这很容易,您只需要使用自己选择的语言进行编码,而无需担心其他任何事情。

  可能有一些缺点,例如:

  · 写更多的代码

  · 一开始有点学习曲线,因为这种方法不同于传统方法

  · 害怕尝试看似未经证实的新事物

  这种架构是否会成为未来的主流,还有待观察,但我可以说我看到了很多潜力。

  请在此GitHub存储库中找到代码。 请随时在下面的评论中提问。 感谢您提供的任何反馈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值