Day31-02|10.1.2 演化和定义的关系:让架构描述跟上系统真实变化
Day31-02|10.1.2 演化和定义的关系:让架构描述跟上系统真实变化
一、教材定位
软件架构定义描述系统的结构、行为、约束、质量目标和利益相关者关注点;软件架构演化则描述这些内容在生命周期中如何变化。二者不是互相独立的工作:架构定义为演化提供当前基线、设计意图和约束,架构演化又会不断检验、修正和扩展架构定义。如果系统已经发生变化,而文档、模型和决策没有同步更新,就会出现“代码是一种架构、文档是另一种架构、团队理解又是第三种架构”的架构漂移。
本节的重点不是记忆一句“演化与定义相互作用”,而是理解它们之间的闭环关系。架构师要能够说明:当前架构如何被描述;变化从哪里产生;哪些变化需要更新架构决策;如何通过版本化、追踪和验证保持定义与实现一致;在渐进迁移期间如何同时管理目标架构、过渡架构和现状架构。
二、架构定义包含什么
1. 结构定义
结构定义说明系统由哪些组件、模块、服务、数据存储和部署节点组成,以及它们之间如何连接。结构不只是类图,也包括层次、分区、服务边界、数据所有权和故障域。
2. 行为和交互定义
行为定义说明组件如何协作、消息如何流动、接口如何调用、状态如何转换以及异常如何处理。对于分布式系统,还要描述超时、重试、幂等、顺序、最终一致性和补偿等运行规则。
3. 约束和原则
约束包括技术选型、依赖方向、接口规范、数据安全、性能目标、部署规则、合规要求和团队边界。原则是指导设计和演化的稳定判断,例如核心交易必须可追溯、服务不得直接修改他人数据、敏感数据必须加密。
4. 质量属性与场景
架构定义要表达可用性、性能、安全性、可维护性、可扩展性、可靠性和可测试性等目标,并通过质量属性场景说明刺激、环境、响应和度量。没有质量目标,演化就容易变成只追求功能和技术潮流。
5. 决策和权衡
架构决策记录为什么选择某种方案、放弃哪些方案、依赖哪些假设、承担什么风险。演化时需要回顾这些决策,判断原有假设是否仍然成立。只记录最终结构而不记录决策原因,会导致团队重复讨论或无意破坏重要约束。
三、架构定义如何支撑演化
1. 提供现状基线
演化必须知道从哪里出发。架构定义把当前组件、数据、依赖、接口、部署和质量指标固定下来,帮助团队识别变化影响。没有现状基线,迁移计划只能依赖个人记忆,容易漏掉隐式依赖。
2. 暴露变化影响
当修改一个接口或数据模型时,可以沿着架构关系追踪调用者、消费者、部署对象和质量属性。如果定义中记录了接口契约、数据所有权和依赖方向,影响分析就更准确;如果定义只画了高层框图,往往无法指导实际迁移。
3. 保护不可破坏的原则
演化过程中需要在速度和稳定性之间取舍。架构定义中的关键约束可以防止临时方案突破安全边界、数据一致性边界和故障隔离边界。约束应分为必须保持、允许过渡违反但需限期偿还和可以重新评估三类,不能把所有规则都写成同等强度。
4. 形成验证标准
架构定义中的质量场景和接口契约,可以转化为测试、监控和评审标准。演化之后比较基线和目标指标,判断改变是否达成目的,而不是凭感觉认为系统“更现代”。
四、演化如何改变架构定义
1. 结构会发生变化
组件可能拆分、合并、替换或迁移,数据存储可能分区、复制或从共享数据库转为领域所有。部署拓扑可能从单机变为集群、多区域或云原生平台。架构定义必须反映这些新结构,并标记过渡阶段中仍存在的旧结构。
2. 行为和协议会发生变化
同步调用可能变成消息,强一致事务可能引入最终一致和补偿,接口可能增加版本和兼容字段。行为定义要说明新旧协议如何共存、消息如何重复处理、失败如何重试以及何时下线旧版本。
3. 约束和权衡会发生变化
系统规模和业务目标变化后,原有的性能、可用性、安全和成本权衡可能不再合适。例如早期强调开发速度,后期需要提高审计和容灾;早期共享数据库降低开发成本,后期却阻碍团队独立交付。架构定义要更新原则和适用范围,而不是假装旧约束仍然成立。
4. 利益相关者关注点会发生变化
新业务部门、运维团队、合规人员和外部伙伴可能加入。架构描述需要覆盖他们关心的可追责、可观测、交付、数据隔离和服务等级问题。架构演化的成功不仅由开发人员判断,还要看相关利益者的质量目标是否满足。
五、现状、过渡和目标架构
大型演化通常不能直接从现状跳到目标,需要同时管理三个视图。现状架构说明当前真实系统和遗留问题;目标架构说明未来结构、质量目标和边界;过渡架构说明阶段性状态、迁移步骤和临时约束。
例如共享数据库拆分为领域数据库时,现状可能是多个模块直接读写同一表;过渡阶段可以引入领域服务、数据访问封装和双写校验;目标阶段由领域服务拥有数据,其他系统通过接口或事件访问。若只画目标架构而不描述过渡状态,团队无法安全执行迁移。
过渡架构也应有生命周期和退出条件。双写、适配器、兼容接口和旧数据同步都是临时复杂度,必须记录开始时间、风险、监控、回滚方式和删除计划,否则临时方案会永久存在。
六、架构演化与架构决策记录
架构决策记录应包含背景、问题、候选方案、选择结果、理由、影响、风险、假设和复审条件。演化过程中,如果原假设被新数据推翻,应更新决策状态,而不是继续执行已经不适用的方案。
可以为决策标记 proposed、accepted、deprecated 和 superseded 等状态。新决策替代旧决策时,要保留历史链路,说明何时、为什么替代。这样既能支持审计,也能帮助团队理解系统为何形成现在的结构。
七、保持定义与实现一致的方法
1. 架构即代码和自动化检查
部署模板、接口契约、数据迁移脚本、基础设施配置和架构规则尽量纳入版本控制。通过静态检查、依赖规则、契约测试、配置校验和持续集成发现实现偏离。
2. 文档与代码同源更新
组件清单、接口目录、数据字典、部署拓扑和运行手册要在变更流程中作为交付物。重要架构变化没有更新文档,不能视为完成。文档不必描述每一行代码,但必须准确表达决策、边界和运维关键点。
3. 变更影响分析和架构评审
涉及边界、数据所有权、协议、部署和质量属性的变更,应进行架构评审。评审不应阻碍所有小改动,而应根据风险分级。高风险变更要有方案、实验、迁移、回滚和指标;低风险变更可以采用轻量记录。
4. 运行反馈反哺定义
线上故障、性能趋势、容量变化、告警、发布失败和用户反馈,都是架构定义的输入。架构图中如果没有反映真实故障域和依赖关系,就需要更新架构模型或补充监控。
八、演化中的架构漂移和腐化
架构漂移是实现逐渐偏离定义,架构腐化则是这种偏离累积后导致结构和质量属性恶化。常见原因包括紧急修复、缺少评审、团队边界变化、文档滞后、临时适配器和共享资源绕过治理。
检测漂移可以检查依赖方向、循环依赖、接口直接访问、数据库越权写入、配置来源和部署差异,也可以将架构规则转成自动化门禁。发现漂移后要区分合理演化和违规偏离:前者更新定义和决策,后者整改实现或记录限期债务。
九、案例分析:共享数据库向领域数据演化
某企业订单、库存和营销模块长期共享数据库。架构文档仍描述三层单体结构,但实际代码中各团队直接读写大量表。为了支持独立发布,项目计划将订单和库存拆成独立服务。
如果只更新部署图,直接创建两个服务,很可能导致双写不一致、旧代码继续绕过服务、事务边界破坏和数据迁移失败。正确做法是先建立现状定义:梳理表的读写者、数据所有权、事务关系、批任务和报表依赖;再定义目标边界和质量场景;过渡阶段通过数据访问封装、领域接口、变更数据捕获、双读校验和逐步切流减少风险。
每个阶段都要更新架构决策和依赖目录,记录哪些旧访问仍存在、何时删除、如何监控差异。迁移完成后,架构定义应明确订单和库存的数据所有权、接口契约、事件语义、故障补偿和部署边界。通过数据一致率、发布独立性、故障影响范围和查询性能验证演化结果。
十、综合知识练习
题1
架构定义为什么必须随着系统演化更新?
参考答案:架构定义承载现状基线、结构关系、约束、质量目标和决策依据。若系统变化而定义不变,会产生架构漂移,影响分析、测试、运维和后续决策,使团队对真实系统理解不一致。
题2
为什么需要同时描述现状、过渡和目标架构?
参考答案:大型系统不能一次性从现状切换到目标。现状帮助识别真实依赖,目标表达最终结构和质量目标,过渡架构说明兼容、迁移、监控和回滚步骤。缺少过渡视图,目标架构难以安全落地。
题3
如何判断一次变化是合理演化还是架构漂移?
参考答案:检查变化是否有明确业务或质量目标,是否经过影响分析和决策记录,是否满足关键约束,是否有验证和退出条件。合理演化应更新架构定义;无目标、无记录、绕过边界且不断累积的变化通常属于架构漂移或腐化。
十一、论文写作素材
论文中可以这样描述定义与演化的关系:
“项目中我将架构定义作为演化基线,持续维护组件边界、数据所有权、接口契约、部署拓扑、质量场景和架构决策记录。面对共享数据库和发布耦合问题,我先梳理现状架构,再设计目标架构,并以过渡架构承载兼容接口、数据同步和双读校验。每次演化都记录背景、方案、约束、风险和验证指标,重大变化通过架构评审和灰度发布控制。运行中的故障、性能和业务指标反向更新架构定义,发现实现偏离时区分合理演化与架构漂移,确保文档、代码、配置和实际部署保持一致。”
十二、今日复盘
- 架构定义描述结构、行为、约束、质量目标和决策,架构演化改变这些内容。
- 定义为演化提供基线、影响分析、约束和验证标准。
- 演化会反馈结构、协议、权衡和利益相关者关注点,必须更新定义。
- 大型迁移要同时管理现状、过渡和目标架构。
- 决策记录、自动化检查、架构评审和运行反馈有助于防止漂移。
- 论文答题要写清“定义—变化—过渡—验证—更新”的闭环。