当前位置: 首页 > news >正文

同城售后系统退款业务重构心得 | 京东云技术团队

一、重构背景

1.1、退款

到家、小时购、天选退款有2套结构,代码逻辑混乱;

其中小时购、天选部分售后单是和平生pop交互退款,部分是和售后中台交互退款;并且兼容3套逻辑;

痛点:代码繁重,缺乏合理性的设计,后续迭代开发以及维护成本高,同时增加了系统的风险和不稳定性

1.2、金额计算

到家、小时购两套独立的逻辑结构计算,在此基础上针对退差和非退差又实现了2套逻辑;

针对商品件维度、商品行维度、售后单维度计算金额混乱,缺乏领域边界分层设计

痛点:售后单维度、商品行维度、拆分件维度金额计算混乱,代码缺乏层次结构;代码易读性维护成本、后续扩展性存在问题

1.3、售后逆向账

售后单详情接口、申诉单详情接口,针对到家和小时购做了两套逻辑;

其中售后单详情接口针对小时购黑名单、小时购白名单、天选、到家退差、到家非退差做了5套逻辑处理;

并且这两个接口都是实时从拆分获取金额进行售后逆向拆分计算,可以直接从数据库中进行取值赋值,不需要进行售后单维度的拆分计算;

痛点:代码大量冗余、改动成本高、增加了系统的风险不稳定性

二、重构思路和方案

2.1、重构思路

什么是重构呢?

名词:对软件内部结构的一种调整,目的是在不改变软件观察行为的的前提下提高其可理解性、降低其修改成本;

动词:使用一系列手法,在不改变软件可观察行为的前提下,调整其结构

重构的目的是使系统或代码更容易被理解、修改、迭代

重构秘诀:胆大心细

胆大(意味着有勇气和决心去改变和改进现有的代码。重构可能涉及对复杂的代码结构进行修改,甚至可能需要重写部分代码。胆大的开发者愿意面对这些挑战,相信通过改变可以带来更好的结果)

心细(指的是在进行重构时保持细致入微的思考和行动。这包括仔细分析代码的结构和逻辑,理解代码的功能和依赖关系,以及考虑每个重构步骤可能带来的潜在影响。心细的开发者会在重构过程中小心翼翼地处理每个细节,以确保代码的正确性和可维护性)

  1. 把握好重构时机:当我发现售后退款、金额计算等业务模块代码存在质量问题、可读性差、可维护性差或存在坏味道时,并且在项目需求排期并不紧张的情况下,是进行重构的好时机;

  2. 前期梳理很重要,先找到痛点 ;不宜长线作战,不宜和业务并行

  3. 明确出目标和价值:售后退款、金额计算重构后能提高开发效率、降低维护、开发成本等

  4. 确定重构的目标:首先要明确需要进行重构的代码块或功能,并明确重构的目标是什么。例如,可能需要提高代码的可读性、可维护性或性能。

  5. 分析代码坏味道:使用代码静态分析工具或手动检查代码,识别出可能存在的代码坏味道;例如退款业务中存在1000多行的类、600多行的方法,过多的变量参数、诸多重复代码等代码坏味道。

  6. 选择适当的重构技术:根据售后代码坏味道的种类和重构的目标,选择适当的重构技术。我采用的重构手法是:小规模重构–>大规模重构–>顶层设计模式;采用先小后大,从大到全的思路进行重构设计。小规模重构:提取方法、消除超大类或函数方法、提取类、重命名、合并重复代码等方法;大规模重构:采用的是分层、模块化、解耦、抽象可复用性等手法;设计模式:退款业务采用策略模式+抽象工厂;金额计算业务采用策略模式+抽象工厂+责任链模式

  7. 编写测试用例:在进行重构之前,编写适当的测试用例来验证重构后的代码的正确性。测试用例应该覆盖重构的代码块或功能的各种情况。

  8. 执行重构:根据选择的重构技术,逐步修改代码。确保每次修改后的代码仍然通过之前编写的测试用例。

  9. 运行测试用例:在每次重构之后,运行之前编写的测试用例,确保重构后的代码仍然正确。

  10. 重构后的代码评估:评估重构后的代码是否达到了预期的目标,例如是否提高了代码的可读性、可维护性或性能。

