AI时代,前后端分离不该再是默认选项

我过去对前后端分离的看法是:前后端应该分离,但开发前后端的人不应该分离。

意思是,系统边界可以拆,接口可以清楚,前端和后端可以有不同的工程结构;但真正负责一个功能的人,最好理解从页面到数据、从交互到业务规则的完整链路。否则前端只知道调接口,后端只知道吐 JSON,最后很容易变成每个人都只对自己那一段负责,却没人真正对用户体验和业务结果负责。

现在我的看法又往前走了一步:在 AI 时代,很多项目连前后端本身都不应该默认分离了。更准确地说,产品层的前后端不该再默认分离。

English version: In the AI Era, Frontend-Backend Separation Should No Longer Be the Default

什么是产品层全栈

这里说的产品层全栈,不是说所有系统都要塞进一个巨大的单体里,也不是否认底层平台、核心系统、数据能力的价值。它指的是一个面向用户的业务功能,应该尽量在同一个上下文里完成:界面、交互、数据读取、权限、状态、提交、校验、业务规则、持久化,以及部署发布。

对于小中型项目,这基本就是整个业务本身。对于大型系统,它也可以是围绕某个业务域的完整产品闭环。至于支付、登录、搜索、推荐、风控、数据分析、数仓等能力,如果复杂到需要独立演进,可以作为平台能力或业务依赖存在。

换句话说,用户如何下单、课程如何售卖、文章如何发布、任务如何流转,这些仍然是产品业务逻辑,应该尽量留在产品层的完整上下文里。底层能力可以拆出去,但一个产品功能不应该天然按“前端”和“后端”切成两个互相等待的半成品。

前后端分离曾经是合理的

过去前后端分离解决的是人的问题。

前端和后端技术栈差异大,关注点不同,团队规模变大后需要协作边界,接口契约可以减少沟通成本,独立部署也能降低互相影响。在工具不够强、个人跨栈成本较高的时候,这些理由都成立。

但很多团队后来把它变成了一种默认先进性:只要做 Web 应用,就先拆前端项目和后端项目;只要有页面数据,就先设计 REST 或 GraphQL 接口;只要有前端和后端岗位,就默认两拨人分别负责。久而久之,“前端不应该碰后端,后端不应该写页面”也变成了一种近乎本能的组织假设。

这个假设在 AI 时代变得越来越可疑。

AI 需要完整上下文

AI 改变的不是某个框架细节,而是开发者处理上下文的能力。AI 写代码的质量高度依赖上下文完整性。

一个功能的页面、数据结构、权限判断、提交逻辑、错误处理、缓存策略、测试用例,如果都在同一个项目、同一种类型系统和相近的文件结构里,AI 可以更容易理解因果关系,也更容易做出连贯修改。

反过来,如果前端在一个仓库,后端在另一个仓库;前端只有接口文档,后端看不到页面真实用法;部署链路也分开;类型还要通过生成代码或文档同步,那么人和 AI 都需要不断在局部信息之间补全上下文。这个成本过去由人承担,现在也会直接影响 AI 的产出质量。

这也是我重新理解同构全栈框架的原因。

同构框架的价值不是只在 SSR

Next.js 这类框架的价值,不只是 SSR 能改善首屏体验,也不只是把 API route 和页面放在一起。更重要的是,它让一个产品功能的上下文重新合并了。

页面怎么展示、数据怎么读、提交动作怎么处理、权限在哪里判断、类型怎么流动、缓存怎么失效,这些事情可以在同一个工程模型里协同。对开发者来说,这是心智负担的降低;对 AI 来说,这是上下文质量的提升。

我个人也更喜欢 Vinext 代表的方向:保留 Next.js 这种全栈同构开发体验,同时尝试把构建和运行时放到更开放的 Vite、Cloudflare Workers 等生态里。当然,Vinext 现在仍然偏实验性,框架本身也不是重点。重点是这个趋势:开发上下文正在重新合并,全栈框架会越来越围绕 AI 友好的工程形态演进。

