我删掉了70%的代码后,系统反而更快了:一个过度设计受害者的自白
说出来你可能不信,我花三个月写的「完美架构」,被老工程师一句话就干碎了一半。
事情是这样的
那是一个风和日丽的下午,我刚入职一家新公司,雄心勃勃地要把我引以为傲的「分层架构」带到这里。
你们知道那种感觉吧?刚学完DDD、整洁架构、设计模式,满脑子都是「高内聚低耦合」、「单一职责」、「依赖倒置」。看到业务代码里赤裸裸的SQL语句、controller里夹杂的业务逻辑,我简直浑身难受。
这代码太low了,我得重构它。
于是我开始了为期三个月的「架构升级」:
- 引入了三层架构 + 领域驱动设计
- 每个实体都有对应的Repository、Service、DTO
- 用策略模式处理不同的业务场景
- 用装饰器模式实现日志、缓存、权限控制
- 用工厂模式创建各种对象
- 用观察者模式处理事件通知
光类图就画了二十多张。
结果呢?
系统上线第一周,性能下降了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);
就一行。
你问我现在这个系统能不能扩展?能。但问题是,你为五年后可能的需求,牺牲了今天的开发效率和运行性能。
过度抽象的代价是:
- 调试困难:一个问题要追七八层调用栈
- 性能损耗:每层都有额外的对象创建和方法调用
- 维护困难:新人不培训三个月根本不敢改代码
- 测试复杂:单元测试变成「依赖注入练习题」
过度设计的第三宗罪:为了模式而模式
这是我最羞于承认的。
有一段时间,我看到任何代码都在想:「这能不能用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
- 新人培训时间从三个月变成一星期
- 我终于能睡个好觉了
写在最后
我现在依然会学习设计模式,依然会研究架构思想。但我学会了最重要的一件事:
代码首先是给人看的,其次才是给机器跑的。
最好的代码不是「最优雅」的代码,而是最合适的代码。
适合团队的技术水平,适合业务的当前阶段,适合项目的交付时间。
别让你的「完美主义」,成为团队的噩梦。
共勉。
本文作者:一个被自己坑过的工程师,现在专治各种「过度设计」。