没有人因为简单而获得晋升
“简洁是一种伟大的美德,但要达到它需要辛勤的付出,而要真正欣赏它则有赖于良好的教育。更糟糕的是,复杂性往往更能卖得出去。”——艾兹赫尔·戴克斯特拉 我认为,有那么一种微妙的机制,正在悄然拖工程团队的后腿。在面试中、在晋升材料里、在设计评审中:那些过度设计的工程师总能讲出引人入胜的故事,而那些只交付最简单却能正常运行的方案的工程师,却往往一无所获。 当然,这绝非有意而为之。没有人会坐下来大声说:“咱们得确保那些把事情过度工程化的人升职!”但当公司对工作评价出现偏差时,这种情况就有可能发生——而且一次又一次地重演。 想象一下,同一团队中有两位工程师。工程师A被分配到一项功能开发任务。她仔细审视这个问题,权衡了几种方案,最终选择了最简单的那一个——一个直截了当的实现,大概只有50行代码。代码易于阅读、易于测试,也方便下一位接手的同事快速上手。这个功能运行得非常顺畅。她在短短几天内就完成了交付,然后继续推进下一个项目。 工程师B也获得了一项类似的功能。他同样审视了这个问题,却从中看到了打造一款更加“稳健”产品的契机。他引入了一层新的抽象层,为各组件之间的通信构建了一个发布/订阅系统,并添加了一个配置框架,使该功能在未来应对更多用例时具备“可扩展性”。整个过程耗时三周,期间提交了多条Pull Request。当他分享那篇详尽阐述这一切的文档时,大家纷纷发来大量兴奋的表情符号。 如今,晋升季又到了。工程师B的工作几乎可以自动写进晋升材料里:*“设计并实现了可扩展的事件驱动架构,引入了被多个团队采用的可复用抽象层,并构建了一个配置框架,为未来的扩展性奠定了基础。”*这简直是在明明白白地宣告:Staff+! 但说到工程师A的工作,几乎没什么可说的。“实现了功能X。”三个字。她的工作做得更好,却因为太过简单而鲜为人知。你根本写不出一段引人入胜的故事来讲述那些你没有打造的东西。没人会因为避开了复杂性而获得晋升。 复杂性看似高明,倒不是因为它本身有多厉害,而是因为我们的体系天生就倾向于奖励复杂性。而这种激励机制的问题,并非始于晋升之时,甚至在你还没拿到这份工作之前就已经埋下了伏笔。 想想面试吧。你正在参加系统设计环节,提出了一套简单的解决方案:一个单一的数据库、一套直白的 API,也许再加一层缓存。面试官一听,立刻追问:“那 scalability 怎么办?要是用户达到一千万怎么办?”于是你开始添置服务、引入队列、进行分片,在白板上画上越来越多的方框。终于,面试官看起来满意多了。 你刚刚学到的一点是:复杂性往往能给人留下深刻印象。那个看似简单的答案本身并没有错,只是不够引人入胜。而这一课,或许会伴随你一路走向职业生涯。说实话,面试官有时确实有充分的理由追问规模问题——他们想观察你在压力下如何思考,以及你是否真正理解分布式系统。可如果对候选人而言,最终得出的结论只是“简单还不够”,那事情就有点不对劲了。 这在设计评审中也屡见不鲜。一位工程师提出了一种简洁明了的方案,却立刻被泼来一盆冷水:“我们是不是该为未来做好准备?”于是,他们只好回过头来,添上眼下根本用不上的层层抽象,为那些可能永远不会出现的问题构建复杂的抽象层,又为那些连用户都没提过的需求预留出无谓的灵活性。这么做并非因为问题本身需要如此,而是因为“领导”或“团队”期望如此。 我曾见过(自己也曾是)一些工程师为了避免重复几行代码而刻意构建抽象,结果却造出了一套比原本的重复代码还要难懂、更难维护的东西。每次做出这样的选择时,总觉得这是再正确不过的决定——代码看起来更“专业”,更像经过精心设计的工程产物。可用户不仅没因此更快地用上新功能,而且下一位接手修改的工程师,还得花上大半天时间去搞清楚这套抽象的来龙去脉,才能动得了一根手指。 现在,让我说明一点:有时候,复杂性反而是正确的选择。如果你要处理数以百万计的交易,或许就需要采用分布式系统;如果你有10个团队在开发同一款产品,那么很可能需要划定服务边界。当问题本身很复杂时,解决方案(大概)也该同样复杂! 问题不在于复杂性本身,而在于无端生出的复杂性。*“我们已经触及数据库上限,需要进行分片”与“我们可能在三年后才会触及数据库上限,所以现在就先分片吧。”*这两者之间是有区别的。 有些工程师深谙此道。当你仔细审视他们的代码(以及架构)时,你会不禁感叹:“嗯,这当然啦。”其中既没有玄妙的魔法,也没有什么令人自惭形秽的巧思,更没有任何让你觉得自己当初没看懂而倍感愚蠢的地方。而这,正是关键所在。 通往资深之路的真正关键,并不是掌握更多工具和模式,而是懂得在何时不必使用它们。任何人都能添砖加瓦、堆砌复杂,但要懂得如何化繁为简,则需要丰富的经验和十足的自信。 那么,我们究竟该如何应对这个问题呢?毕竟,说“保持简单”容易,但改变激励机制却要难得多。 如果你是一名工程师,请明白:简洁性必须被清晰地展现出来。工作本身并不会自我说明——并非因为它不够好,而是因为大多数系统在设计时并未考虑到倾听它的声音。 先从你如何描述自己的工作说起。“实现了功能X”听起来没什么分量。但如果你说:“评估了包括事件驱动架构和自定义抽象层在内的三种方案,最终认定采用一种简洁直接的实现方式就能满足当前及未来的所有需求,并在短短两天内顺利上线,在长达六个月的时间里零故障运行”——同样是这项简单的工作,只是用更精准、更能凸显背后决策过程的方式来加以阐述。不去构建某样东西本身也是一种决策,而且是至关重要的决策!务必如实地将其记录下来。 在设计评审中,当有人问“我们是不是应该为未来做好准备?”时,别只是轻易妥协、一味地增加层层叠叠的复杂结构。不妨这样回应:*“如果我们将来真有需要,要追加这项功能的话,大概需要做这些工作;而我们现在就把它加进去,成本大概是这样。我觉得还是再等等吧。”*你并不是在硬抗,而是在表明自己已经做了充分的功课——你权衡了其中的复杂性,最终选择暂不接手。 是的,不妨和你的主管沟通这件事。你可以这样说:“我想确保自己记录工作的方式,能够真实反映我所做的决策,而不仅仅是我在写哪些代码。我们能不能聊聊,在下一次绩效评估中,该如何更好地呈现这一点?” 大多数主管都会很欣赏这种做法,因为你在帮他们省心——你为他们提供了可以用来为你发声的语言和框架。 现在,如果你把这一切都做到了,可你的团队依然只提拔那些打造最复杂系统的人……这也同样是一条很有价值的信息。它能让你看清自己所处的工作环境。有些文化真正崇尚简约;而另一些文化口头上说崇尚简约,实则却奖励截然相反的做法。如果你身处后者,要么就顺势而为,要么就另谋高就,去寻找一个真正赏识明智判断的地方。但至少,你心里会明白自己究竟身在何处。 如果你是一名工程领导者,这一点比任何人都更关乎你。无论你是否意识到,你都在制定激励机制。而问题在于,大多数晋升标准本质上都是为了奖励复杂性,即便它们本意并非如此。“影响力”往往以某人所打造之物的规模与覆盖范围来衡量——而这些指标往往至关重要!但同样重要的是,他们本该避免的问题也理应被纳入考量。 所以,不妨先从改变你提出的问题入手。在设计评审中,与其问“我们有没有考虑过规模问题?”,不如试试这样问:“我们能交付的最简单版本是什么?又有哪些具体的信号能告诉我们,我们需要更复杂的方案?” 仅仅这一句话,就能彻底改写游戏规则:它让简洁成为默认选项,把举证责任放在复杂性身上,而不是反过来! 在晋升讨论中,当有人提交的方案基本上只是一长串听起来很唬人的系统列表时,不妨适时提出质疑:「这些东西真的都非用不可吗?我们这里到底是不是真的需要一个发布/订阅系统,还是说它只是在纸面上看起来很炫酷?」而当团队里的某位工程师交出了一套简洁明了的成果时,不妨帮他们把背后的故事讲得更精彩。「经过多方比选,最终选择了最简捷、却能完美解决问题的方案」——这样的表述本身固然算得上一份有力的晋升申请材料,但前提是你得真正把它当作一份值得认真对待的“故事”来打磨。 还有一件事:要留意你在公开场合庆祝什么。如果你的团队频道里每次点赞、表扬都只针对那些庞大而复杂的项目,大家自然就会把精力都放在这些项目上。不妨开始多关注那位删掉代码的工程师——正是他当时说“我们暂时用不着这个”,结果却一语中的。 归根结底,如果我们一味奖励复杂、忽视简单,那么最终得到的正是我们所期待的结果,也就不该感到意外。不过,解决问题的办法其实并不复杂——我想,这大概就是关键所在。 来源:Nobody Gets Promoted for Simplicity – Terrible Software