影像文本 · 原子能

经得起时间考验的才是好代码【让编程再次伟大#7】

大家好,这里是原子能。经过本频道有史以来最焦灼的一次投票,时间获胜了。首先承认我是个标题党,因为时间本身并不是我们的敌人,但时间会带来变化,我们所写的软件,所处的环境以及人本身随着时间而变化,并且互相会影响,互相造成破坏。这一点往往会被大多数人所忽略。 著名程序员 atomic energy 曾经说过,command is most ac…

查看原始文档
经得起时间考验的才是好代码【让编程再次伟大#7】封面

大家好,这里是原子能。经过本频道有史以来最焦灼的一次投票,时间获胜了。首先承认我是个标题党,因为时间本身并不是我们的敌人,但时间会带来变化,我们所写的软件,所处的环境以及人本身随着时间而变化,并且互相会影响,互相造成破坏。这一点往往会被大多数人所忽略。

著名程序员 atomic energy 曾经说过,command is most accurate when first written down. 这句话的意思就是随着时间的推移,代码会经过很多次的改动,而注释则会变得越来越不准确。这里的原因主要有两个:

  1. 我们最可靠的队友“编译器”以及相对没有那么可靠的“测试”。他们两个都没有办法帮助我们去检查这个注释的准确性。所以即使注释在某一个时间节点开始出现了偏差,我们也不会收到任何的报错信号或者是告警的信息。
  2. 和相对规范的技术文档不同,注释的书写没有任何标准。一个程序员奉命修改代码的时候,他要不要把旁边的注释也改了?要怎么样改?这完全取决于个人的表达习惯。个人最苛刻的 code review,大概率也不会揪着你的注释改动发表太多的意见。所以久而久之你就会发现很多人的语文或者是英语,它就是体育老师教的。

这个故事其实就揭示了时间对软件开发决策的影响。因为我们通常对于可控的变量都可以做出一系列科学的预防机制。就算我们很没有特别严格的执行他们,但至少这些变量所造成的负面影响都是属于可控范围的。然后从上面我们可以了解到的是注释的本质它就是不可控的。所以随着时间的推移,它无可避免的会成为一个累赘,甚至还会有可能误导后来的程序员。

有聪明的小伙伴可能就会问啊,你这是不是在建议我们不要写注释了?但是那这个想法就会有点极端啊,就像之前的视频里面提到的,一切的决策都是取舍,一切优秀的决策都是来源于对于各个选项的优点和缺点的准确的挖掘。我们现在挖掘出来了注释的缺点之后,我们作为一个团队就要去决定我们要不要接受它所带来的价值的同时,去承受它所带来的这些问题。我们要不要额外的投入资源去修复它的这些问题。比如说制定注释的书写的规范,或者说在 code review 的时候,我们要加强对注释的一个审查等等。

当然,注释这种小问题只是茶余饭后的一个吐槽话题。吴伤大雅,就像前面的视频里面反复提到过的软件项目,它是一项人与人高强度互动的一个工程。而且不可控的因素非常多,不可控的变化非常频繁。在上一个视频里面也提到过,越高层面的决策影响力就越大。那么两者结合再加上本期的时践话题,我们就可以看得到有一些在大方向上的技术决策是怎么样给产品甚至是业务带来长久的影响的。啊,微服务这个我们即将要深入讨论的话题就是这么一个东西。

在微服务这个概念刚成为一个热门话题的时候,当时我所在的公司也非常的赶时髦,在每一个新的项目里面都探讨了微服务可以怎么用。当然它的理念也确实非常符合当代的计算机行业的这种小块灵的开发风格,也就是小团队快速发布灵活变种。我们也确实在开发阶段、投产阶段,甚至是运维阶段的初期,都享受到了不少微服务带来的这些好处。但就像之前视频里面提到过,软件的生命周期远远超出了开发和投产的阶段。你可能开发用了一年,但是在之后的十年里面,你还要在监控、维护、升级、修复、扩容等各种事情上持续的投入人力物力去维持他的生命。所以当时我们的团队在享受完微服务带来的早期红利之后,在后面就开始狠狠的吃苦头。

