前情提要:https://www.v2ex.com/t/796126?p=1#r_10794970
实践中,我们一般可以同时提供两种接口:一种是不依赖其他业务的“原子”接口;另一种是依赖其他业务的“组合”接口。
比如搜索,我可以同时提供:返回 id 集合的接口和返回 item 集合的接口。item 信息是我从 item 服务拿到的,这样我等于组合了 item 服务和搜索。反过来也类似,比如敏感内容过滤,我也可以提供两种接口:传参 id 集合和传参 item 集合,如果只传 id 我需要去 item 服务查 item 信息,就是组合接口;如果传给我 item 集合,我就不需要去依赖 item 服务。
这种做法有什么好处呢?我们可以先考虑这样一个问题,我们有底层服务 A ( atom ),有两个上层服务 C1 、C2 ( combination ),现在有个需求要调用 C1 的接口 C1.I1 和 C2 的接口 C2.I1 ,这两个接口都要调用 A 的接口 A1.I1 ,这样我们为何不先调 A1.I1 ,然后把返回的信息传给 C1 和 C2 呢?当然当我们没有这种冗余调用的时候,还是用原来的接口,这样更方便。
我分析下来这样做从性能方面应该是有利无害的。从 IO 方面来看,虽然直接传递 item 信息增加了传递参数的网络开销,但是由于不需要去查 item 服务,减少了一次 item 服务返回 item 信息的网络开销,这两者已经抵消了。而后者还减少了查 item 的请求网络开销,item 服务的计算开销,和依赖服务或 db 的计算和网络开销。所以性能无疑是提高了很多。
上面只讨论了最简单的情况,其实实践中远比这复杂。上层服务会依赖多个下层服务,组合是千变万化的,不可能为每种组合都开个接口。比如 C 依赖 A1 和 A2,那就要四个接口,依赖 A1 的接口( A2 信息通过传参);依赖 A2 的接口( A1 信息通过传参);都不依赖(全部信息通过传参);都依赖。假设依赖 n 个服务,就需要(排列组合 n 选 n 、n-1...1,0 加和)个接口(科里化?),所以还是要根据实际情况具体问题具体分析,只提供那些用户普遍需要的组合,必要的时候可以另起服务以维护业务模型的清晰性( message passing -> multiple dispatch?)。
XDM 觉得这种实践靠不靠谱,欢迎分享讨论
1
qin20 2021-08-17 09:32:53 +08:00
前端,我上一个项目就是这样写的,禁止直接把原子组件放在页面上然后去写绑定业务逻辑,我抽象了一层,业务组件,页面中只能用业务组件。
之前受到名言 never repeat you code 影响,一直是在代码的重复上去考虑是否封装,其实重用和重复确实存在区别,重复不等于重用,如果单纯的从代码的重复性去考虑代码的封装,并没有从业务去考虑这么好用。 |
2
shilianmlxg 2021-08-17 09:50:10 +08:00
@qin20 我们的产品 你在的话会跟吃 shi 一样难受。同一个模块,不同页面的相同组件,他说不是一个东西,我高度封装吃了 shi 一样,所以之后干脆封的差不多得了
|
3
CasualYours 2021-08-17 10:45:01 +08:00
微服务的目的就是降低服务之间的耦合性,从开发的角度讲,一个业务需求只需要调用 C1 和 C2,就不应该调用 A,从而达到和 A 解耦的目的。你这种先拿到 A 再去调用 C1 和 C2 的方案是为了性能而丧失了服务间的解耦,得不偿失。
|
4
qin20 2021-08-17 11:27:51 +08:00
@shilianmlxg 前端达成共识很难。。。
|
5
xuanbg 2021-08-17 16:39:05 +08:00
从来就没有什么依赖其他业务的“组合”接口。“原子”接口要不要依赖其他服务看情况。
|
6
golangLover 2021-08-18 19:47:39 +08:00
@qin20 有具体的例子吗,想学习一下。谢谢
|