如何基于DDD设计并实现模块化单体应用?
Jan Stenberg
讲述:初明明大小:3.98M时长:04:21
最近,华沙 ITSG Global 的系统架构师卡米尔·格兹别克(Kamil Grzybek)在 GitHub 发布了一个项目,给出了使用 DDD(领域驱动设计,Domain-Driven Design)方法设计并实现一个单体(monolith)应用的详细介绍。该项目的目标,就是展示如何以模块化方式设计并实现一个单体应用。此外,格兹别克还基于他在应用开发实践的收获,给开发者提出一些有用的架构建议和设计模式。
格兹别克指出,该项目的目标并非是要创建一个极简应用,或是一个验证原型(PoC,proof of concept),而是给出一种适用于生产环境的完整实现。该项目的动机,来自于格兹别克对一些类似的但并未取得成功的项目的审视。在他看来,大多数示例应用过于简单,或是不够完整。他一直认为,这些应用至少在某些部分上存在着设计和实现上的问题,或是存在着相关文档缺失的问题。
格兹别克强调指出,他的实现只是解决类似业务问题的许多方法之一。系统的软件架构需要考虑多种因素,例如功能要求、质量属性和技术约束等,另一方面也会受开发人员的经验、技术约束、时间和预算等因素的影响,所有这些因素都会影响解决方案。
该应用针对的是为大多数开发人员所认可的会议组(meeting group)领域。应用实现中考虑了额外的复杂性,因此相比基于 CRUD 的常规应用更具意义。格兹别克将主领域进一步划分为四个子域,即会议、支付、管理,以及用户访问。
从更高层次上看,该架构中定义了一个 API 层、包含存储的四个模块,分别对应于所发现的四个子域,还包含一个用于通信的公共事件总线(EventBus)。
模块也相应地划分为四个子模块,并分别实现为独立的二进制文件,分别为:处理所有请求的 Application、实现领域逻辑的 Domain、实现基础架构代码的 Infrastructure,以及在 EventBus 上发布事件并且是模块间唯一共享组件的 IntegrationEvents。格兹别克使用了 Decorator 模式,实现添加工作单元( Unit of Work )和日志等交叉关注点(cross-cutting)。
为分离应用内部的命令和查询,格兹别克使用并实现了 CQRS 的一种变体。该 CQRS 变体针对命令所涉及的同一数据库表,在查询中使用了原始 SQL 和视图。虽然 CQRS 还具体其他变体,但格兹别克力图避免使应用过于复杂化。
模块间的集成是基于异步事件传输的。事件传输使用了“发件箱模式”/“收件箱模式”( outbox and inbox pattern ),以及基于内存中的 EventBus 代理。为存储要发布的事件,发件箱模式在数据存储中添加了独立的表。事件的添加,实现中通过执行任务的命令,以及等同于命令的事务。此后,这些事件通过单独的流程,转发到另一个模块的收件箱中。在该项目中,事件传输是通过各模块中的后台 Worker 实现的。该实现提供了多次交付和处理。
最后,格兹别克强调该项目仍在开发中,欢迎贡献者的加入。项目是使用 C# 编写的.NET Core 应用,使用了像 Autofac (用于 IoC )、 Dapper (一种用于读取模型的 MicroORM )之类的类库。项目中还包括基于 Arrang-Act-Assert 模式的测试,使用 NUnit 实现。
此外,格兹别克在与 InfoQ 的访谈中表示,与微服务体系架构相比,模块化单体应用的主要差别之处在于部署方法和模块间通信。
在微服务架构中,每个模块都以独立的进程运行。模块间的通信必须使用网络实现,并且通常通过同步服务 API 调用(即 RPC,远程过程调用),或是使用代理(即消息传递)实现。微服务架构是一种分布式系统,具有分布式的所有优点和缺点。
对于模块化单体应用,则无需考虑分布式系统。所有模块均以同一进程运行,无需使用网络即可相互通信。各模块可以通过方法调用直接同步引用内存中对象,或是异步地使用运行于同一进程中的某个中介者(Mediator)。
以上就是就是今天的内容,希望对你有所帮助。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
该免费文章来自《极客视点》,如需阅读全部文章,
请先领取课程
请先领取课程
免费领取
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
精选留言
由作者筛选后的优质留言将会公开显示,欢迎踊跃留言。
收起评论