交易系统模块划分,模块拆分,设计,重构实战.状态

2023-11-01

父文章 技术设计金字塔  包含了实体设计文章

相关文章 如何梳理和重构_含复杂性度量

相关文章,代码级:  如何写可维护的代码 - 万物ddd ddd primitive . 封装,对象来实现可维护代码._个人渣记录仅为自己搜索用的博客-CSDN博客_ddd 代码demo

随着代码越来越多,引发了很多问题.

企业架构分为事业部,

其中又分为产品,开发,ui 。

这是两种划分 垂直切分和水平切分

说到我们技术系统,水平切分和垂直切分是什么?

最小划分到什么层级?答案: 最小的流程力度.可能会有进一步拆分出底层支持模块.比如帐户,比如券.


关于需求评审和设计拆分步骤:

   如何识别模块.

            架构的设计(识别人,识别流程,自人向下思考,沿着生命周期思考)和架构的优化(设计思想+下沉上浮,下沉spi化,上浮后期代码少点一次)

         生命周期法.

                抓住create流程. 1.create流程明显另外一波人执行. 企业支付. 需要现有企业账户. 故 企业账户和企业支付能力专门搞个模块,甚至部门 2. create流程和读是两个系统依赖. 谁都不强,下沉.

                例如费用和优惠需要订单的数据,故拆出来的费用模块需要依赖订单.

         相应的思维转变难点: 1. 新增费用 改同步调用为通知(实现懒惰生成机制,避免通知没有收到来获取费用), 最好是双向依赖, 费用提供接口出来.  2.读取费用直接从费用模块读取

         依赖倒置法:

                本质:  人的各个流程都用到某个实体. 故最好下沉,不要放到任何一个业务里.

                      1. 设计初期,提前识别到,本质是:增进效率.

                      2. 接受老系统时能否拆解,识别到可以独立出去. 新增一个引发对实体架构和对流程设计的改进,是否可优化.

                费用模块,需要订单的数据.  但是把费用反转作为支撑模块,需要订单把数据传递过来. 相当于只是作为一个存储系统,提供增删改查功能. 业务逻辑有上游自己完成. 解耦 合适生成费用等逻辑.

                类似的还有 帐户支付系统. 帐户在生命周期最前面. 但是支付需要订单,费用等数据. 这些有一个模块调用订单,然后再把数据提供给支付支撑模块.

                其实任何新增模块后,都可以采用这种思路,进一步抽象出支撑模块,提供平台化.

          企业支付全流程模块法:

                  将企业支付各个流程提取出来,集中管理,提供增删改善,冻结接口.

   先大的垂直拆分:

         出租车,专车,代驾. 贴吧广告,品专广告.

   再水平拆分:

        核心流程拆分: 

                   下单,预估,获取订单费用,订单支付,优惠计算.

       新增模块的分类:

               支持模块,顶层模块.

               顶层模块:

                   一旦出现顶层模块,对应的 api 就需要迁移

              

               1. 举例:

                    订单和费用 即可以是订单依赖费用,也可以是费用依赖订单.

                    订单依赖费用:

                          数据传输改领域获取为接口传递. (支撑模块,基础模块)

                    费用依赖订单:

                        费用生命周期在订单之后. 故可以提取出一个顶层模块.

        表归属整理:

             然后将领域实体划分到对应的业务流中.

             3.1 另外最好将表拆分,最小化功能原则. 按照流程和业务将通用的部分提取出来.

            比如帐户流水和订单,支付,充值业务都相关.那这些就属于非帐户模块属性. 泛化为一个biz_type和desc描述.

             比如订单表,分为orderBase orderResult  1对1 .下单和成单后属性

        接口重新整理(难点):

              把调用费用的接口归类到费用模块. 不然你就会觉得别扭了.

   模块内再垂直拆分:

       支付,提现. 可以抽象出帐户的实体.

       充值,支付,押金支付可以抽象出支付账单的概念.

       退款,打款打款,可以提现出退款的概念. 底层调用的一个是原路退款,一个是提现.

       提现分为司机提现,打款退款.

    引擎 or 基础服务:    

          何为引擎:

          如何选择: 

                如果组织架构相同,优先引擎,如果组织架构不同,优先基础模块.

            举例: 

                     引擎层有帐户的支付功能, 支付时关系到优惠的冻结,解冻,等操作

                    类似引擎的反例:

                              有一种优惠实现是券,券的绑定,计算券抵扣面额,券的冻结,券的核销,券的解冻都是基础能力.券是具体. 并不是抽象. phoenix 把券的功能封装掉不算引擎. 只能是平台提供的一种功能.       

                     引擎实现:

                            但如果说业务方有各自的优惠,这些优惠如何冻结,如何解冻,如何绑定,如何核销,一开始只传入类型值. 控制流程有平台控制,但具体逻辑有业务方自己实现. 这就属于引擎了.

                     基础实现:

                           各种业务入口各自管理各自的优惠.可能每个优惠各自的逻辑不同. 不一定都有冻结,核销等逻辑, 然后调用帐户的支付功能

