摘要
- 本文源自2018领域驱动设计中国峰会《领域驱动设计与演进式架构专题》的Session之一,是其博客版
- 在实践领域驱动设计时,可以挑选一些方法互为参照,端口和适配器架构概念简单,容易掌握,适合作为实践领域驱动设计的辅助方法。
大概一个月前,在做2018年领域驱动设计大会预告的时候,上一届大会的主题演讲者肖然提出这样的担忧:工具和方法似乎没有很好地解决“落地难”的挑战
- 没有一套方法能够打遍天下,具体到采用哪一种方案,仿佛都需要增加一个定语“这取决于……”。
- 不管是在DDD原著,还是后续不少专家的书籍中,都暗示、甚至明示架构设计的终极大招还是By Experience ——靠经验吃饭。
- 从战略角度的子领域划分,到战术建模层面实体、值对象的选择,最终的决策很可能不是完全“理性”的,经验这个“感性”的东西发挥着很大的作用”
所以,推动领域驱动设计实践的方向是否应该从介绍方法转变为介绍如何累积经验?
看了这篇文章后,我放弃了之前准备的话题《CQRS和Event Sourcing,从入门到放弃》,因为可能你一年都不会遇到一个需要使用这两种方法才能解决的复杂项目。
如何快速获取经验?无非就是多练,但是练了要讨论和总结,我遇到过这样的对话,我将它称为”两小儿辩DDD“:
A: 我觉得你这里不该使用实体,应该使用值对象
B: 我觉得你这个接口不是领域服务,它其实是应用服务,你这样做不DDD
A: 你的实体不应该调用Repository,你这样做也不DDD
B: (看着我)你来评评理,我们谁说的对
我:俺也不知道,这取决于…
这样的复盘方式效果欠佳,我建议不妨从DDD中跳出,找一种方法互为参照和检验,比如”端口和适配器架构“
什么是端口和适配器架构
套用流行的提问方式:当我们在说架构时,我们在说什么?在本文中我们不是在讨论微服务架构,也不是讨论基础设施架构,这里的架构指:
- 在单个应用(进程)中
- 代码是如何组织起来实现一个端到端的用户请求的
- 它与框架无关,不管你是使用ORM框架或是JDBC,这不是架构的关键差异点
一个例子是三层架构,展现层负责接收用户指令、渲染视图;业务逻辑层负责处理"业务逻辑";数据层负责和数据库打交道,保存和读取数据。
“经典”的三层架构
三层(或多层)架构仍然是目前最普遍的架构,但它也有缺点:
- 架构被过分简化,如果解决方案中包含发送邮件通知,代码应该放置在哪些层里?
- 它虽然提出了业务逻辑隔离,但没有明确的架构元素指导我们如何隔离
因此,在实际落地时,业务逻辑容易泄漏到展示层中,导致当应用需要一种新的使用方式时(例如开放API),原有的业务逻辑层可能不能快速重用,同样的问题也发生在数据层和业务逻辑层之间。
那么有没有替代的方案?Alistair Cockburn是敏捷运动的早期推动者之一,他于2005年在其博客中提出了端口和适配器架构,他对该架构的一句话定义是:
“应用应能平等地被用户、其他程序、自动化测试或脚本驱动,也可以独立于其最终的运行时设备和数据库进行开发和测试”
原文为“Allow an application to equally be driven by users, programs, automated test or batch scripts, and to be developed and tested in isolation from its eventual run-time devices and databases.”
该架构由端口和适配器组成,所谓端口是应用的入口和出口,在许多语言中,它以接口的形式存在。例如以取消订单为例,“发送订单取消通知”可以被认为是一个出口端口,订单取消的业务逻辑决定了何时调用该端口,订单信息决定了端口的输入,而端口为预订流程屏蔽了通知发送方式的实现细节。
而适配器分为两种,主适配器(别名Driving Adapter)代表用户如何使用应用,从技术上来说,它们接收用