x

假如你五行属商家,如何和淘天做生意?

🌸 本文已部分在《阿里技术》上发布。

公司的财务管理远不止打钱收钱,远不止业财一体和钱账票一体化,而仅仅业财一体也是非常大的话题,非几本书不能讲清楚。这里笔者之所以“大言不惭“,其一是为了说明财务管理不是简单的报表和SQL,在业务和技术上都有非常多挑战;其二希望能给各位同学带来一点兴趣,从而可以加入我们一起迎接挑战。

前言

个人吃穿用度、迎来送往,都得花钱;节日红包、工资年终,也记账上。那么一家企业更是如此,新开了什么项目,办了什么活动,哪里该收钱,哪里该花钱,更是一分不能漏,一厘不能错。比如

  • 消费者在淘宝上买的东西到了,还是包邮的,他没有付钱,但是你作为商家会被收取物流费、仓内操作费、包裹的材料费;
  • 消费者在淘宝上要买冰箱,下单的时候平台顺便送冰格或保鲜膜,他也不会付钱,消费者未必会想到为什么他们可以在一起买一送一件赠品。不过这自然是平台在背后有这个营销活动,而撮合了这笔交易的同时你作为商家一笔服务费;
  • 再比如消费者买东西需要评价,有时候页面上会提示消费者评价了返红包给消费者,同样地我们需要扣你钱然后再把这笔钱当作红包给消费者;
  • 又比如消费者买东西有运费险不需要消费者单独付钱,但是如果是你提供额运费险,是肯定要给保险公司打钱的....
  • 另外如果是收钱,需要给消费者开发票;如果是打钱,需要给淘天开发票

诸如此类,而淘天本身也可以理解为一个大的商家,他和你与钱打交道的这个过程可以简单描述流程如下:
Finance Technology Area Relation
报价可以简单理解为我们会在你作为商家入驻平台或者后续报名活动时与商家签订相关协议,明确各项费用的收取标准。那么我们作为财务开发,如何从技术系统上管好公司这些打钱收钱的事?

定义问题

业务问题

你问:为什么扣我这么多钱?

如前所述,双方会明确报价,但是你怎么知道对方有没有算错,从而多扣钱呢?所以你需要对淘天给你的明细账单,看是否和你的预期一致。而且更重要的是,站在你的视角来说,你还需要知道对于每个提供给消费者的商品链接目前投入了多少钱、已经赚了多少钱、还有多少钱没到账,还要不要投入,要怎么继续投入?
这个专业一点说,就是你作为商家也有自己的财务团队,他们会通过对公司各项业务数据的统计和分析,计算公司的投资回报率(Return on investment,ROI),定期为公司提供详细的财务报告,以便公司领导层了解公司的经营状况,为公司的发展制定合适的策略。
所以我们作为财务开发不仅这个钱不能搞错了或者搞迟了,还得有凭有据--也就是要有清晰明确的账单,以及对应的经验分析数据。

TT问:我ROI怎么样?

那我们在的独立核算的BU业务自然更关注成本支出的细节,计算我们自己的ROI,出财报以及决策后续如何投资。
所以我们作为财务开发需要保证对外对内的数据都一致,并且对内的数据会实际用于分析决策以及稽核。

应收应付 Vs 实收实付

另外具体在处理公司财务时,我们还需要区分应收应付和实收实付。应收应付是指公司在一段时间内应该收到或支付的款项,而实收实付是指公司实际收到或支付的款项。你打给别人钱,他的账户被银行冻结了收不回来,这就是应付而未付;同理,你收别人钱,结果他账户没有这么多钱,这就是应收而未收;而那些没有成功结算的钱我们称之为不可结算。
就像商家会问“为什么扣我这么多钱?”一样,我们的财务需要应收应付来看当前公司的财务情况,也要关注不可结算及时追回该结算的钱。当然,如果财报里只有实收实付本身也是有合规性风险的。
所以我们作为财务开发要通过合理的设计,清楚的记录应收应付,并且确保应收应付与实收实付最后能准确对应,避免出现资金的损失。

业财一体