支撑模块(基础模块)的两种来源:

     依据生命周期,生命周期在之前的顺其自然就是上游模块,在底层.

   

    来自于水平拆分:

           费用的生命周期本来在订单之后,但是你可以进行反转. 将其费用中的订单 id 抽象化,变成支撑模块.

    来自于垂直拆分:

          帐户. 司机充值,订单支付的支付功能. 行为数据更适合作为支持模块保存. 另外帐户本身生命周期就先于

模块拆分项目执行:

    1. 代码存放形式

          由于 java 的模块化领域隔离能力较弱. 所以切割为两个工程,互相之间通过 rpc 调用隔离边界.

    2. 先底层支持领域模块代码和直接暴露的接口迁移过去.

          根据自己领域暴露读/写接口.

          不需要变成引擎模式

    3. 复杂上层模块的职能流程图.

         整理出需要的领域接口.

   

实例:

    帐户系统为什么拆分出来.

   费用和优惠模块的变迁?

        本来优惠计算都是支付系统完成的. 放在支付模块里. 后来订单前期也需要这些数据.导致订单模块需要调用支付模块. 改造: 增加 api 层(cos 层) 由 cos 层去组合. 这样领域的概念就弱化了. 更好的方案是 优惠和费用计算模块下沉到底层去. 优惠和人相关的,费用和订单相关,有些优惠比如权益也和订单的费用相关. 从生命周期来说, 一个是订单下游,一个是订单上游. 所以为了避免双向依赖.

      方案1: 费用计算订单把相应的数据传递给费用模块. 

      方案2: 这个模块是订单和支付的中间层模块. 但是这样的话,领域模块就越来越细了.

      最核心的理念转变:  获取订单费用, 不一定要从订单模块获取. 预估的费用,可以直接前端把数据传递给来计算(这种数据不需要存储) 不需要订单那边过一遍. 降低订单的认知. 而不是让订单系统来逆向调用.

原模块重构流程:

1. 首先通过垂直拆分业务流, 然后水平切分复杂业务流. (个业务流功能点。)

2.1 合并流程命名对应的模块名. [流程模块法]

4.将业务入口划分到各个模块中.

5. 可能不能的模块会共用同一张表,那这张表的service就是支持模块.

6.  找出现有的 type 值和 status 值, 看看是否可以归并出子 type , 下游保存的 type 是否是上游传入. 例如 cashier_thirdparty 的 biz_type

7. 难点的地方(找出原系统可改造的点,不被原有代码所所述的 实体结构影响 ):

     增加中间实体,更或者组合:

     7.1  共存的组合:变静态写死的多个组合,抽象为相同实体的 list ( 券,权益,支付渠道抽象为渠道,不同渠道的不同静态参数,用泛型来实现, 或者 map )

     7.1.1 有些叫计数,有些叫记账(还和 orderId 在同一张表) .这些抽象为帐户的概念. 这个是难点, 不过最终还是和现实世界匹配,领域世界匹配.因为有这些概念领域已经运转的很好了.

     7.2  互斥接口: 变互斥的多个为接口,然后 creator, kuaipay ,phoenix, 第三方支付的支付,支付查询,支付回调,退款

     7.3  不同流程依据的分流 type 不一样, 比如费用流程按代保养,代驾分,支付流程按支付系统分,再按支付渠道分.(业务只是其中的一个值了,取微信的配置用)

     7.4  分拆后又聚合: 流程分拆后, 发现各自的流程也有共同的, 那么就需要抽象出面向抽象接口的组装类 manager,比如 支付 要保存支付流水和向下游系统交互. 这个就是 manager 的功能, 或者说是抽象父类. 但是最好不要用继承,用接口组合是最好的. 衍生性比较好.

     7.5 稳定性相关重构. 减少计算,增加存储. 例如: 根据费用要计算很多. 乘客支付金额, 平台垫付金额, 司机报单优惠, 权益等.  每次计算都要获取大量的数据,增加依赖和不稳定性.

          券也能先计算(企业支付不能用券,微信等可以用券)

    7.6 入口变更. 例如费用和订单. 费用后生成,

  

