@ultime/codecraft 0.0.0-stage → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,85 @@
1
+ # Gates(两层门禁)
2
+
3
+ > Codecraft 只内置“规范性通用门禁”;业务门禁由项目实现,Codecraft 负责编排与汇总。
4
+
5
+ ## 1. 两层模型
6
+
7
+ | 层 | 负责 | 例子 | 是否内置 |
8
+ |---|---|---|---|
9
+ | **Universal(通用)** | Codecraft | A2 / A4 / A11 / A17、密钥扫描、文档路径 | 是 |
10
+ | **Business(业务)** | 项目 | typecheck、单测、`kit:check`、契约测试、视觉回归、迁移检查 | 否,通过 config 调用 |
11
+
12
+ 原则:**通用规则内置,业务门禁编排。** 不复制项目门禁,避免第二套实现。
13
+
14
+ ## 2. Gate Contract(门禁契约)
15
+
16
+ 每个 gate 必须满足:
17
+
18
+ - 命令可直接运行,不需要交互;
19
+ - 退出码 `0` 成功、`1` 失败、`2` 用法 / 配置错误;
20
+ - stdout 输出结论,stderr 输出日志;
21
+ - 幂等;除非是 Apply 模式,否则只读;
22
+ - 有超时;默认 120s;
23
+ - 失败时输出下一步,不只输出堆栈。
24
+
25
+ ## 3. 配置
26
+
27
+ ```json
28
+ {
29
+ "pack": "auto",
30
+ "gates": [
31
+ { "name": "typecheck", "run": "pnpm typecheck", "timeoutMs": 120000 },
32
+ { "name": "kit", "run": "pnpm kit:check", "timeoutMs": 120000 }
33
+ ]
34
+ }
35
+ ```
36
+
37
+ - `pack`:`app` / `library` / `design-system` / `auto`;CLI `--pack` 优先。
38
+ - `gates`:数组;每项必须有 `run`,可选 `name` / `timeoutMs`。
39
+ - 配置文件默认 `codecraft.config.json`;可用 `--config` 指定。
40
+
41
+ ## 4. 按项目类型选门禁
42
+
43
+ | 项目类型 | 通用 | 业务 |
44
+ |---|---|---|
45
+ | **App** | A17 / A21(A4 人工评审) | typecheck、单测、e2e、视觉回归 |
46
+ | **Library** | A2 / A11 / A21 | build、单测、exports 检查、依赖对账 |
47
+ | **Design System** | A2 / A11 / A21 | `kit:check`、契约快照、视觉回归、a11y |
48
+ | **Docs** | A21 | 死链、三线头、交付白名单 |
49
+
50
+ ### 4.1 内置规则
51
+
52
+ | Rule | Pack | 检查 |
53
+ |---|---|---|
54
+ | A2 | library / design-system | 包不 import apps;相对路径不逃逸;workspace 依赖必须声明 |
55
+ | A11 | library / design-system | 生成物必须有“勿手改 / 派生”标记 |
56
+ | A17 | app | `pages / components / behavior` 不 import `external/` / `generated/` |
57
+ | A21 | all | 高置信密钥模式(私钥 / AWS / GitHub / Slack / API key) |
58
+ | A21 | design-system | 包内公开文档(README / USAGE / CHANGELOG / contract)不引用内部 `docs/` |
59
+
60
+ A4(单一收口)是结构判断,仍由 review / 项目门禁负责,不由静态扫描替代。
61
+
62
+ ## 5. 执行顺序
63
+
64
+ 1. 快速静态(内置规则、lint);
65
+ 2. typecheck;
66
+ 3. 单测;
67
+ 4. 契约 / 集成;
68
+ 5. 视觉 / e2e;
69
+ 6. 交付检查。
70
+
71
+ 失败策略:默认继续跑完再汇总;`--fail-fast` 遇到第一个失败即停止。
72
+
73
+ ## 6. 安全
74
+
75
+ - gates 是任意命令,只能来自可信配置。
76
+ - 执行前打印命令;`--ci` 下非交互。
77
+ - 不把密钥写进 config;用环境变量。
78
+ - 不让 gate 修改工作区,除非明确是 Apply 模式。
79
+
80
+ ## 7. Codecraft 的职责
81
+
82
+ - `check`:只跑内置规则。
83
+ - `audit`:内置规则 + config gates,汇总成一份报告。
84
+ - `plan`:只读升级计划;默认不跑 gates,`--with-gates` 才跑。
85
+ - `init`:dry-run 脚手架,只输出目录 / 文件 / 配置;不跑业务门禁。
@@ -0,0 +1,243 @@
1
+ # 设计模式工具箱(可选)
2
+
3
+ > 用途:AI 与人的「可选工具」,不是必背清单;按力(forces)选,不按名字选。
4
+ > 术语:English(中文)。
5
+ > 原则:**先有痛点,再选模式;没有代价说明的模式,不许用。**
6
+
7
+ ## 0. 选型四问
8
+
9
+ 1. **变化点是什么?** 创建、结构、行为、数据、交互、横切?
10
+ 2. **生命周期是什么?** 一次性、请求级、页面级、应用级?
11
+ 3. **有替换需求吗?** 多实现、多平台、mock、灰度?
12
+ 4. **代价是什么?** 文件数、缩进、运行时、认知、包体积?
13
+
14
+ > 四问答不出来,说明还不需要模式;先写直白代码(A14)。
15
+
16
+ ## 1. 创建型(Creational)
17
+
18
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
19
+ |---|---|---|---|---|
20
+ | Singleton(单例) | 保证一个类只有一个实例,并提供全局访问点 | 配置、日志、连接池、全局 store | 业务状态、可测试性要求高、多实例 | 全局可变状态、测试隔离差 |
21
+ | Factory Method(工厂方法) | 定义创建接口,让子类 / 实现决定实例化哪个类 | 多实现、按环境 / 平台选择 | 只有一个实现、创建逻辑简单 | 多一层间接 |
22
+ | Abstract Factory(抽象工厂) | 创建一组相关对象家族 | 多主题 / 多平台组件族 | 只创建一个对象、家族不稳定 | 抽象重、扩展成本高 |
23
+ | Builder(建造者) | 分步构建复杂对象 | 多参数、可选步骤、配置对象 | 参数少、对象简单 | 样板多 |
24
+ | Prototype(原型) | 通过克隆已有对象创建新对象 | 初始化昂贵、对象结构复杂 | 对象简单、需要独立构造 | 深浅拷贝陷阱 |
25
+
26
+ ## 2. 结构型(Structural)
27
+
28
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
29
+ |---|---|---|---|---|
30
+ | Adapter(适配器) | 把外部接口转成内部统一接口 | 多平台请求 / 存储 / 路由 / 导出 | 只有一个实现且不会换 | 多一层映射、能力差异被抹平 |
31
+ | Bridge(桥接) | 抽象与实现分离,各自独立变化 | 多维度变化(平台 × 主题) | 只有一个维度 | 抽象层增加 |
32
+ | Composite(组合) | 树形结构,叶子与容器同一接口 | 菜单、组件树、文件树、槽位 | 扁平列表、层级不稳定 | 递归、调试深 |
33
+ | Decorator(装饰器) | 动态给对象加职责,不改进原对象 | 加日志 / 权限 / 缓存 / 重试 | 需要改内部结构、顺序敏感 | 包装层多、调试跳转多 |
34
+ | Facade(外观) | 给复杂子系统一个简单入口 | 请求层、SDK 封装、跨模块流程 | 子系统简单、入口会变上帝对象 | 门面膨胀、隐藏能力 |
35
+ | Flyweight(享元) | 共享内在状态,减少对象数量 | 图标 / 字体 / 大列表、缓存 | 状态差异大、对象少 | 共享状态管理复杂 |
36
+ | Proxy(代理) | 用代理控制对原对象的访问 | 懒加载、权限、缓存、响应式 | 直接访问更简单、无控制需求 | 多一层、性能开销 |
37
+
38
+ ## 3. 行为型(Behavioral)
39
+
40
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
41
+ |---|---|---|---|---|
42
+ | Chain of Responsibility(责任链) | 请求沿处理器链传递,直到被处理 | 中间件、拦截器、审批流 | 处理顺序不重要、链短 | 链路难追踪、可能无人处理 |
43
+ | Command(命令) | 把请求封装成对象,可排队 / 撤销 / 重放 | 撤销重做、patch、宏、队列 | 一次性操作、无撤销需求 | 对象多、序列化成本 |
44
+ | Interpreter(解释器) | 为语言定义文法并解释句子 | DSL、规则引擎、查询表达式 | 文法简单、只一种规则 | 类爆炸、性能 |
45
+ | Iterator(迭代器) | 顺序访问集合,不暴露内部结构 | 分页、游标、树遍历 | 直接数组访问足够 | 多一层抽象 |
46
+ | Mediator(中介者) | 用中介集中对象间通信 | 复杂表单联动、组件通信 | 对象少、直接通信更清晰 | 中介变上帝对象 |
47
+ | Memento(备忘录) | 捕获并恢复对象状态 | 撤销、快照、草稿 | 状态大、无恢复需求 | 内存、序列化 |
48
+ | Observer(观察者) | 发布者通知订阅者 | store subscribe、事件、跨组件通知 | 简单父子通信、事件链短 | 泄漏、顺序 / 异常、事件意大利面 |
49
+ | State(状态) | 行为随状态改变,状态是一等类型 | 异步、互斥状态、多步流程 | 纯视觉开关、无守卫 | 样板、状态爆炸 |
50
+ | Strategy(策略) | 可互换算法,运行时按键选择 | 多算法 / 多渠道 / 多导出 | 分支签名不同、只有 2–3 个局部分支 | 表丢穷尽性、调试多一跳 |
51
+ | Template Method(模板方法) | 骨架固定,步骤由子类 / 回调实现 | 流程骨架、生命周期钩子 | 步骤差异大、流程常变 | 继承耦合、难组合 |
52
+ | Visitor(访问者) | 在不改对象结构的前提下加操作 | AST、报表、树遍历 | 结构常变、操作少 | 双分派、理解成本 |
53
+
54
+ ## 4. 函数式与 JS/TS 惯用(Functional / JS)
55
+
56
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
57
+ |---|---|---|---|---|
58
+ | Higher-Order Function(高阶函数) | 接收或返回函数 | 回调、装饰、策略注入 | 简单直接调用 | 调试栈深 |
59
+ | Function Composition(函数组合) | 把小函数组合成大函数 | 数据管道、转换链 | 步骤有副作用、顺序敏感 | 错误定位难 |
60
+ | Currying(柯里化) | 多参函数转成一元函数链 | 配置复用、部分应用 | 参数固定、可读性优先 | 调用形式陌生 |
61
+ | Partial Application(偏应用) | 固定部分参数,返回新函数 | 复用配置、事件处理 | 简单调用 | 额外函数 |
62
+ | Memoization(记忆化) | 缓存纯函数结果 | 昂贵计算、重复查询 | 结果易变、内存敏感 | 缓存失效、内存 |
63
+ | Lazy Evaluation(惰性求值) | 需要时才计算 | 大列表、昂贵初始化 | 结果马上要用 | 时机难追踪 |
64
+ | Immutable Data(不可变数据) | 不修改原数据,返回新数据 | 状态更新、撤销、并发 | 大对象高频更新 | 拷贝成本 |
65
+ | Lens(透镜) | 可组合的嵌套 getter / setter | 深层状态更新 | 浅层对象 | 概念成本 |
66
+ | Monad(单子) | 带上下文的链式计算 | 可选值 / 错误 / 异步链 | 普通同步代码 | 学习成本高(前端少用) |
67
+
68
+ ## 5. 前端与 UI(Frontend / UI)
69
+
70
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
71
+ |---|---|---|---|---|
72
+ | Container / Presentational(容器 / 展示) | 容器取数,展示只渲染 | 页面与纯展示分离 | 组件很小、取数简单 | 文件多 |
73
+ | Higher-Order Component(高阶组件) | 函数接收组件返回新组件 | 横切能力(权限 / 埋点) | Hooks 可解决、层级多 | 嵌套地狱、props 冲突 |
74
+ | Render Props(渲染属性) | 用函数 prop 决定渲染 | 共享有状态逻辑 | Hooks 可解决 | 嵌套、可读性 |
75
+ | Hooks / Composables(钩子 / 组合式函数) | 复用有状态逻辑 | 取数、表单、分页、订阅 | 纯函数足够、逻辑简单 | 规则约束、闭包陷阱 |
76
+ | Provider / Inject(提供 / 注入) | 跨层级传递依赖 | 主题、i18n、权限、弹窗 | 层级浅、props 清晰 | 来源难追踪 |
77
+ | Compound Components(复合组件) | 父子组件共享隐式状态 | Tabs、Select、Menu | 结构简单、无共享状态 | 隐式契约 |
78
+ | Headless Components(无头组件) | 只给状态与行为,不给样式 | 设计系统、跨端 UI | 一次性页面 | 抽象成本 |
79
+ | Controller(控制器) | 把 UI 逻辑从视图抽出 | 复杂页面、可测逻辑 | 简单页面 | 多一层 |
80
+ | State Machine(状态机) | 显式状态 + 事件 + 转移 | 异步、互斥、多步流程 | 纯视觉开关 | 样板、状态爆炸 |
81
+ | Reducer(归约器) | `(state, action) => state` | 可预测状态更新 | 简单局部状态 | 样板 |
82
+ | Store(状态仓库) | 集中状态 + 订阅 | 跨页面共享、持久化 | 局部状态 | 全局化、耦合 |
83
+ | Event Bus / Pub-Sub(事件总线 / 发布订阅) | 全局发布订阅 | 跨模块解耦 | 可追踪性要求高 | 意大利面、泄漏 |
84
+
85
+ ## 6. 数据与韧性(Data / Resilience)
86
+
87
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
88
+ |---|---|---|---|---|
89
+ | Repository(仓储) | 集合式数据访问,隔离存储细节 | API 模块、缓存、离线、多数据源 | 一次性请求、纯展示 | 抽象泄漏、分页 / 缓存语义 |
90
+ | Optimistic Update(乐观更新) | 先改本地,失败回滚 | 点赞、收藏、低风险写操作 | 金额 / 权限 / 强一致 | 回滚与冲突处理 |
91
+ | Cache-Aside(旁路缓存) | 先查缓存,未命中再加载 | 读多写少、配置 / 字典 | 强一致、频繁写 | 失效策略 |
92
+ | Stale-While-Revalidate(过期重验) | 先返回旧数据,再后台刷新 | 列表、详情、弱实时 | 强一致、首次必须最新 | 数据短暂过期 |
93
+ | Circuit Breaker(熔断) | 连续失败后暂停调用,半开探测 | 第三方 API、不稳定下游 | 本地纯函数 | 状态与阈值 |
94
+ | Retry / Backoff(重试 / 退避) | 失败后延迟重试 | 网络抖动、幂等请求 | 非幂等、确定性失败 | 放大流量、延迟 |
95
+ | Feature Flag(特性开关) | 运行时开关功能 | 灰度、AB、回滚 | 永久配置、无开关治理 | 分支膨胀、技术债 |
96
+
97
+ ## 7. 架构(Architecture)
98
+
99
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
100
+ |---|---|---|---|---|
101
+ | MVC(模型-视图-控制器) | Model / View / Controller 分工 | 简单–中型应用、传统框架 | 复杂状态、强测试 | 规模化难 |
102
+ | MVP(模型-视图-展示器) | View 被动,Presenter 承担逻辑 | 需要可测展示逻辑 | 简单页面 | 样板多 |
103
+ | MVVM(模型-视图-视图模型) | ViewModel 暴露状态,View 自动绑定 | 响应式框架、复杂 UI | 无响应式系统 | 绑定魔法、调试 |
104
+ | Flux / Redux(单向数据流) | 单向数据流 + 纯 reducer | 可预测全局状态、时间旅行 | 局部状态、小应用 | 样板、全局化 |
105
+ | Clean Architecture(整洁架构) | 依赖向内,核心独立 | 长期、复杂业务 | 小工具、脚本 | 层多、映射多 |
106
+ | Hexagonal Architecture(六边形架构) | 端口与适配器,核心不知外部 | 多外部系统、可替换 IO | 单一 IO、简单应用 | 端口 ceremony |
107
+ | Vertical Slice(垂直切片) | 按功能切竖片 | 功能多、变更按 feature | 共享逻辑多、强横切 | 跨片重复 |
108
+
109
+ ## 8. 并发与数据访问(Concurrency / Data Access)
110
+
111
+ | 模式(中英) | 一句话 | 何时用 | 何时不用 | 代价 |
112
+ |---|---|---|---|---|
113
+ | Unit of Work(工作单元) | 跟踪变更,一次提交 | 多写操作需原子性 | 单条写、无事务 | 状态跟踪复杂 |
114
+ | Data Mapper(数据映射器) | 在对象与存储之间映射 | 领域模型与存储解耦 | 简单 CRUD | 映射代码多 |
115
+ | Active Record(活动记录) | 对象自带 CRUD | 简单 CRUD、小项目 | 复杂领域、测试隔离 | 领域与存储耦合 |
116
+ | Identity Map(身份映射) | 同一行只保留一个对象 | 避免重复实例、一致性 | 无对象身份需求 | 内存、生命周期 |
117
+ | Actor(参与者) | 独立状态 + 邮箱,串行处理消息 | 并发、隔离、分布式 | 简单同步逻辑 | 消息协议、调试 |
118
+ | Worker / Queue(工作线程 / 队列) | 后台任务队列 | 重任务、异步、削峰 | 即时轻任务 | 运维、重试、幂等 |
119
+
120
+ ## 9. 反模式(Anti-patterns)
121
+
122
+ | 反模式(中英) | 表现 | 后果 | 替代 |
123
+ |---|---|---|---|
124
+ | God Object(上帝对象) | 一个类 / 模块什么都知道 | 难改、难测、冲突多 | 按职责拆 |
125
+ | Anemic Domain Model(贫血领域模型) | 数据与行为分离,逻辑散在 service | 规则重复、边界模糊 | 把规则放回领域 / 纯 core |
126
+ | Event Bus Spaghetti(事件总线意大利面) | 全局事件到处发 / 收 | 难追踪、泄漏、顺序问题 | 显式调用 / 状态机 |
127
+ | HOC Hell(高阶组件地狱) | 多层包装、props 改名 | 调试难、类型难 | Hooks / Composables |
128
+ | Inheritance Hell(继承地狱) | 深继承、覆写链 | 脆弱、难组合 | 组合优先 |
129
+ | Prop Drilling(属性钻透) | 层层传 props | 中间层污染 | Provider / Inject / Store |
130
+ | Global Singleton(全局单例) | 全局可变状态 | 测试隔离差、隐式依赖 | 显式传参 / 依赖注入 |
131
+ | Over-abstraction(过度抽象) | 为未来造层、造 port | 认知成本、文件多 | 等第二个消费方 |
132
+ | Golden Hammer(金锤子) | 所有问题都用同一模式 | 不适配、变形 | 按力选型 |
133
+
134
+ ## 10. 八个深潜
135
+
136
+ ### 10.1 Strategy(策略)
137
+
138
+ - **一句话**:把可互换的算法抽成同一签名的函数表,运行时按键选择。
139
+ - **何时用**:多算法 / 多渠道 / 多导出,分支签名一致。
140
+ - **何时不用**:分支签名不同、只有 2–3 个局部分支。
141
+ - **代价**:表丢穷尽性;键与实现会漂移;调试多一跳。
142
+ - **形态**:
143
+
144
+ ```ts
145
+ const fetchers = { a: fetchA, b: fetchB } satisfies Record<Kind, Fetcher>
146
+ const fetcher = fetchers[kind]
147
+ ```
148
+
149
+ - **反例**:两个分支返回形状完全不同,还硬做成函数表。
150
+
151
+ ### 10.2 State(状态)/ State Machine(状态机)
152
+
153
+ - **一句话**:状态是一等类型,事件驱动转移,非法状态不可表示。
154
+ - **何时用**:异步、互斥状态、多步流程、上传 / 支付 / 鉴权。
155
+ - **何时不用**:纯视觉开关、无异步 / 无守卫 / 无动画。
156
+ - **代价**:样板;状态爆炸;状态机库是运行时依赖。
157
+ - **形态**:discriminated union(可辨识联合)+ reducer;需要层级 / 并行 / 取消时再上库。
158
+ - **反例**:`loading && error && data` 同时为真。
159
+
160
+ ### 10.3 Adapter(适配器)
161
+
162
+ - **一句话**:把不同外部接口转成统一内部接口。
163
+ - **何时用**:多平台请求 / 存储 / 路由 / 设计 token 出口。
164
+ - **何时不用**:只有一个实现且不会换。
165
+ - **代价**:多一层映射;外部能力差异被抹平。
166
+ - **形态**:一个内部接口 + 每平台一个实现;选择在入口一次完成。
167
+ - **反例**:为每个函数都包一层 adapter。
168
+
169
+ ### 10.4 Facade(外观)
170
+
171
+ - **一句话**:给复杂子系统一个简单入口。
172
+ - **何时用**:请求层、SDK 封装、跨模块流程。
173
+ - **何时不用**:子系统本身简单;入口会变上帝对象。
174
+ - **代价**:门面膨胀;隐藏能力。
175
+ - **形态**:门面只编排,规则留在子系统;门面不写业务分支。
176
+ - **反例**:Facade 里塞业务分支。
177
+
178
+ ### 10.5 Observer(观察者)
179
+
180
+ - **一句话**:发布者维护订阅者列表,状态变化时通知。
181
+ - **何时用**:store subscribe、事件、跨组件通知。
182
+ - **何时不用**:简单父子通信、事件链短。
183
+ - **代价**:内存泄漏、顺序 / 异常、事件意大利面。
184
+ - **形态**:订阅返回取消函数;使用方负责释放。
185
+ - **反例**:全局事件总线,谁都能发。
186
+
187
+ ### 10.6 Command(命令)
188
+
189
+ - **一句话**:把操作封装成对象,可排队、撤销、重放。
190
+ - **何时用**:undo / redo、patch、宏、队列。
191
+ - **何时不用**:一次性操作、无撤销需求。
192
+ - **代价**:对象多、序列化、状态一致性。
193
+ - **形态**:命令 = 数据 + 执行 + 逆操作;历史栈只存命令数据。
194
+ - **反例**:为每个按钮造一个 Command 类。
195
+
196
+ ### 10.7 Composite(组合)
197
+
198
+ - **一句话**:树形结构,叶子与容器同一接口。
199
+ - **何时用**:菜单、组件树、布局槽位、文件树。
200
+ - **何时不用**:扁平列表、层级不稳定。
201
+ - **代价**:递归、父子边界模糊、调试深。
202
+ - **形态**:节点统一 `children` 契约;遍历与渲染分离。
203
+ - **反例**:为两层结构造 Composite。
204
+
205
+ ### 10.8 Repository(仓储)
206
+
207
+ - **一句话**:把数据访问封装成集合式接口,隔离存储细节。
208
+ - **何时用**:API 模块、缓存、离线、多数据源。
209
+ - **何时不用**:纯展示组件、一次性请求。
210
+ - **代价**:抽象泄漏、分页 / 缓存语义、过度封装。
211
+ - **形态**:仓储只做取数 / 归一,不写 UI 逻辑;分页与缓存语义在契约里写清。
212
+ - **反例**:Repository 里写 UI 逻辑。
213
+
214
+ ## 11. 选型速查(力 → 模式)
215
+
216
+ | 遇到的力 | 优先模式 |
217
+ |---|---|
218
+ | 运行时选算法 / 渠道 | Strategy(策略) |
219
+ | 状态互斥 / 异步 / 多步 | State(状态)/ State Machine(状态机) |
220
+ | 多平台 / 多实现 / 多出口 | Adapter(适配器)/ Ports & Adapters(端口与适配器) |
221
+ | 给对象动态加能力 | Decorator(装饰器) |
222
+ | 简化复杂子系统 | Facade(外观) |
223
+ | 撤销 / 重放 / 队列 | Command(命令)+ Memento(备忘录) |
224
+ | 解耦发布 / 订阅 | Observer(观察者)/ Pub-Sub(发布订阅) |
225
+ | 统一数据访问 | Repository(仓储) |
226
+ | 树形结构 | Composite(组合) |
227
+ | 延迟创建 / 复用对象 | Flyweight(享元)/ Singleton(单例) |
228
+ | 调用前后加逻辑 | Proxy(代理)/ Decorator(装饰器)/ Middleware(中间件) |
229
+ | 多步骤构建 | Builder(建造者) |
230
+ | 跨组件共享 | Provider / Inject(提供 / 注入)/ Store(状态仓库) |
231
+ | UI 逻辑与渲染分离 | Headless(无头)/ Controller(控制器)/ State Machine(状态机) |
232
+ | 按功能组织 | Vertical Slice(垂直切片) |
233
+ | 按技术职责组织 | Layered(分层)/ MVC / MVVM |
234
+
235
+ ## 12. AI 使用契约
236
+
237
+ - **先答四问**:变化点 / 生命周期 / 替换需求 / 代价;答不出就不许上模式。
238
+ - **输出必须写三件**:为什么选它、替代方案是什么、代价是什么。
239
+ - **不许用模式名当装饰**:没有代码结构支撑的「策略模式」不算。
240
+ - **不许无说明引运行时依赖**:先说明体积与必要性。
241
+ - **优先语言原生**:能用函数、联合类型、模块解决的,不造类层次。
242
+ - **每个模式附一个反例**:没有反例,说明还没理解边界。
243
+ - **同族同形**:同一代码族只用一种实现方式;换模式要写迁移理由(A1)。
@@ -0,0 +1,263 @@
1
+ # 架构设计方法(可选)
2
+
3
+ > 用途:系统级 / 模块级 / 演进级的决策方法;代码级模式见 `05-patterns.md`。
4
+ > 原则:**方法先于模式;约束先于图;边界先于抽象。**
5
+ > 术语:English(中文)。
6
+
7
+ ## 0. 先分开六个词
8
+
9
+ | 词 | 一句话 | 产出 |
10
+ |---|---|---|
11
+ | **Architecture(架构)** | 系统的结构 + 约束 + 决策理由 | 模块、依赖方向、public API、ADR、验证规则 |
12
+ | **Architecture Style(架构风格)** | 可复用的结构方案 | 分层、模块化单体、六边形、事件驱动… |
13
+ | **Design Pattern(设计模式)** | 代码级解法 | Strategy、Adapter、State…(见 `05-patterns.md`) |
14
+ | **Method(方法)** | 产出架构的过程 | 目标 → 质量场景 → 边界 → 规则 → 验证 |
15
+ | **View(视图)** | 面向某类关注点的投影 | Context / Container / Runtime / Deployment |
16
+ | **Tactic(战术)** | 为某个质量属性做的局部决策 | 缓存、限流、重试、冗余 |
17
+
18
+ > **Fitness Function(适应度函数)**:把架构约束写成可自动执行的检查(lint / test / 指标 / 预算)。
19
+
20
+ ### 0.1 什么才算架构决策
21
+
22
+ 同时满足三条才值得记录:
23
+
24
+ 1. **难逆转**:回退成本高(数据模型、部署单元、公共 API、技术栈)。
25
+ 2. **影响面大**:跨模块、跨团队、跨生命周期。
26
+ 3. **有取舍**:不是唯一解,换方案会得到不同代价。
27
+
28
+ 命名、目录微调、单个组件实现是规范问题,不是架构决策。
29
+
30
+ ### 0.2 架构的第一目标
31
+
32
+ - **让变化便宜**:改一个需求最多动一族(M4)。
33
+ - **让错误可见**:依赖方向、边界、失败模式能被检查(M5)。
34
+ - **让新人 / AI 可导航**:命名、目录、public API 能读出骨架(A13 / A16)。
35
+
36
+ ## 1. 三个档位
37
+
38
+ | 档位 | 触发条件 | 产物 | 方法 |
39
+ |---|---|---|---|
40
+ | **L0** 单文件 / 原型 / 脚本 | 需求探索期、一次性 | 目录约定 + 一张上下文草图 | 命名 + 边界常识 |
41
+ | **L1** 多页应用 / 小团队 | 要交付、维护 3 个月以上 | Context + Container + 模块边界 + 依赖规则 + 3–5 条 ADR + 关键 fitness | 轻量七步法 |
42
+ | **L2** 多团队 / 长期 / 强合规 | 多团队、独立部署、强质量属性 | 完整文档骨架 + 质量场景 + 上下文映射 + 全量 fitness + 演进路线 | 质量属性驱动 + 场景评估 |
43
+
44
+ > 默认 L0;有真实触发才升级(A14 / A18)。**档位不是能力等级,是工程量。**
45
+
46
+ ## 2. 轻量七步法
47
+
48
+ 1. **写一页目标与约束**:3 条质量目标、3 条硬约束、1 条「不做什么」。
49
+ 2. **画两张图**:System Context + Container;不画类图。
50
+ 3. **列变化轴**:业务、平台、团队、部署、数据;每条写「多久变一次、谁推动」。
51
+ 4. **切边界**:先按变化轴,再按数据所有权,最后按团队;用「删掉它谁会塌」检验。
52
+ 5. **定依赖规则**:谁能 import 谁、public API 在哪、禁止环 / 跨层;写成 lint / CI。
53
+ 6. **选模式**:只对已经疼的力选;一次只引入一个;写替代方案与退出条件。
54
+ 7. **记录与验证**:ADR(难逆转的)+ fitness function(能自动的)+ 定期场景走查。
55
+
56
+ **不要做**:
57
+
58
+ - 需求未稳定就定最终架构;先用 walking skeleton(可走通的骨架)验证。
59
+ - 只有一个消费方就抽公共层 / 公共包。
60
+ - 团队 < 5 人、部署不痛,就上微服务 / 微前端。
61
+ - 没有自动验证手段,却写一堆「必须遵守」的规则。
62
+ - 为「以后可能」预建层。
63
+
64
+ ## 3. 图:最小集
65
+
66
+ | 视图 | 回答 | 读者 | 不该出现 |
67
+ |---|---|---|---|
68
+ | **System Context** | 系统是什么、谁用、连哪些外部系统 | 所有人 | 技术选型、内部模块 |
69
+ | **Container** | 有哪些进程 / 应用 / 存储,怎么通信 | 技术、运维 | 类、函数 |
70
+ | **Component** | 容器内有哪些组件、职责、依赖 | 开发 | 具体实现 |
71
+ | **Code** | 类 / 接口级 | 开发(按需) | 通常不画,交给 IDE |
72
+
73
+ - 多数项目 **Context + Container 足够**;Component 只在边界说不清时画。
74
+ - 图要**跟着代码走**:能由图生成就不手绘;不能生成就在 CI 里比对。
75
+ - 图不覆盖质量属性与决策理由,所以必须配 ADR。
76
+
77
+ ## 4. 切边界
78
+
79
+ ### 4.1 三个切法,按顺序
80
+
81
+ 1. **变化轴**:什么一起变、什么独立变。
82
+ 2. **数据所有权**:谁是唯一写入者;数据边界比代码边界难改。
83
+ 3. **团队边界**:谁维护、发布节奏是否一致(Conway)。
84
+
85
+ > 上下文边界 ≠ 团队边界 ≠ 部署边界;三者可以不同,但要对齐考虑。
86
+
87
+ ### 4.2 边界是否成立(五问)
88
+
89
+ - 删掉这个模块,谁会塌?(M1)
90
+ - 改一个需求,要动几个模块?> 3 个就检查切分。(M4)
91
+ - 核心逻辑能否不启动框架就测试?(A2)
92
+ - 有没有循环依赖?有环 = 边界没切好。
93
+ - 数据归谁?谁是唯一写入者?
94
+
95
+ ### 4.3 前端默认结构
96
+
97
+ ```text
98
+ src/
99
+ app/ 组合根:路由、provider、全局错误、启动
100
+ pages/ 路由级页面(薄)
101
+ features/ 业务能力(垂直切片:ui + model + api)
102
+ entities/ 领域实体(可选)
103
+ shared/ ui 原语、lib、api 客户端、config、types
104
+ ```
105
+
106
+ - 依赖只能向下;同层不互相 import;跨模块只走 public API。
107
+ - `shared/api` + adapter + interceptors 是承重墙,不塞进 feature。
108
+ - server state 与 client state 分开:server state 用 query 层;client state 用 store / 状态机。
109
+ - 测试分层:纯 core 单测 → feature 行为测试 → 页面 smoke → API 契约测试。
110
+
111
+ ### 4.4 上下文关系(选型)
112
+
113
+ | 关系 | 一句话 | 代价 |
114
+ |---|---|---|
115
+ | Partnership(伙伴) | 两个上下文同生共死 | 协调成本高 |
116
+ | Shared Kernel(共享内核) | 共享一小块稳定模型 | 一改全动 |
117
+ | Customer-Supplier(客户-供应商) | 下游提需求,上游排期 | 上游可能不响应 |
118
+ | Conformist(遵奉者) | 下游直接遵从上游模型 | 下游失去表达力 |
119
+ | Anti-Corruption Layer(防腐层) | 下游加翻译层 | 多一层映射 |
120
+ | Open Host Service(开放主机服务) | 上游提供稳定公开协议 | 协议治理 |
121
+ | Separate Ways(各行其道) | 不集成 | 重复建设 |
122
+
123
+ ## 5. 依赖规则与 fitness function
124
+
125
+ > 先有约束,再有检查;不要为了工具造规则。规则**少而硬**:10 条能执行的,胜过 50 条写在文档里的。
126
+
127
+ | 约束 | 检查方式 |
128
+ |---|---|
129
+ | 依赖方向:核心不 import 上层 | dependency-cruiser / eslint boundaries |
130
+ | 分层:页面不直接调 API;UI 不 import 数据层 | `no-restricted-imports` |
131
+ | 公共 API:只能从入口导入,禁止深路径 | package `exports` + lint |
132
+ | 无环 | 依赖图检查 |
133
+ | 体积预算:首屏 / 单路由 chunk | size-limit / bundlesize |
134
+ | 性能预算:LCP / INP / CLS | Lighthouse CI |
135
+ | 契约:schema diff / consumer-driven | 契约测试 |
136
+ | 安全:依赖漏洞 / 密钥 / CSP | SCA + secret scanning |
137
+
138
+ - 拒绝用 `eslint-disable` 大面积绕过;例外必须登记(A10)。
139
+ - 架构腐烂信号:规则被大量禁用、例外失控、图与代码不一致。
140
+
141
+ ## 6. 架构模式速查
142
+
143
+ ### 6.1 组织形态
144
+
145
+ | 模式 | 一句话 | 何时用 | 何时不用 | 代价 |
146
+ |---|---|---|---|---|
147
+ | **Layered**(分层) | 按技术职责分层 | 职责清晰、传统应用 | 变化按 feature 走 | 层多、易千层饼 |
148
+ | **Feature-first**(按功能) | 顶层按业务能力切 | 业务变化快 | 强共享 / 强横切 | 跨 feature 重复 |
149
+ | **Vertical Slice**(垂直切片) | 一个功能从 UI 到数据一条竖片 | 功能独立 | 强事务、共享多 | 跨片重复 |
150
+ | **Modular Monolith**(模块化单体) | 一个部署单元,内部强边界 | 小团队、边界可稳定 | 需独立扩缩容 | 边界靠纪律 / lint |
151
+ | **Microservices**(微服务) | 独立部署、独立数据 | 多团队、独立扩缩容 | 小团队、事务复杂 | 分布式事务、运维 |
152
+ | **Micro-frontend**(微前端) | 前端按团队独立发布 | 多团队独立发布 | 单团队、组件复用 | 运行时 / 样式隔离 |
153
+ | **Microkernel / Plugin**(微内核 / 插件) | 核心最小,能力靠插件 | 多品牌、多平台 | 无插件生态 | 插件契约、版本治理 |
154
+
155
+ **默认**:个人 / 小团队 / 单产品 → 模块化单体 + feature-first(或垂直切片);只有「独立发布 / 独立团队 / 独立扩缩容」真实存在时,才拆微服务或微前端。
156
+
157
+ ### 6.2 边界与依赖
158
+
159
+ | 模式 | 一句话 | 适用力 | 代价 |
160
+ |---|---|---|---|
161
+ | **Clean Architecture**(整洁架构) | 依赖向内 | 长期、复杂业务 | 层多、映射多 |
162
+ | **Hexagonal**(六边形 / 端口与适配器) | 核心定义端口,外部用适配器 | 多外部系统、可替换 IO | 端口 ceremony |
163
+ | **Screaming Architecture**(会尖叫的架构) | 目录先喊业务,不喊框架 | 新人要一眼看懂 | 需要团队共识 |
164
+ | **BFF**(前端专属后端) | 每个前端一个聚合层 | 多端差异大 | 多一个服务 |
165
+ | **ACL**(防腐层) | 边界翻译外部模型 | 外部模型脏 / 会变 | 映射代码 |
166
+ | **Composition Root**(组合根) | 入口集中组装依赖 | 需要可测试、可替换 | 集中点易膨胀 |
167
+
168
+ ### 6.3 数据与一致性
169
+
170
+ | 模式 | 一句话 | 何时用 | 代价 |
171
+ |---|---|---|---|
172
+ | **Database per Service**(每服务一库) | 服务独占数据 | 微服务 | 跨服务查询复杂 |
173
+ | **Saga**(长事务) | 本地事务 + 补偿 | 跨服务流程 | 补偿逻辑、幂等 |
174
+ | **Transactional Outbox**(事务性发件箱) | 业务数据与事件同事务落库 | 要可靠发事件 | 投递器、去重 |
175
+ | **CQRS**(命令查询分离) | 读写模型分开 | 读写差异大 | 双模型、延迟 |
176
+ | **Event Sourcing**(事件溯源) | 存事件流,状态重放 | 审计、可回放 | 事件版本、存储 |
177
+ | **Idempotency Key**(幂等键) | 重复请求结果一致 | 重试、支付 | 键管理 |
178
+
179
+ > 先定「谁是数据的唯一写入者」,再谈模块 / 服务。微服务的第一道裂缝通常是共享数据库。
180
+
181
+ ### 6.4 演进
182
+
183
+ | 模式 | 一句话 | 何时用 | 代价 |
184
+ |---|---|---|---|
185
+ | **Strangler Fig**(绞杀者) | 新系统逐步包住旧系统 | 遗留迁移 | 双系统并存 |
186
+ | **Branch by Abstraction**(分支抽象) | 先加抽象层,再换实现 | 不能停的大改造 | 临时复杂度 |
187
+ | **Expand-Contract**(扩展-收缩) | 先兼容新旧,再删旧 | 数据 / API 迁移 | 两阶段窗口 |
188
+ | **Feature Flag**(特性开关) | 运行时开关 | 灰度、回滚 | 分支膨胀 |
189
+ | **Canary / Blue-Green**(金丝雀 / 蓝绿) | 小流量验证 / 双环境切换 | 高风险发布 | 监控 / 双倍资源 |
190
+
191
+ 演进原则:不做大爆炸重写;每次迁移都要有回滚路径与验证指标;最小单位是「可独立验证的切片」。
192
+
193
+ ### 6.5 前端五个轴(不要混着谈)
194
+
195
+ | 轴 | 选项 | 关键判断 |
196
+ |---|---|---|
197
+ | 渲染 | CSR / SSR / SSG / ISR / Streaming / Islands | 首屏、SEO、实时性、部署 |
198
+ | 路由 | 集中式 / 文件式 / 分布式 | 团队边界、发布独立性 |
199
+ | 数据 | REST / GraphQL / tRPC / BFF / 本地优先 | 聚合、缓存、离线 |
200
+ | 状态 | 局部 / 全局 store / server state / 状态机 | 生命周期、共享范围、异步复杂度 |
201
+ | UI 组合 | 单应用 / 微前端 / 设计系统分层 | 团队规模、复用范围、品牌数量 |
202
+
203
+ ## 7. ADR(架构决策记录)
204
+
205
+ ```md
206
+ # ADR-0001: 采用模块化单体而非微服务
207
+
208
+ - Status: Accepted | Superseded by ADR-0005 | Deprecated
209
+ - Date: 2026-10-26
210
+ - Deciders: ...
211
+ - Context: 3 人团队、单产品、部署不痛;微服务会引入分布式事务与运维成本。
212
+ - Decision: 先做模块化单体,模块间只通过 public API 通信;预留按模块拆出的可能。
213
+ - Consequences: 边界靠 lint 维持;未来拆分需要先做数据所有权梳理。
214
+ - Alternatives: 微服务(运维成本高)、大泥球(不可接受)。
215
+ ```
216
+
217
+ - **append-only**:不删、不改历史;被取代就标 `Superseded`。
218
+ - 放在代码仓里,跟代码一起 review。
219
+ - 只记**难逆转**的;可逆决策用 RFC / PR 描述。
220
+ - 每条必须有 **Consequences** 与 **Alternatives**;没有代价说明的决策不算记录。
221
+ - 反模式:**Documentation Theater(文档剧场)**——只写「未来的人会问为什么」的那部分。
222
+
223
+ ## 8. 反模式
224
+
225
+ | 反模式 | 表现 | 后果 | 替代 |
226
+ |---|---|---|---|
227
+ | **Big Ball of Mud**(大泥球) | 没有边界 | 改一处崩一片 | 切模块 + 依赖规则 |
228
+ | **Distributed Monolith**(分布式单体) | 拆了服务,仍共享库 / 强耦合 | 两头不讨好 | 先模块化单体,按数据所有权拆 |
229
+ | **Cargo Cult**(货物崇拜) | 抄大厂架构不看前提 | 水土不服 | 先问约束 / 团队 / 规模 |
230
+ | **Resume-Driven Development**(简历驱动) | 为用新技术而用 | 复杂度失控 | 按力选型,写代价 |
231
+ | **Ivory Tower**(象牙塔) | 架构师不写代码 | 设计与实现脱节 | 伴随实现 |
232
+ | **Diagram-Driven**(图驱动) | 图漂亮,代码没约束 | 图与代码两张皮 | 图 + lint + ADR |
233
+ | **Over-layering**(千层饼) | 每层只转发 | 认知 / 维护成本 | 合并层,按变化切 |
234
+ | **Architecture by Implication**(默认架构) | 没人决策 | 隐性耦合 | 显式 ADR + 边界 |
235
+ | **God Module**(上帝模块) | 一个模块什么都知道 | 难改、冲突多 | 按职责拆 |
236
+ | **Cyclic Dependency**(循环依赖) | A→B→A | 无法独立测试 | 提共享层 / 依赖倒置 |
237
+ | **Premature Platform**(过早平台化) | 1 个产品就建平台 | 平台没用户 | 第二个产品出现再平台化 |
238
+ | **Folder Architecture**(目录即架构) | 只分目录,没有规则 | 目录好看,耦合照旧 | 依赖规则 + public API |
239
+ | **Monorepo as Architecture**(同仓即解耦) | 以为一个仓就自动解耦 | 隐式耦合依旧 | 包边界 + 依赖规则 |
240
+ | **AI-Generated Entropy**(AI 生成熵) | AI 复制最近的模式 | 同族不同形、边界漂移 | 约束 + 正面样例 + lint |
241
+
242
+ ## 9. 评审清单(12 条)
243
+
244
+ 1. 每个模块能用一句话说清职责?
245
+ 2. 依赖是否单向、无环?
246
+ 3. 核心逻辑能否脱离框架 / 网络 / UI 测试?
247
+ 4. 每份数据是否有唯一写入者?
248
+ 5. 新增一个功能要改几个模块?> 3 个就检查切分。
249
+ 6. 换平台 / 渠道要改几处?差异是否收在边界?
250
+ 7. 失败模式是否明确:超时、重试、降级、幂等?
251
+ 8. 是否有 public API?能否禁止深路径 import?
252
+ 9. 难逆转决策是否有 ADR:替代方案 + 代价 + 退出条件?
253
+ 10. 约束是否可自动验证?规则是否少而硬?
254
+ 11. 每个引入的模式是否有退出条件?
255
+ 12. 是否只有一个消费方就抽象了?是否预建了「以后可能」的层?
256
+
257
+ ## 10. AI 协作下的架构
258
+
259
+ - 架构是 AI 的**上下文压缩器**:边界清晰 → 搜索空间小 → 生成稳定。
260
+ - AI 会复制最近的模式:坏架构会被放大;先修边界,再让 AI 写。
261
+ - 给 AI 的架构输入:目录树 + 依赖规则 + 1 个正面样例 + 1 个反例 + 禁止清单。
262
+ - **不让 AI 做架构决策**;让 AI 出「候选方案 + 代价表」,人拍板。
263
+ - 评审看 **diff 的依赖方向**,不只看代码风格。