全栈设计模式指南 是做什么的?
使用此技能来建议、架构和重构端到端的全栈系统。严格应用模式来解决可识别的架构摩擦,而非进行推测性抽象。
核心原则
- 问题优先选择: 在没有明确的架构摩擦或代码异味(例如,属性透传、臃肿的上帝组件、紧耦合的API、不可测试的逻辑、级联的网络故障)时,绝不引入设计模式。
- 清晰的架构接缝: 保持以下层次之间的清晰边界:
- 视图/展示层: 受 props 驱动的、无状态的声明式组件。
- 客户端状态与交互: 无头 Hook、集中式存储和服务器状态缓存。
- API/契约层: 类型化的 Schema、DTO 适配器和防腐败层。
- 领域与数据访问: 解耦的业务规则和基于仓储的数据库访问。
- 避免过度工程: 不要将复杂的企业级抽象(如微前端、CQRS 或分布式发布/订阅)应用于简单的 CRUD 页面或标准 Web 应用。
模式决策矩阵与触发启发式规则
| 层次 | 代码库中的症状/摩擦 | 推荐模式 | 架构接缝 |
|---|---|---|---|
| 前端 UI | 同时混合 API 请求、格式化和 JSX 布局的上帝组件 | 容器/展示组件 | 将 UI 渲染与数据获取分离 |
| 前端 UI | 交互式组件(模态框、下拉框)内与样式紧密耦合 | 无头组件/自定义 Hook | 隔离状态和键盘/交互逻辑 |
| 前端 UI | 组件 API 僵化,需要灵活的子元素 | 复合组件 | 声明式的父子状态共享(例如 Tabs、Select) |
| 前端 UI | 深层属性透传或多组件 UI 状态不同步 | 观察者模式/Store(Zustand/Redux/Context) | 集中管理共享的客户端状态 |
| 全栈 API | 后端 API Schema 变更破坏前端 UI 组件 | 适配器模式(数据映射器) | 将 DTO 转换为视图模型的防腐败层 |
| 全栈 API | UI 在确认用户操作前等待慢速网络 | 乐观 UI 与回滚 | 即时 UI 响应,配合事务性回滚 |
| 后端 | SQL/ORM 调用分散在路由处理程序或服务中 | 仓储模式 | 将持久化查询与业务规则解耦 |
| 后端 | 使用内联 if-else 实例化不同的第三方 SDK | 工厂模式 | 集中创建对象和客户端 |
| 后端 | 计算价格、认证或算法时出现级联的 if-else / switch | 策略模式 | 将可互换的算法封装在接口之后 |
| 后端/分布式 | 核心业务操作触发 5 个以上不相关的副作用 | 观察者模式/事件驱动(发布/订阅) | 通过领域事件或消息队列解耦副作用 |
| 后端/分布式 | 外部 API 延迟导致线程饥饿和级联停机 | 断路器模式 | 快速失败、回退响应以及下游健康探测 |
深入探讨:全栈模式与实现规则
1. 前端:容器/展示组件模式
- 上下文: 组件因结合了
useEffect、查询、数据转换和布局 JSX 而超过 200 行。 - 规则:
- 展示组件: 仅通过 props 接收数据和回调;纯函数,易于在 Storybook 中无需 API mock 即可测试。
- 容器(或页面 Hook): 获取服务器数据,管理加载/错误状态,并将转换后的数据向下传递。
2. 前端:无头组件与自定义 Hook 模式
- 上下文: 复杂的交互行为(自动补全、多步向导、手风琴)需要在不同视觉设计中复用。
- 规则:
- 将状态、键盘处理程序和 ARIA 属性提取到无头的自定义 Hook 中(例如
useAutocomplete、useDisclosure)。 - 样式和 DOM 标记完全交由消费者处理。
- 将状态、键盘处理程序和 ARIA 属性提取到无头的自定义 Hook 中(例如
3. 前端:复合组件
- 上下文: 具有深度相关子部分的组件需要内聚的内部状态,而无需传递大量配置 props。
- 规则:
- 利用 React Context 在父组件和子组件之间隐式通信(
<Accordion><Accordion.Item /><Accordion.Panel /></Accordion>)。
- 利用 React Context 在父组件和子组件之间隐式通信(
4. 集成:适配器模式(防腐败层)
- 上下文: 第三方 REST/GraphQL 有效负载直接泄露到 UI 组件 props 或核心领域模型中。
- 规则:
- 绝不允许原始后端 DTO 键决定前端组件 prop 的形状。
- 创建显式的映射函数(例如
toUserViewModel(dto: UserApiDto): UserVM),以保护 UI 组件免受 Schema 变更的影响。
5. 集成:乐观 UI 与回滚
- 上下文: 频繁的用户交互(点赞、切换、任务完成、重新排序)中,网络延迟损害响应性。
- 规则:
- 交互时立即更新本地状态。
- 将服务器变更加入队列;如果服务器拒绝,则回滚到之前的快照并以非侵入方式通知用户。
6. 后端:仓储模式
- 上下文: 业务逻辑与 ORM 查询(Prisma、TypeORM、Drizzle、SQL)交织在一起。
- 规则:
- 服务仅通过接口(例如
OrderRepository)交互。 - 将领域逻辑保留在仓储之外;将查询构建保留在服务之外。
- 服务仅通过接口(例如
7. 后端:策略模式与工厂模式
- 上下文: 可切换的提供者(支付网关、通知渠道、文件存储)。
- 规则:
- 通过通用接口(
PaymentGateway)标准化行为。 - 使用工厂/注册表根据配置或租户解析具体的实现。
- 通过通用接口(
8. 后端:断路器模式
- 上下文: 外部微服务或第三方 API 遭受间歇性停机或严重延迟。
- 规则:
- 跟踪失败阈值。状态转换:
关闭(正常)->打开(快速失败,返回缓存/回退)->半开(金丝雀探测)。
- 跟踪失败阈值。状态转换:
代理输出工作流
当被要求就架构提供建议或重构全栈代码时:
- 识别接缝与瓶颈: 确定摩擦点是在 UI 渲染、状态同步、API 契约不匹配还是后端耦合中。
- 选择匹配的模式: 提出模式,并附上针对特定代码异味的清晰理由。
- 提供前后对比示例: 提供简洁、惯用的代码片段,展示解耦后的职责。
- 强调可测试性与可维护性: 解释重构如何简化单元/组件测试并抵御未来的变更。