为什么我最终放弃了前后端分离?
2021年我坚定地拥抱前后端分离,认定这是现代Web开发的“正规军”路线。五年后的今天,在AI辅助开发成为日常之后,我又重新回到了全栈框架的阵营。这篇文章不打算说服任何人,只是记录下我自己在架构选型上的思考变化——以及AI如何改变了这个决策的天平。
2021年,我在一个项目里推动前后端分离,花了整整两周说服团队把模板引擎换成Vue + RESTful API。理由很充分:专业分工、技术解耦、多端复用。那会儿觉得,这才是现代Web开发该有的样子。
今年做新项目选型,我选了Next.js的App Router。前后端代码写在一个仓库里,Server Components直接查数据库,Server Actions处理表单提交。没再纠结“分不分离”这件事。
前后端分离我用了五年,不能说它不好。只是现在的条件和需求不一样了。
2015年前后,分离为什么成为主流
当时React和Vue刚兴起,前端从“切图仔”真正变成了一个独立的工程领域。RESTful API成为标准,微服务开始流行,移动端需求爆发——Web、iOS、Android需要共用同一套后端接口。
在那个背景下,分离确实解决了几个实际问题:
- 前端可以独立迭代,不用等后端发版
- 一套API同时服务Web和App
- 前后端团队可以并行开发,互相不阻塞
- 前端用SPA实现了接近原生App的交互体验
我也是坚定站分离派的。项目里Vue调Spring Boot,Swagger文档写得整整齐齐,前端后端分开部署,觉得这就是“正规军”的做派。
当时很少有人质疑这套架构。它确实比前后端混在一起的JSP/PHP页面先进太多了。
但分离的隐性成本,比想象中高
用了几年分离架构后,我开始注意到一些始终绕不开的问题。
接口契约的维护成本最高。 每改一个字段,前后端要同步。Swagger文档永远赶不上代码变化的速度。联调时最常听到的话是:“你这个接口改了吗?”“我这边还没部署。”“字段名怎么变了?”
在一个快速迭代的项目里,接口文档几乎是从生成那一刻起就落后于代码。后来我们用TypeScript生成API类型定义,用OpenAPI Generator自动生成客户端代码,总算是解决了“类型不一致”的问题。但接口变更的沟通成本依然存在——每次改完接口,后端要部署,前端要重新生成类型定义,CI要重新跑一遍。
状态管理做了两遍。 前端用Redux管理页面状态,后端用数据库事务管理业务状态。表单校验前端做一遍、后端再做一遍。权限判断前端控制UI展示、后端控制数据访问。同一份业务逻辑,硬生生拆成两套实现。
DRY原则在架构层面被彻底打破了。这倒不是技术问题,而是组织问题——前后端各有一个负责人,各自的代码风格和抽象方式不一样,很难统一。
运维复杂度翻倍。 前端要配CDN、配跨域、配环境变量;后端要配服务器、配数据库连接池、配监控告警。两套构建流程、两套部署脚本、两套日志收集。对于小团队来说,这套体系的维护成本几乎是不可承受的。
还有首屏性能。SPA的TTFB很快,但FCP和LCP受限于JS的下载和解析。解决这个问题得靠SSR或预渲染——而SSR本质上就是在服务端渲染页面,等于往分离架构里塞了一个“不分离”的模块。
这些成本不是不能接受,但它让我开始思考一个问题:分离带来的好处,真的能抵消这些成本吗?
AI出现后,天平开始倾斜
2023年以后,我日常开发越来越依赖AI辅助——Cursor、Claude、Copilot换着用。用的时间越长,越明显地感觉到:AI在工程化完善的全栈项目里表现最好,在前后端分离的项目里反而容易“精神分裂”。
原因很简单。AI要帮你写一个“用户注册”功能,它需要同时处理:数据库Schema、后端API逻辑、前端表单校验、错误处理、成功跳转。在前后端分离的架构下,这些逻辑散落在至少三个目录、两套框架、两种语言里。AI的上下文窗口有限,它很难一次性理解所有约束,生成的东西往往需要人工拼接。
而在Next.js这类全栈框架里,这些逻辑可以写在相近的位置——Server Action里同时包含数据校验和数据库操作,页面组件直接调用Server Action,错误处理在同一个文件里搞定。AI只需要看这一个上下文,就能生成端到端可用的代码。
另一个变化是部署成本的降低。以前分离架构的优势之一是“前端可以部署到CDN,不用买服务器”。现在Vercel、Cloudflare Workers这类平台让全栈应用的部署也变得一样简单——你提交代码,它自动构建部署,CDN分发,连数据库都帮你配好了。分离在部署层面的优势,已经不那么明显了。
还有一个因素比较微妙:小团队的精力是有限的。
我以前觉得“专业分工”是优势——前端专注交互,后端专注数据。但对一个五六个人的团队来说,同时精通React生态和Spring Cloud生态,本身就是很高的要求。大部分成员其实是“偏前端”或“偏后端”的,沟通成本比想象中高。
全栈框架把这套体系简化了。你只需要懂JavaScript/TypeScript,从数据库到UI都用同一套语法、同一套类型系统。不是“一个人干两个人的活”那种卷,而是“不需要两个人来干一个人的活”那种效率。
让我做出最终决定的一次实践
去年有个内部工具需要重构。功能不复杂:用户管理、权限配置、操作日志、几个报表页面。放在以前,我会自然而然地选择Vue + Spring Boot。但那次我决定试一下Next.js + Prisma。
开发过程比预想中顺畅很多。
最直观的感受是“不用写API了”。之前做CRUD,后端要写Controller、Service、Repository三层,前端要写API调用、状态管理、错误处理。用Next.js的Server Actions,直接在组件里调用数据库操作,TypeScript类型从数据库一路贯通到UI。删掉一个字段,编译直接报错,不需要等联调发现。
性能也比预想中好。Server Components让页面在服务端直接渲染HTML返回,客户端不用加载大坨JS。首屏加载时间比之前的SPA版本快了将近一倍。
最重要的是,这个项目只用了1.5个开发(我一个人全职,另一个同事偶尔帮忙)。换成分离架构,至少需要前后端各一个人。
这次的实践让我真正相信:对于中小型项目,全栈一体化的效率优势是压倒性的。
那分离架构过时了吗?也不是
我会继续在以下场景选择分离架构:
- 团队超过20人,前后端有明确的组织边界,分开协作反而更清晰
- 需要同时服务Web、App、第三方OpenAPI,一个后端接口被多个前端消费
- 后端已经是微服务架构,本身就是分布式系统,跟前端强行合并反而奇怪
- 遗留系统改造,不可能全部重写,只能在新模块上用新方案
这些场景下,分离依然是合理的选择。架构决策没有“永远正确”,只有“当下合适”。
我理解的这次回归
很多人把全栈框架的回归理解为“回到了PHP/JSP那种服务端渲染的老路”。
我觉得不是。
Next.js和Django们没有回到那个“HTML里嵌SQL”的混沌年代。它们把前后端分离十年里积累的好东西保留了下来:
- React/Vue的组件化交互体验
- TypeScript的端到端类型安全
- 清晰的目录结构和关注点分离
- 需要时依然可以暴露REST/GraphQL给外部调用
它不是什么新鲜发明,而是把“分”和“合”的边界重新划了一道。
以前那道边界划在“前端代码”和“后端代码”之间。现在划在“服务端组件”和“客户端组件”之间。后者的划分依据是“这个逻辑该不该暴露给浏览器”,而不是“这个代码是JS还是Java”。
这个变化比它看起来的要大。因为边界划得更合理的时候,很多以前需要额外工具和流程来解决的问题,就自然消失了。
写在最后
我花了五六年时间拥抱分离,又花了一年多时间回到全栈。这个转变不是因为我发现分离是错的,而是因为技术条件和业务需求都变了。
AI改变了开发效率的曲线——全栈框架的代码密度和上下文完整性,让它成了AI辅助开发更好的土壤。部署平台抹平了全栈应用的上线门槛。而业务对“快速迭代”的渴求,比任何时候都强烈。
架构选型没有标准答案,只有适合当下的选择。如果你也在思考这件事,不妨从一个小功能开始,试试Next.js的Server Actions,或者Django的类视图。有时候少即是多,合即是分。