我们如何才能把一个复杂的项目做出来,并且做好?

一直以来,我们接受的教育都会教导我们,把问题拆解开来,把事情拆细,分而治之。诚然,这卓有成效。对于树状的组织人员结构来说,每个分支、每个成员都有自己负责的部分,每个分支把负责的部分做好,最终整合起来,整体就做好了。划分细致之后,各个细节也都会变得清晰,便于具体追踪。然而,太多地使用拆解之后,我们往往忘记了系统性思考,从整体的角度仔细揣摩,这也造成了很多问题。

思考1 组件间的问题转移

分而治之,每个组件处理自己的事情,组件之间减少耦合,这是多数从业者都理解的主题。不过组件之间的问题也存在转移的可能性,如果不注意,一个分支的成就可能成为整个系统的噩梦。

单纯地为了减少获取新配置的延迟,而增加轮询的频率,那么目的肯定是达到了,而代价是配置中心的访问量大大增加了,获取配置的错误率也可能上升,这使得获取新配置的不稳定性增加,系统的不稳定性增加。
为了尽快完成新产品的推广,在没有完全了解可能隐含的问题情况下,强行增加上线的量。这会导致使用方发现很多问题,SRE的工单堆积。推广覆盖率的难题,转化为问题排查和解决的难题。

当然这两个例子比较简单,而且你可能认为这是显然,很容易避免。这是因为轮询组件和配置中心可能是同一个人在维护,问题的转移出现在一个小型的系统内部容易定位;Dev团队和SRE团队之间的交流可能比较通畅,工单的量很好量化。而如果这种问题的转移出现在更大的系统内呢?如果问题从一个明确的可度量的问题,变成一个模糊的无法度量的问题呢?

思考2 Hack fix 比问题更有害

理论化的代码只存在于理论之中。
为了工程,为了真正把内容应用于生产,我们可能不得不向代码中塞入一些不太优雅的Hack成分。所谓的 hack fix,大多是指对特殊情况最特殊判断,然后避开问题的一个方式。
当系统出现一个问题,打补丁往往是最快速最容易解决的,但这也是最危险的。
当hack的代码变多,整体思考就会变得困难,甚至有可能遗漏hack的情况。在对另外一个组件进行修改的过程中,可能导致此处hack造成严重问题。
所以,尽量减少 hack 代码的量,思考这个问题能否使用更加通用的方式解决;如果不得不这样,务必要在 hack 的代码附近,用注释明确标出原理,以及带来的风险。

思考3 一个组件暴露的问题,可能须由另一个组件解决

在城市天际线这个游戏中,Traffic是最为恼人的问题。当城市的规模发展到一定程度的时候,堵车问题也会一发不可收拾。
道路不断加宽,立体交通不断增进,最终还是拥堵严重。

实质上,问题可能并不在交通,而在于城市区域规划。如果从高速路到工业区必须要经过居民区,那居民区就会有大量的车流;如果工厂、商店过于密集,生产和消费的类型不匹配,进出口需求量大,这本身就会造成巨量的运输压力,无法通过道路交通系统解决。

在问题发生的时候,主动寻求整体最优的解决方案,而不应该在一个组件上耗费太大的精力。在城市规划不合理的时候,必须要优先修改产业布局;在系统规划不合理的时候,务必要优先调整组件排布。磁盘压力过大,网络压力过大,也许是缓存组件没做好。

思考4 大力不一定出奇迹,强推可能会反弹

这是在新功能推广过程中出现的。
耗费了很多精力,吹嘘了很多优势,推广了很多的接入,但突然因为一个不稳定,导致所有接入全部回滚,很长一段时间使用者心有余悸,不愿意主动接入。

组件和组件之间要系统性思考,权衡利弊,追求整体利益;时间维度上,也需要系统性思考。
目标是确定的,在某个时间区间内完成稳定的接入,那么必须在长时间维度上综合考虑,一时的强推很容易造成反弹。