本文是浅谈软件架构设计实践之业务核心与配置分离的后续。
最近,一位同事和我分享了他们遇到的一则生产事故:
背景
他们有一个面向消费者的前端及若干后端,同时也有一个管理后台供运营人员配置营销活动参数
事故
某新活动上线后,消费者前端感受到延迟激增,不多时管理后台崩溃,活动中断
原因
营销活动前端开发人员误将管理后台的API当做营销活动后端的API使用,后者是有缓存保护的,而前者为了方便运营人员配置是没有缓存的
我们共同的看法是,这是一个低级失误,但通过性能测试应该是可以发现的。可惜的是,由于各种原因,这个性能测试并没有发生。如果性能测试的设计场景和实际生产场景不匹配或是性能测试覆盖不全呢,有没有一种架构设计上的防呆机制,即使漏掉了性能测试也能避免这样的低级失误呢?
既然在项目中,已经实施了“业务运行域与配置域的分离”,那么说不定可以在此基础上再进一步,将两者间的业务运行域=>配置域
反转为业务运行域<=配置域
。
即由:
通过这个依赖反转,我们可能还能收获两个有益的副作用:
有个关于架构设计的玩笑是,没有什么问题是不能用两个框加一条连线解决的,如果有的话,那就再加一个框和一条连线。
确实架构师们经常用框和连线来表达架构决策是什么。但有时候我们更希望理解这个决策的前因后果,尤其是那些正因为这个历史决策承受痛苦的人。如果我们不理解这个历史决策背后的动机,那么我们只有两个选择:
闷头接受这个决策
如果这个决策的上下文没有变化,这个选择可能没有问题。但如果这个决策的上下文已经改变了,可能我们错过了一个调整决策的机会。我很怀疑,如果我们不理解某个决策背后的动机时,是否真得能在实际工作中贯彻这个决策,不会走样。
闷头绕过这个决策
同样的,如果这个决策的上下文已经失效了,那么绕过它可能没有问题。但另一种可能即我们在无意间把事情搞砸了。
因此,这两个选择都不是好主意。那么我们如何穿越到历史决策制定的时间线去一窥背后的动机呢?还是得靠文档,我们称之为架构决策记录(Architecture Decision Record,简称ADR)。
在网络上,可以找到各种各样的架构决策记录模板,那么架构决策记录应该包含什么呢?既然记录架构决策的动机是为了理解该决策背后的动机(好拗口),那么我们应该将更多的笔墨放在Why & What上。本着精简文档的原则,我认为架构决策记录至少应该包括以下几项:
问题描述
描述要解决什么问题以及为什么是现在这个时间点来解决这个问题
约束
描述在解决该问题时有什么限制条件,例如预算/时间线/资源
假设
描述在做出决策时带着什么假设,由于各种原因在决策当时,尚无法验证
相关的架构决策/原则
列举相关的架构决策或架构原则,它们也有助于帮助读者理解决策推导过程
备选方案
一组备选方案,如果有人总是问“你们有没有考虑过这种方案”,那么这里是回应的好地方。每个备选方案除了方案本身的描述外,还应该说明如果选择了该方案会有什么后果/代价
决策
最终选择了哪个备选方案,其后果/代价是什么
####状态
草稿/待评审/已通过,可以根据你所在组织的架构决策流程来定义
那么什么样的决策适合以架构决策记录的形式来记录呢?这个需要根据你所在组织的情况来定,但原则上太细粒度的设计决策或太宏观的方向决策都不太适合。但不管什么样的决策,其背后的动机都值得记录下来,只是未必以架构决策记录的形式而已。
例如,需要新增一个API或是修改已有的API,那么通过代码的提交备注就能记录了。而引入中台架构则太宏观了,可能需要一个报告来能说清。
原则上,架构决策记录应该尽可能开放,这样才能最长程度避免“有时候我们更关心架构决策背后的动机”中出现的闷头干的情况。所以不管是直接放到Wiki上,或是放在共享文件夹里,都需要将如何在避免泄密(如果有的话)的前提下,最大化读者可见性作为考量之一。
另外,应该考虑将架构决策记录纳入配置管理(指保存历史版本),某些Wiki(例如Confluence自带历史版本功能),或者采用普通文档(是类似于Markdown的普通格式,而不是二进制的Word文档,以便更方便的观测修订历史)搭配源码工具(Git/SVN等)。
下面我将用一个虚拟的例子来演示一个架构决策记录,我不会对其做背景介绍,请帮我验证一下这个架构决策记录能否达到它应有的作用。
标题: ADR-34-初步建立在线收款能力
问题描述
我们是一家依赖经销商分销的企业,现在正在尝试将指定商品直接向消费者销售(详见关于B2C试点业务),这要求我们为之建立在线收款的能力。
假设
- B2C试点业务只需要支撑付款,而不包含退款、订单二次收款等功能
约束
时间约束:B2C试点项目预计于20年9年上线运行,期间大约有2周的时间完成与在线支付供应商的集成。
业务约束:需要保障财务对账工作可以某种方式进行。考虑到B2C试点业务的计划,对账工作未必需要以自动的方式执行。
相关的架构决策/原则
根据ADR-32-引入在线支付供应商,为尽可能以最小的代价,支持多种支付方式,我们会与一家在线支付供应商合作,但商务协商仍在进行中。
备选方案
O1 由结账组件直接与在线支付供应商集成
- 由结账组件与在线支付供应商集成
- 由“结账单”业务实体负责兼顾在线收款的生命周期
优势:
- 由于B2C试点业务只需要支撑付款,而不包含退款、订单二次收款等功能,因此,在线收款的生命周期与结账单的生命周期有较大重合。这种重合可以降低初始的工作量。
劣势:
- 可以预见,将来会有更多需要在线收款能力的场景,这些场景未必是基于结账单工作的。因此从长远看,并不适合由结账组件来提供线收款能力
影响:
- 如果选择该备案,可以预见在将来需要通过重构迁移至O2
O2 引入专职的在线支付组件与在线支付供应商集成
- 引入在线支付组件与在线支付供应商集成
- 引入“在线收款”业务实体负责管理在线收款的生命周期
优势:
- 独立的“在线收款”实体可以将在线收款的生命周期与结账单的生命周期解耦,使其可以更容易扩展将来对订单二次收款等特性的支持
劣势:
- 需要额外一名工程师投入,但目前已无足够人手
决策
从长远来看,O2是更好的选择,但我们目前需要在没有足够的工程师的情况下满足非常有挑战的项目时间线。因此建议先采用O1,在需要引入订单二次收款能力时切换到O2。
####状态
待评审