业财一体的概念诞生于国内复杂的商业活动,本身是一个很大的概念,相比字面的简洁,其阐释是复杂的。这里做个人不准确的一些阐述。

  • 业:指的是企业所有的经营活动和企业运营活动
  • 财:财务会计(帮企业数钱)和管理会计(帮企业赚钱)

业财一体的核心目标是建立财务和业务运营两个领域数据的映射关系,从而允许从财务角度及时和准确地解读业务运营中存在的问题。
业财一体目前具体在淘工厂技术领域的正向实现可以简单表示为4个流程:
业财一体.canvas
所以我们作为财务开发要实现业财一体,这样才能解决账单、财报等数据从哪里来的问题

代码不到位,资损两行泪

而说到资损,就不得不提到一句中国的俗话,“常在河边走,哪能不湿鞋”;或者说外国的墨菲定律,“该发生的一定会发生”。也就是说,代码总有出bug的时候、业务逻辑总有少考虑的时候、三方系统调用总会不符合预期的时候等等等等,但是一定不能出资损。
所以我们作为财务开发的你**要如何做到无资损?

技术难点

说完了上面业务上给你提的问题,实际开发中我们就要问这些问题了:

  • 业务和财务的数据分散在各处,怎么关联?
  • 上百个结算场景,怎么快速接入?
  • 上百个账单类目,怎么快速接入?
  • 几百亿条账单,hold得住吗?
  • 流程这么长,怎么样让所有数据都对得上?
  • 上百个账单类目,财务时不时要换角度看怎么办?

核心技术

别一个头两个大了,我们都有解决办法。

接的快: 淘宝TMF 2.0

TMF,全称为Trade Module Framework,诞生自阿里巴巴交易中台的业务场景。2017年双11,阿里的交易峰值达到了32.5万笔/秒,同时系统需要支撑全集团几十个事业部的所有交易类需求:要考虑如何能更快响应需求、加快发布周期;如何能为新小业务提供快速支撑、降低准入门槛;是否足够开放使得业务方能做到自助式扩展;新需求是否已经在其他事业部有可复用资产等问题。
由此诞生的TMF成功为快速接入多个业务流程到平台提供了一套解决方案。我们模拟一下它在财务结算场景下的技术实现流程:
1. 物流费的业务方找到你,你按照业财一体的流程实现了一笔交易物流费的收单、业财链路、业财集成与销账
2. 买冰箱送冰格这个营销活动的业务方希望你也找到你,你发现收单的某些信息可以复用,其他流程也是,而销账这个流程几乎整个都可以复用,你想起来设计模式里面的策略模式和责任链模式,于是封装了一系列策略接口,让不同的业务实现不同的策略接口,并通过判断业务身份决定走哪些业务逻辑
3. 业务越来越多,你会发现流程中多出了一个又一个的策略点需要对应的业务方开发实现,这时候业务方需要理解具体的结算流程才能实现这一个个点,接入和debug门槛过高。于是你引入了TMF2.0,将你的策略接口封装入一个个模版类,并开发扩展点,接入者只需要实现扩展点即可,而对于某些必要要指定的逻辑通过模型的校验逻辑、抽象方法等会“强迫”接入方实现
4. 模版类也越来越多,业务方开发仍然需要梳理清楚自己需要实现哪些扩展点,这时你进一步将扩展点的类生成逻辑封装到可交互的GUI中(我们是IDEA插件),业务方只需要填写一些信息,就能生成对应的类和部分通用代码,这样对于新手他就知道自己要实现哪些扩展点;对于老手也避免了复制黏贴
5. 业务逻辑更加复杂,以至于模版类越写越长,于是可以再用TMF 将策略接口和模版类都封装成解决某个通用业务问题的产品,让有业务开发者直接以JAR包的形式实现产品的特定逻辑,进而启动应用时加载对应JAR包
事实上我们还没有走到第5步哈哈。
如此我们就解决了结算场景如何快速接入的问题。

对的清: 钱账票一体化

就像开篇介绍的报价-计费-结算-账单-发票流程一样,这其中钱账票在业务链路上是天然的顺序关系,所以是否能将这整个过程自动化,即智能感知市场报价,根据交易计费、结算后,自动化地生成账单和发票是一个业务上、效率上和数据质量上都值得思考的问题。特别是数据质量上,只有大家的数据尽可能少的从外部传入,都是在业务流程上自上而下消费,数据一致性的问题才能自然而然解决。
Practices-for-Processing-l0-Billion-Bill-data
如此我们解决了如何快速接入百亿级别账单,以及让所有数据都对得上的问题,特别地,对于财务时不时要换角度看我们还对前端图形做了抽象。