2.2、重构方案

2.2.1、重构前系统交互图

2.2.2、重构后系统交互图

退款业务强耦合到售后系统中,并且业务代码分散到各个业务层,严重缺乏系统的领域边界和分层设计,重构后退款业务逻辑不强依赖售后核心业务逻辑,做到可以独立部署。

2.2.3、重构前金额计算流程图

2.2.4、重构后金额计算流程图

将2套金额计算业务逻辑利用设计模式将其合并为1套金额计算业务逻辑,打造防腐层

2.3、重构设计类图

依据上述制定的设计方案流程图,我进行了UML类图的绘制,以下是关于金额计算业务模块的类图

2.3.1、抽象工厂+策略模式类图

2.3.2、责任链模式类图

三、系统稳定性保障

3.1、小步重构

将售后重构分成退款、金额计算、逆向账三个步骤,并在每个步骤之后运行测试用例。这样可以及时发现并修复引入的错误,避免错误在整个系统中蔓延

3.2、逐步验证

在每个重构步骤之后,进行系统的逐步验证。分批次进行上线灰度,灰度配置绝对隔离,不能复用。确保系统的各个部分在重构过程中都能正常运行,并与其他部分协调良好。

3.3、监控和性能测试

在重构完成后,进行系统的监控和性能测试,确保重构没有引入性能问题或影响系统的稳定性。如果发现问题,及时进行修复和优化。

3.4、团队代码审查和测试

在进行重构时,与团队成员进行合作,并进行代码审查。多个人的视角和经验可以帮助发现潜在的问题,并提供改进的建议;针对重构代码进行深度解刨,能更有效地保障重构的安全性。

重构业务及时通知测试人员,使测试人员能够评估到测试点,更加完善测试用例

3.5、灰度步骤

3.5.1、bcp持续比对校验

3.5.2、按照商家灰度

依据售后单量 小->中->大 的顺序逐步进行灰度切量,观察其退款、金额计算等售后单数据是否异常

四、重构成果

  1. 降低开发、维护成本

  2. 提升代码质量、系统稳定性

  3. 系统扩展性和灵活性的加强;

  4. 系统应用、业务边界定位更加清晰

  5. 统一和规范售后核心业务脉络,降低业务学习成本,提升开发效率

  6. 提升自己的技术能力、代码质量意识、问题解决能力、团队合作和沟通能力;经典著作《重构》这本书中有这么一段话:

一开始,我所做的重构都停留在细枝末节上。随着代码趋向简洁,我发现自己可以看到一些设计层面的东西了,这些是我以前理解不到的,如果没有重构,我达不到这种高度

五、code show

5.1、重构前金额计算

到家售后单金额计算service方法

京东售后单金额计算service方法

一个大的金额计算class类就有1000多行代码,每个方法中都有几百行代码,以下是到家售后单金额计算部分代码

5.2、重构后金额计算

到家和京东售后单金额计算用同一个接口才承接业务实现,并且使用策略+抽象工厂模式实现到家、小时购、天选业务的金额计算

策略模式获取金额拆分结果集

金额计算核心方法只有4步骤

其中金额计算的核心则采用的是责任链业务进行计算

在件维度、sku维度针对不同的业务又采用了责任链模式进行金额计算

六、参考文献

代码的坏味道: https://www.qinglite.cn/doc/87036476d565d55f9

《重构改善既有代码的设计》:[美]MartinFowler

《敏捷软件开发》:[美]RobertC.Martin

作者:京东零售 高凯

来源:京东云开发者社区 转载请注明来源

相关文章:

同城售后系统退款业务重构心得 | 京东云技术团队

一、重构背景 1.1、退款 到家、小时购、天选退款有2套结构,代码逻辑混乱; 其中小时购、天选部分售后单是和平生pop交互退款,部分是和售后中台交互退款;并且兼容3套逻辑; 痛点:代码繁重,缺乏…...

