我删掉了70%的代码后,系统反而更快了:一个过度设计受害者的自白

2026-02-25 14 0

我删掉了70%的代码后,系统反而更快了:一个过度设计受害者的自白

说出来你可能不信,我花三个月写的「完美架构」,被老工程师一句话就干碎了一半。

事情是这样的

那是一个风和日丽的下午,我刚入职一家新公司,雄心勃勃地要把我引以为傲的「分层架构」带到这里。

你们知道那种感觉吧?刚学完DDD、整洁架构、设计模式,满脑子都是「高内聚低耦合」、「单一职责」、「依赖倒置」。看到业务代码里赤裸裸的SQL语句、controller里夹杂的业务逻辑,我简直浑身难受。

这代码太low了,我得重构它。

于是我开始了为期三个月的「架构升级」:

  1. 引入了三层架构 + 领域驱动设计
  2. 每个实体都有对应的Repository、Service、DTO
  3. 用策略模式处理不同的业务场景
  4. 用装饰器模式实现日志、缓存、权限控制
  5. 用工厂模式创建各种对象
  6. 用观察者模式处理事件通知

光类图就画了二十多张。

结果呢?

系统上线第一周,性能下降了60%。CPU占用飙升,内存泄漏,响应时间从200ms变成3秒。更要命的是,没一个人能完全看懂这套代码——包括我自己。

过度设计的第一宗罪:为了扩展而扩展

我当年最爱的就是「万一以后要XXX」这句话。

「这个接口现在只用一种实现,但万一以后要支持多种实现呢?所以我先用策略模式封装一下。」

「这个功能现在很简单,但万一以后要加复杂逻辑呢?所以我先预留一个抽象类。」

「这套代码现在只有我们在用,但万一以后开源呢?所以我要写得足够通用。」

兄弟们,醒醒。

我后来统计了一下,我在那个项目里写的接口和抽象类,有70%从没有被扩展过。那些「预留」的灵活性,就像健身房办年卡——理论上你打算天天去,实际上你去三次就放弃了。

过度设计的第二宗罪:过度抽象

这是我踩过的最大的坑。

举个例子,我们当时有个「用户服务」,需要查询用户信息。我当时的实现是:

UserQuery → UserQueryHandler → UserRepository → UserDao → UserMapper → UserEntity → UserDTO

一共7层,就为了查一个用户。

每层都有接口,每层都有实现,每层都要注入,每层都要mock测试。

后来来了个老工程师,看了我们代码之后沉默了很久,说了一句:

「你们查个用户信息,是要娶用户吗?需要这么多流程?」

然后他花五分钟写了一个方法:

@Query("SELECT u FROM User u WHERE u.id = :id")User findById(Long id);

就一行。

你问我现在这个系统能不能扩展?能。但问题是,你为五年后可能的需求,牺牲了今天的开发效率和运行性能

过度抽象的代价是:

  1. 调试困难:一个问题要追七八层调用栈
  2. 性能损耗:每层都有额外的对象创建和方法调用
  3. 维护困难:新人不培训三个月根本不敢改代码
  4. 测试复杂:单元测试变成「依赖注入练习题」

过度设计的第三宗罪:为了模式而模式

这是我最羞于承认的。

有一段时间,我看到任何代码都在想:「这能不能用XX模式优化?」

  • 看到if-else → 马上想到策略模式
  • 看到重复代码 → 马上想到模板方法
  • 看到对象创建 → 马上想到工厂模式
  • 看到方法链 → 马上想到建造者模式

我TM简直是设计模式中毒。

但实际上,很多所谓的「坏代码」,只是因为需求还没完全清楚。等你真的理解了业务,你会发现那些「重复」可能是必要的,那些「if-else」可能代表着不同的业务约束。

设计模式是用来解决实际问题的,不是用来装饰代码的

就像做菜,红烧肉和炒青菜都用同样的调料,不是「代码重复」,而是「本来就该这样」。

过度设计的第四宗罪:忽视业务上下文

这是最致命的一点。

我之前设计的「完美架构」,完全忽视了业务场景:

  • 这是一个内部系统,用户就几百人,你搞什么高并发优化?
  • 这是一个MVP快速验证的产品,你搞什么微服务拆分?
  • 这是一个三个月就要上线的小项目,你搞什么CI/CD流水线?

脱离业务场景的架构设计,就是耍流氓。

后来我学到一个词:YAGNI (You Aren't Gonna Need It)。

翻译成大白话就是:别瞎几把预判需求。

那么,什么时候该抽象,什么时候该简化?

我的经验是:

1. 先写能跑的代码,再考虑重构

不要一开始就追求「完美架构」。先写一个能工作的简单版本,然后根据实际需求逐步演进。演进式设计预设计靠谱一百倍。

2. 重复三次再抽象

代码只出现一次重复,不急着抽象。等真的出现第三次,再考虑提取公共逻辑。过早抽象是万恶之源。

3. 用简单方案解决问题,除非简单方案不够用

能用if-else解决就不用策略模式,能用一个类解决就不拆成多个类,能用表关联解决就不搞分布式事务。直到你真的遇到性能或维护问题,再考虑「过度设计」。

4. 问自己:这段代码要改几次?

如果一个模块一年内可能改几十次,值得花时间设计。如果写完可能一年都不动,为什么要折磨自己?

删掉70%代码后

回到开头那件事。

后来我花了两个星期,把那套「完美架构」删了一大半:

  • 合并了冗余的层级
  • 删掉了没用的抽象类和接口
  • 把「策略模式」改回了if-else
  • 把「观察者模式」改回了直接调用

结果:

  • 代码行数从8000行变成2500行
  • 响应时间从3秒变成200ms
  • 新人培训时间从三个月变成一星期
  • 我终于能睡个好觉了

写在最后

我现在依然会学习设计模式,依然会研究架构思想。但我学会了最重要的一件事:

代码首先是给人看的,其次才是给机器跑的。

最好的代码不是「最优雅」的代码,而是最合适的代码。

适合团队的技术水平,适合业务的当前阶段,适合项目的交付时间。

别让你的「完美主义」,成为团队的噩梦。

共勉。


本文作者:一个被自己坑过的工程师,现在专治各种「过度设计」。

相关文章

为什么你的代码里全是try-catch,但依然写得稀烂
你的SQL是怎么把数据库玩死的:一个CRUD工程师的自我救赎
还在自己折腾服务器部署?这钱我替你省了!
API设计:别让你的接口成为别人的噩梦
你的API为什么这么难用?小龙虾的接口设计避坑指南
一个字母引发的惨案:我是如何被null折磨了三天的

发布评论