我见过太多后端系统死在"太聪明"上。
不是性能不够,不是技术栈过时,是六个月后再看代码,连作者自己都看不懂当初为什么要这么写。过去这些年,我用.NET、ASP.NET Core、SQL Server、Redis、EF Core搭过各种系统,Clean Architecture、CQRS、DDD、模块化单体这些模式也都试过。一个真相越来越清晰:好的后端工程,核心就三件事——清晰、克制、在关键处做性能。
以下是五个彻底改变我建系统方式的教训。
一、先求可维护,再谈复杂度
把系统做得看起来很复杂很容易,做得六个月后人还能看懂,很难。
干净的代码库不是抽象最多的那个,而是开发者能快速回答三个问题的那个:这段逻辑在哪?这个依赖为什么存在?请求进来后会发生什么?如果答案不明显,架构已经在悄悄吃你的成本了。
我见过太多项目开局轰轰烈烈,微服务拆分、事件总线、领域事件全套上阵,结果三个月后需求一变,改一行代码要动五个仓库。不是技术选错了,是时机选错了。复杂度是负债,不是资产,能欠多少取决于你什么时候能还清。
二、性能是设计出来的,不是补丁打出来的
性能问题往往源于太早或太随意的架构决策。
几个典型场景:不必要的数据库往返、EF Core里滥用Include、领域逻辑泄露到数据层、忽视缓存机会、设计API时完全不考虑负载模式。这些问题在代码评审阶段几乎不会被发现,因为单测能过,本地跑得飞快。等生产环境告警响起,往往已经积重难返。
我学到的经验是:性能工作最有效的时候,是在设计阶段,而不是生产环境开始疼之后。一个接口的QPS预估、一个查询的索引规划、一个缓存策略的失效逻辑——这些在写第一行代码前就该想明白。事后优化的成本,通常是事前设计的十倍以上。
三、模块化单体被严重低估了
不是每个系统都需要微服务。
对很多业务应用来说,结构良好的模块化单体能带来:更简单的部署、更容易的调试、更好的一致性、更低的运维开销、更清晰的领域边界。关键是纪律。模块化单体仍然要强制执行边界,否则它只是命名更好的一团乱麻。
微服务的成本被严重低估了。网络延迟、分布式事务、服务发现、监控链路、数据一致性——这些不是"顺便做掉"的事,是专门的工程领域。如果你的团队还没有成熟到能独立运维多个服务,强行拆分就是在给自己造坑。模块化单体给你一个中间态:代码层面隔离,部署层面统一,等边界真的稳定了,再拆也不迟。
四、SQL Server值得真正的工程投入
很多后端问题,其实是数据库问题。
良好的SQL设计、索引策略、查询塑形、事务边界——这些的重要性被太多开发者低估了。我见过系统里一次小小的查询优化,效果超过应用层的完整重构。如果你的数据库慢,你的API就慢。如果你的查询 sloppy,你的架构迟早要为此买单。
一个常见的反模式:开发者把ORM当黑箱用,LINQ写得行云流水,生成的SQL看都不看一眼。执行计划是什么?索引有没有命中?锁粒度合不合理?这些"数据库的事"被推到DBA头上,但现代应用里,数据库和应用层的边界已经模糊了。懂查询优化,是后端工程师的基本功,不是加分项。
五、简单比聪明更能扛住规模
最容易维护的系统,通常不是最聪明的那个。
简单的代码更容易测试、更容易评审、更容易调试、更能经受团队变动、老化得更优雅。一个聪明的解决方案今天可能让人印象深刻,但简单的那个往往是明天还能让系统活着的。
什么是"聪明"的代码?过度设计的抽象、为了用模式而用模式、一行lambda链式调用干五件事、自定义DSL解决本可以用标准库的问题。这些在提交时很有成就感,但在凌晨三点的故障排查中,你会恨不得把它们全部重写。
我现在的判断标准很简单:一个新同事能在多长时间内理解这段代码并安全地修改它?如果超过半天,就是过度设计了。
最后
后端工程不是追趋势。它是关于建造可靠、可理解、为变化做好准备的系统。
所以我关心的是:干净的边界、有目的的性能、真正有帮助的领域驱动设计、以及支持业务而非与之对抗的架构。技术债会累积,复杂度会膨胀,唯一能让你走得远的,是对"足够好"的清醒判断——知道什么时候该停手,比知道什么时候该出手,难得多。
热门跟贴