【计算机网络笔记】TCP连接管理(图解三次握手和四次挥手)

系列文章目录 什么是计算机网络? 什么是网络协议? 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能(1)——速率、带宽、延迟 计算机网络性能(2)…...

C++ 初阶 类和对象(中)

前言:C初阶系列,每一期博主都会使用简单朴素的语言将对应的知识分享给大家,争取让所有人都可以听懂,C初阶系列会持续更新,上学期间将不定时更新,但总会更的 目录 一、构造函数 1.1为什么要有构造函数&…...

【漏洞复现】Metinfo5.0.4任意文件包含漏洞复现

感谢互联网提供分享知识与智慧,在法治的社会里,请遵守有关法律法规 文章目录 1、蚁剑直接连接图片马2、读取敏感目录3、读取php源码4、执行PHP命令5、包含木马写Shell (图片马制作新方法) 以 metinfo_5.0.4为例 该环境的文件上传…...

【计算机网络实验/wireshark】tcp建立和释放

wireshark开始捕获后,浏览器打开xg.swjtu.edu.cn,网页传输完成后,关闭浏览器,然后停止报文捕获。 若捕获不到dns报文,先运行ipconfig/flushdns命令清空dns缓存 DNS报文 设置了筛选条件:dns 查询报文目的…...

STM32:I²C通信原理概要

一、IIC通信原理 IIC通信和串口通信有一定的相似之处,都有一根共地线和两根数据线。但是传递外部信息,串口有两根数据线可以进行双向通信,也就是全双工通信。而在IIC通信下,其中一条数据线是用于提供同步时钟脉冲的时钟线(SCL)&am…...

【开题报告】基于 Spring Boot 的在线预约导游系统的设计与实现

1.引言 在旅游行业中,导游起到了重要的作用,他们为游客提供了专业的旅游服务和相关信息。然而,传统的导游预约方式可能存在一些问题,如信息不透明、预约流程繁琐等。因此,我们计划开发一个基于 Spring Boot 的在线预约…...

如何使用ps制作ico图标文件

如何使用ps制作ico图标文件 Chapter1 如何使用ps制作ico图标文件Chapter2 ICOFormat.8bi(Photoshop Ico、Cur插件)的下载使用1. ICOFormat.8bi的作用2. ICOFormat.8bi使用 Chapter3 ps手机计算机图标教程,手绘设计精美手机APP软件图标的PS教程步骤 01 制…...

【Linux】logrotate实现“日志文件定时分割“

问题背景 项目部署的过程中,经常会需要查看程序的执行日志。我之前的做法都是用nohup ... > xxx.log 2>&1 &将日志保存到xxx.log文件中的。但是问题是,程序有时会运行很长时间,一直保存在一个文件里,文件会越来越大…...

Android可绘制资源概览(背景、图形等)

关于作者:CSDN内容合伙人、技术专家, 从零开始做日活千万级APP。 专注于分享各领域原创系列文章 ,擅长java后端、移动开发、商业变现、人工智能等,希望大家多多支持。 目录 一、导读二、概览三、drawable 分类3.1 Bitmap fileXML …...

力扣2095.删除链表的中间节点(java快慢指针)

Problem: 2095. 删除链表的中间节点 文章目录 思路解题方法复杂度Code 思路 利用快慢指针,快指针每次走两步,慢指针每次走一步(循环退出条件是fast指针不为空同时fast.next不为空),但是我们容易发现这样到最后slow指针…...

【Vue-Element-Admin】table添加自定义索引

通过给 typeindex 的列传入 index 属性&#xff0c;可以自定义索引。该属性传入数字时&#xff0c;将作为索引的起始值。也可以传入一个方法&#xff0c;它提供当前行的行号&#xff08;从 0 开始&#xff09;作为参数&#xff0c;返回值将作为索引展示。 <el-table:data&q…...

0008Java安卓程序设计-ssm基于Android平台的健康管理系统

