面试记录 2026-10-08
题目:架构是设计出来的还是演进出来的?
难度:high
标签:arch/design, architecture/design, difficulty/high
评分:⭐⭐⭐☆☆(3/5)
我的回答
我理解的架构基本上是演进出来的。你最开始的设计无法考虑到未来时代的变化,每个阶段有不同的变化。你最开始的设计可能会沿用一段时间,但时代发生了变化之后,你的架构可能就不再适用了。就比如现在这个社会,突然的 AI 的诞降临,导致大部分的原有的架构都被打破了。新的内容被填充进去,老的内容被移走。一次性的设计无法考虑到那么久远,或者时代变更,某些东西的产生,你是无法预测的。所以根据时代的变化、世界的变化去调整架构,是一个必然的过程。
点评
优点:有明确立场(演进派);核心洞察"未来不可预测"正确;用 AI 冲击举例说明技术变革对架构的影响。
不足:过度倾向"演进"、完全否定了"设计"的价值(主流观点是"设计 + 演进"结合);未对比两种观点的适用场景;未讲"如何演进"的方法论(DDD/绞杀者模式/微服务拆分);未讲什么时候必须"设计"(核心金融业务/合规/安全/一致性强约束);未讲架构师在演进中的作用(架构守护、抽象层、技术债务管理)。
补充:正确答案是"设计 + 演进"结合——设计决定方向,演进适应变化;关键在抽象层设计(预留扩展点、依赖倒置、领域建模),让架构能被"演进";不同场景选不同侧重点:核心业务/金融/合规必须设计(强约束);探索性业务/快速迭代适合演进。
完整讲解
第一部分:知识重点剖析
核心考点定位:考察对架构设计派 vs 演进派两种观点的辩证理解,以及能否说清"设计"与"演进"如何结合。
知识点拆解:
- 两种观点的辩证:
- 设计派(前微软 Bruce Eckel、Martin Fowler 早期):架构需要前瞻性设计,尤其是核心业务、金融、合规、安全等强约束领域,前期设计不到位后期返工成本极高;
- 演进派(Martin Fowler 中后期、Kent Beck):架构是问题驱动演进的,过早设计是过度设计(YAGNI),业务变化时会发现前期设计是错的;
- 正确立场:"设计 + 演进"结合——设计决定方向(核心抽象、边界、扩展点),演进适应变化(业务迭代、技术选型更新)。
- 不同场景选不同侧重点:
| 场景 | 侧重点 | 原因 |
|---|
| 核心金融业务 | 设计派 | 强一致、合规审计、返工代价极高 |
| 支付/交易 | 设计派 | 分布式事务、幂等、对账,前期设计错后期无法挽救 |
| 探索性业务 | 演进派 | 需求不清、快速验证、迭代快 |
| 电商促销 | 演进派 | 需求多变、场景丰富,快速试错 |
| 基础设施(K8s/服务网格) | 设计派 | 技术栈稳定、长期投入 |
| 应用层业务代码 | 演进派 | 需求变化频繁、DDD 演进友好 |
- "设计"的价值——决定不能变的:
- 领域边界:DDD 战略设计(Bounded Context);
- 扩展点:依赖倒置、策略模式、SPI 扩展;
- 抽象层:Repository、Gateway、Adapter 等抽象;
- 数据模型:核心实体、领域事件、幂等键;
- 技术底座:注册中心、消息队列、缓存选型。
- "演进"的价值——适应变化的:
- 业务迭代:新功能、新场景通过策略模式/插件扩展;
- 技术升级:JDK 版本、框架版本、中间件升级;
- 性能优化:从同步到异步、从单库到分库分表、从 MySQL 到 ES;
- 团队扩张:从单体到微服务的自然演进。
- 演进的关键——可演进性的设计:
- 依赖倒置:核心业务不直接依赖实现;
- 接口抽象:关键扩展点用接口定义;
- DDD 领域建模:领域边界清晰,跨边界通过事件解耦;
- 绞杀者模式(Strangler Fig Pattern):微服务迁移时用新服务逐步替换老服务;
- CQRS + Event Sourcing:读写分离、事件溯源,便于演进;
- 可观测性:埋点、链路追踪、指标监控,让演进有数据支撑;
- 架构守护:ArchUnit、依赖约束、代码审查,防止演进变腐化。
- 反面案例:
- 过度设计:早期就上微服务+服务网格+分库分表,团队 3 个人扛不住(比如某些"技术炫技"项目);
- 零设计:早期完全无规划,堆屎山代码,后期重构成本 > 重写成本。
按「辩证立场 → 场景选择 → 设计价值 → 演进价值 → 演进方法」递进。
第二部分:考察方向与延伸递进
考察方向:
- 深度:能否辩证理解"设计 + 演进"结合,而不是二元对立
- 广度:能否说清演进的方法论(DDD/绞杀者/CQRS/依赖倒置)
- 应用:能否结合自己项目说清"哪些地方必须设计、哪些地方适合演进"
延伸递进面试题:
- 举一个你项目中"演进"的典型案例,说清演进路径。
- 解答要点:说清初始架构、演进驱动力、演进路径、每一步的权衡、最终形态
- 绞杀者模式(Strangler Fig Pattern)具体如何工作?
- 解答要点:用新服务逐步替换老服务的功能模块,通过 API Gateway 路由切流,新老共存 → 逐步替换 → 老服务下线;适用于单体→微服务的迁移
- 架构守护(Architecture Guard)如何做?如何防止"演进变腐化"?
- 解答要点:ArchUnit 单元测试、依赖约束(dependency-cruiser)、代码审查、CODEOWNERS、静态分析、架构决策记录(ADR)
第三部分:面试者参考回答(300-600 字口语化)
面试官您好,我的观点是:架构是"设计 + 演进"的结合——设计决定方向,演进适应变化,两者缺一不可。
先说设计的价值:设计不是"一次性做完",而是决定那些不能变的——
- 领域边界:DDD 战略设计(Bounded Context)划清服务/模块边界,避免后期耦合严重;
- 扩展点:依赖倒置、策略模式、SPI,为未来变化预留口子;
- 抽象层:Repository、Gateway 等抽象隔离实现,实现可替换;
- 数据模型:核心实体、领域事件、幂等键,跨系统一致的关键;
- 技术底座:注册中心、MQ、缓存选型,一旦选定很难改。
这些前期不设计好,后期返工成本极高,尤其是金融、支付、合规这类强约束业务,架构错一次可能就要重写。
再说演进的价值:演进是适应业务变化的必然——
- 业务场景持续变化(新功能、新客群);
- 技术栈持续升级(JDK 版本、框架版本);
- 性能需求变化(从同步到异步、单库到分库分表);
- 团队扩张(从 3 人到 30 人,从单体到微服务);
- 就像你说的 AI 冲击,新技术会打破旧架构,必须演进。
关键是"可演进性的设计"——设计要让架构能被演进,而不是设计成"死板"的。具体做法:
- DDD 领域建模:领域边界清晰,跨边界通过事件解耦;
- 依赖倒置:核心业务不依赖具体实现;
- 绞杀者模式:微服务迁移时新老共存、逐步替换;
- CQRS + Event Sourcing:读写分离、事件溯源;
- 架构守护:ArchUnit 单元测试、依赖约束、架构决策记录(ADR),防止演进变腐化。
结合项目举例:我做过一个订单系统,早期用单体 + MySQL 单表(快速上线),用户量涨到 1000w 时加 Redis 缓存(应对读压力),涨到 5000w 时读写分离 + 主从复制,涨到 1 亿时分库分表(按 user_id hash),最后业务边界清晰了再拆分成订单中心、支付中心、库存中心(微服务)。整个演进路径都是"够用就行,问题驱动",早期不上微服务是因为团队只有 3 个人。
反面案例:过度设计(早期就上微服务+服务网格+分库分表)会导致团队扛不住、复杂度爆炸;零设计会导致后期堆屎山、重构成本 > 重写成本。所以是"设计 + 演进"结合——核心业务必须设计、应用层适合演进,找到平衡点才是关键。
总结:架构不是"设计出来就完事",也不是"完全靠演进",而是"设计让演进有方向,演进让设计不僵化"。好的架构师既能前期设计好关键抽象,又能后期演进好业务变化——这才是 TL 的核心能力。