有些问题呢就来自一些典型的草台班子理论。除了这种问题的话,我们其实还可以连夜不救。但是还有另一些就是前面提到了这种随着时间推移不可控的因素累计达到一个节点,达到一个溢出的点所引发的灾难级的问题。我这里举两个例子,我觉得是业界通用的。就是如果你用到了微服务,当是还没遇到这两个问题的话,那只能说明你用的规模不大,或者时间还不够长啊。

第一个问题就是随着时间的推移,微服务架构只会越来越复杂。每一个新加入来的服务,或者每一个使用这个微服务的新项目,它都等同于是在一个网状结构里面新增的点和线。这张大网里面的每一个节点都是把命根子交给了附近的节点。所以一旦某个节点出现问题,就很有可能会出现多米诺骨牌那样的连锁反应。而且因为企业架构和管理方式的原因,我们经常会发现服务之间的交流就是个黑箱。比如说服务 A 需要使用到服务 B 啊,服务 B 需要使用到服务 C D 但是从服务 A 的角度来说,他往往是不知道服务币是有什么依赖的这就会导致的不可控因素的放大,就你永远不会知道明天和意外哪个先到。

我举一个很经典的例子,世界上最大的云服务平台亚马逊,去年发生了一次大规模的单机事件的这个的服务可以说是微服务史上的一个里程碑的角色。它让很多公司第四用上了微服务架构,而且是在几乎没有什么沉淀成本的情况下,体验到了这个东西的好处,它也促进了微服务的普及。然而在 2023 年 6 月 13 号的一次日常的扩容流程里面,因为达到了某一个临界点,激活了 la 么 da 代码里面的一个 bug,导致了代码的故障以及整一个 lambda 服务的瘫痪,当然如果只是 lambda 服务自己出问题也还好,问题在于亚马逊内部热爱微服务的人太多了,所以很多其他服务也在内部使用的 lambda。包括管理安全凭证的登陆服务,aws 控制台提供事件管理的 bridge,管理容器集型的呃管理容器集群的 E K S 以及支撑客服中心的 Amazon connect。这些服务全部因为 lambda 无法调用而瘫痪,整一个故障持续了 4 个小时才被修复。对于承诺五个九稳定度的云服务来说,4 个小时的单机时间那就是史诗级的灾难。

而微服务发展中的第二个问题则是它在代码演化过程中是非常不灵活的。当一个系统的代码所有权是掌握在一个团队手上的时候,它的功能更新、bug 的修复、配置的调整等等的操作,他都是由一个团队来处理,这里就没什么问题。但是当这个改动涉及到外部的微服务的时候,这个问题就来了。就说你敲开对方团队办公室的大门,你说出你要改动的这个想法,你基本上会遇到包括但不是不限于以下几种的踢皮球式的回复。一他们会说手头上的任务很繁重,一年半载没有安没有时间安排你这个改动需求。不好意思啊,你这个改动可能会影响到其他使用者,我们得事先跟他们沟通好,然后我们再重厂记忆这个事情。3、你这个改动不太符合我们本身的产品路线,那么我们希望你们能够针对我们的产品路线对你的改动的需求再进行改动,我们再继续讨论。

在很久很久以前,在一个大数据的项目里面,我们要抽取一些用户的数据。所以当时按照公司的一个微服务架构这么一个大方向,我们就找到了负责提供这个数据接口的团队。我们获得了用户信息、购物记录、浏览记录在内的一系列这种微服务接口,而且文档也很齐全。所以当我们当时拿到的时候是挺开心的,回去我们就接入了我们的系统。然后随着项目的推进,我们就发现这些接口很有问题,他们都太原始了。所以我们的应用比较复杂的情况下,我们需要在我们的应用层对这些接口进行各种的打包和组装,这个效率是非常低下的这是让我们的代码非常的复杂。所以我们向对方提出了一个整合型接口的这么一个开发的建议。当然对方真的是鸟都不鸟也没办法,我们还隔着一整个部门,对吧?我们领导都不是同一个领导,但是最后我们是真的没办法。