一期后的重新思考,不仅仅局限于水平,垂直. 还包括(亮点,创新收获):

  1. 模块划分的意义在于边界和隔离变化(高内聚). 起到上游的变化尽量少影响下游.

        边界 : 和支付宝打交道需要一个系统, 网关

        底层领域(复杂Bean和新技术栈)屏蔽隔离 :

              1. 比如公司内一个C技术栈层面的系统,封装后提供给java使用. 

              2. 业务层面, 分润和支付都需要对订单层面的费用明细要了解,虽然支付和分润都属于不同的业务流.但是面向的领域都是同一个,而且期望得到的数据又单一. 一个是收,一个是支出. 所以费用归类属于到一个模块上去.. 将复杂的各种费用类型,已经费用类型的变更给隔离掉.

                  面向领域去维护模块(自己的领域独立,别人的领域也独立), 而不是流程. 1. 要分层次,每个层次要将输入收缩后输出. 这就是(模块)层次的意义. 2.将水平切割后,共同面对的领域再抽象. 如上, 支付和分润都不再需要关注订单模块.

      代码结构和模块划分 http://blog.csdn.net/fei33423/article/details/53908470

2.

    2.2 模块划分优先划分通用性的模块(接口字段就是通用性的,mongdb): 业务无关.

        比如, 帐户和收支系统. 比如发票系统. 比如流水系统.

    2.2. 再考虑业务层面可以分哪些系统.

3. 妙用组合,而不是扩展. 比如冻结金额.用两个帐户组合. 并发用分布式锁.

      现金支付,先扣司机钱. 但是考虑到扣的太多,后续分润又延迟,怕影响司机接单.

      转用冻结司机金额的概念.后续从冻结帐户上解冻和转钱.这样帐户流水层面就能体现出每一笔帐户变动.起到每笔操作都要记账的作用.

  

这就是微服务,微服务虽然只维护一张表,但是

支付中疑难问题:

   1. 兼容支付问题. 迁移换回调地址导致. 

   2. 旧的pay重新换流水号.一天内不换.

   3.  幂等问题.

   4. 支付没有回调回来的问题. 网络抖动.

   5. 未代扣签约用户体验优化

   6. 

重构依赖梳理:可以通过ide的导致call hierechary去分析.

模块划分通过接口强制隔离引发的问题:

   1. 枚举类无法传递

   2. 原有代码结构夸层调用导致代码迁移成本过高.

   3. 底层模块变动,不了解到底要回归哪个业务. 兼容性回归.

1. 想要的代码不知道去哪里找:

   1. 哪个包下面

   2.哪个类下面,会不会有人专门对某个业务又建了个类.

   3. 怎么确保已经遍历过了.

    一个模块的bizService放很多地方,放在几个目录里,一开始可能大家都清楚,慢慢的可能就混乱了,.最开始是连这种意识都没有,特别是相同模块的BizSerice要放在一起.

    有些通用的代码,有些写在了service,有些写在了bizService,有些写在了sharedService.

   有些自己新增了一些bizService,然后放在了其他包里. 老人开发自己不熟悉的代码的时候,也会闷逼了. 同时依赖的层级可能是多层的,放在同一个jar里,可能包结构都是扁平化的.

2.跨层级模块思维: 这个可能大家基本都是不重视的.  现在所有的dao,entirty都在一层. 但是他们显然是在不同层次的..(微服务链,虽然某些微服务只维护了一个实体,但是其功能是很强大的)

问题:   状态和类型混合在一起,期望起到cas锁的作用.但是把业务通过实体来控制了.增大了底层复杂性.

问题2:  模块划分清楚了,有些业务代码怎么放就更会小心. 比如支付系统应该收多少钱,应该是独立一个模块计算的.

问题3:  有些方法比较大,可能和模块划分无关. 比如订单代金券和费用是一起返回的.

问题4:   1. 现有系统:  企业支付等不能,权益等不能用代金券是某个代码维护的. 但是现金支付的支付金额又是另外一个地方维护的.

              2. 支付阶段已经不需要关心订单等消息,也不需要关心给乘客通知等问题.不需要关心是哪个人. 没有强制模块划分和依赖独立,这些问题可能都发现不了. 通过模块依然自然而然的通过编译报错解耦了.

              

     

解决方案: 多模块--这也是微服务的基础.

微服务的好处: 业务代码解耦明显,不通过人去维护

方法:

1. 先熟悉流程,细化. 比如何时通知司机,乘客.  这些考虑到了,流程基本上会想到很细.
想到把支付和回调两个流程分开. 才能把代扣和支付流程分开.

对应问题点方法:

2. 状态重构,不要把类型和状态混合起来

