随笔·阅读约 2 分钟·
Grug 脑开发者的智慧:一个自嘲的程序员怎样看透软件工程的复杂性

Grug 脑开发者的智慧:一个自嘲的程序员怎样看透软件工程的复杂性

《The Grug Brained Developer》用原始人 Grug 的口吻,讲述了一个资深开发者对软件工程复杂性的深刻洞察——从说不的艺术到测试的辩证法,从微服务的陷阱到类型系统的价值。

原文来源:The Grug Brained Developer — 一个用原始人自嘲口吻写成的软件工程智慧集,作者是资深开发者,以"Grug"自居,分享对复杂性、架构和工程实践的深刻洞察。

Grug 曾经也觉得自己挺聪明的。

他读过那些大部头的设计模式书,追过最新的框架,在会议上听过关于微服务和事件驱动架构的演讲。那时候 Grug 相信,好的软件工程师就应该用大词、画复杂的图、设计通用的抽象层。

后来 Grug 吃了苦头,学到了一个血淋淋的教训:复杂性是软件开发的永恒敌人,而且你看不见它。

复杂性:看不见的恶魔

Grug 说,如果让他在"跟一只霸王龙一对一"和"跟复杂性搏斗"之间选,他会选霸王龙。至少你能看见霸王龙。

复杂性就像恶魔的灵魂,它会悄悄钻进你的代码。等你发现的时候,它已经占据了整个代码库,而且非常危险。你想用棍子打它?没用,棍子打不到恶魔。更糟的是,有时候是你自己把恶魔放进来的。

所以 Grug 反复强调一句话:复杂性很坏。

最好的武器:说"不"

对抗复杂性恶魔最有效的武器,是一个魔法词:"不"

Grug 承认,这在工程上是好建议,但在职场上是烂建议。"好"才是那个能让你拿到更多闪亮石头、当上大部落首领的魔法词。悲哀但真实:学会说"好",然后学会在失败时怪别的 Grug,这才是理想的职场生存指南。

不过 Grug 不在乎。要那么多闪亮石头干嘛呢?

说"好"的时候:80/20 原则

当然,你不可能对一切都说不。有时候需求真的合理,有时候老板真的在意。这时候 Grug 的策略是找 80/20 的解决方案——用 20% 的工作量解决 80% 的问题。

不要追求完美。完美是复杂性的温床。做一个够用的方案,交付,然后看反馈。很多时候你会发现,"够用"已经比 90% 的竞品好了。

代码拆分的艺术

下一个策略更难:把代码库合理地拆开。Grug 用的词是"factor your code properly",但他承认这很难给出通用建议,因为每个系统都不一样。

不过 Grug 有一个坚定的信念:不要在项目早期就拆分!

项目初期,一切都是抽象的,像水一样流动,没有固定的形状。这时候你很难判断哪里是好的切割点。Grug 的做法是等一等,让系统的"形状"自然浮现,好的切割点会从代码里自己长出来。

好的切割点有一个特征:它跟系统的其他部分只有很窄的接口——少数几个函数或抽象,就能把内部的复杂性像困在水晶里一样封装起来。

Grug 会耐心地看着切割点从代码里浮现,然后慢慢重构。没有硬性规则,Grug 看到切割点就知道那是切割点,但这需要时间和经验来培养这种直觉。

一个特别有效的技巧是做一个能工作的演示。强迫那些大脑袋做点什么实际能跑的东西,这样他们就能更快地看到地面上的现实,而不是在抽象里打转。

测试:又爱又恨

Grug 对测试有一种复杂的爱恨关系。

测试救了 Grug 无数次,Grug 爱测试、尊重测试。"哦,别担心,测试会告诉你需要做什么。"

但 Grug 在这里必须非常自律。

单元测试有时候太底层,测试的是实现细节而不是行为。你在 A 机器上改了实现,单元测试在 B 机器上可能就挂了——而且不能保证在别的机器上也能工作。

端到端测试又太高层,出了问题很难定位具体是哪一行代码坏了。

Grug 认为 集成测试 是甜点:足够高层来验证系统的正确性,又足够底层——配合一个好的调试器——能比较容易地看出哪里坏了。

Grug 不喜欢的一个例外是"第一个测试":当发现 bug 时,Grug 总是先写一个能复现这个 bug 的回归测试,然后再去修。这样修完之后就能确保这个 bug 不会悄悄回来。

敏捷:不是银弹

Grug 对敏捷的态度很务实:原型、工具和招到好的 Grug 比流程更重要。敏捷流程有时候有帮助,但太认真反而会坏事。

