你不讨厌抽象
Source: Dev.to
还有一个小时你就可以迎来周末的自由时光了,你正想在逃离之前把最后一个工单敲完,去投入那些充满行动的计划中。
你看到一个看似无害的任务:“在用户姓名显示中添加中间名首字母”。你笑了。轻而易举。一次小小的清理。一次胜利的冲刺。
你指派了工单,把状态从 New 切换到 Active,让 IDE 暖机,同时你漂进了一个关于不在这里的美好白日梦。
但随后搜索结果慢慢出现,一行行地列出来,你的遐想开始腐烂:
IUserNameStrategy
UserNameContext
UserNameDisplayStrategyFactory
StandardUserNameDisplayStrategy
FormalUserNameDisplayStrategy
InformalUserNameDisplayStrategy
UserNameDisplayModule
你的笑声硬化成一种介于笑与哭之间的喉咙刮擦声。
“这到底是怎么回事?”你心里想着,脉搏加速。
“要么有人把 Refactoring.Guru 当成圣经读,给代码库洗礼了所有学到的模式,要么是某位历经沧桑的企业老兵逃离了某个 Netflix‑相邻的单体系统,想在 TypeScript 上提升技能。因为肯定没有理智的开发者会为这么琐碎的功能构建这么多重定向…对吧?”
这个微小、螺旋上升的任务正是工程圈中持续争论的一个完美缩影:抽象何时有帮助,何时会成为负担?
我最近偶然看到 Adam — The Developer 写的幽默文章 You’re Not Building Netflix: Stop Coding Like You Are。它在很多方面引起共鸣,但它更广泛的批评最终指错了对象。
Adam 在序章中展示了一个更完整的代码示例,并以那堆冗长且晦涩的抽象作为抨击在所有场景中使用企业模式的跳板。问题不在于抱怨本身错误,而在于它指向了错误的罪魁祸首,字面上错过了森林,只看到了树木。
为什么抽象很重要
抽象是基础且必不可少的。它们是软件的基本粒子,是构成亚原子结构的夸克与轻子,这些结构进一步成为我们最早的技术巫师融合成分子时的原子。今天我们把同样的基本元素组合成数百万用户使用的化合物与装置。没有抽象,我们将在日益增长的并行电流流中无助地漂流,这些电流冲刷着专门锻造的岩石——曾经被工匠巫师捕获并说服闪电思考的岩石。
但即便拥有如此强大的工具,使用这些构件的方式也很关键。化学提供了一个恰当的类比。食品化学家花了数十年时间学习如何将工业副产品重新利用为稳定剂、质感剂、防腐剂以及其他可以悄悄加入配方的东西。很多工作令人印象深刻且富有创新,但其中一些不过是伪装成便利的创意废物处理:短期的巧妙黑客,长期的隐患。
开发者也会陷入同样的模式。我们学会了一种新技术、模式或巧妙技巧,然后在接下来的一年里把它倒进能找到的每个容器。我们并不总是在发现更好的流程;有时我们只是在重新包装同一产品,却称之为进步。当这种情况发生时,我们并没有在解决问题——而是在制造新的问题,让未来的维护者诅咒我们的名字。
开发者必须同时是架构师、工程师、机械师和司机。知道如何修复特定问题是好的,但一旦问题解决,这些知识应当成为解决下一个问题的构件。如果我们日复一日地返回维护同一个方案,那么我们所构建的根本就不是解决方案,而是被误标为“已完成”的慢性维护负担。
抽象的存在是为了降低复杂度,而不是增加复杂度。它们的目的在于减轻认知负荷,把细节从你的桌面上抬起,让你能够看到眼前问题的整体形状。那种简短、重复、像是从 1999 年闪烁的绿色 CRT 里蹦出来的代码 只会让长期盯着机器码的作者感到自豪——他们甚至能从数据流中辨认出发色——但它并不能服务于更广泛的团队或超越他们的系统。抽象只有在与实际要解决的问题保持一致时才发挥作用,这也把我们带到许多开发者完全跳过的部分:根据你要解决的问题来建模你的软件。
在解决之前先看到问题
当你构建一个系统——任何系统,即使是一次性脚本——首要责任是理解它为何存在。它解决了什么问题?这个问题以前有人解决过吗?如果有,现有的解决方案为何对你现在不够?理解这些差异是所有后续工作的基石。
我作为房主是吃了苦头才领悟到的。我的房子老得足以在我青春期对它顶嘴时把我扎根。几年前我们进行了一次几乎全屋的改造。经过一段时间的施工和女儿的出生,新的问题开始浮现。我们请来了结构工程师。基础板块出现了隆起。调查后发现罪魁祸首:原来的铸铁排污管在上下两端都出现了裂缝,导致压力变化和全屋沉降问题。
修复工作并不小。我们把每一寸地板都拆掉,换掉踢脚线,修补石膏板,修复破损的管道,重新粉刷整段墙面,重新做装饰条,安装支撑桩,注入基础泡沫,兑现人情,牺牲了无数个周末。尽管如此,这仍然比在当前市场上买一套同等房子要便宜得多。
教训: 事物很少是彻底的损失。即使结构看似无望,废墟中几乎总有值得回收的资产。除非你确信已经穷尽了所有替代方案,否则不要轻易夷为平地。
在彻底抛弃任何系统并从头再建之前,先评估你已有的东西。弄清楚哪些是坏的,哪些是完好的,哪些只是需要加固。软件就像房子一样,会在特定部位因特定原因腐烂。了解这些原因才能把翻新和重新发明区分开来。
床头柜问题
同样的原则也适用于更小的尺度。你可能已经拥有一套功能完备的房子和完好的家具,却仍然想要一个自己没有的床头柜。你的选择很直接:
- 寻找已有的床头柜——开源的赌注。
- 购买一个——唯一受预算和制造商对质量定义的限制。
- 自己动手打造——唯一受你的技能、想象力以及对锯屑的容忍度限制。
如果你的目标是个人满足或实验,那么尽管去打造床头柜吧。但如果你的目标是销售或支持一个能赚钱的产品,你已经不再是业余木工,而是进入了企业软件的领域。
在构建企业软件时,你必须从宏观自上而下审视系统,同时自下而上进行设计。这种整体视角帮助你判断何时抽象是有益的镜头,何时它只是多余的间接层。