行的稳: 事前、事中、事后

事前约定与评估

正式开发之前,每一个业务的接入或变更,都需要经过业务方、产品经理和领域资深同学的评估,并且将结论落实到文档中以便后续查阅和对焦。
另一方面,实际开发中,标准化命名和类型约定将节省大量繁琐的工作。命名上比如数据表中使用a_b_c,应用中统一是aBC;类型上比如数据库中存储的统一是String格式,日期格式统一采用yyyy-MM-dd hh:mm:ss。这将使我们也能够标准化数据类型。

事中测试、Code Review

测试

在实际业务开发中,账单涉及数据时间跨度长,计费规则也常变,如何既覆盖各种异常case,同时长期保证transformation 的数据质量值得思考。而测试是帮助我们将发现问题的时间尽可能提前的好手段,同时也是保障长期不会出意外变更问题的必要手段。不过实际生产中,除了普通的单元测试,我们可能还需要根据业务需要自己开发工具。
比如物流服务费账单因为实际计费口径和希望给用户展示的口径不一致,后台需要处理来自三个不同接口的4份数据,然后再按照订单包裹维度解析。然而4份数据:物流费、包材费、防护费和仓内操作费都没有办法和订单包裹关联上,只能按照一定的顺序和商品的关系关联,又因为历史上包材计费的系统迁移过,历史数据格式大变过且是灰度逐渐切流,更增加了数据处理的难度。基于此,可以采用参数化测试。
这就是最简单的参数化测试:将数据和逻辑分离。同样地,我开发了@JsonFileSource 传入JSON格式的对象,并将每个时期变动的计费逻辑都覆盖到,于是我们对数据处理正确的信心大大增加了。

@ParameterizedTest
@CsvSource(value = {
        "1,2",
        "3,4"
})
void should_show_how_to_parse_multi_args_with_csv(Integer in,Integer out){
    assertEquals(out,in + 1);
}
Code Review

CR 的重要性毋庸置疑,不仅是代码上线的最后一关,也是让CR双方快速学习的重要手段。
在TT,代码写得好的前辈很多,新人来TT才能看到他们写的优秀代码,也才能让自己被他们CR啊。

事后自动化测试、资损监控

自动化测试

之前写的测试在实际生产过程中,每次的变更都会触发其运行,从而起到保证原有逻辑不受意外变更、保驾护航的作用。
另外当我们把数据导入数据仓库时,ETL中的每个步骤中都可能会遇到数据质量错误,比如

  • 与源系统的连接错误,抽取数据可能会失败
  • 由于数据类型冲突,数据转换可能会失败
  • 由于数据生产者新增或变更了存储逻辑,导致处理后的数据异常

对于ETL过程中不是单点的错误,我们监控一些数据任务的指标。

数据任务监控
  1. 校验每天新增的记录数波动范围:比如突然下降了100%(即一条数据都没有),这种肯定是不正常的
  2. NULL和0 值 校验:保证每天增量数据中的NULL或0值不能超过新增数据的99%
  3. 主键校验:通常来说基于主键的数据不应该重复

而对于长期维护数据消费逻辑的过程中,每一条记录的数据质量保证,最好还得基于约定和测试。

数据核对

核对是对代码执行逻辑是否符合预期的事后保障。比如你认为当前1笔交易应该产生2笔资金流,你就可以通过对既成事实的交易数和资金流数目进行核对,从而知道事实上运行的系统是否保证了1笔交易应该产生2笔资金流的逻辑。

如此,我们尽力地保证了没有资损。

总结

笔者能力也有限,不能完全保证表达的概念都准确,希望大家批判地阅读。不过笔者简要介绍的TT财务开发做的业财一体和钱账票一体化事情不知道有没有引起优秀的你们一点点兴趣,有兴趣就加入我们吧!

Left-click: follow link, Right-click: select node, Scroll: zoom
x