2.2.2 按节奏分类:触发式、持续式和时间式
执行节奏是另一种区分适应度函数的方式。触发式适应度函数可以基于特定事件执行,比如单元测试、运行单元测试的部署流水线,或者QA人员执行探索性测试。它涵盖了传统测试类型,例如单元、功能和行为驱动开发(Behavior-Driven Development,BDD)的测试等。
持续式测试不按固定计划执行,而是持续地验证架构的某些方面,例如事务处理速度。举例来说,架构师想要在一个微服务架构里构建一个测试事务处理时间的适应度函数,事务处理时间即完成单个事务所花费的时间的平均值。任何触发式测试都只能窥见真实世界行为的一角。因此,架构师构建了一个持续式适应度函数来模拟有真实事务发生的生产环境里的一个事务,通常使用一种叫作合成事务的技术。它可以帮助开发人员验证行为并收集系统在真实环境里的数据。
合成事务
在微服务架构中,团队应该如何度量服务之间真实而复杂的相互作用呢?一个常见的技术利用了合成事务(synthetic transactions)。对于这个实践,进入系统的请求中有一个标志,标明这个特定的事务可能是合成的。它完全遵循架构中正常的交互过程(通常通过用于法医学分析的关联ID进行跟踪),直到最后一步,系统重新审视该标志,不会把它作为真实事务提交。这允许架构师和DevOps精确地了解复杂系统的行为方式。
任何没有提到数百台设备发生意外的事故的关于合成事务的建议都不完整,因为有人忘记切换“合成”标志,而该标志本身可以由适应度函数管理——确保将任何标识为合成事务的适应度函数(例如,通过注解)都设置了该标志。
需要注意的是,使用监控工具不意味着你就有适应度函数了,适应度函数必须有客观的结果。相反,如果架构师使用监控工具为偏离目标度量指标一定差值的情况创建了告警,那么这样就从单纯地使用监控工具转化为使用适应度函数。
监控驱动开发(Monitoring-Driven Development,MDD)(https://oreil.ly/2fPIe)是另外一种渐渐流行起来的测试技术。它通过监控生产环境来评估技术和业务的健康程度,而不是仅依赖测试验证系统的输出结果。这些持续式适应度函数确实比标准触发式测试更为动态,也属于更广泛的适应度函数驱动架构的范畴,第7章会加以细述。
大部分适应度函数不是触发式的就是持续式的,在某些情况下,架构师可能希望在评估适应度时加入时间要素,形成一个时间式的适应度函数。举例来说,如果项目使用了加密库,架构师可能会想要一个时间式的适应度函数,来提醒自己是否有重要更新。这种类型的适应度函数的另外一个常见用途是升级中断测试。在像Ruby on Rails这样的平台上,开发人员迫不及待地想要尝试下一版本里的新功能,所以他们通过向后移植在当前版本里增加一个新功能,这是一种未来功能的自定义实现。问题出现在当项目终于升级到新版本的时候,向后移植往往和“真实”版本不兼容。开发人员利用升级中断测试来保护这些向后移植功能,从而迫使自己在升级时重新评估这些实现。
时间相关适应度函数的另一个常见用途来自重要但不紧急的需求,这个需求不可避免地在每个项目中出现。许多开发人员都经历过升级项目所依赖的核心框架或库的多个主版本号的痛苦——两次主要版本发布之间有太多变化,直接跳跃版本通常相当困难。然而,升级核心框架耗费时间而且又不紧急,更容易一不小心就落得很远。架构师可以使用一个时间相关的适应度函数结合诸如Dependabot(https://github.com/dependabot)或snyk(https://snyk.io)这样的工具,它们可以追踪软件的发布、版本和安全补丁,一旦满足了企业定义的条件(例如,第一个补丁的发布),就创建更加强烈的升级提醒。