因为大数据项目数据处理的效率是重中之重了。所以为了打破这个效率上的瓶颈,我们直接抛弃了微服务原则。我们直接联系了广核心数据的部门,我们申请了直连数据库的权限。最后相当于是在自己的系统里面实现了一个迷你版的定制版的这么一个接口。代码的复杂度大大的减轻了,效率大大的提高了,维护的难度大大的降低了,bug 的数量大大的减少了。真的,所以从此以后对于微服务架构,我的态度就是你用我推荐,我用我不用。

回头看这两个微服务的问题,你就会发现它和前面举例的这个注释的这两个问题其实很类似。一个是基于这个事件本身的结构性的弱点,另一个是基于这个事的参与者的人性弱点。啊,这两个都是无法避免的。所以在这个客观的现实条件下,你只有两条路可以走。一你就不用它,二这是你要投入额外的资源去对这些问题进行补救。然而在我十几年的职业生涯里面,我发现更多的人选择了第三条路,那就是管他那么多用就得了。

我只是一直在思考这种现象的本质。首先不否认有些人纯粹就是比较笨,他没有推理能力,没办法发现某一个决策会使随着时间的推移会带来一些问题。但是呢这个行业总归是相对比较高科技的,所以我相信大部分人的智商应该都是在线的。那么就只能够引出一个答案,他们就是故意的。但是呢这个故意我也觉得要分两种,一种就是故意的故意。这些人知道自己不会很长时间的负责这个项目,所以为了给自己捞足这个政治资本,在策划的阶段就猛猛的堆掉,把这个项目包装到足够的高大上。至于以后会有什么问题,那就是我死之后哪管洪水滔天的心态了。但是第二种我就称之为无意的故意。这些人我觉得就是过于追捧硅谷带来的那种开发文化。这里我指的就是 move fast and break things。也就是说不要顾忌长期的问题,要快速的迭代,快速的试错。

这种做法呢其实在特定场景下确实很好。比如说某一个新功能或者是某一个新活动,你靠空想是想不出来最完美的方案的。这种情况下你就要快速的推出到市场,收集真实的反馈,甭管好的坏的,你拿回来复盘总结,做出调整,然后再赘出。但是这种做法它不是通用的。因为在企业的层面,你不同的错误有着不同的代价。有些错误的影响是长期的,就像一种慢性疾病那样,会把你折磨致死。就比如说品牌,品牌形象、品牌价值,它就是产品的基石之一,长期的支撑着产品的推广。一个活动搞砸了没问题,但是如果影响到了品牌形象,它就会造成很无法挽回的影响。

就回到技术上也一样,我们造的产品其实就像品牌一样,也是长期存在的。它的错误也是会长期的影响到企业的发展。就比如说大家应该都知道脸书最开始是用 php 来写的那纯粹就是因为那个时候 php 方便。扎克伯格也不是计算机专业的,他学这个东西也快,但是这一个角色错误他们画了十几年才能够补救,当然因为他们财大气粗啊,他们可以投入几千个工程师,几十年的人力物力。直接把 php 给改造成一个非常靠谱的语言。但是呢这种补救方案给你,你也学不会。

如果你有看完 ma 系列前面的视频,你就会发现我好像经常反对一些比较主流的观念。比如 clean code,比如 agile,就比如本期的 move fast and break things。但是你要是仔细看我的观点,你就发现我不是以非黑即白的方式去反对他们,反而我是反对以非黑即白的方式去接受他们。因为他们往往是没有你想象中的那么的通用。就比如前面和视频里面提到的空间,本一期视频里面提到的时间,以及我每一期视频都提到的人都是完全不按套路出牌的东西。所以你一句两句的口号是没有办法概括这些问题的。

那么总结本期的 MPGA,如果说时间是你最大的敌人,那么我可以说辩证的思维就是你最好的武器。请拿起你的武器,我们一起 make progragreat again,下期再见。

档案路径:原子能/经得起时间考验的才是好代码【让编程再次伟大#7】.md

返回「原子能」