点击↑上方↑蓝色“编了个程”关注我~
这是Yasin的第 69 篇原创文章
网关
在领域驱动设计中,有好几种推荐的架构(感兴趣的可以去我的个人网站看这篇文章《DDD之代码架构》)。但他们都有一个共同的特点:最外层都是网关(也有的叫适配器)。
南向和北向
对于网关来说,其实是分为南向和北向的。按照上北下南的概念,北向网关对应输入,南向网关应对输出。举例来说,一个服务提供的controller接口、消息队列监听接口、RPC接口等,都是北向网关,用来接受、监听其它请求进来的;而一个服务调用下游的DB、MQ producer、其它服务的http、RPC接口等,都是南向网关。
防腐层的作用
防腐层服务
防腐层这个概念最开始来源于DDD,后来也被用于微服务的架构中。顾名思义,防腐层的主要作用是“防止架构腐烂”。熵增原理在软件领域也是同样适用的,随着不断地迭代,代码和架构总会趋向于混乱。所以需要专门为这种可能变化的未来提前做出考虑,增加一层防腐。
在微服务中,防腐层指的是单独抽一个服务来做防腐,主要用于系统迁移等场景。而在DDD中,防腐层其实也可以叫“适配层”,是用来隔离上下游依赖的。
防腐层代码
除了作为单独的一个服务外,每个微服务也应该有属于自己的防腐层代码。
在大型团队,会拆分非常多的微服务。出于业务发展或者架构升级等种种原因,很有可能某些服务、某些接口会在某个时间进行升级。这个时候一般的做法就是找到上下游依赖,然后通知他们使用新的接口。
但这带来了一个问题:如果某个上游服务在代码中大量的地方调用了这个接口,改造成本就会变得非常大,而且这种系统间的改造比较难测试,风险很高。这个时候如果上游服务在调用之前有一层自己的适配层,那他只需要改一下适配层的代码就可以了。
而如果推不动上游服务改造,那在自己的服务内部去适配也是可以的,这也算是北向网关自己的一层适配,只不过这种做法不是很推荐,不利于自己后期迭代。
比较推荐的实践是:所有南向网关都要尽量做适配,尤其是调用外部接口;所有北向网关都尽量简单,不做适配,由上游自己去适配。
防腐层如何写
防腐层的代码一般会应用「适配器模式」。一般其它微服务暴露出来的接口,都会以SDK的形式提供给其它微服务使用,这些服务一般会叫xxService、xxClient。而防腐层代码是在此基础上包装一层,一般会叫xxWapper、xxAdapter。其中Request和Response也会包一下。但自己重新定义一个类的工作量比较大,所以一般会用继承或者组合的方式直接复用原本的结构体,等有必要覆盖字段的时候,才在此基础上定义一个新的字段,然后转移到新的字段上面去。
举个例子,原有的response里面有一个字段叫id。突然某一天,上游弃用了这个字段,改成了projectId,其业务含义与原有的id一致。如果没有防腐层,那所有使用了这个response的地方,都要修改代码。而如果有了防腐层,可以在防腐的response里面重写getId方法,返回父类的projectId就可以了,业务代码中无需任何改动。
除此之外,也可以自己定义自己需要的结构体,使用「mapStruct」等工具来自动转换数据。
防腐的利与弊
写防腐层也是有代价的。最大的代价就是有「额外的开发成本」。所以如果你的上下游比较少,且比较稳定,其实是可以不用防腐层的。
而在大型团队,付出这些额外的开发成本是有价值的,因为大型团队的上下游关系非常复杂,他们可能不是在一个团队,也有可能经常进行迭代升级,通过我自己的经验来看,接口变化是经常会发生的。
虽然我们倡导不要修改原有的接口,不要修改字段名、方法名等。但也偶尔会发现,之前设计的有些东西并不合理,不利于长期维护。如果我们基于新的模型设计出v2的接口,而又要维护原本的v1接口,维护成本会增加。所以一般会推之前使用了v1接口的上游切换到v2,然后下线v1接口。这个时候调用方有防腐层就非常重要了,可以减少改动成本。
关于作者
我是Yasin,一个爱写博客的技术人
微信公众号:编了个程(blgcheng)
个人网站:https://yasinshaw.com
欢迎关注这个公众号