当前位置: 首页 > 后端技术 > Node.js

【译文】TheCleanArchitecture

时间:2023-04-04 00:29:10 Node.js

介绍基于NodeJS和GoodPractices。我想尝试下一个分层。做的时候又发现了一个类似的分层,继续翻译记录。原文:TheCleanArchitectureOriginMyGitHubText在过去的几年里,我们看到了一系列关于系统架构的想法。其中包括:AlistairCockburn的HexagonalArchitecture(又名端口和适配器)和在SteveFreeman中采用JeffreyPalermo的OnionArchitecture和NatPryce的优秀著作GrowingObjectOrientedSoftware我去年的文章ScreamingArchitecturebyJamesCoplienandTrygveReenskaug'sDCI来自Ivar雅各布森的书面向对象的软件工程:一种用例驱动的方法虽然这些架构在细节上都不同,但它们非常相似。它们都服务于相同的目的,关注点分离。他们都通过将软件划分为不同的层来实现这种分离。每个层至少有一层用于业务规则,另一层用于接口。这些架构中的每一个都会产生一个独立于框架的框架。该架构不依赖于功能丰富的软件库。这使您可以将这些框架用作工具,而无需将系统塞入其有限的约束中。可测试的。无需UI、数据库、Web服务器或任何其他外部元素即可测试业务规则。独立于用户界面。无需更改系统的其余部分即可轻松更改UI。例如,可以在不更改业务规则的情况下将WebUI替换为控制台UI。独立于数据库。您可以将Oracle或SQLServer换成Mongo、BigTable、CouchDB或其他。您的业??务规则未绑定到数据库。独立于任何外部机构。事实上,您的业务规则根本不知道有关外部世界的任何信息。本文顶部的插图试图将所有这些架构集成到一个可操作的想法中。依赖规则同心环代表软件的不同区域。一般来说,越深入,软件的等级就越高。外圈是机制。内圈是政策。使此体系结构正常工作的最重要规则是依赖性规则。规则是源代码依赖项只能指向internal。内圈的人不可能知道外圈的人。特别是在外环声明的事物名称不能在内环代码中提及。这些包括函数、类、变量或任何其他命名的软件实体。同样,外环中使用的数据格式不应由内环使用,特别是如果这些格式是由外环中的框架生成的。我们不希望外环中的任何东西对内环产生影响。实体实体封装了企业范围内的业务规则。实体可以是具有方法的对象,也可以是一组数据结构和函数。只要该实体可以被计划中的许多不同应用程序使用就没有关系。如果你没有计划(企业),只是写一个单一的应用程序,那么这些实体就是应用程序的业务对象。它们封装了最通用和最高级别的规则。当外部事物发生变化时,它们最不可能发生变化。例如,您不希望这些对象受到页面导航或安全更改的影响。对任何特定应用程序的操作更改不应影响物理层。用例层中的软件包含特定于应用程序的业务规则。它封装并实现了系统的所有用例。这些用例协调进出实体的数据流,并指导这些实体使用其范围内的业务规则来实现用例的目的。我们不希望这一层的变化影响实体。我们也不希望这一层受到数据库、UI或任何公共框架等外部因素变化的影响。该层与这些问题无关。但是,我们确实希望对应用程序操作的更改会影响用例,从而影响该层中的软件。如果用例的细节发生变化,这一层的一些代码肯定会受到影响。InterfaceAdapters层中的软件是一组适配器,可将数据从对用例和实体最方便的格式转换为对数据库或Web等外部机构最方便的格式。例如,正是这一层将完全包含GUI的MVC架构。演示者、视图、控制器都属于这里。这个模型就像一个数据结构,从控制器传递给用例,再从用例返回给演示者和视图。同样,在该层中,数据从实体和用例最方便的形式转换为持久性框架(例如数据库)最方便的形式。此循环中的任何代码都不应知道有关数据库的任何信息。如果数据库是SQL数据库,那么所有的SQL都应该限制在这一层,尤其是与数据库相关的部分在这一层。该层也是用于将数据从某种外部形式(例如外部服务)转换为用例和实体使用的内部形式的适配器。FrameworksandDrivers(框架和驱动程序)最外层通常由框架和工具组成,例如数据库、web框架等。一般不会在这一层写太多代码,除了与下环向内。这一层是所有细节所在的地方。网络是一个细节。数据库是一个细节。我们把这些东西放在外面,这样它们造成的损害就尽可能小。只有4个戒指?不,圆圈只是一个图表。您可能会发现您需要的不只是这四种。没有规定说你必须只有这四个。但是,依赖规则始终适用。源代码依赖总是向内的。当您向内移动时,抽象级别会增加。最外面的环是低级别的特定细节。当您向内移动时,软件变得更加抽象并封装了更高级别的策略。最内圈是最通用的。跨越边界插图的右下角是如何跨越边界的示例。它显示了控制器和演示器与下一层中的用例进行通信。注意控制流。它从Controllers开始,通过用例,然后在Presenters中执行。还要注意源代码依赖性。他们每个人都向内指向用例。我们通常使用依赖倒置原则来解决这个明显的矛盾。例如,在像Java这样的语言中,我们安排接口和继承关系,使源代码依赖性与控制流在边界上的正确点相反。例如,考虑一个调用presenter的用例。但是,这不能是直接调用,因为那样会违反依赖规则:外环中的任何名称都不能被内环提及。因此,我们让用例在内环调用一个接口(这里是图中的UseCaseOutputPort),让外环的presenter去实现。相同的技术用于跨越架构中的所有边界。我们利用动态多态性来创建针对控制流的源代码依赖性,这样无论控制流向哪个方向发展,我们都可以遵循依赖性规则。什么数据跨越边界通常,跨越边界的数据是简单的数据结构。如果您愿意,可以使用原始结构或简单的数据传输对象。或者数据可能只是函数调用中的参数。或者你可以把它放入一个哈希表(hashmap)中,或者把它构造成一个对象。重要的是跨越边界传递的数据结构是独立的和简单的。我们不想欺骗和传递实体或数据库行。我们不希望数据结构有任何违反依赖规则的依赖。例如,许多数据库框架以方便的格式返回数据以响应查询。我们可以称它为行结构(RowStructure)。我们不希望跨边界传入行结构。这将违反依赖规则,因为它会强制内循环了解外循环的一些信息。所以当我们跨界传递数据时,总是以最方便内循环的形式传递。结论遵循这些简单的规则并不困难,而且会在以后为您省去很多麻烦。通过将软件分层并遵循依赖性规则,您将创建一个具有所有优点的本质上可测试的系统。当系统的任何外部部分(例如数据库或Web框架)过时时,您可以轻松地替换那些过时的元素。参考资料TheCleanArchitectureFrontEndArchitecture—Makingrebuildfromscratchnotsopainful