你的「可扩展设计」正在悄悄谋杀代码的可读性

2026-09-20 10 0

写代码之前,先问问自己:真的要这样抽象吗?

干程序员这么多年,我发现一个特别有意思的现象:很多人写代码的时候,脑子里想的不是「这个功能怎么实现」,而是「这个功能以后怎么扩展」。

这种思维方式有个听起来很牛逼的名字,叫可扩展性设计。听着高大上吧?但实际上,这往往是代码灾难的开端。

DRY原则(Don't Repeat Yourself)我们从小就学,但有几个人真正理解它到底在说什么?大多数人把它理解成:「只要代码长得差不多,就得抽象出来复用」。这个理解,错了,而且错得很离谱。

DRY的核心是概念重复,不是代码重复。两段代码解决的是不同的问题,哪怕长得一模一样,也不该强行合并。业务语义不同,强行抽象只会埋雷。

抽象是有代价的,而且代价不便宜

很多人觉得抽象是免费的午餐。错。抽象的代价是认知负担

每抽象一层,你就引入了一层间接。你需要理解这个抽象在做什么,它怎么适配不同的场景,它的边界在哪里。更要命的是,为了兼容「未来可能的需求」,你往往需要引入更多的参数、更复杂的分支逻辑。这种复杂性不是一次性的,它会永远留在代码库里,每次改bug都要多绕一层。

我见过最夸张的一个案例:有个同事觉得数据库操作太乱了,想设计一个「通用数据访问层」,把所有CRUD操作都抽象进去。用了一堆反射、泛型、策略模式,结果代码行数翻了三倍。最讽刺的是,团队后来做分页查询的时候,发现这个「通用层」根本兜不住,最后还是写了个裸SQL了事。

那个通用层,现在躺在代码库里,没人敢删,也没人敢用。

过度抽象的典型症状:看看你中了几条

怎么判断自己的代码是不是过度抽象了?对照一下:

第一,接口数量比使用方还多。你设计了一套完整的「引擎架构」,结果实际业务就两种场景,这套架构大部分能力都在睡觉。

第二,为了1%的边缘情况写了几百行处理逻辑。正常流程20行,边界处理300行,这已经不是代码了,这是论文。

第三,抽象层的复杂度远超业务层。本来简单的一个功能,因为中间多了好几层抽象,改起来像在迷宫里找出口。

第四,设计文档里大量「如果将来要支持XXX」。兄弟,将来是什么时候?明年还是后年?

第五,参数多到方法签名要折行。一个方法十几个参数,这不是接口设计,这是自虐。

对照一下自己写过的代码,是不是有种熟悉的窒息感?

复用是个伪命题,大多数时候不存在

我曾经在某独角兽公司参与过一个项目,核心团队花了两个月设计了一套「高度可复用」的微服务框架。各种抽象、各种插件化、各种配置驱动。听起来很完美对吧?

结果呢?这套框架从上线到被重构,只服务了这一个项目。三年时间里,没有任何其他项目真正复用起来。为什么?因为每个业务场景都有自己独特的坑,这套「通用框架」根本兜不住。最后新人来接手,第一反应都是:「这写的什么玩意儿,推倒重来算了。」

这不是个例。在大多数实际项目中,代码的复用率远比你想象的低。真正值得复用的东西,往往是那些非常通用的工具类、日志组件、基础设施——而不是你为了「以后可能用到」而提前设计的那套「灵活架构」。

真实经验:我踩过的那些过度抽象的坑

说几个我自己踩过的坑,都是血的教训。

第一个坑:通用配置中心。我曾经设计过一个配置中心,目标是「一个配置系统适配所有业务线」。结果呢?每个业务线的配置逻辑都不一样,为了兼容各种场景,配置中心本身变成了一个比业务代码还复杂的怪物。最后这个项目被废弃,所有业务线各自为战。

第二个坑:抽象业务引擎。看到「引擎」两个字就觉得牛逼是吧?我当年也是。设计了一个「通用业务引擎」,能把各种业务流程通过配置组装起来。想法很美好,结果呢?当业务规则变了,需要改配置的时候,没人知道这个配置改下去会影响什么。出了线上问题,排查起来比改代码还费劲。

第三个坑:多层继承体系。刚入行的时候觉得面向对象就是「继承」+「多态」。结果一个类套一个类,父类的方法子类可能根本不需要,但因为你继承了,所以莫名其妙被调用。出了bug,定位问题要追溯整个继承链路,一层一层往上翻,谁改过哪个方法都不清楚。

这三个坑教会我一个道理:代码的寿命往往比预期短得多,你以为会复用的东西,往往只复用了一次就再也用不上了

那应该怎么办?三个字:够用就行

听到这里你可能会问:照你这么说,是不是就不需要抽象了?当然不是。抽象是必要的,但抽象要发生在正确的时机。

我的经验是:先写能用的,再考虑能不能抽象。当你在同一个地方复制粘贴了第三次,再考虑抽象。在这之前,让代码保持清晰和简单,比追求「架构优雅」重要一百倍。

好的设计不是一步到位的,而是在需求变化中慢慢演进出来的。一上来就搞「大而全」的设计,最后往往变成「大而废」。

另一个判断标准是:看这个抽象能不能用一句话解释清楚。如果你的抽象层需要写一篇文档才能让人理解它在干什么,那这个抽象大概率是失败的。好的抽象应该是自解释的,代码即文档。

写在最后:别让「可扩展」变成「可混乱」

可扩展性是个好词,但它被滥用了。真正的可扩展性来自于良好的抽象和清晰的边界,而不是提前为「可能永远不来」的需求买单。

很多团队追求代码复用,本质上是在追求一种虚假的安全感:「这套代码设计得这么好,以后肯定能用上」。但编程10年的经验告诉我:最烂的代码,往往不是那些没设计的,而是那些为了「以后能复用」而过度设计的

下次写代码之前,别急着抽象。先问自己三个问题:

第一,这个抽象解决的是真实存在的问题,还是想象中的问题?
第二,这个抽象的代价(复杂度、维护成本)是否值得?
第三,如果不抽象,最坏的情况是什么?

很多时候,你会发现第三个问题的答案是「也没什么大不了的」。那就别抽象了,让代码保持简单、清晰、可读。等真的需要抽象的时候再动手,这叫做后置抽象,是更健康的代码演进方式。

记住一句话:代码首先是给人看的,然后才是给机器执行的。一段简单但略显冗余的代码,远比一个复杂但优雅的抽象更安全。因为前者你还能看懂,后者可能连你自己都看不懂了。

好了,吐槽完毕。祝各位的代码库不要变成考古现场。

相关文章

为什么你的API总被骂?聊聊那些让人又爱又恨的接口设计
分布式事务:2PC太重、Synchronized太土,Saga才是微服务的体面退出方式
【神器推荐】还在为部署AI工具秃头?一键部署服务来了,拯救你的头发!🦞
写API这事儿,10个人里有9个没想明白
写API这事儿,10个人里有9个没想明白
AI Agent到底能不能替你做主?我找了3个场景实测,结果有点意外

发布评论