当前位置: 首页 > 科技观察

学习洋葱架构,轻松实现DDD

时间:2023-03-15 20:34:33 科技观察

的领域是知识的范畴。它指的是我们的软件要建模的业务知识。领域驱动设计的核心是领域模型,它对领域的过程和规则有着深刻的理解。洋葱架构实现了这一理念,大大提高了代码质量,降低了复杂性,支持不断发展的企业系统。1、为什么要用洋葱架构?领域实体是核心和中心部分。洋葱架构建立在领域模型之上,其中各层通过接口连接。它背后的想法是尽可能地排除外部依赖,而领域实体和业务规则构成架构的核心部分。它提供了一个灵活、可持续和便携的架构。层与层之间没有紧密耦合,并且存在关注点分离。提供更好的可维护性,因为所有代码都依赖于更深层或集线器。改进了整体代码的可测试性,因为可以在不影响其他模块的情况下为各个层创建单元测试。可以在不影响核心领域的情况下轻松更改框架/技术。比如RabbitMQ可以换成ActiveMQ,SQL可以换成MongoDB。2.原理洋葱架构由多个同心层组成,这些层相互连接并朝向代表领域的核心。它基于控制反转(IoC)的原理。架构不关注底层技术或框架,而是关注实际的领域模型。它基于以下原则:1.依赖环代表不同的责任层。一般来说,我们潜得越深,我们就越接近领域和业务规则。外圈代表机制,内圈代表核心领域逻辑。外层依赖于内层,内层对外环一无所知。通常,属于外圈的类、方法、变量和源代码依赖于内圈,但反之亦然。数据格式/结构可能因层而异。外层的数据格式不应该被内层使用。例如,API中使用的数据格式可能与数据库中用于持久化的数据格式不同。数据流可以使用数据传输对象。每当数据跨越层/边界时,它都应该采用对该层方便的形式。例如,API可以有DTO,DB层可以有实体对象,这取决于存储在数据库中的对象与域模型的不同之处。2.数据封装每一层/圈封装或隐藏内部实现细节,对外暴露接口。所有层还需要提供信息供内层使用。其目的是最小化层间耦合并最大化跨层垂直切片内的耦合。我们在更深层定义抽象接口,并在最外层提供它们的具体实现。这确保我们可以专注于领域模型,而不必过多担心实现细节。我们还可以使用依赖注入框架,例如Spring,在运行时将接口与实现连接起来。例如,域中使用的存储库和应用程序服务中使用的外部服务都是在基础设施层实现的。Onion架构中的数据封装3.关注点分离应用程序分为若干层,每一层都有一组职责并处理不同的关注点。每一层都充当应用程序中的模块/包/命名空间。4.耦合低耦合允许一个模块与另一个模块交互,而无需关注另一个模块的内部结构。所有内层都不需要关心外层的内部实现。三、洋葱架构层让我们通过一个创建订单的用例来了解架构的不同层及其职责。当收到创建订单的请求时,我们验证订单,将订单保存在数据库中,更新所有订单项目的库存,扣除订单金额,最后向客户发送订单完成的通知。说明层之间依赖关系的包图1.域模型/实体域实体是域驱动设计的基本构建块,它们用于在代码中对公共语言概念进行建模。实体是在问题域中具有唯一标识的域概念。领域实体封装了属性和实体行为。它应该独立于特定技术,例如数据库或WebAPI。例如,在Orders域中,Order是一个实体,具有OrderId、Address、UserInfo、OrderItems、PricingInfo等属性以及AddOrderItems、GetPricingInfo、ValidateOrder等行为。订单实体类2.领域服务领域服务负责维护领域逻辑和业务规则。所有业务逻辑都应作为域服务的一部分来实现。域服务由应用程序服务协调以服务于业务用例。它们不是典型的CRUD服务,通常是独立的服务。领域服务负责复杂的业务规则,例如处理订单时计算价格和税收信息,保存和更新订单的订单库接口,更新采购商品信息的库存接口等。它包含对其目标和实现至关重要的算法用例作为应用程序的核心。3.应用服务应用服务,又称“用例”,是一种只负责协调请求步骤的服务,不应该有任何业务逻辑。应用程序服务与其他服务交互以满足客户请求。让我们考虑使用项目列表创建订单的用例。我们首先需要计算价格,包括税金计算/折扣等,保存订单商品并发送订单确认通知给客户。定价计算应该是领域服务的一部分,但涉及定价计算、检查可用性、保存订单和通知用户的协调工作应该是应用程序服务的一部分。应用程序服务只能由基础设施服务调用。4.基础设施服务基础设施服务,也称为基础设施适配器,是洋葱架构的最外层。这些服务负责与外界交互,不解决任何领域的问题。这些服务只是与外部资源通信,没有任何逻辑。例如:外部通知服务、GRPC服务器端点、Kafka事件流适配器、数据库适配器。5.可观察性服务可观察性服务负责监控应用程序。这些服务有助于完成以下任务:数据收集(指标、日志、跟踪):主要使用库/副业在代码执行期间收集各种数据。数据存储:使用能够集中存储所收集数据的工具(分类、索引等)。可视化:使用允许您可视化收集的数据的工具。一些示例包括Splunk、ELK、Grafana、Graphite、Datadog。4.测试策略洋葱架构的不同层次有不同的职责,相应的有不同的测试策略。测试金字塔是一个很好的框架,它指定了不同类型的测试。与域模型、域服务和应用程序服务有关的业务规则应该用单元测试来测试。当我们转向外层时,在基础设施服务中进行集成测试更有意义。对于我们的应用程序,端到端测试和BDD是最合适的测试策略。不同层的测试策略5.微服务当孤立地看每个微服务时,洋葱架构也适用于微服务。每个微服务都有自己的模型、自己的用例,并定义自己的用于检索或修改数据的外部接口。这些接口可以用一个适配器来实现,该适配器通过公开HTTPRest、GRPC、ThriftEndpoints等连接到另一个微服务。它非常适合微服务,其中数据访问层不仅包括数据库,还包括例如http客户端从另一个微服务甚至外部系统获取数据。6.应用程序结构和层应用程序结构和层,包括层如何映射到模块以及它们之间的依赖关系。它还描述了用于不同层的测试策略。7.模块化和打包应用程序的源代码有两种组织方式:我们可以将所有包放在一个模块/项目中,或者将应用程序分成不同的模块/项目,每个模块/项目负责洋葱架构在很大程度上取决于应用程序的复杂性和项目的大小,将源代码划分为模块的层。在微服务架构中,模块化可能有意义也可能没有意义,这取决于复杂性和用例。8.框架、客户端和驱动基础设施层由网络或服务器框架、数据库客户端、队列或外部服务组成。它负责配置和拼接所有外部服务和框架。洋葱架构提供解耦功能,因此可以更轻松地随时交换技术。9.我们需要每一层吗?分层组织我们的应用程序有助于实现关注点分离。但是我们需要所有层吗?也许,也许不是。这取决于用例和应用程序的复杂性。根据应用程序的需要,还可以创建更多的抽象层。例如,对于没有大量业务逻辑的小型应用程序,拥有域服务可能没有意义。无论哪一层,依赖关系都应该是从外层到内层。10.小结洋葱架构初看可能比较难,但是已经得到了业界的普遍认可。这是一个强大的架构,使软件易于发展。通过将应用程序分成几层,系统可以更容易测试、维护和移植。当旧框架过时时,它有助于轻松采用新框架/技术。类似于六边形、分层、干净架构等其他架构风格,它提供了常见问题的解决方案。