3. 数据流重构,大的方法要变小.  比如支付这边每次都获取 费用列表+券 +最终的支付金额. 这其实可以分成三个接口.

如何把帐户和网关系统提取出来. 很简单..你抽象出了提现模块,也抽象出了支付模块.他们共同操作的都是帐户模块,很自然就抽出来了.

同样帐户流水模块也一样..

解决方案引发的问题:

   1. 新api对应的bean需要 set get

   2. 不可能同时移过来, 只能保持副本维护. 特别是非常通用的cashier表. 这种可能就先不服务化了.

逐步把dao收拢到各个模块中.. 这样对方只能看到比较上层的service,不会自己盲目的去组装. 减少重复代码生成.

整体安排

  1. 模块切分
  2. 整体业务梳理责任到人. 文本化,大家都可以去看.
  3. 落地方案讨论,对应可能需要的预估点讨论
  4. 按照方案出改动设计文档和预估时间
    1. 业务整理,梳理非本模块代码,依赖哪些非本模块接口.
    2. 解耦mq.
    3. 适当的跨层依赖重构.
    4. 内部重构: 方法拆分,形参确认
  5. 分几期,安排排期开发测试.

拆分总体思想:

  1. 水平切分和垂直切分.

      2. 重要流程先行.

模块依赖图:

描述:

    trade: 交易模块,订单相关业务.

    account:帐户管理,提现,充值等

    bill: 乘客支付的金额和优惠金额

    pay: 线上支付,代扣等相关逻辑.

    shareBenefit: 分润规则读取,分润计算,入账,分润通知

    task: 重试修复的定时任务总控制器;

子模块工程划分

service和领域实体entity分开: service需要隔离,领域实体可在内部传播可见.

 api

   api-impl

 biz-interface

   biz-impl

 dal-interface :

   dal-impl :

 dal-entity : 包含本领域实体,依赖外部领域(order,voucher)实体.

将interface和领域实体entity分开,这样使领域实体entity可以在模块内部传播.

模块切分影响点和工作量评估:

  1. 对应代码是否非自己模块业务.
     1.1 不是,那么就需要抽出到对应模块中.

  2. 单元测试工作量,至少成功和失败两个case. (准入case,测试提供)

  3. mq解耦

  4. 跨层重构,跨层调用. 原本biz层调用了dal层.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

交易系统模块划分,模块拆分,设计,重构实战.状态 的相关文章

  • 科学计数法

    链接 http www nowcoder com pat 6 problem 4050 题目描述 科学计数法是科学家用来表示很大或很小的数字的一种方便的方法 其满足正则表达式 1 9 0 9 E 0 9 即数字的整数部分只有1位 小数部分至
  • Mallox勒索病毒:最新变种malloxx袭击了您的计算机?

    导言 随着互联网的普及和数字化生活的发展 网络安全问题也逐渐成为了我们生活中不可忽视的一部分 其中 勒索病毒是一种恶意软件 它可以将您的数据文件加密 并要求您支付赎金以获取解密密钥 本文91数据恢复将介绍一种名为 malloxx的勒索病毒

