本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
适应变化
软件系统往往会变得复杂。造成这种情况的原因之一可能是业务需求的频繁变化以及几乎没有时间相应地调整软件架构。另一个原因可能是在项目开始时投资不足,无法建立软件架构,以适应频繁的变化。不管是什么原因,软件系统都可能变得复杂,以至于几乎不可能进行更改。因此,从项目一开始就建立可维护的软件架构非常重要。良好的软件架构可以轻松适应变化。
本节介绍如何使用可轻松适应非功能或业务需求的六边形架构来设计可维护的应用程序。
通过使用端口和适配器适应新的非功能要求
作为应用程序的核心,域模型定义了外部世界为满足业务需求而需要采取的行动。这些操作是通过抽象定义的,抽象被称为端口。这些端口由单独的适配器实现。每个适配器负责与另一个系统的交互。例如,您可能有一个用于数据库存储库的适配器和另一个用于与第三方 API 交互的适配器。该域不知道适配器的实现,因此很容易将一个适配器替换为另一个适配器。例如,应用程序可能会从 SQL 数据库切换到 NoSQL 数据库。在这种情况下,必须开发新的适配器来实现域模型定义的端口。该域不依赖数据库存储库,而是使用抽象进行交互,因此无需更改域模型中的任何内容。因此,六边形架构可以轻松适应非功能要求。
使用命令和命令处理程序适应新的业务需求
在传统的分层架构中,域依赖于持久层。如果要更改域,还必须更改持久层。相比之下,在六边形架构中,该域不依赖于软件中的其他模块。域是应用程序的核心,所有其他模块(端口和适配器)都取决于域模型。该域使用依赖倒置原理通过端口与外界通信。依赖关系反转的好处是,你可以自由地更改域模型,而不必害怕破坏代码的其他部分。由于域模型反映了您要解决的业务问题,因此更新域模型以适应不断变化的业务需求并不是问题。
在开发软件时,关注点分离是需要遵循的重要原则。要实现这种分离,可以使用稍作修改的命令模式。这是一种行为设计模式,其中完成操作所需的所有信息都封装在命令对象中。然后,这些操作由命令处理程序处理。命令处理器是接收命令、更改域状态然后向调用者返回响应的方法。您可以使用不同的客户端(例如同步 API 或异步队列)来运行命令。我们建议您对域上的每项操作都使用命令和命令处理程序。通过采用这种方法,您可以通过引入新命令和命令处理程序来添加新功能,而无需更改现有的业务逻辑。因此,使用命令模式可以更轻松地适应新的业务需求。
使用服务外墙或 CQRS 模式解耦组件
在六边形架构中,主适配器负责将来自客户端的传入读写请求松散地耦合到域。实现这种松散耦合的方法有两种:使用服务外墙模式或使用命令查询责任分离 (CQRS) 模式。
服务立面图案提供前置界面,为呈现层或微服务等客户端提供服务。服务外墙为客户提供多种读取和写入操作。它负责将传入的请求传输到域,并将从域收到的响应映射到客户端。对于只负责多项操作的微服务来说,使用服务外墙很容易。但是,在使用服务外墙时,很难遵循单一责任和开放式原则。单一责任原则规定,每个模块应仅对软件的单一功能负责。开放封闭原则规定,代码应开放以供扩展,封闭以供修改。随着服务外观的扩展,所有操作都收集在一个界面中,更多的依赖关系被封装到其中,更多的开发人员开始修改同一个外墙。因此,我们建议只有在开发过程中服务显然不会扩展太多的情况下才使用服务外墙。
在六边形架构中实现主适配器的另一种方法是使用 CQRS 模式,该模式使用查询和命令将读取和写入操作分开。如前所述,命令是包含更改域状态所需的所有信息的对象。命令由命令处理程序方法执行。另一方面,查询不会改变系统的状态。他们的唯一目的是将数据返回给客户。在 CQRS 模式中,命令和查询是在不同的模块中实现的。这对于遵循事件驱动架构的项目尤其有利,因为命令可以作为异步处理的事件来实现,而查询可以使用 API 同步运行。查询也可以使用针对其进行了优化的其他数据库。CQRS 模式的缺点是,与服务外墙相比,它需要更多的时间来实施。对于您计划长期扩展和维护的项目,我们建议使用CQRS模式。命令和查询为应用单一责任原则和开发松散耦合软件提供了一种有效的机制,尤其是在大型项目中。
从长远来看,CQRS有很大的好处,但需要初始投资。因此,我们建议您在决定使用 CQRS 模式之前仔细评估项目。但是,您可以从一开始就使用命令和命令处理程序来构建应用程序,而无需分开读/写操作。如果您稍后决定采用 CQRS 方法,这将帮助您轻松地为 CQRS 重构项目。
组织部门扩展
六边形架构、领域驱动设计和(可选)CQRS 的组合使您的组织能够快速扩展您的产品。根据康威定律,软件架构往往会演变以反映公司的通信结构。这种观察在历史上有负面含义,因为大型组织通常根据数据库、企业服务总线等技术专长来组建团队。这种方法的问题在于,产品和功能开发总是涉及诸如安全性和可扩展性之类的交叉问题,这需要团队之间不断进行沟通。基于技术特征组建团队会在组织中造成不必要的孤岛,从而导致沟通不畅、缺乏所有权和忽视大局。最终,这些组织问题反映在软件架构中。
另一方面,Inverse Conw ay Maneuver根据促进软件架构的领域定义了组织结构。例如,跨职能团队负责一组特定的有界上下文,这些上下文是使用 DDD 和事件风暴来识别的。这些有限的上下文可能反映了产品的非常具体的特征。例如,客户团队可能对付款环境负责。每项新功能都分配给一个具有高度凝聚力和松散关联责任的新团队,因此他们只能专注于该功能的交付,从而缩短上市时间。团队可以根据功能的复杂性进行扩展,因此可以将复杂的功能分配给更多的工程师。