作者:京东科技 康志兴
前言
可以看到,越现代的架构风格越倾向于清晰的职责定位,且让领域模型成为架构的核心。
传统三层架构
传统服务通常使用三层架构:
• 服务层:作为核心业务层,包含所有业务逻辑。并对基础层能力进行简单组合提供一定的能力复用。通常服务层会进行实体定义来防止下层对象体直接暴露给外部服务,导致底层任何变化都有可能直接传递到外部,非常不稳定。
三层架构特点就是简单,适用于一些无复杂业务场景的小型应用,或者“数据不可变”作为基础原则的DOP(面向数据编程)服务。
DDD架构
• 适配层:用来做外部不同端请求的适配器,隔离不同端的协议差异,包装不同端不同样式的响应体。
• 领域服务层:包含核心的领域服务定义,并定义了gateway来做一层依赖倒置,使基础设施层仅做实现。
优点
• 敏捷:适合不同团队一起开发和维护而不会产生冲突。
• 可扩展:添加新的功能非常简单,从而使得开发人员能够更快的部署和调整。
如此多的优点自然带来明确的缺点
• 专业性要求较高:需要对业务、架构原则理解深刻的人员进行设计和维护,不恰当的领域模型将使后续迭代极为痛苦。
• 不再适合简单的业务场景:实现一个简单的CRUD显得过于复杂。
简单的微服务分层架构
基于六边形架构规范的接口适配原则和防腐理念,同时借鉴了CQRS模式的优点,我们定义了一个简单的微服务分层架构。
• 门面层:作为程序的入口,通过包隔离来存放JSF服务、Rest服务、定时任务和MQ消费,其中对外提供服务的接口定义存放在单独的api包中。该层的请求定义命名以Request结尾,响应体命名以Response结尾。
• 基础设施层:存放数据库、ES、远程调用服务的封装。该层的持久化数据定义命名以Po结尾。远程命令服务入参命名以RpcCommand结尾,远程查询服务入参命名以RpcQuery结尾,响应体命名以RpcDto结尾。
最佳实践
-
参数校验、请求出入参日志、审计日志记录、TraceID预埋、异常处理等非核心业务能力均由公共组件完成,减少项目内部的边缘能力代码。
-
实际开发过程中,门面层、领域服务层和基础设施层均有各自的实体定义,跨层调用的对象体转换使用MapStruct组件来减少手写映射代码的工作量。
优点
1. 开发效率
2. 服务隔离
3. 外部服务防腐
缺点
- 基础设施层的实体作为顶层依赖
由于对基础设施层的依赖没有通过api包进行隔离,所以基础设施层的对象会直接暴露在领域服务层和门面层。对此可以通过使用ArchUnit组件进行架构防腐。
最后
软件工程的方方面面都遵循一个最基本的道理:没有银弹,架构分层模型更是如此,每一种都有各自优缺点,所以请根据不同的业务场景,并遵循简单、可演进这两个重要的架构原则选择合适的架构分层模型即可。
架构不只是工作,更是一门艺术。