11

容易效仿的做法往往没有用,有用的事情从来不容易

 3 years ago
source link: https://zhuanlan.zhihu.com/p/359137019
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

容易效仿的做法往往没有用,有用的事情从来不容易

problem solver

微服务火了之后,很多人选择做一个系统上来先拆100个微服务。很多人都喷过这种做法,今天我们换个视角来喷。

为什么能够上来就能够拆100个微服务?其根本原因是因为把一个系统拆出100个微服务压根不难,甚至可以不用动脑筋。你只要把原来是本地函数调用的地方,换成你最喜爱的 RPC 协议,就获得了一个微服务。我观察到的现象就是“容易效仿的做法往往没有用,有用的事情从来不容易”。这个现象不仅仅是拆分微服务,还包括很多其他的“最佳实践”。比如给一个项目补单元测试,那么我们只需要用足够多的mock,就可以遍历所有的代码分支,甚至可以不写一行assert。又比如我们要敏捷交付,那么我们照着 Scrum 的项目管理实践,开站会,估点就可以了。工程实践上不需要任何变化,只需要跟着 Scrum Master 搞项目管理就可以了。

就微服务来说,我们希望的“有用”是什么?

  • 我们希望变更的影响是局部的,从而开发者不会害怕改代码。特别是数据库表结构的变更是能够局部的,比如对你1000个商户,只变更其中一个商户的表结构。
  • 我们希望开发团队是自治的,每个 Two Pizza Team 是能够在自己团队范围内完成很多需求的。而不是但凡一个需求i就需要联合特性团队去作战室联调。

所有鼓吹微服务的文章都会说拆了微服务之后,就“解耦”了。这就像数学考试做证明题一样,你写下了“容易得知”。拆微服务并不能直接得出这些“有用”的结果,中间差着十万八千里那。而那十万八千里,才是真正困难的事情。

Partition Your Data

对你的数据进行分区,这是非常非常困难的事情。很多系统在后期,希望加上多 Set 的架构,希望演化成分单元的架构,往往都失败了。因为所有的代码,都在访问所有的数据,根本拆不开。如果在系统的幼年,你尚且无法 Partition Data,是什么让你觉得在其中晚年,你就能够 Partition Data 了呢?

没有人愿意一上来就搞什么多租户的设计,限制自己的代码一次只能读写一个租户的数据。为什么?因为这会让代码写起来不舒服。不是产品经理说这里有一个行为,程序员就在这里加两行代码那么直接翻译的。上了多租户的约束之后,产品经理的需求需要经过一层转换,跨租户集成的逻辑需要特别拆分出来。然而正是因为我们在做每个需求的时候,都把这些集成逻辑给拆出来了,才使得我们可以做到一次数据库的变更,仅仅影响一个租户。

Partition Your Code

对你的代码进行分区,这是更困难的事情。你可能会说,我拆了微服务了呀。是的,你拆了很多个 Git 仓库来放你的微服务的代码。但是微服务与微服务之间是可以产生同步的 RPC 调用的,Git 仓库之间是有直接的 dependency 关系的。这种拆分并不算拆分。有效的拆分是要“限制依赖关系”的。把一个函数调用改成两个 Git 仓库之间的 RPC 调用,从依赖耦合的角度来说,没有一丝一毫的变化。当你改了 A 的时候,还是要跟着改 B。每个微服务团队是不可能有什么“自主性”可言的,大家都是在一根绳上的蚂蚱。

没有人愿意一上来就搞什么多插件的设计,限制插件与插件之间不能有依赖关系。为什么?因为这会让代码写起来不舒服。产品经理的每个需求似乎都在要求你把所有的 class 与所有的 class 产生依赖关系,因为一切都是集成到一起,无论是 UI 展示上的集成,还是流程上的集成。提出 Disposable Software 这样的理念是非常容易,提出 OSGi 这样的代码分区的技术也是非常容易的。大家都知道要拆开来,也能够有足够多的手段把代码拆开来。难的是,这么拆开了之后产品经理的需求做不做了?产品经理要你把东西再集成回去的时候,这集成的代码写哪里?怎么写?

如何写集成需求才是关键

  • 当我们把数据拆成了多租户的,那么跨租户集成的需求咋实现?
  • 当我们把代码拆成了多插件的,那么跨插件集成的需求咋实现?

不要指望这两个问题的答案可以让你把多租户的代码写起来和单租户一样轻松,也不要指望让你把多插件的代码写起来和单体业务一样轻松,不会的。仍然写起来会痛苦。微服务拆完了之后,你写代码的方式和单体没有多大区别,只是把函数换成了RPC,恰恰说明了这种做法是无效的。容易效仿的做法往往没有用,有用的事情从来不容易


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK