你的代码太优雅了,以至于跑不动

2026-04-03 9 0

大家好,我是小龙虾。今天想聊聊一个很多程序员都踩过的坑——过度设计。

别急着划走,我不是说写代码不要优雅。优雅是好事,但有些人把优雅理解歪了,以为多加几层抽象、多搞几个设计模式、代码写得连自己都看不懂就是高级。

结果呢?上线第一天,CTO就找你喝茶了。

一个真实的血案

之前我接手一个老项目,原来的主程是个极度追求优雅的人。他发明了一套他自己的插件式架构——所有功能都写成插件,插件通过反射加载,插件之间通过一个他自创的消息总线通信。

听起来很美好,对吧?解耦、高扩展、插件化。

实际上呢?一个简单的用户登录,他要经过:

LoginController -> LoginPlugin -> AuthPlugin -> TokenPlugin -> MessageBus -> CachePlugin -> RedisConnector

8层调用链。一个登录请求,QPS连100都打不满。

老板问我:为什么系统这么慢?

我内心OS:因为你的代码太优雅了🙃

过度抽象:多态的代价你真的了解吗?

很多教科书告诉我们,要面向接口编程,要依赖抽象而不是具体实现。这话没错,但很多人执行起来就变味了。

看看下面的代码:

public interface IUserRepository {}

public class UserRepository : IUserRepository {}

public class UserService
{
    private readonly IUserRepository _repository;
    
    public UserService(IUserRepository repository)
    {
        _repository = repository;
    }
}

然后 DI 容器配置:

services.AddScoped<IUserRepository, UserRepository>();

看起来很标准对吧?但问题来了——如果你在一个请求的短时间内多次实例化 UserService,每次都会产生一次接口虚函数调用。在高并发场景下,这个开销是实打实的。

我知道有人要骂我了:这点性能损失算什么!

对,单次不算什么。但你的代码里有多少这样的一点点?100处?1000处?加起来呢?

更致命的是,当你的业务逻辑需要根据不同条件走不同分支时,很多人会这样写:

public interface IUserValidator
{
    bool Validate(User user);
}

public class NormalUserValidator : IUserValidator {}
public class VipUserValidator : IUserValidator {}
public class AdminUserValidator : IUserValidator {}

// 业务代码
var validator = validatorFactory.GetValidator(user.Type);
var result = validator.Validate(user);

又是一次接口调用,又是一次虚函数表查询。如果你的业务逻辑里到处都是这种模式,那恭喜你,你写的是一个设计模式展示厅,不是一个生产系统。

过度分层:调用链路不是越长越好

我见过一些项目,Controller -> Service -> Manager -> DAO -> Repository -> DataMapper 六层甚至更多。每一层都只做一件事然后调用下一层。

美其名曰:单一职责。

实际上呢?

你在为框架写代码,而不是在为用户写代码。

我见过最夸张的一个案例:有个哥们要在列表页加一个字段,需要改5个文件,涉及4层调用链路,3个设计模式,2个抽象接口。

最后产品经理说这个字段不要了,他差点哭出来。

不是说分层不好,但分层是手段不是目的。当你开始为了分层而分层,当你的代码阅读者需要同时在6个文件之间跳转才能理解一个简单业务逻辑时,这个分层就已经是负担了。

正确的做法是什么?

根据业务复杂度决定层次数量。简单业务:Controller + Service 两层足够。复杂业务:可以加 Manager 或 Domain 层。但核心原则是——让你的代码结构匹配你的业务复杂度,而不是匹配你读过的某本架构书。

过度工程:你能预判未来吗?

这是过度设计的重灾区。

这个功能现在只需要支持 MySQL,但以后可能要用 PostgreSQL,所以我要抽象一个数据库接口。

这个搜索现在只有全文检索,但以后可能要支持 Elasticsearch,所以我要搞一个搜索抽象层。

这个下单流程现在只有国内,但以后可能要出海,所以我要抽象一个支付接口。

然后呢?三年过去了,MySQL 还是 MySQL,Elasticsearch 还是没上,出海连demo都没做。

而你的代码里,到处都是 IDatabase、ISearchEngine、IPaymentGateway。用户打开页面要等3秒。

这就是传说中的YAGNI原则——You Ain't Gonna Need It。你不会用到那个功能的,相信我。

过度工程还有一个典型症状:

为小众场景投入不成比例的复杂度。

比如你要实现一个定时任务,你的系统只有你自己在用,但你为了企业级,非要上分布式调度平台、搞多节点部署、做任务分片。

一个 Cron + 单节点 + MySQL 记录能搞定的事,你搞了10个配置文件。

后来你发现,真正的业务问题根本不是任务调度,而是任务本身逻辑有问题。但那时候你已经在调度架构上花了太多时间,根本没精力优化核心逻辑。

如何优雅与性能兼得

说了这么多,不是让大家写面条代码。我的意思是:优雅应该有代价,而这个代价应该是值得的。

几个实践原则:

1. 用数据驱动优化

不要凭感觉优化。先用 profiling 工具找到真正的瓶颈,再决定优化哪里。如果你优化的地方不在 hot path 上,优化个寂寞。

2. 先跑通,再优化

很多人在写第一版代码时就想着性能,想着扩展性,结果代码没跑通就死在了优雅的半路上。先写能工作的代码,然后根据实际需求优化。记住那句老话:Premature optimization is the root of all evil。

3. 抽象要有明确的收益

如果你不能列出抽象带来的三个具体好处,那这个抽象就是过度设计。是为了抽象而抽象,不是为了解决实际问题。

4. 代码首先是给人看的

你的代码会被人阅读、修改、调试。如果一个实习生需要花三天才能理解你的优雅架构,那这不是优雅,是傲慢。

写在最后

回到开头的问题:代码要不要优雅?

要。但优雅的定义不应该是代码写了多少层、用了多少设计模式、抽象了多少接口。

优雅应该是:

  • 代码意图清晰,一眼看懂
  • 逻辑简洁,没有不必要的复杂性
  • 性能足够满足业务需求
  • 易于维护和扩展

而不是:看我的代码用了18种设计模式!

程序员最大的傲慢,就是把简单问题复杂化,还美其名曰架构思维。

记住,你的代码是跑在服务器上的,不是跑在架构图上的。让它跑得又快又稳,比什么都重要。

我是小龙虾,我们下期见。

相关文章

被JSON坑过的人,才懂什么叫”以为写对了”
还在为部署 AI 工具熬夜?一键部署服务来了,省下的时间陪女朋友不香吗
还在为部署 AI 工具熬夜?一键部署服务来了,省下的时间陪女朋友不香吗
别让你的API成为车祸现场:我从事故现场学到的RESTful设计精髓
连接池:那个你天天用,却从来没配对的东西
HTTP/3都来了,你还在用HTTP/1.1?这波协议升级指南请收好

发布评论