每接入一个新的支付方式,所有已上线的业务都要跟着改一遍账务逻辑;每上线一个新业务,所有已有的支付方式又得重新适配。系统小的时候看不出问题,两边一长大,集成成本就开始成倍往上翻。
这不是平台该有的样子,这是一张矩阵。作者在支付账务上撞到了这堵墙,但他说,真正的教训其实不在支付本身。
![]()
当两边互相知道对方是谁
设想有 B 个业务、P 个支付方式。如果每个支付方式都带着业务专属的行为,那么每一个交叉点都是一次集成,成本会朝着 O(B × P) 的方向走。
账务让这件事格外难看,因为对客户看起来完全相同的两条资金流,在账本上可能截然不同。预付余额支付就是最干净的例子:客户看到的是余额减少、订单付清;账务看到的是一笔必须减下来的负债。业务侧还要确认商品收入、税费、运费、折扣等一堆科目。
时间点也是分裂的。有些分录在支付被接受时就触发,另一些要等到履约或交付。在作者所处的系统里,这些任务已经缠在了一起——同一个支付方式,可能因为服务的是不同业务,就需要不同的科目、配置、事件读取和记账逻辑。
于是两条坏规则浮出水面:
- 加一个业务,支付团队要干活。
- 加一个支付方式,业务团队要干活。
两边谁都没法单独行动。作者说,这就是他现在盯着的味道:如果在一侧新增东西,会迫使另一侧不相关的团队改代码,那说明边界画错了地方。
把中间那层交给交接
真正有用的问题不是怎么把每一对都映射好,而是:支付方式为什么需要理解业务?它不需要。支付要记的是支付,业务要记的是销售。它们相关,但职责不同。
所以做法是:不再让两个领域直接对话,而是在中间放一个分类式的中间层,作者把它叫作交接。支付侧对着交接结算,业务侧也对着交接结算,谁都不对着对方结算。
一句话,改动很大。在预付余额场景里,支付系统可以借记预付余额负债、贷记交接;业务系统则按自己的节奏,借记交接、贷记商品收入、税费和运费。交接就是那道缝。
它最有用的性质,是穿过它的东西足够少。共享契约不需要写成 StoredValueBalanceForRetailOrderInCountryX,金额 100、类别 PRE_FUNDED_BALANCE 就够了。一旦边界开始携带两个领域的想法,矩阵就会悄悄爬回来。
各管各的烂摊子
缝一旦存在,归属就变得无聊,而且是好的那种无聊。支付系统管支付行为:钱什么时候真的动、来自外部账户还是内部预付余额还是某种递延、它的负债、它的生命周期。业务系统管业务账务:订单怎么拆成商品收入、税、运费、折扣、费用,以及这些金额在它的履约模型下何时可确认。
两边都不导入对方的领域模型,这是最大的收获。人们把解耦描述成依赖更少,作者觉得这低估了它。真正有用的目标,是一个团队需要理解另一个团队世界的程度有多低。
如果一个支付工程师上线一种方式前,得先学会每个业务的账务,那组织就扩不起来,哪怕服务之间是通过 API 说话的。如果一个业务团队必须了解每种支付工具的底细,那些 API 也没保护到任何人。服务边界不会自动变成团队边界,得刻意去画。
几十种类型,不等于几十种行为
第二个乱局藏在第一个里面。平台上堆了几十种支付类型,最直觉的做法是把它们全部暴露给下游。业务确实和实现解耦了,却仍然被一个长长的 if/elif 卡住:信用卡、银行转账、礼品卡、积分,一个接一个。这么搞下去,矩阵会被一个分支一个分支地重建出来。
真正的问题不是这是哪种工具,而是:客户的钱到底什么时候动?就这一个问题,把几十种工具压缩成了三种账务行为,其中第一种是即时结算——钱被收进来。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.