声明式编程:by example
声明式优于命令式编程,这个是晚上大量文章中建议的观点。同时比较喜欢举的例子就是 SQL 语言。但是,我们在日常的架构设计过程中,怎么实现算声明式设计,声明式能收到什么样的好处,估计大部分的架构师还是有一定困惑的。最近在做外汇服务和链路的升级,中间有个例子可以很好的说明问题。
业务场景很简单:就是在做外汇交易时,首先需要获取报价信息。虽然获取报价是一个很简单的交互,本质就是要拿到一个价格。但是,由于外汇业务的特殊性,给到客户的价格,和客户、业务场景、时间段等有密切的关联,同时还有营销优惠券需要考虑。
最初的设计,是妥妥的一个命令式编程的范例。获取报价的系统会顺序执行如下步骤:
根据用户 Id,去行业外汇系统咨询得到用户相应的等级信息;
根据支付场景(户到户还是流出、结汇还是非结汇等),根据参数中心的配置获取外汇场景码;
获取用户在页面上选择的营销券;
结合上面的信息,再带上交易币种金额,去外汇中台获取报价;
计算出最终的交易对手方金额。
这个设计在日常运营过程中,遇到过相当多的问题:
新增站点缺少支付场景和外汇场景码的配置,导致获取报价失败;
每次一个场景的改动,都需要回归所有场景,否则就容易导致报价逻辑错误;
每次外汇报价策略的改动,都需要所有询价相关调用方进行改造和回归;
最后一步计算,经常由于 offer 和 bid 价格用错导致金额有偏差。
纠其根本原因,就是这个命令式的交互设计,违反了高内聚低耦合的原则,将外汇相关的领域知识扩散到了上游的使用方,导致运营、变更都有很大的开销。
对于这个问题,如果我们引入声明式的设计,就可以很好的解决这个问题。
上游不需要理解各个步骤,只需要了解自己的诉求:针对单个用户、单个交易场景,顺带带上优惠券信息,加上交易自带的金额和币种,获取一个合适的价格。
所以,报价的接口设计就成为了这么一个函数:
报价服务提供方会完成上述的过程的执行:
根据 userId 获取用户等级;
根据 bieScene 获取外汇报价策略;
将 benefitId 翻译成点差或者券信息;
调用中台获取价格;
计算 buyAmount 返回上游。
同时,未来如果有一些变更的需求,上游也完全不需要感知:
用户等级升级成 by 单用户运营的价格优惠,或者根据用户历史交易量打的分数;
增加按照时间段的报价策略,应对周末无市场的场景;
根据交易金额分级定价;
……
总结一下,对于声明式样的设计,屏蔽内部的实现逻辑,暴露给上游明确的业务信息输入,处理后返回明确的执行结果。声明式的设计,就是很好的将架构职责做了一个明确的切分:调用方只需要了解自己业务领域边界内部的概念,将业务要素给到服务提供方后,有提供方执行并返回同样有业务含义的结果信息。由于架构职责的清晰切分,从而满足了高内聚低耦合的特性,最终在集成、变更和运营运维上都可以收到理想的效果。
版权声明: 本文为 InfoQ 作者【agnostic】的原创文章。
原文链接:【http://xie.infoq.cn/article/59530cf681740db414da78859】。文章转载请联系作者。
评论