实例分享:如何稳妥重构消费金融系统

架构师(JiaGouX)我们都是架构师!
架构未来,你来不来?



  • 1、背景

    • 1.2 业务重组与合并

    • 1.2 解决技术债务

    • 1.3 影响开发效率

    • 1.4 监控体系不够完善

  • 2、重构目标

  • 3、设计

    • 3.1 调研

    • 3.2 规划

    • 3.3 修缮者模式

    • 3.4 领域设计(横向拆分)

    • 3.5 模块设计(纵向拆分)

    • 3.6 代码设计

  • 4、上线过程

  • 5、监控

  • 6、总结


1、背景

1.2 业务重组与合并

  随着需求不断迭代,转转消费分期整体出现了一些调整,并提出了新的产品方向,在此背景下,对于经历了久经沧桑的历史服务,已经逐渐不适合未来的产品规划。面对新的业务整合和重组,急需新的架构和思想来承载未来的业务。

1.2 解决技术债务

现阶段存在的主要问题:
  1. 代码模块之间边界感不强,需要通过模块拆分、服务拆分来区分业务边界。
  2. 代码实现缺少层次感,设计模式单一,一层到底的冗长代码。
       此前,微服务拆分原则是按消费分期、合作方分期产品等维度进行整体拆分的,优点是明确了项目职责,简单的从需求维度进行服务拆分,确实是一种行之有效的方式,缺点是没有对基础功能进行剥离,以至于很多场景需要维护重复的代码,增加了项目的维护成本。

1.3 影响开发效率

  即使我们接手项目已经有一段时间,并对项目足够了解时,但排查问题起来依然费力费时,而且系统内部代码错综复杂,调用链路交错,难以正常维护,从长远的开发效率考虑,尽快提出新型方案来代替现有结构。

1.4 监控体系不够完善

  线上异常机制不够敏感,缺少关键业务指标的告警看板,作为一个业务开发,应保持对核心指标数据的敏感性。

2、重构目标

  1. 不影响业务的正常运转和迭代;
  2. 改善现有代码结构设计,让代码易于扩展,提升开发效率;
  3. 采用新工程逐步替代原有接口,旧工程逐渐废弃。

3、设计

3.1 调研

开始重构之前,调研了互联网消金通用的架构解决方案:

通用方案

  由于是外部调研的通用架构设计,所以并非完全契合转转消费分期产品,但可以借鉴其分层架构设计的思想,在代码设计阶段,可以先对核心模块进行拆解和规划。

3.2 规划

  前端页面与后端重构计划分两次迭代进行,分阶段进行,可以有效分摊并降低项目上线风险,第一次迭代围绕后端主要模块进行剥离重新设计并上线;第二次重构目的是解决产品需求,对接前端新页面。

3.3 修缮者模式

  作为一个一线的业务开发,需要开展重构工作的同时还得保证产品需求的正常迭代,修缮者模式无疑是最佳选择。   第一次迭代历程,对于历史工程边缘逻辑保留并隔离,只对核心代码进行重构后转移到到新工程,新工程逐步接手老旧逻辑,并对老工程提供RPC接口,逐渐取代。此方案整体风险最低,同时能兼顾到正常的需求迭代。
   第二次迭代历程,经历了第一次迭代后,新系统运行稳定,同时也具备接手新产品的能力,新工程开始与前端对接、联调,在此之后,V2版本也正式上线。

3.4 领域设计(横向拆分)

模块拆分
  1. 聚合业务:涵盖了消费分期主要业务,根据其各自产品需求特点,作为上层业务代码,对前端、收银台提供聚合接口。

  2. 基础服务:用户信贷所产生的数据、或依托合作方数据,围绕金融分期服务提供的数据支持。

  3. 三方对接:基于转转标准API下的逻辑实现,同时具备灵活接入合作方接口的能力。

3.5 模块设计(纵向拆分)

  基于以往项目存在的问题,再结合消费分期的特点,我们对分期购买到账单还款结清的整个流程进行拆解:用户主动填写申请信息,提交授信申请并获额,挑选商品分期下单,生成还款计划,提供绑卡、账单还款等功能。以上就是一个简单的分期购物流程,基于以上流程,我们把消费分期所包含的公共模块,如授信前获额、用信、账单还款,这些富有金融服务属性的功能进行剥离。消费分期作为转转的产品原型,在聚合层中各自维护,互不影响。
   设计原则:在不改变原有代码逻辑的情况下,根据单一职责和依赖倒置原则的思想:对系统进行模块拆分与合并,以明确项目职责降低耦合度;对包进行重新规划,划分包与包之间的边界,进一步减少代码间的耦合。

