在 AI 时代重新思考架构 — 第 1 部分:仓库管理

发布: (2026年3月16日 GMT+8 14:24)
9 分钟阅读
原文: Dev.to

Source: Dev.to

请提供您希望翻译的正文内容,我将为您翻译成简体中文并保持原有的格式、Markdown 语法以及技术术语不变。

仓库管理 – 为什么单体仓库是合理的

关于 AI 如何快速加速原型制作的内容层出不穷——但中期可维护性同样值得关注。
(如果这篇文章只是一次性发布,提前致歉。)

我的前置结论

选择单体仓库。

什么是 Monorepo?

Monorepo 是在单一仓库中管理多个应用的实践。“多个应用”可以指以下任意情况:

  • 前端和后端共存
  • Service A 与 Service B 的全栈应用并排
  • 应用代码与共享库共存

关于微服务的简短说明

虽然在微服务的语境中有时会讨论 Monorepo,但我没有将两者结合的实际经验,所以此处不作讨论。我的直觉是,要充分利用 Monorepo,需要保持技术栈相对统一——这在某种程度上与微服务的目标相冲突。我描述的 Monorepo 风格可能并不适合微服务。

Source:

实用答案:Turborepo

Turborepo 已经成为 TypeScript 项目中 monorepo 设置的事实标准。虽然它在技术上定位为通用构建工具,但在实际使用中,当你采用 monorepo(或想要更智能的构建缓存)时,通常会选择它。

代表性目录结构(Web 前端 + 后端)

my-turborepo/
├── apps/
│   ├── web/                  # 前端应用(例如 Next.js)
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── api/                  # 后端应用(例如 Hono、Express)
│       ├── src/
│       ├── package.json
│       └── tsconfig.json
├── packages/
│   ├── ui/                   # 共享 UI 组件库
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── tsconfig/            # 共享 TypeScript 配置
│   │   ├── base.json
│   │   ├── nextjs.json
│   │   └── package.json
│   └── utils/                # 共享工具函数
│       ├── src/
│       ├── package.json
│       └── tsconfig.json
├── .claude/
│   ├── CLAUDE.md
│   └── skills/
├── .codex/
│   └── skills/
├── turbo.json
├── biome.json
├── package.json
├── pnpm-workspace.yaml
└── tsconfig.json
  • apps/ 保存各个独立的应用。
  • packages/ 保存共享代码——工具函数、UI 组件以及像 tsconfig 这样的配置文件。

你可以在没有 Turborepo 的情况下复制此布局,但 Turborepo 带来的实际价值在于:

  1. 读取每个 package.json
  2. 批量或并行运行构建和测试。
  3. 智能处理构建缓存——当构建时间开始成为瓶颈时,这一点优势尤为明显。

AI 时代的知识库管理

知识库只有在被实际引用时才有价值。要便于引用,知识必须彼此紧密相连。

使用 monorepo,克隆单个 GitHub 仓库即可在一个地方获取所有内容:

  • 应用代码
  • 开发文档
  • 代理技能(例如 Claude、Codex)

你可以想办法让 AI 识别多个仓库属于同一个项目,但何必费心?monorepo 免费为你提供了这种一致性。

常见异议与重新框定

“前端和后端只需要通过 API 合约进行通信——混合它们的上下文是没有必要的。”

在 AI 辅助编码的时代,优势来自能够让你看到全局并快速迭代的架构——而不是严格的上下文分离。

当 Monorepo 发光(尤其在 AI 时代开发中)

  1. 你的后端使用 TypeScript 编写

    • 混合技术栈(例如,前端使用 TypeScript,后端使用 Python)在技术上可以是 monorepo,但共享的 packages/ 会变成仅前端使用,价值被削弱。
    • 你还需要为两种不同的语言管理 lint、格式化和工具链。
    • 注意: Turborepo 围绕 TypeScript(以及 package.json 作为主要配置单元)构建,因此将技术栈统一到 TypeScript 是阻力最小的路径。
  2. 你的审查流程已适配 AI 辅助开发

    • 在使用 AI 编码的 monorepo 中,实现单个功能往往意味着 AI 同时编写前端 后端代码,一次性完成。Pull request 自然会体现端到端的实现。
    • 如果仍然坚持 AI 时代前的审查仪式,人类就会成为瓶颈。至少,需要整合 AI 辅助的代码审查;更广泛地重新思考 PR 工作流也是值得考虑的。

真实案例:Chronock

我的应用 Chronock 采用 monorepo 结构,使用 TypeScript 构建全栈。

chronock/
├── apps/
│   ├── chronock-app/          # Frontend (React + TanStack Start)
│   ├── chronock-backend/      # Backend (Bun + Connect RPC)
│   ├── chronock-book/         # Booking page (React + TanStack Start)
│   └── chronock-www/          # Marketing site (Astro)

├── packages/
│   ├── contract/              # Proto definitions & generated code
│   ├── i18n/                  # Internationalization utilities
│   └── typescript-config/     # Shared TypeScript config

├── specs/                     # Product specifications

├── .claude/
│   ├── CLAUDE.md
│   └── skills/
├── .codex/
│   └── skills/
├── biome.jsonc                # Linter / Formatter config
├── bunfig.toml                # Bun config
├── docker-compose.local.yml
├── package.json
└── turbo.json                 # Turborepo config

值得关注的几点

  • 营销站点(Astro)与主应用一起位于 monorepo 中,使整个产品——包括面向公众的站点——拥有唯一的真相来源。
  • 共享的合约、i18n 工具以及 TypeScript 配置集中在 packages/,从而减少重复。
  • 规格说明和 AI 代理技能定义(.claude/.codex/)紧邻其描述的代码,知识库可即时访问。

TL;DR

  • Monorepos 提供代码、文档和 AI‑agent 技能的唯一真实来源。
  • Turborepo 是面向 TypeScript 为中心的 monorepos 的首选工具,提供并行构建、智能缓存和统一工作流。
  • 将你的技术栈对齐到 TypeScript,并调整你的 review process 以适应 AI 辅助开发,从而获得最大的收益。

敬请期待下一篇,我们将深入探讨 AI‑first monorepos 的版本控制策略和 CI/CD 流水线。

概览

这使得诸如 “在网站上反映新功能信息”“检查最新实现与着陆页文案之间的不一致性” 之类的任务,自然地可以交给 AI 代理处理。

前端 ↔ 后端 通信

  • 使用 Connect RPC(Protocol Buffers)。
  • .proto 定义文件位于 packages/contract,这使得在单一位置管理接口定义并为前端和后端生成代码变得无缝。

仓库结构

  • 产品规格代理技能 位于同一个仓库。
  • 这种集中化使得编写代理更加高效——它们拥有所需的上下文,无需跨仓库跳转。

摘要

AI 时代的架构选择

  1. 将上下文集中在单体仓库中,并将其视为活的知识库。
  2. 将技术栈统一到 TypeScript 上——它在多方面都有回报。
  3. Pull‑request 问题不会自行解决;它需要专门的解决方案。

第一部分完结。

0 浏览
Back to Blog

相关文章

阅读更多 »