如何做架构治理并避免过度设计
问题
随着团队和系统规模增长,如何保持架构一致性、控制技术债和依赖风险,同时避免架构委员会成为交付瓶颈,或者为了未来可能的需求过度设计?
我理解的架构治理不是集中审批,而是把关键约束变成团队默认遵守的 Guardrails:
- 少量稳定原则定义方向,例如单向依赖、契约优先、默认可观测;
- 领域边界和负责人明确“谁可以依赖谁、谁对演进负责”;
- 重要且难逆的决策写 ADR,普通可逆选择留给团队;
- 能自动检查的规则做成适应度函数,进入 Lint、测试和 CI;
- 技术雷达、依赖生命周期和例外机制管理长期演进;
- 通过交付流、故障、变更成本和边界违规衡量治理效果。
避免过度设计的原则是:为当前明确约束设计,为可观察的变化保留演进点,不为想象中的规模提前支付全部复杂度。
一、架构治理要解决什么问题
- 模块边界持续被穿透,修改一个功能影响多个系统;
- 同类问题出现多套框架、协议和基础组件;
- 关键决策只存在于少数人的记忆;
- 依赖升级、下线和安全漏洞无人负责;
- 团队为了统一而增加大量审批,交付反而更慢;
- 提前设计了复杂平台,但真实需求和采用率不足。
治理目标不是让所有项目一模一样,而是降低不可控差异和高成本决策。
二、治理分层
1. 架构原则
原则要少、稳定、能指导取舍,例如:
- 业务模块只通过公开契约协作;
- 服务端状态与客户端 UI 状态分离;
- 外部输入在边界校验;
- 新能力默认带日志、指标和回滚路径;
- 优先选择团队能长期维护的简单方案。
“统一使用 React”属于技术标准,不是架构原则;“所有模块低耦合”太空泛,无法指导具体决策。
2. 领域和依赖边界
为模块定义:
- 业务职责和明确非职责;
- 公开 API、事件或数据契约;
- 允许的依赖方向;
- 数据所有者和变更负责人;
- 版本兼容与废弃策略。
3. ADR
只记录影响广、难回滚或有重要权衡的决策:
# 客户端服务端状态统一使用 Query Cache
## 状态
Accepted
## 背景
当前三个业务模块分别维护请求、缓存和重试逻辑,行为不一致。
## 决策
新模块统一通过 Data Access 层使用 Query Cache;局部 UI 状态不进入该缓存。
## 备选方案
- 继续由各模块自行实现
- 全部状态统一进入全局 Store
## 后果
- 正向:统一失效、重试和 DevTools
- 负向:需要迁移、培训和 SSR 约束
## 复核条件
当包体积、SSR 或非 React 客户端成为主要约束时重新评估。
ADR 是当时上下文中的决策记录,不是永久命令。被替代时保留历史并链接新 ADR。
4. 适应度函数
可以自动验证的架构约束应进入工具链:
import { describe, expect, it } from 'vitest';
import { collectImports } from './architecture-helpers';
describe('模块依赖边界', () => {
it('领域层不能依赖页面和基础设施实现', async () => {
const imports = await collectImports('src/domain');
const violations = imports.filter(item =>
item.target.includes('/pages/') || item.target.includes('/infrastructure/'),
);
expect(violations).toEqual([]);
});
});
其他适合自动化的约束:
- 包体积和性能预算;
- 循环依赖、跨层导入、重复依赖;
- API Schema 兼容;
- 安全 Header、许可证和依赖风险;
- 关键组件无障碍规则;
- 新模块必须注册负责人和监控。
5. 技术生命周期
技术雷达可分为 Adopt、Trial、Assess、Hold,并回答:
- 允许使用的范围;
- 试点负责人和验证指标;
- 是否允许进入核心链路;
- 退出或替换条件;
- 谁负责升级、安全和文档。
三、什么决策需要治理
可以用“影响范围 × 可逆性”判断:
| 决策 | 影响范围 | 可逆性 | 治理方式 |
|---|---|---|---|
| 局部工具函数 | 小 | 高 | 团队自行决定 |
| 页面状态库 | 中 | 中 | 团队评审、参考标准方案 |
| 跨团队组件契约 | 大 | 中 | ADR + 相关方评审 |
| 身份、权限、数据模型 | 大 | 低 | 架构评审 + 安全评审 |
| 全公司构建平台 | 极大 | 低 | PoC、阶段门和退出指标 |
治理精力应集中在难逆且影响大的决策上。
四、避免架构评审成为瓶颈
- 提供推荐路径和模板,常规方案自助通过;
- 只有触发条件出现时才升级评审;
- 评审关注问题、约束和取舍,不做代码风格争论;
- 评审者给出时限和明确结论;
- 可逆方案允许先做小规模实验;
- 决策记录公开,避免不同团队重复讨论。
五、如何识别过度设计
常见信号:
- 为没有明确时间和规模的数据预建复杂扩展能力;
- 没有第二个消费者就抽象成通用平台;
- 引入的组件比业务核心模块还多;
- 故障模式、监控和维护人力没有设计;
- 只讲未来收益,不讲当前迁移和长期运营成本;
- 方案无法分阶段上线,也没有退出路径。
YAGNI 不等于不做设计
可以保留低成本演进点:
- 明确接口边界,而不立刻拆成远程服务;
- 使用可迁移的数据模型,而不提前分库分表;
- 为第二种实现保留适配器,而不先建设插件平台;
- 记录规模触发指标,而不按最大想象容量建设。
六、例外机制
架构规则不可能覆盖所有场景。例外申请应包含:
- 为什么标准方案无法满足;
- 影响范围和风险;
- 负责人和截止时间;
- 监控、回滚和退出方案;
- 例外是一次性的还是应推动标准演进。
没有到期日的“临时例外”通常会成为永久技术债。
七、如何衡量治理是否有效
正向指标:
- 跨模块变更影响范围下降;
- 新成员完成常见任务所需时间缩短;
- 标准方案采用率和自助完成率提高;
- 架构相关事故、循环依赖和重复建设减少;
- 关键依赖升级和漏洞修复时间缩短。
护栏指标:
- 方案评审等待时间;
- 例外数量与平均处理时间;
- 团队对认知负荷和自主性的反馈;
- 平台维护成本和真实采用率。
如果架构一致性提高但交付等待显著增加,说明治理方式需要调整。
常见面试问题
Q1: 架构委员会是否有必要?
答案:大组织需要跨团队决策机制,但不应审批所有技术选择。它更适合维护原则、处理高影响难逆决策、协调共享能力和演进标准方案。
Q2: ADR 是否所有项目都要写?
答案:不需要。只记录重要、难逆、有争议或需要跨团队理解的决策。记录成本应低于未来重新讨论和误用的成本。
Q3: 如何推动团队遵守架构边界?
答案:先让边界清晰、标准路径易用,再把可验证规则自动化。仅靠文档和人工提醒难以长期维持,处罚也不能替代好工具。
Q4: 如何判断什么时候应该平台化?
答案:至少存在多个稳定消费者、重复问题和共同演进需求,并且维护方、服务等级和迁移成本明确。一个项目的可复用代码不等于平台。
Q5: 简单方案未来不够用怎么办?
答案:定义容量和组织变化的触发指标,保持清晰边界和可迁移数据,达到阈值再演进。可演进的简单设计通常优于一次到位的复杂设计。
Q6: 统一技术栈是否就是架构治理?
答案:只是其中很小一部分。真正治理还包括领域边界、数据所有权、契约、质量属性、生命周期、例外和演进机制。