One Order API 的代码实现原理,实际上就是设计模式里的模板(Template)模式和观察-发布者模式的结合体。
我们学习模板模式的时候,有一个经典的例子,上帝通过模板模式主宰芸芸众生的生老病死。
我们每个人被父母实例化出来之后,只能被动地实现上帝在模板里定义好的四个方法:生,老,病,死,而不能够更改这个模板本身,比如调换这四个方法的顺序。即使是乔布斯,也没有办法给自己添加一个"永生"的方法。听起来很残酷,但这是事实。
那么,One Order框架里,作为One Order应用的上帝,定义了哪些模板方法?
事务码CRMV_EVENT,指定 BUS2000116, 执行:
得到下图列表。红色的第一列,就是前文提到的组成One Order模型的积木。蓝色的第二列,是这些积木对发生在自己身上的感兴趣的事件列表。从图中可以看到这些事件名称都是自描述的,比如AFTER_CREATE, BEFORE_CHANGE, BEFORE_DELETE等等。
第三列黑色的ABAP函数,就是这些事件的监听函数。
这些监听函数的后缀 EC 代表 Event Callback.
————————————————
版权声明:本文为CSDN博主「汪子熙」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/i042416/article/details/124761739
得到下图列表。红色的第一列,就是前文提到的组成One Order模型的积木。蓝色的第二列,是这些积木对发生在自己身上的感兴趣的事件列表。从图中可以看到这些事件名称都是自描述的,比如AFTER_CREATE, BEFORE_CHANGE, BEFORE_DELETE等等。
第三列黑色的ABAP函数,就是这些事件的监听函数。
这些监听函数的后缀 EC 代表 Event Callback.
借助上述框架,One Order应用的开发人员的开发工作就变得无比轻松:
(1) 通过搭积木的方式,定义出自己应用需要的One Order模型
(2) 实现模型里需要关注的事件对应的监听函数。
至于这些监听函数什么时候被调用到?应用开发人员完全不用操心。
由此我们能发现,One Order框架的实现,把编程复杂度从应用开发人员身上转移到了框架实现身上。
One Order框架内部的实现比较复杂。通常情况下,One Order框架的使用者只需要了解CRM_ORDER_READ, CRM_ORDER_MAINTAIN等API的用法即可。
One Order的API之一,为消费者提供修改操作的CRM_ORDER_MAINTAIN, 所有SAP标准支持的结构体都作为输入参数之一出现在参数列表里:
这种设计方法虽然让参数列表显得有点冗长,但是从另一方面看,也起到了自描述的效果, 确保API的使用者即使不阅读文档,仅凭浏览这些参数本身,就能大概了解该API到底支持One Order哪些数据的修改。
这也符合那份著名的来自 Google 的API设计最佳实践文档里提到的,好的API应该满足的条件之一:易学易用,自描述,不易造成误解。
SAP CRM 的部分功能迁移到 SAP S/4HANA后,部分实现做了一些改造,其中就包括One Order的改造。
为什么要改造?因为SAP CRM搬到了S/4HANA上,而S/4HANA的一个强大之处,即 S/4HANA在 SAP 历史上第一次实现了 OLTP 和 OLAP 的完美结合,即一套系统的唯一数据源,可以同时满足Transaction事务型应用和Analytics分析报表型应用的需要。
而SAP CRM One Order没有改造之前的模型是无法和S/4HANA的上述特性匹配的。
改造之前,每个组成One Order模型最小粒度的结构体,都有自己独立的一张专属数据库表,命名规范一般是CRMD_加上结构体名。
这套底层存储模型如果原封不动地搬到S/4HANA里,在运行报表统计等应用时会出现性能问题——为了取出报表结果,后台需要在很多个结构体的存储表中做各种数据库表的内外连接操作。当参与连接操作的数据库表尺寸增长到一定数量级后,整个应用的性能表现不佳。笔者也参与了性能评测,最后我们决定对One Order的底层数据模型做改造。
因为留给我们从调研到改造的原型开发,再到正式开发一共只有八个月的时间,因此我们选择了一种代价最小,对One Order框架改动最小的方式。
首先我们抛弃了之前每个结构体拥有一张专属数据库表的做法,在 S/4HANA 里,每种订单类型只拥有两张表,一张存储抬头级别的数据,另一张存放行项目数据。之前散落在不同结构体表中的字段,如今统一维护在这两张表里。由于所有的字段都平铺在这两张表里,我们内部形象地称其为平坦表(Flattened Table)。
存储模型大大简化之后,我们基于这两张表再创建CDS view,让上层的报表应用消费。这样改造后简化的模型,能满足S/4HANA中OLAP应用的需求。
针对S/4HANA OLTP应用的改造,用一句话概括,就是我们采用设计模式里的适配器模式(Adapter), 在API与简化后的数据库表之间引入一个微型的中间件,扮演Adapter的角色。
当消费者通过One Order API进行读操作时,中间件负责把存储在简化后的数据表中的数据进行还原,再填充到One Order API上层的缓存中。对后者来说,它对底层存储模型发生的变化毫不知情,因为Adapter封装了底层数据读取的逻辑并做了格式转换,所以One Order API上层不需要做任何改动,也完全能够像在SAP CRM里一样正常运行。
而当消费者调用One Order API进行写操作时,在存储于各个结构体对应的缓存中的数据持久化到数据库之前,同样是Adapter负责把这些分散在不同缓存结构中的数据做一个合并,合并后的结构体再写入平坦表。
讲完了CRM One Order订单模型的设计,我们再来简单看看SAP Cloud for Customer的订单模型设计。
虽然SAP Cloud for Customer的后台对客户和Partners不可见,但我们仍然可以从合法渠道获得一些其订单模型的设计信息。
从SAP社区上这位SAP员工的回复,我们得知ESF2和BOPF有很多相似之处,设计理念类似,但ESF2主要用于部署在云端的产品,比如SAP Cloud for Customer上Business Object的开发,而后者主要服务于On Premises解决方案比如S/4HANA。
同之前介绍的SAP CRM One Order框架一样,通过BOPF实现的订单模型,同样由若干个结构体通过搭积木的方式组成,这些结构体如上图红色高亮区域所示,每个结构体也有自己的专属存储数据库表。而SAP CRM One Order里每个结构体的事件监听函数,采取的是 ABAP 传统的面向过程的函数实现,而BOPF则采取了实现指定接口的ABAP类,二者原理相同,只是实现细节有差异。
SAP C4C的订单模型,虽然和SAP CRM传统的One Order模型一样,每个结构体拥有一张专属的数据库表,但是在运行报表程序时并不会出现性能问题,这是怎么做到的?
答案是采用了TREX,一个专为只读报表应用优化过的存储仓库。换句话说,SAP C4C的事务处理和报表处理使用的是两套不同的存储系统,这一点和S/4HANA不同。
SAP Cloud for Customer的订单模型,在Cloud Application Studio里对客户和Partners是可见的,大家感兴趣的可以自行去查看。
总结
本文首先详细介绍了 SAP CRM 系统里订单模型的演进历史和设计原理,以及消费该订单模型的 API,接着介绍了这种模型迁移到 S/4HANA 系统时面临的挑战,以及笔者所在项目团队给出的迁移重构方案。最后将另一款云端 CRM 系统的订单模型进行类比,希望对工作于客户关系管理领域的读者能有所帮助。