3.6 代码设计

  好的代码重构一定离不开设计模式,基于原有单一的策略模式,我们把合作方对接模块与基础服务模块进行了拆解,采用双层模板、策略、工厂模式的组合,分别对授信、用信、贷后几个模块单独设计接口,维护好对合作方通用标准API接口,同时具备灵活接入的特点,举个例子,以下为授信模块主要代码类图:

第一层作为基础服务的策略模式;
第二层作为合作方对接的策略模式。
主要类图设计:

  在定义接口与实现类后,形成了对合作方对接层依赖,同时对订单、用信、授信等核心数据进行落地,对消费分期提供数据支撑,举个例子,以下为授信模块主要代码:

  1. 基础服务接口定义
/**
 * 授信接口定义
 **/

public interface ICreditService {

    /**
     * appId,资方定义的一个唯一ID
     */

    String getAppId();

    /**
     * app名称
     *
     * @return zz or zlj
     */

    String getAppName();

     /**
     * 获取授信结果
     *
     * @return result
     */

    CreditResult creditResult(String logStr, Long uid);
}


  1. 标准流程抽象
/**
 * 标准API对接实现
 *
 **/

public abstract class AbstractCreditService implements ICreditService {
 
    /**
     * 标准API对接
     *
     * @return IBaseApiService
     */

    protected abstract IBaseApiService getApiThirdService();

    @Override
    public AppConfig getPartner() {
        return commonConfigUtil.getAppConfig(getAppId());
    }
    
    @Override
    public CreditResult creditResult(String logStr, Long uid) {
        CreditResultInput input = new CreditResultInput();
        input.setUid(uid);
        ResponseProtocol<CreditResultOutput> output = getApiThirdService().creditResult(logStr, input);
        String creditStatus = TransformUtil.approvalStatusTransform(output.getData());
        return CreditResult.builder().result(creditStatus).build();
    }
}

/**
 * 合作方差异化接入
 */

@Service
@Slf4j
public class ZZABCCreditServiceImpl extends AbstractABCCreditService {

    @Resource
    ZZABCThirdServiceImpl abcThirdService;

    @Override
    public String getAppId() {
        return PartnerEnum.ABC_ZZ_API.getAppId();
    }
    @Override
    public String getAppName() {
        return AppNameEnum.ZZ.getValue();
    }
    @Override
    protected IABCThirdService getABCThirdService() {
        return abcThirdService;
    }
}

  1. 标准API对接
/**
 * 标准API对接
 *
 * @author Rouse
 * @date 2022/4/24 13:57
 */

public interface IBaseApiService {
    /**
     * 标准API,获取appId
     *
     * @return appId
     */

    String getAppId();
    /**
     * 获取授信结果
     */

    ResponseProtocol<CreditResultOutput> creditResult(CreditResultInput input);
}

  1. 内部标准API实现
/**
 * 合作方,标准API对接实现
 *
 * @author Rouse
 * @date 2022/4/24 14:04
 */

@Slf4j
public abstract class AbstractBaseApiService implements IBaseApiService {
    @Override
    public ResponseProtocol<CreditResultOutput> creditResult(CreditResultInput input) {
        // 通用加解密
        return getDataResponse(logStr, getAppConf().getUrl4CreditResult(), input, CreditResultOutput.class);
    }
}
  1. 差异化合作方接入

/**
 * ABC合作方接口封装
 **/

public interface IABCThirdService extends IBaseApiService {
    /**
     * 标准API,获取appId
     *
     * @return appId
     */

    String getAppId();
    /**
     * 获取授信结果
     */

    ResponseProtocol<ABCCreditResultOutput> creditResult(ABCCreditResultInput input);
}

/**
 * 合作方抽象方法封装
 **/

@Slf4j
public abstract class AbstractABCThirdService extends AbstractBaseApiService implements IABCThirdService {
    @Override
    public ResponseProtocol<ABCCreditResultOutput> creditResult(ABCCreditResultInput input) {
        // 加解密差异化实现
        return getDataResponse(logStr, getAppConf().getUrl4CreditResult(), input, ABCCreditResultOutput.class);
    }
}


