重构:又喜欢又害怕
一个企业级的应用,即使是诸葛亮级别的设计人员,最初的考虑都不可能尽善尽美,会存在设计不够或者设计过头的情况。加上业务的发展可能与当初的推想不一致,这样就使得上线初期稳稳当当的一个系统,在若干轮的需求驱动下,就变成了补丁之上打补丁,活成自己讨厌的样子。当然,我们也可以把锅往最初的设计和开发上面扔,但还是解决不了系统维护越来越困难的事实,“累了,毁灭吧”想推倒重构的想法其实是大家喜闻乐见的。
然而对于企业级的应用,系统的重构,不管是对软件供应商,还是对企业本身,还都是个痛苦的过程。重构不仅要需要考虑众多的技术、业务因素,也需要考验甲乙双方的管理水平,协调能力等等。如果涉及到软件供应商的更换,那么这个事情就难上加难了。
大家所期待的,是重构后系统更加适应现在的业务,使新的需求、新的业务开发更加丝滑,大家所担心的,其实是伤筋动骨后,系统如何能够保证业务的稳定性和准确性,大家对于重构的态度其实是:像一个少女等待他的男朋友,既怕他不来,又怕他乱来。
对于喜欢的部分,主要靠设计和开发的大牛们来实现,而对于害怕的部分,就主要看我们交付的兄弟们了。
虽然如此,但是现在如果去百度一下,如何确保系统重构时的业务准确性,甚至你去问 chatgpt(没错,我问过了),得到的答案绝大部分与设计和开发有关,却很少有测试和实施的部分。
主要原因是实施方面与业务相关性太强了,要总结这方面的共性,无非就是数据迁移要准确、回归测试要充分之类的,至于如何保证,那就要开始说业务特性,但说业务,有点无从下嘴的感觉。
当然,今日份的骨头,我啃了。
电信运营商的计费系统可能是最不敢在重构时乱来的企业级应用了,“计费”这两个字就说明需要极强的准确性。在计费系统的重构实施中,对于如何确保业务准确性,形成了自己固定的一个自己固定的套路,也就是对账。计费系统的工程实施人员,很多从事的第一项工作就是对账。当然,对于发量充足的新手,这时候自然要发出灵魂三问:
我是谁?你是计费系统实施人员。
我从哪儿来?刚从公司总部出差而来。
要到哪儿去?你要对账。什么是对账?
(头发丝落在了地上,没听见一点声响,忧伤的悲伤的音乐响起)。
本文的目的,首先是介绍一下计费对账的这个套路,给新手一些指引,也顺便让计费专业的同学更好地理解计费系统的实施过程。当然,高度还是要有,也想对给企业级应用重构实施的准确性保证提供一点方法论,给其他专业的同学一点点那种“他山之石”的感觉。
什么叫对账
对于被这么硬核强扯到“对账”这个名词一脸无辜的同学,还是要先给对账做个定义,这个词源头应该来自于会计专业(可能与计费系统的前身与财会有很大关系有关),在计费专业,对账这个词的意思一般是,对重构前(老系统)和重构后(新系统)的系统运行的结果,进行差异比对的过程。只有这个比对的差异到了足够小,一般是一致率到 99.99%,才说明新系统的计费结果是准确的。你可能认为这种手段比较极端,但是本着我能崩溃,程序不能崩溃的原则,这种手段其实是很必要的,不然计费系统永远没底气上线。
聪明如你,其实已经发现,对账其实是一种回归测试手段,因为如果对任何程序:“输入 + 程序处理 = 输出”的话,那么对账就是对输出的比对,用来确认新的程序是否存在不能兼容老的程序的问题。
也就是说,对账其实就是使用相同的数据源输入(有时候未必能做到,可以使用尽可能一致),经过不同的程序处理(老系统和新系统)后,通过比对输出,来对新程序的正确性进行判断,并且通过修改程序来纠正新程序的错误的一个过程。当然,对于一个大的系统重构,这个程序处理应该替换为系统处理,因为整个大的系统处理的流程、配置、资料结构都可能出现大的修改,差异的原因,也往往需要从程序、流程、资料、配置等几个大的方面去寻找。
计费对账在计费系统重构时,非常重要,甚至可以说,工程实施的很多工作,都是围绕对账来进行的。基本上,计费系统的所有工程实施人员,从事的第一项工作就是对账,其实这并不是因为对账是个简单的工作,恰恰相反,对账是所有工程实施工作中最难的,它需要有扎实的业务功底,也需要非常熟悉新老系统。
那为什么基本上所有的工程实施人员第一课都是对账呢?原因很简单,从业务学习的角度来说,对账是一个最好的切入方式,也是一个相对容易上手的方式。但是,也因为这个工作要做好,实际比其他任何的工程实施工作要复杂,要难,所以基本上所有的新手压力都非常巨大。
对账的准备
首先要说个无用的废话,对账的准备最重要的是,对于计费系统的重构实施的进度,到了能够对账的程度。这其实也是实施中一个重要的里程碑点:
研发方面,至少已经到了大部分需求都已经开发完成并测试通过。
部署方面,程序已经在新的部署环境下部署完成并且稳定运行。
数据迁移方面,基本的静态资料(批价配置)和用户资料数据迁移已经可以完成。
当然,大家都懂这些事情不卷是不可能的,不能指望所有的料都准备好了再下锅,所以如果没有完成的部分,要留下遗留问题列表,免得对账的兄弟在这些坑下面越挖越深。
除了项目进度已经到了可以对账的程度,对账本身还需要如下准备:
对账环境
这个可能很多人存在疑问,老系统的程序输出结果(清单、账单等)在老系统就有,而新系统既然已经能够部署完成,准生产环境已经具备,那么环境还存在问题吗?主要需要说明的是,我们尽量不要使用老系统程序历史的输出结果(生产环境的输出结果)来比对。因为我们要保证系统的输入是相同的,这个输入,不仅仅包含计费系统要处理的数据源(话单),也包括计费系统的用户资料,套餐的配置资料,其实还包括一些更加动态的资料(如累积量)这些都要保持稳定,而生产系统的这些资料,都是在不停的变化中,如果使用生产系统的结果,那么就需要有可靠的手段来能够排除这些变化的部分,这就加大的对账的难度。所以,新老系统的环境我们还是需要准备的。
-
老系统环境:我们必须要搭建一个跟生产环境资料、程序配置一致的环境(硬件规模不必和老系统相同)来重新处理相同的话单,得到结果后再与新系统比对。
-
新系统的环境:如果准生产环境已经建好,那当然好,但是也有很多卷起来的时候,准生产环境的硬件并未到为,这时候需要使用一个临时搭建的新系统环境。
对账数据源
前面已经说到,计费的数据源不仅仅包含了我们要处理的数据(原始话单),也包括了处理数据过程中要用到的用户资料、配置等。对于老系统,直接使用生产的备份数据即可,对于新系统,需要将这份数据迁移到新的对账环境中。
对账人员
对账的人员往往是一个团队,人数看项目的大小,大的项目可能多达十多人。内部还要分组,一般来说,我们按照模块分组,比如租费、语音、流量等等。除了对账人员以外,配合对账的角色也不能缺:
-
系统运行:熟悉新系统、老系统的运行人员都需要有,负责新老系统的跑账。
-
业务专家:熟悉新系统、老系统的业务处理流程和逻辑的专家,参与差异结果分析和确认。
-
资料割接人员:参与资料割接的人员担任,负责解释资料迁移的逻辑,参与差异结果分析和确认。
对账脚本
对账脚本的作用是从新老系统的对账环境抽取输出结果,然后对输出结果进行比对,生成差异。这个当然要提前准备好(现在我们有专门的工具来做)。对于脚本如何编写,这涉及到对账的方法,在下文讨论。
差异的生成
之所以认为对账这个事情,对于其他的系统有借鉴的意义,也是因为这个过程,有很多共通的地方,比如差异的生成,其实很多系统都有类似的方法来比对两边数据的一致性,大家的方法也都差不多。
能确定唯一数据的字段
要生成两个系统的差异,首先要确定的是,对于处理的结果,我们如何确定是来自于同一个输入的数据源,这就是数据比对唯一字段,一般而言是字段的组合。在计费系统中,比如语音业务(电话拨打),一般就是用计费号码、开始时间、结束时间标记是否同一条话单(同一个数据源),在差异生成前,应该先确定这三个字段(话单属性)是否可以做为唯一字段。
在选择唯一字段的时候,需要尽可能的选用不是程序产生的属性,而要选用话单数据源中就有的属性,比如对于某些交换机产生的话单,结束时间并不会填,由开始时间+时长计算出来,这时候,就最好使用开始时间和时长做为唯一字段。当然,如果确定一个属性新老系统都绝对不会存在算法差异,作为唯一字段也是可行的,现在计费对于语音业务,计费号码一般也是通过话单类型(主被叫、呼转等)和主被叫号码判断而来,不会存在差异,也可以作为唯一字段使用。
比对字段
比对字段确定哪些输出的结果需要和老系统一致。比如对于计费,金额是最敏感的字段,肯定需要参与比对,同样,一般参与比对的还有账务科目(涉及到账单展示和财务列收),这就能够确定金额和账务科目是比对字段。
参考字段
参考字段的意思就是对账分析原因时,可能会用到的字段,比如新老系统的批价的费率标记,计费时长等等,这些字段只用来做参考而放入对账结果中。
确定这三类字段后,对账脚本或者程序使用唯一字段,生成如下四种记录:
-
老有新无:老系统存在的结果记录在新系统中不存在。
-
新有老无:新系统存在的结果记录在老系统中不存在。
-
不一致:新老系统都存在此记录,但是比对字段不一致。
-
一致:新老系统都存在此记录,结果也一致。
很多刚开始接触对账的新手,会不明白为何有新有老无或者老有新无的差异。这种差异产生的原因,一方面是因为我们的程序,不仅会输出正常有处理结果的话单,也会输出一些因各种原因无法处理的错单,而实际上,计费的整个流程中,有多个程序在处理,如预处理、批价、合账、入库等流程,在每一步,都可能产生错单。如果某条原始记录,在某个流程中处理成了错单,那么在结果中就无法找到,这就造成了新有老无或者老有新无的情况。当然还有一种可能,就是因为新系统的业务处理规则与老系统不同,故意抛弃了一些话单不进行处理,比如一些原始话单的时长为 0 的话单,就可能存在老系统不处理,新系统处理的情况,这种情况下,也会造成老有新无和新有老无的情况。
差异的分析
输出差异结果后,就开始对差异的结果进行分析。分析结果,了解新老系统的处理流程和处理逻辑是非常必要的。
前面提到的,输入+程序处理=输出。这对于一个程序,实际是明确的,但是,其实这儿的程序处理,并不是指单个程序, 这中间会有很多个程序,实际上,是多个程序。程序的输出,也不可能只包括一种,肯定有多个的输出。举实际的例子,比如语音话单:
-
输入 = 联采话单。
-
程序 A = 预处理 输入=联采话单 正常输出= 预处理正常话单 过滤输出 = 预处理过滤话单 错单输出= 预处理错误话单
-
程序 B = 捡重 输入=预处理正常话单 正常输出 捡重正常话单 错单输出= 捡重错误话单
-
程序 C = 批价 输入= 捡重正常话单 正常输出 = 批价正常话单 错单输出 = 批价错误话单
-
程序 D = 合账入库 输入= 批价正常话单 正常输出 = 合账正常话单 错单输出 = 合账错误话单。
甚至在老系统或者新系统,可能将程序 A 分拆成 A1,A2,这些都是很正常的情况。而实际上我们比对的结果,一般来说,是合账后的正常话单,所以,产生差异,在期间任何一个环节都可能出现问题。
对于新有老无或者老有新无的话单
这些话单主要是因为在中间这么多程序中,都会因为各种无法处理(无法找到费率、无法找到用户资料等等)而丢掉一些话单(错单),或因为处理规则不同,过滤一些话单(过滤单)。造成比对中存在老有新无和新有老无的情况。所以分析的要点是:
-
这些话单是否在某一步的错单或者过滤单中?如果在错误或者过滤的原因是什么?是否合理?
-
是否存在话单,并不存在于所有结果表中的情况?这种情况是否存在规律(如来自于同一个原始文件)?如果遇到这种,需要给运行人员和研发人员进一步分析。
对于不一致的话单
对于结果不一致的话单,则更加复杂。对于计费,结果的不一致往往因为找到了不同的费率引起,前面提到的参考字段有有了大的用处。
-
如果参考字段不一致,那么这些字段是程序的哪一步转换而来?为何会出现参考字读的不一致?
-
如果参考字段均一致,那么是否漏掉了其他应该注意到的字段未列入参考?
对于计费,一般来说,不一致的差异一般都是这三种情况造成:
资料迁移的错误
我们的比对的第一步,是从资料开始,首先,就是比较资料割接的对不对,原来老系统,用户有 ABC 三个销售品,而在新系统只有 AB 两个,老系统用 C 销售品进行了批价,这时候你就要去质疑资料割接的人员,为何 C 销售品在系统中没有体现,是否存在问题。
配置割接的错误
面对上面同样的问题,你先去找了销售品割接人员,销售品割接人员告诉你,已经跟配置约定好,原来的 BC 销售品,目前都对应到 B 销售品,那么,你就要去检查,是否 B 销售品涵盖了原来 BC 销售品所有的批价逻辑?如果检查到有资费缺失,那就要去联系配置人员,为何这条资费没有被配置。
程序逻辑
如果检查到配置是有的,条件也符合,那最终的怀疑对象是程序逻辑,程序为何没有按照配置进行批价?这时候去找研发人员,跟配置人员与资料割接人员一起讨论。
一点点经验
不断学习,减少黑盒
如果系统重构的新老系统厂家不一样,那么对于新系统厂家而言,老系统的程序方面的黑盒子很多,甚至于对部分对账的新手,新系统都可以叫做黑盒子,正因为这样所以在对账之前,需要请教新老系统的业务专家,至少熟悉两边的处理流程,清楚流程中每一个程序的输入输出,对大概的处理逻辑也需要做一个大致的了解。另外,也需要请教用户资料、静态资料(资费配置)的割接人员,新老系统的模型差异以及割接逻辑。当然这些问题也基本上都有文档输出,比如前期的流程调研文档,用于数据割接的模型差异文档,用户某些单独需求的专题设计文档等等,这些文档都需要一一看过先有个整体的印象。
在对账期间,不管是新老系统的业务专家还是程序研发人员还是数据割接人员,他们都会很烦.因为对账的团队人会非常之多,但是,作为对账人员的你肯定需要不停的是骚扰他们,你的目的是,不管是新系统还是老系统,不管是程序还是资料还是配置,这中间的黑盒子越来越少。
小步快跑,逐步覆盖
对于新老系统的对账环境,有时候硬件环境并不能与生产等同,所以运行大量的数据还是需要很多的时间,所以,对账中一般会采用这样的原则:从小到多,从代表业务到全业务这种方式.所谓从小到多,是指先对小的业务量,比如一天,从代表业务到全业务,是指先完成某类业务(如语音),确认资料割接和配置割接没有大的问题后,再进行其他业务的对账。这样做的好处一个是不需要把大量的时间放在运行上,另外也不会被海量的数据搞得对账无从下手。当然,一般在对账之初,就会列出一个对账的计划,会包含这个部分的内容。这是一个典型的例子:
关注重点,不钻牛角
对账开始的时候,初始的差异肯定是非常大的,首先还是不要被巨大的差异吓倒,因为大的差异,完全可能就是那么几个原因引起。
找差异时,首先要找共性最多的去分析(比如按照参考字段的差异去分析)。
找到差异后,要把同类错误的话单更新原因,再找下一类没有更新原因的差异,也要尽量找共性最多的。
切记前期对账时,如果某条话单找不到原因,不要钻牛角尖,因为这种话单,可能被多个原因覆盖,非常难于分析。当你一个个原因找到后,可能问题就解决了。