随机推荐

  • [Unity&]PlayerPrefs.GetString的使用案例

    根据官方 案例PlayerPrefs SetString 进行测试 https docs unity3d com ScriptReference PlayerPrefs SetString html PlayerPrefs https do
  • 【华为OD机试c++】解压报文【2023 B卷

    题目描述 为了提升数据传输的效率 会对传输的报文进行压缩处理 输入一个压缩后的报文 请返回它解压后的原始报文 压缩规则 n str 表示方括号内部的 str 正好重复 n 次 注意 n 为正整数 0 lt n lt 100 str只包含小写
  • 猿创征文

    文章目录 1 KingbaseES是什么数据库 2 KingbaseES数据库产品优势 3 KingbaseES安装包下载地址 4 KingbaseES数据库安装 1 windows安装KingbaseES 1 图形化界面安装 2 命令行安
  • Java构造方法为private

    class A public String name 构造函数限定为private 不可以直接创建对象 private A 需要创建对象实例时 调用此函数 public static A Instance return new A clas
  • H.323协议分析

    感谢原作者 http blog csdn net bripengandre article details 2230087 整理记录 版本 时间 内容 整理人 V1 0 2008 03 28 H 323协议分析初稿 彭令鹏 H 323协议分
  • Vue 新手学习笔记:vue-element-admin 之入门开发

    说实话都是逼出来的 对于前端没干过ES6都不会的人 vue视频也就看了基础的一些 但没办法 接下来做微服务架构 前端就用 vue 这块你负责 说多了都是泪 脚手架框架布了都没看过 干就完事 不过好在做好了 这里写下给和我一样苦逼的同学能快点
  • 写技术文的三个原则是什么?

    本文章原创首发于公众号 编程三分钟 我关注了很多技术类的公众号 看着大佬的公众号几千的阅读量 甚是羡慕 这直接导致了我没有心情减肥 甚至多吃了一个鸡腿 要怎么才能写出一篇好技术文章 让读到的人感到身心舒畅 快速Get到想说的点 我想破了脑袋
  • Jetpack架构组件库:DataStore

    Jetpack DataStore 是一种经过改进的新数据存储解决方案 旨在取代 SharedPreferences DataStore 基于 Kotlin 协程和 Flow 构建而成 提供以下两种不同的实现 Preferences Dat
  • 【解决方法】chrome和edge浏览器出现“你的连接不是专用连接“的问题

    原创作者 运维工程师 林琪 1 问题描述 chrome和edge浏览器访问一些证书不受信任的网页会出现 你的连接不是专用连接 的问题 无法继续访问网页 2 解决方法 在上图这个问题界面的时候 输入法在英文状态下 输入 thisisunsaf
  • ByteBuffer之HeapByteBuffer与DirectByteBuffer

    HeapByteBuffer HeapByteBuffer 是写在jvm堆上面的一个buffer 底层的本质是一个数组 用类封装维护了很多的索引 limit position capacity等 在实际操作时 会把jvm堆上数据拷贝出来到系
  • WSL2+Ubuntu18.04+gnome图形界面+docker搭建开发环境

    最近换了电脑 系统更新到2004 捣腾了一下WSL2 尝试把开发环境搭建在WSL2里面 看了很多教程 基本都是Xfce的 但是更喜欢Gnome 所以就用Ubuntu主流的Gnome作为桌面GUI WSL2的安装 WSL 2的安装因为微软提供
  • VS2015和QT代码快捷键

    VS2015 代码自动对齐快捷键 1 Ctrl A 2 Ctrl K 3 Ctrl F QT 代码自动对齐快捷键 1 Ctrl A 2 Ctrl I
  • 专利交底书

    qq
  • Java在Quant应用_BigQuant人工智能量化平台使用

    BigQuant人工智能量化平台使用 BigQuant人工智能量化平台使用 Author By Runsen 在2020年一月初 也是我大三上的寒假 我开始写书 为什么呢 因为化工原理和化工热力学挂了 我需要重拾自己的自信 对于一个大学三年
  • 今天和朋友们分享如何巧用MACD指标进行恒指多空方向判断

    说起MACD指标 我们无论是做股票还是期货的朋友其实都有了解 之前也有相关文章专做分析过此指标的一些妙用 今天受一些朋友建议 均已将带领大家重温 MACD 指标课堂 今日课题主要同大家讲解一下 MACD柱线与0轴位置切换 以及MACD变化过
  • 渗透测试技术题(面试、笔试)

    本篇文章主要涉及一下几个方面 java view plain copy 对称加密非对称加密 什么是同源策略 cookie存在哪里 可以打开吗 xss如何盗取cookie tcp udp的区别及tcp三次握手 syn攻击 证书要考哪些 DVW
  • python13个小题

    python小题 1 从键盘输入3个数 求最大值 2 买彩票 如果体彩中了500万 我买车 资助希望工程 去欧洲旅游 否则我买下一期体彩 继续烧高香 写程序描述 3 会员购物时 根据积分的不同享受不同的折扣 计算会员购物时获得的折扣 小于2
  • Linux PXE详解

    今天我们继续给大家介绍Linux相关内容 本文主要内容是PXE系统的部署 并且通过实战 完成PXE环境的实战部署 由于PXE环境牵扯到的服务众多 因此 您需要了解FTP DHCP等服务的原理 安装 部署等知识 如果您对此还存在困惑 欢迎查阅
  • Jtti:Linux大文件重定向和管道的效率哪个更高

    在Linux中 重定向和管道是不同的工具 用于不同的任务 它们的效率也取决于具体的使用情况 让我们比较一下它们的特点和效率 重定向 特点 重定向是将命令的输出写入文件或设备的过程 它通常用于将命令的输出保存到文件中或将输入从文件中读取 重定
  • 交易系统模块划分,模块拆分,设计,重构实战.状态

    父文章 技术设计金字塔 包含了实体设计文章 相关文章 如何梳理和重构 含复杂性度量 相关文章 代码级 如何写可维护的代码 万物ddd ddd primitive 封装 对象来实现可维护代码 个人渣记录仅为自己搜索用的博客 CSDN博客 dd