仓库源文

.. Kenneth Lee 版权所有 2019-2020

:Authors: Kenneth Lee :Version: 1.0

没有规则的规则


有一次和人讨论错误日志的输出的原则。这个问题大体是这样的:比如你有三个模块A,B ,C。A调用B,B调用C,然后C发现错误了(好比分配内存不成功什么的),返回错误码给B ,B返回给C。

这个过程中要输出错误日志,现在的问题是,应该是A输出呢,还是B输出呢?还是C输出? 还是都输出?

对一些开发人员来说,无所谓的,多打印一些,更容易跟踪而已。但如果你做过产品,你 就知道客户看见你这种冗余打印有多恨你了。我还遇到过这样极端的案例:十几年前的时 候,我们刚刚开始做GSM,有一次有些位置更新(所谓位置更新,是手机开机或者移动到另 一个GSM的站点,要告诉新的站点“我到你这里来了”)会随机找不到用户号码,工程师就在 位置更新上增加了一条打印,打印相关的上下文信息。这个版本上线以后,第二天早上, 一大批人同时开机,队列里同时排队了很多等待位置更新的消息,这个打印导致每个处理 都变慢了,所以等某个消息排队完成以后,这个消息已经超时了,如此类推,每个消息都 超时……然后那天早上,全省的人开机找不到网络,酿成一次全国级别的责任事故。

这个问题严格来说是超时设计的锅,但当时的责任可是加这行打印的小伙子(当然,处罚 的是他的主管)。我举这个例子,只是想说明,只要你往系统里面加代码,它的影响就是 全局的,不是你开发人员自己的事情。

回到最初的问题,每个模块都输出,显然是不合适的,这个问题的评判标准是最终呈现的 用户接口,用户接口不需要冗余的输出。其他性能影响什么的,你能罩得住,也没人理你 ,但你自己还是要弄清楚。

就A、B、C三个模块这个具体情形来说,让C来报这个错是个不错的选择。因为C才知道真正 的错误原因,A和B只是以讹传讹。但让C去报错,其实也是有缺点的,首先代码量会增加, 假如C有好几处都有内存分配,每个都要打印内存不足日志,这就产生代码冗余了。这种情 况下,B来打印是更合适的。

那么正确的日志输出原则是什么呢?原则是:“符合系统设计要求”。对很多人来说,这基 本上是告诉他:“没有原则,具体情况具体分析。”。对不少人,特别是基层管理者来说, 就感觉不可接受:“没有原则,没有指标,怎么管理啊?怎么下要求啊?怎么考评啊?”—— 你看,我们又有了一个用“名”来锁住你自己的“道”的例子了——你到底是要用自己定义的“规 则”来证明你“没错”呢,还是要做出好的产品呢?(当然,我知道不少基层管理者其实不关 心产品好不好,他们更关心自己的考评好不好,关心自己拿好了鞭子没有。但心小不成大 事,求仁得仁,我不是要说服你,我只是讨论事情是怎么做成的)。

这是一个很小的例子,但证明了一件事:不是任何情形都可以抽象的,但不抽象不表示事 情就没有最优解了。没有简单的日志输出原则,不表示在某个设计中我们不知道如何输出 日志是最好的。抽象不出3个硬件的共同之处(关键在于这个共同之处是否有利于使用), 不表示我们不能为这三个硬件各自提供合适的对外接口。没有一种最优的编程语言,不表 示我们不能为每个领域开发新的DSL。“抽象”,是“自然”决定的,是现实本身决定你可以如 何“抽象”。不是有了“抽象”, 你就解决问题了。很多人对架构的理解是“抽象”,是“模式” ,却不明白架构师的高明表现在知道“这里能不能抽象”。

所以,你学做架构的“样子”,你其实根本就不是在做“架构”这件事。