什么是Vertical Structure
feature-based structure
domain-based structure
vertical slice / vertical structure
前端里也常和 Feature-Sliced Design、DDD 风格组织 放在一起讨论
核心意思是:不要先按“技术类型”分目录,而是先按“业务能力”分目录。 这类做法在大型前端和 monorepo 里越来越常见。Nx 官方文章也明确把它和传统“按技术职责分层”的 horizontal approach 对比,建议围绕业务域来组织代码,并强调这样更清晰边界、更利于长期维护。
- 反对按类型(components/utils)组织代码
- 建议按功能/业务垂直划分
- 声称更利于 AI 工具理解和维护简述
简述
1. 什么叫“按类型组织” vs “按功能垂直组织”
按类型组织(horizontal)
src/
components/
hooks/
utils/
services/
types/
pages/
问题是,一个业务功能的代码会被拆散到很多地方。 比如“订单列表”功能,可能会分散在:
components/OrderCard.tsxhooks/useOrders.tsservices/orderApi.tsutils/orderFormat.tstypes/order.ts
这样做的坏处是:你想改一个功能,要到处找。
按功能/业务垂直组织(vertical)
src/
features/
order-list/
ui/
model/
api/
lib/
types/
checkout/
ui/
model/
api/
entities/
order/
product/
shared/
ui/
lib/
api/
这里“订单列表”相关代码尽量都放在 order-list/ 下面。 也就是:先看这是哪个业务,再看里面有哪些技术实现。
Feature-Sliced Design 官方文档也是这个方向:先按 slice(业务切片)组织,再在切片内部用 ui / model / api / lib 这些 segment 继续分。
2. 为什么有人反对纯 components/utils 这种组织方式
不是说 components/utils 完全错,而是它更适合:
- 小项目
- demo
- 业务很简单
- 团队人数少
- 生命周期短
一旦项目变大,这种结构会有几个典型问题。
第一,业务边界被打散
技术类型目录会把“同一个业务功能”的代码拆开。
开发者看到的是“组件、hook、工具函数”,而不是“支付、订单、登录、用户资料”。
这会导致:
- 改需求时,需要跨多个目录跳来跳去
- 新人很难快速理解“某个业务到底由哪些代码组成”
- 删除一个功能时,很难知道能删到哪里
Nx 也在讲这个点:从 layered/horizontal 走向 domain-oriented structure,目的是让代码围绕业务能力形成清晰边界,并且这些边界能相对独立演进。
第二,shared/utils 很容易变垃圾场
很多团队最后会出现:
utils/index.tscomponents/common/services/base/helpers/
表面上“复用”很多,实际上常常是:
- 谁都能往里塞
- 依赖方向混乱
- 很多工具其实只被一个业务使用
- 时间长了没人敢动
Feature-Sliced Design 专门强调要控制 shared 的范围,并通过公开 API 和依赖方向来避免“所有东西都互相 import”。
第三,跨团队协作时 ownership 不清楚
按业务垂直拆以后,通常更容易看出:
- 订单谁负责
- 支付谁负责
- 用户体系谁负责
Nx 文章里也提到,业务域边界往往会映射团队边界,这和 Conway 定律是相通的。
3. “Vertical Structure” 到底好在哪
好处 1:改一个需求时,影响面更集中
比如“优惠券在结算页展示逻辑要改”,你大概率先去:
features/checkout/
而不是满项目搜:
- components
- hooks
- services
- utils
- constants
这会明显降低“找代码”的成本。
好处 2:更容易做边界控制
垂直组织不是只换个目录名,它真正有价值的是:
- 同一个业务的内部实现尽量封装
- 外部只通过有限公开接口访问
- 依赖方向单向清晰
Nx 明确建议用项目/库边界和自动化规则来守住这些边界;FSD 也强调 slice 的 public API 和受控依赖。
好处 3:删除、迁移、拆分功能更容易
如果未来要把一个模块拆成子应用、微前端、独立包,垂直结构更容易迁走。
Nx 的文章就把这一点讲得很直接:先把单体应用按业务域 modularize,之后无论拆成多个 app 还是 microfrontend,成本都会小很多。
好处 4:更容易理解项目
更容易理解:
- 登录
- 支付
- 订单
- 个人中心
而不是先理解:
- hooks
- utils
- ui
- services
因为业务域本身就更贴近产品语言。
4. 为什么有人说“这更利于 AI 工具理解和维护”
这个说法有一定道理,但要说清楚:这是一个合理推断,不是已经被严格证明的通用定律。
像 Copilot、Cursor 这类工具,本质上都依赖:
- 代码上下文
- 文件结构
- 命名
- 边界信息
- 指令/文档
GitHub Copilot 官方文档明确说,它可以帮助理解代码库的内容、结构和功能,并且它的效果依赖上下文。GitHub 还专门有关于“为 Copilot 提供上下文”的文档。
Microsoft 的 Copilot 最佳实践也建议:给 AI 提供项目架构、模块边界和约定,这样它才能更好处理架构级改动。
Nx 也提到它在编辑器里给 AI 提供 workspace metadata,让模型获得更具体、更贴近项目边界的上下文。
所以,从原理上说:
- 如果目录就是业务边界
- 文件命名清晰
- import 关系干净
- 每个 feature 自包含
那 AI 更容易推断:
- 这个功能在哪
- 改动该落在哪
- 哪些文件相关
- 哪些依赖不该碰
这个推断是成立的。
“更利于 AI 理解”不等于“只要 vertical 就一定更强”。
AI 效果还很依赖:
- 命名是否清楚
- 是否有 README / ARCHITECTURE 文档
- 是否有模块边界约束
- 是否有生成器/规范
- 是否有大量历史烂代码
- 文件是不是过大
- 公共层是不是失控
换句话说,坏的 vertical structure,也可能比好的 type-based structure 更难让 AI 理解。
更准确的说法应该是:
垂直结构 + 清晰命名 + 稳定边界 + 明确约定,通常更适合 AI 工具在大项目里做理解、检索和局部修改。 但这更像“工程实践上的高概率优势”,不是绝对定律。
5. 来源依据
1)Nx:按业务域组织代码,强调边界、可维护性和演进性 Nx 官方文章明确对比了 horizontal 与 vertical/domain-oriented structure,并给出为什么业务域边界更清晰、更易维护。
2)Feature-Sliced Design: 前端 里很系统的一套 feature-first 方法论 它不是简单“建 feature 文件夹”,而是:
- 分层
- 分 slice
- 限制依赖方向
- 使用 public API 这些都是为了让前端随着业务增长还能稳定维护。
3)GitHub Copilot / Microsoft 文档: AI 依赖结构化上下文与架构信息 官方文档很明确:AI 对代码库的理解依赖结构、上下文、模块边界和项目级说明。