Loading...
Loading...
Compare original and translation side by side
"What does this code DO, not what TYPE of thing is it?"
「这段代码是做什么的,而不是它是什么类型的代码?」
src/
components/ ← all UI components mixed together
hooks/ ← all hooks mixed together
utils/ ← everything else
types/ ← all types
services/ ← all API callssrc/
components/ ← 所有UI组件混合存放
hooks/ ← 所有hooks混合存放
utils/ ← 其他所有工具类代码
types/ ← 所有类型定义
services/ ← 所有API调用src/
dashboard/ ← everything related to the dashboard
billing/ ← everything billing-related
auth/ ← everything auth-related
design-system/ ← truly generic, reusable across projects
shared/ ← shared business logic (not generic enough for design-system)src/
dashboard/ ← 所有与仪表盘相关的代码
billing/ ← 所有与账单相关的代码
auth/ ← 所有与认证相关的代码
design-system/ ← 真正通用、可跨项目复用的代码
shared/ ← 共享业务逻辑(通用性不足以归入design-system)1. Is it tied to a specific feature or domain?
YES → put it in that vertical (e.g. src/billing/)
│
└── Is it used by multiple features?
YES → does it contain business logic specific to this app?
YES → make it its own vertical or put in /shared
NO → put it in /design-system (or /lib)
NO → keep it private inside the feature vertical
2. Is it purely generic with zero business logic?
(could live in any project, any company)
YES → /design-system or /lib
3. Is it infrastructure / cross-cutting concern?
(logging, config, error handling, i18n, routing)
YES → /infrastructure or /core1. 它是否与特定功能或领域绑定?
是 → 放入对应的垂直文件夹(如src/billing/)
│
└── 它是否被多个功能使用?
是 → 它是否包含该应用特有的业务逻辑?
是 → 为其创建独立的垂直文件夹,或放入/shared
否 → 放入/design-system(或/lib)
否 → 保留在所属功能的垂直文件夹内,设为私有
2. 它是否是完全通用、无业务逻辑的代码?
(可在任意项目、任意公司中复用)
是 → /design-system 或 /lib
3. 它是否是基础设施/横切关注点?
(日志、配置、错误处理、i18n、路由)
是 → /infrastructure 或 /coresrc/billing/
billing-service.ts
billing-types.ts
billing-utils.ts
invoice-list.tsx (if frontend)
use-invoice.ts (if frontend)
invoice.test.tssrc/billing/
billing-service.ts
billing-types.ts
billing-utils.ts
invoice-list.tsx (如果是前端项目)
use-invoice.ts (如果是前端项目)
invoice.test.tsA feature vertical can only import from,shared, andinfrastructure. Never from another feature vertical.design-system
feature vertical → shared ✅
feature vertical → infrastructure ✅
feature vertical → design-system ✅
feature vertical → feature vertical ❌ lint error
shared → feature vertical ❌ lint error
design-system → anything ❌ lint error/shared功能垂直文件夹仅能从、shared和infrastructure导入代码。禁止从其他功能垂直文件夹导入。design-system
功能垂直文件夹 → shared ✅
功能垂直文件夹 → infrastructure ✅
功能垂直文件夹 → design-system ✅
功能垂直文件夹 → 功能垂直文件夹 ❌ Lint错误
shared → 功能垂直文件夹 ❌ Lint错误
design-system → 任意文件夹 ❌ Lint错误eslint-plugin-boundarieseslint-plugin-boundaries// eslint.config.js
import boundaries from "eslint-plugin-boundaries";
export default [
{
plugins: { boundaries },
settings: {
"boundaries/elements": [
{
type: "feature",
pattern: "src/!(shared|infrastructure|design-system)/*",
},
{ type: "shared", pattern: "src/shared/*" },
{ type: "infrastructure", pattern: "src/infrastructure/*" },
{ type: "design-system", pattern: "src/design-system/*" },
],
},
rules: {
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{
from: "feature",
allow: ["shared", "infrastructure", "design-system"],
},
{ from: "shared", allow: ["infrastructure", "design-system"] },
{ from: "infrastructure", allow: ["design-system"] },
{ from: "design-system", allow: [] },
],
},
],
},
},
];// eslint.config.js
import boundaries from "eslint-plugin-boundaries";
export default [
{
plugins: { boundaries },
settings: {
"boundaries/elements": [
{
type: "feature",
pattern: "src/!(shared|infrastructure|design-system)/*",
},
{ type: "shared", pattern: "src/shared/*" },
{ type: "infrastructure", pattern: "src/infrastructure/*" },
{ type: "design-system", pattern: "src/design-system/*" },
],
},
rules: {
"boundaries/element-types": [
"error",
{
default: "disallow",
rules: [
{
from: "feature",
allow: ["shared", "infrastructure", "design-system"],
},
{ from: "shared", allow: ["infrastructure", "design-system"] },
{ from: "infrastructure", allow: ["design-system"] },
{ from: "design-system", allow: [] },
],
},
],
},
},
];| Language | Tool |
|---|---|
| Python | |
| Go | |
| Rust | Cargo workspaces + |
| Java/Kotlin | Package-private + ArchUnit |
| Monorepo (any) | |
| 语言 | 工具 |
|---|---|
| Python | |
| Go | |
| Rust | Cargo workspaces + |
| Java/Kotlin | Package-private + ArchUnit |
| Monorepo (any) | |
| Code | Where it goes | Why |
|---|---|---|
| Generic button, input, modal | | No business logic, reusable anywhere |
| | Pure utility, zero business logic |
| | Business logic, even if used everywhere |
| | Shared but product-specific |
| | Depends: generic math → shared, billing-specific → billing |
| Error boundary wrapper | | Cross-cutting concern |
| 代码类型 | 存放位置 | 原因 |
|---|---|---|
| 通用按钮、输入框、弹窗 | | 无业务逻辑,可在任意项目复用 |
| | 纯工具类,无任何业务逻辑 |
| | 包含业务逻辑,即使被多处使用 |
| | 被共享但属于产品特有的功能 |
| | 取决于:通用数学逻辑 → shared,账单特有的逻辑 → billing |
| 错误边界包装器 | | 属于横切关注点 |
src/
auth/
auth-service.ts
auth-middleware.ts
auth-types.ts
auth.test.ts
users/
user-repository.ts
user-service.ts
user-types.ts
billing/
stripe-client.ts
billing-service.ts
billing-types.ts
shared/
pagination.ts
date-utils.ts
infrastructure/
logger.ts
config.ts
database.tssrc/
auth/
auth-service.ts
auth-middleware.ts
auth-types.ts
auth.test.ts
users/
user-repository.ts
user-service.ts
user-types.ts
billing/
stripe-client.ts
billing-service.ts
billing-types.ts
shared/
pagination.ts
date-utils.ts
infrastructure/
logger.ts
config.ts
database.tssrc/
auth/
__init__.py
service.py
middleware.py
models.py
test_auth.py
billing/
__init__.py
stripe.py
service.py
models.py
shared/
__init__.py
pagination.py
date_utils.py
infrastructure/
logger.py
config.py
database.pysrc/
auth/
__init__.py
service.py
middleware.py
models.py
test_auth.py
billing/
__init__.py
stripe.py
service.py
models.py
shared/
__init__.py
pagination.py
date_utils.py
infrastructure/
logger.py
config.py
database.pyinternal/
auth/
handler.go
service.go
repository.go
types.go
billing/
handler.go
service.go
stripe.go
shared/
pagination.go
timeutil.go
pkg/ ← truly public/reusable packages (like design-system)
middleware/
validator/internal/
auth/
handler.go
service.go
repository.go
types.go
billing/
handler.go
service.go
stripe.go
shared/
pagination.go
timeutil.go
pkg/ ← 真正公开/可复用的包(类似design-system)
middleware/
validator/src/
dashboard/
DashboardPage.tsx
dashboard-store.ts
use-dashboard-data.ts
dashboard-types.ts
widgets/
WidgetCard.tsx
use-widget.ts
widget-types.ts
widget-api.ts
design-system/
Button.tsx
Modal.tsx
useMediaQuery.ts
tokens.css
shared/
use-current-user.ts
format-currency.ts
infrastructure/
router.ts
i18n.ts
error-boundary.tsxsrc/
dashboard/
DashboardPage.tsx
dashboard-store.ts
use-dashboard-data.ts
dashboard-types.ts
widgets/
WidgetCard.tsx
use-widget.ts
widget-types.ts
widget-api.ts
design-system/
Button.tsx
Modal.tsx
useMediaQuery.ts
tokens.css
shared/
use-current-user.ts
format-currency.ts
infrastructure/
router.ts
i18n.ts
error-boundary.tsx"It's a hook/service/util, so it goes in /hooks /services /utils"
"I might need this elsewhere, so I'll put it in /shared"
"It's used in billing AND dashboard, so it goes in /shared"
/invoices/reports"is used in 10 places, so it's design-system material"useCurrentUser
src/features/billing/components/invoice/list/items/InvoiceItem.tsx
「这是一个hook/service/util,所以应该放在/hooks /services /utils里」
「我以后可能在其他地方用到它,所以放在/shared里」
「它在billing和dashboard中都被用到,所以放在/shared里」
「在10个地方被使用,所以应该归入design-system」useCurrentUser
src/features/billing/components/invoice/list/items/InvoiceItem.tsx
💡 Readfor a step-by-step migration plan.references/refactoring-guide.md
💡 查看获取分步迁移计划。references/refactoring-guide.md
| Question | Answer |
|---|---|
| Where does X go? | In the vertical that OWNS the functionality |
| What's a vertical? | A folder grouping code by what it does, not what it is |
| What goes in design-system? | Zero business logic, could exist in any project |
| What goes in shared? | Business logic used by multiple verticals |
| What goes in infrastructure? | Cross-cutting concerns (logging, config, DB) |
| How do verticals talk to each other? | Direct imports, but direction enforced by linter |
| Two verticals need to share code? | Extract to /shared — never create a linter exception |
| When to create a new vertical? | When a concept is big enough to own, or when shared code warrants it |
| 问题 | 答案 |
|---|---|
| X应该放在哪里? | 归入拥有该功能所有权的垂直文件夹 |
| 什么是垂直文件夹? | 按代码功能而非类型分组的文件夹 |
| 什么代码归入design-system? | 无业务逻辑,可在任意项目中复用 |
| 什么代码归入shared? | 被多个垂直文件夹使用的业务逻辑 |
| 什么代码归入infrastructure? | 横切关注点(日志、配置、DB) |
| 垂直文件夹之间如何交互? | 直接导入,但依赖方向由Linter强制管控 |
| 两个垂直文件夹需要共享代码? | 提取到/shared — 永远不要在Linter中添加例外规则 |
| 何时创建新的垂直文件夹? | 当一个概念足够独立需要单独维护,或共享代码规模足够时 |