/**
 * ABC合作方对接
 *
 */

@Service
@Slf4j
public class ZZABCThirdServiceImpl extends AbstractABCThirdService{

    @Override
    public String getAppId() {
        return PartnerEnum.ABC_API_ZZ.getAppId();
    }

    @Override
    public String getAppName() {
        return AppNameEnum.ZZ.getValue();
    }
}

4、上线过程

  对于老系统的重构,新系统上线过度期也至关重要,因为采用了新的表结构进行重新设计,涉及到数据的同步,我们采用单向数据同步,逐渐弃用老系统数据,如果灰度期间需要回滚,首先对数据进行回滚,优先保证线上服务稳定。
   以下是经历两次重构迭代的过程:

5、监控


  1. 项目重构监控先行,这次我们采用了转转告警机制和Prometheus线上监控,另外搭建了一套线上看板,及时发现各个模块的潜在隐患。

  2. 日志,一个完美的系统离不开合理的日志,日志往往是定位问题最便捷的工具。

6、总结

  通过此次技术重构,我们不仅解决了过去存在的技术债务问题,还提升了服务的稳定性和用户体验,也提升产品交付效率。  技术重构并非一蹴而就,但只要我们有坚定的信念和不懈的努力,终将取得成功。引用一句名言:”不要因为懒惰而拒绝重构,不要因为无暇重构而成为你拖延的理由 。” 是的,重构是持续优化代码质量和可维护性的过程,需要我们时刻关注并付诸行动。  我认为,重构的另一种价值:一个重构好的系统、往往具备通用性,可移植性。简单说就是我们重构后的系统以最小的改动且能在同行中快速复用,因为你创造了一个稳定可靠的“轮子”,如果做到这点,无非你是这个行业技术解决方案的专家。



如喜欢本文,请点击右上角,把文章分享到朋友圈
如有想了解学习的技术点,请留言给若飞安排分享

因公众号更改推送规则,请点“在看”并加“星标”第一时间获取精彩技术分享

·END·

相关阅读:

作者:罗思

来源:转转技术


版权申明:内容来源网络,仅供学习研究,版权归原创者所有。如有侵权烦请告知,我们会立即删除并表示歉意。谢谢!

架构师

我们都是架构师!



关注架构师(JiaGouX),添加“星标”

获取每天技术干货,一起成为牛逼架构师

技术群请加若飞:1321113940 进架构师群

投稿、合作、版权等邮箱:admin@137x.com

相关推荐

  • 由浅入深的混合精度训练教程
  • 硕士生一作!985,发Science!
  • 美联储鲍威尔 | 货币政策半年度参议院听证会 全文+视频
  • 在抖音卖书半年,我如何从月亏十万到月GMV两千万?
  • 被一支笔硬控不止30秒!大模型时代的学生辅导“全能选手”
  • 三星的Galaxy Ring 智能戒指有点意思;附国内外AI产品6月数据
  • 点线面的智慧: 转转JTS技术如何塑造上门履约地理布局
  • 实现LLM应用的可观测,难在哪里?
  • JetBrains IDE全系列采用新的默认“皮肤”:即将面向所有用户提供
  • 谁该有“金融羞耻感”?
  • 5年融资87亿,苏州明星独角兽要IPO了
  • 腾讯和去哪儿网官宣两件大事,上热搜了!
  • CVPR'24 Highlight|一个框架搞定人物动作生成,精细到手部运动
  • ControlNet作者又出爆款!一张图生成绘画全过程,两天狂揽1.4k Star
  • 这些VLM竟都是盲人?GPT-4o、Sonnet-3.5相继败于「视力」测试
  • GitHub 8k Star,一作实习生,字节这个大模型成果被苹果选中了
  • 18个月326项能力,这家大厂猛猛上新生成式AI,如今纯靠Prompt就搞定企业级应用了
  • 微软宣布放弃OpenAI观察员席位,苹果也将搁置,反垄断见效?
  • 全现金!6.65亿美刀!AMD大手一挥收购欧洲最大私人AI实验室
  • DeepMind CEO称AI智力不如猫!LeCun持相同看法!曝光谷歌新项目AI将突破聊天限制