没有银弹。没有哪种方法论能替代好的判断和经验。

重构:J2EE 和 OSGi 的教训

Grug 年轻的时候经历过 J2EE 和 OSGi 的时代。那些框架承诺解决一切问题,结果带来的复杂性比解决的问题还多。Grug 说,重构是好的,但不要为了重构而重构。有时候"烂"代码能跑五年,比"优雅"但没人能懂的抽象强得多。

Chesterton 的栅栏

Grug 喜欢引用 Chesterton 的栅栏寓言:

路上有一道栅栏或 gate,现代改革者走过去说:"我看不出这有什么用,拆了吧。"更聪明的改革者会回答:"如果你看不出它的用处,那我肯定不会让你拆。去想想。等你回来说你确实看出它的用处了,我也许才会允许你拆掉它。"

代码里那些看起来"多余"的东西,往往是有原因的。在你理解为什么它存在之前,不要删掉它。

微服务:Grug 的警告

Grug 对微服务的态度很直接:微服务解决了"组织问题",不是"技术问题"。如果你的团队只有几个 Grug,微服务带来的分布式复杂性可能比你解决的问题还多。

工具:Grug 热爱工具

Grug 热爱工具。工具和控制欲是区分 Grug 和恐龙的东西。工具能帮 Grug 的脑子写出本来不可能写出的代码,总是很好的减负。

Grug 每到一个新环境,都会花两周学习周围的工具,这往往能让开发速度快一倍。而且经常需要四处打听、问别的开发者,因为文档往往不全。

一个好的调试器价值连城。Grug 面对 bug 时,愿意用所有的闪亮石头——甚至几个孩子——来换一个好调试器。反正调试器也不重,据 Grug 所知。

类型系统:自动补全才是价值

Grug 对类型系统的看法很务实。类型系统最大的价值不是"防止错误"——Grug 见过太多类型安全但逻辑错误的代码了。类型系统最大的价值是:按个点就能看到你能做什么,永远不要忘记这一点。

表达式复杂性:拆分它

Grug 经常跟别的开发者吵架,因为他们在条件表达式里塞了太多东西。Grug 大喊:"更容易调试!每个表达式的结果看得更清楚!好名字!更容易理解条件!更容易调试!"

一个复杂的表达式拆成几步,中间变量取好名字,调试时能看到每一步的结果。这看起来多了几行代码,但省下的调试时间值得。

DRY:不要过度追求

过去十年,Grug 对"不要重复自己"(DRY)没那么执着了。只要重复的代码足够简单、足够明显,Grug 觉得复制粘贴加一点小改动,比搞一堆回调、闭包或复杂的对象模型要好。后者的复杂性往往超过收益。

关注点分离 vs 行为局部性

经典的 Web 开发模式是把样式(CSS)、结构(HTML)和逻辑(JavaScript)分开到不同文件。这是关注点分离(SoC)的典范。

但 Grug 发现了一个问题:当你想理解一个按钮到底怎么工作的时候,你得在十几个文件之间跳来跳去。这叫行为局部性(LoB)的丧失。

Grug 认为,有时候把相关的东西放在一起,即使违反了"纯"的分离原则,实际上更容易理解和维护。

闭包:像盐一样用

Grug 警告说,闭包像盐、像类型系统、像泛型:少量使用效果很好,但用多了会坏事。小心别给代码搞出心脏病。

日志:Grug 的趣事

Grug 曾经崇拜一个技术偶像,那个偶像说"日志是调试的最后手段"。Grug 信了,结果花了三天追踪一个生产环境的问题,最后发现如果有基本的日志早就解决了。现在 Grug 的观点是:日志是好朋友,但要控制级别。生产环境不要输出 DEBUG,但 ERROR 和关键路径的 INFO 是必须的。

Grug 的总结

Grug 不是什么大师。Grug 只是一个吃过亏、愿意自嘲的开发者。但 Grug 的经验是真实的,教训是血淋淋的。

如果你只能带走一件事,那就是:复杂性很坏。 每当你要引入一个新的抽象、一个新的服务、一个新的框架时,先问问自己:这真的是必要的吗?还是只是让代码看起来更"高级"?

Grug 说,大多数时候,简单直接的方案更好。不是因为它不够聪明,而是因为它能被理解、被维护、被调试。

而能被理解的代码,才是能长期活下去的代码。

分享到
微博Twitter

© 2026 四月 · CC BY-NC-SA 4.0

原文链接:https://aprilzz.com/ramble/grug-brained-developer