文章目录 **摘要**目录系统实现开发环境 编程技术交流、源码分享、模板分享、网课教程 &#x1f427;裙&#xff1a;776871563 摘要 首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,…...

Mac 禁用一些高占用cup的进程

什么是CrashReporter&#xff1f; CrashReporter在应用程序崩溃的任何时候都会运行&#xff0c;它旨在保存应用程序状态&#xff0c;以帮助开发人员找出应用程序崩溃原因。基本上&#xff0c;一个进程是启动、崩溃&#xff08;并调用CrashReporter&#xff09;&#xff0c;然后…...

layui form表单 调整 label 宽度

这个可以调整所有label .layui-form-label {width: 120px !important; } .layui-input-block {margin-left: 150px !important; }情况是这样的&#xff0c;表单里有多个输入框&#xff0c;只有个别label 是长的&#xff0c;我就想调整一下个别长的&#xff0c;其它不变 <di…...

轻量封装WebGPU渲染系统示例<12>- 基础3D对象实体(源码)

当前示例源码github地址: https://github.com/vilyLei/voxwebgpu/blob/main/src/voxgpu/sample/PrimitiveEntityTest.ts 此示例渲染系统实现的特性: 1. 用户态与系统态隔离。 细节请见&#xff1a;引擎系统设计思路 - 用户态与系统态隔离-CSDN博客 2. 高频调用与低频调用隔…...

[ element-ui:table ] 设置table中某些行数据禁止被选中,通过selectable 定义方法解决

业务需求&#xff1a;需要做到table表格中某些行数据不能被选中&#xff0c;比如在审核一些记录数据时&#xff0c;已经被审核的数据就不能再次提交审核&#xff0c;特别是批量多选的情况&#xff0c;列表中既有已经审核的&#xff0c;也有未审核的&#xff0c;只要求选中未审核…...

【PY】倒计时日历

大家有时候会不会觉得时间记不住呢&#xff1f;PY倒计时日历可以满足你。 main.py&#xff1a; from tkinter import Tk,Canvas from datetime import date,datetime def get_events():list_events[]with open(events.txt)as file:for line in file:lineline.rstrip(\n)curre…...

windows mysql安装

1、首先去官网下载mysql安装包&#xff0c;官网地址&#xff1a;MySQL :: Download MySQL Community Server 2&#xff1a;把安装包放到你安装mysql的地方&#xff0c;然后进行解压缩&#xff0c;注意&#xff0c;解压后的mysql没有配置文件&#xff0c;我们需要创建配置文件 配…...

【蓝桥杯省赛真题42】Scratch舞台特效 蓝桥杯少儿编程scratch图形化编程 蓝桥杯省赛真题讲解

目录 scratch舞台特效 一、题目要求 编程实现 二、案例分析 1、角色分析...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

Nginx server_name 配置说明

Nginx 是一个高性能的反向代理和负载均衡服务器&#xff0c;其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机&#xff08;Virtual Host&#xff09;。 1. 简介 Nginx 使用 server_name 指令来确定…...

新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案

随着新能源汽车的快速普及&#xff0c;充电桩作为核心配套设施&#xff0c;其安全性与可靠性备受关注。然而&#xff0c;在高温、高负荷运行环境下&#xff0c;充电桩的散热问题与消防安全隐患日益凸显&#xff0c;成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

【LeetCode】算法详解#6 ---除自身以外数组的乘积

1.题目介绍 给定一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O…...

Spring AOP代理对象生成原理

代理对象生成的关键类是【AnnotationAwareAspectJAutoProxyCreator】&#xff0c;这个类继承了【BeanPostProcessor】是一个后置处理器 在bean对象生命周期中初始化时执行【org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization】方法时…...

数据分析六部曲?

引言 上一章我们说到了数据分析六部曲&#xff0c;何谓六部曲呢&#xff1f; 其实啊&#xff0c;数据分析没那么难&#xff0c;只要掌握了下面这六个步骤&#xff0c;也就是数据分析六部曲&#xff0c;就算你是个啥都不懂的小白&#xff0c;也能慢慢上手做数据分析啦。 第一…...