Django、Rails、Laravel 这类传统全栈框架当然也属于全栈路线。它们长期证明了“一个项目完成产品功能”并不是什么落后的做法。只是对于前端交互复杂、组件生态依赖较重的现代 Web 应用,Next.js、Vinext 这类同构方案更贴近当前前端工程的工作方式。

接口契约没有消失

有人会说,前后端分离的价值在于接口契约。

契约仍然重要,但它不一定需要表现为一个只服务本项目、却伪装成公共服务的 HTTP API。外部系统、移动端、多端复用、第三方集成,当然需要稳定 API。但 Web UI 自己消费的数据接口,不必天然被设计成公共契约。

产品层全栈之后,契约不是消失了,而是内化了。它可以是 TypeScript 类型、schema、server action、组件 props、数据库模型、单元测试、集成测试和端到端测试。相比一份前后端隔着仓库维护的接口文档,这些契约更贴近代码真实运行的位置,也更容易被 AI 和工具一起理解。

数据库也是类似的问题。小项目里,产品层直接读写数据库很正常;大项目里,可以通过领域服务、存储服务或平台能力访问数据。但不应该为了“前后端分离”而强行包装一层只服务页面的 API。

BFF 的位置也变了

BFF 也是类似的问题。

很多 BFF 实践,本质上是在前后端分离之后补出来的胶水层:转发接口、裁剪字段、拼装数据、做一点鉴权和格式转换。它的存在反过来说明了一件事:纯 API 并不能很好地服务页面体验。既然如此,很多低价值 BFF 不如直接收回到产品层全栈里。

当然,BFF 不是永远没有价值。如果它承担的是复杂聚合、安全治理、流量控制、缓存、灰度、降级,或者多个产品共享的体验编排,那它可以成为独立系统。但如果它只是为了让前端不要碰后端而存在,那它很可能只是组织边界制造出的额外复杂度。

团队也应该按业务域组织

更合理的组织方式,也不应该继续按前端和后端切人,而应该按业务域组织小型全栈团队。

一个业务域里的工程师可以有专长,有人更熟悉交互,有人更熟悉数据,有人更熟悉基础设施;但团队整体应该拥有从产品需求到上线运行的完整闭环。长期按技术栈切人,会让工程师只理解链路的一段,最终没人真正理解用户需求如何落地。

这并不意味着所有项目都不该拆。多端复用同一套 API、开放平台、复杂核心业务系统、强安全合规、极致性能、超大团队协作、顶级大厂面向 C 端的应用,这些场景仍然可能需要清晰的前后端边界。尤其是多端场景,同一套业务能力需要服务 Web、iOS、Android、小程序、第三方系统时,稳定 API 的价值会明显上升。

但这些应该是拆分的理由,而不是默认起点。

一点个人实践感受

我的实践感受也很直接。以前做个人项目时,我常用 NestJS 加一个 Web 页面。这个组合不是不能用,但接口定义、类型同步、联调、部署、文件跳转、上下文切换,都会不断出现。

后来换到 Vinext 这类全栈同构方案,最明显的变化不是少写了几行代码,而是一个功能终于能在一个上下文里完成。对人是这样,对 AI 更是这样。

这不是什么大规模项目里的严谨结论,更像是一个开发者在实际写代码时积累出来的取舍感受。但很多架构判断,最终也会回到这种朴素的问题:一个功能到底是在帮助人更快地理解业务,还是在制造更多需要同步的边界?

默认全栈,除非有理由拆开

所以现在我更倾向于一个新的默认判断:

  • 如果只有一个主要 Web 端,优先产品层全栈。
  • 如果页面数据强依赖 UI 形态,优先产品层全栈。
  • 如果 API 主要服务自己的页面,而不是外部消费者,优先产品层全栈。
  • 如果团队规模还没大到需要强边界,优先产品层全栈。
  • 如果业务复杂了,先按业务域和平台能力拆,而不是先按前端和后端拆。

以后讨论架构时,不应该再先问“要不要前后端分离”,而应该先问:

这个业务有没有足够强的理由,把产品上下文拆开?

如果没有,前后端分离就不该再是默认选项。它不是先进性的象征,而是一种需要证明必要性的复杂度。