吸积效应:为什么接口会越来越臃肿?我们从一个接口说起

共 5620字,需浏览 12分钟

 ·

2024-03-22 22:00



JAVA前线 


欢迎大家关注公众号「JAVA前线」查看更多精彩分享,主要内容包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时也非常欢迎大家加我微信「java_front」一起交流学习




1 从一个接口说起

1.1 初始接口

假设现在有一个创建订单接口:

      public OrderCreateResultDTO createOrder(OrderCreateDTO order)
  • 创建订单对象:
      public class OrderCreateDTO {
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnC;
    private String bizColumnD;
}
  • 订单响应对象:
      public class OrderCreateResultDTO {
  private String orderId;
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnC;
    private String bizColumnD;
}

1.2 发生变化

现在业务发生变化:创建订单时不需要C和D字段,新增E和F字段。如果你是开发人员,你会怎么设计这个接口?有一种比较朴素的思路是直接删除C和D字段,新增E和F字段:

  • 创建订单对象:
      public class OrderCreateDTO {
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnE;
    private String bizColumnF;
}
  • 订单响应对象:
      public class OrderCreateResultDTO {
  private String orderId;
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnE;
    private String bizColumnF;
}

1.3 发现问题

我们想一想上述方案是否可行呢?答案是不行,有以下三方面原因:

原因一是接口契约性:接口是本服务暴露给外部使用的,相当于上下游签了合同,如果随意修改合同,那么合同严肃性荡然无存。

原因二是版本兼容性:我们知道APP是有版本号的,假设APP版本1使用的是初始接口,这时APP版本2由于新业务需要使用新接口,但是你不能直接把初始接口改的面目全非,因为APP版本1有很多用户在用,如果只考虑新版本,那老版本将会报错。

原因三是时间窗口:我们知道APP发布版本是需要审核的,即使这一版本是强更,也会有一个时间窗口新功能和老功能是并存的,所以服务端接口在升级是必须考虑这种情况。


2 如何思考

既然不能直接升级,那么应该如何解决这个问题?我认为需要从两个维度思考:

  • 分层维度
  • 分端维度

2.1 分层思考

在代码落地实践中可以分为多层,但是核心还是三层,我们分别分析每一层如何适配接口变更:

  • 数据层
  • 业务层
  • 表现层

2.1.1 数据层

因为要考虑新老版本并存问题,所以数据层必须保留新老版本所有字段,标记老字段标记为废弃,但是需要修改字段是否必填性,因为一些老版本字段变成不必填:

      public class OrderCreateDO {
    private String orderId;
    private String bizColumnA;
    private String bizColumnB;
    @Deprecated
    private String bizColumnC;
    @Deprecated
    private String bizColumnD;
    private String bizColumnE;
    private String bizColumnF;
}

2.1.2 业务层

业务层是承载核心业务的层级,所以包含大量的业务逻辑,有两种方案:

  • 方案一:新增业务对象,重写业务方法
  • 方案二:修改业务对象,适配业务方法

方案一优点是不与老业务耦合,缺点是新老方法逻辑可能只有少部分不一样,所以需要复制老业务方法大量逻辑到新方法中。

方法二优点是可以复用老逻辑,缺点是新老逻辑耦合,如果适配逻辑没有处理好,可能会影响老逻辑。

所以两种方案有各自使用场景,方案一适用于业务逻辑重大变动场景,既然是重构所以可以重新声明新业务对象:

      public class OrderCreateNewBO {
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnE;
    private String bizColumnF;
}

方案二适用于业务逻辑微调变动场景,所以老业务对象需要包含新老字段:

      public class OrderCreateBO {
    private String bizColumnA;
    private String bizColumnB;
    @Deprecated
    private String bizColumnC;
    @Deprecated
    private String bizColumnD;
    private String bizColumnE;
    private String bizColumnF;
}

2.1.3 展示层

展示层不应该处理复杂业务逻辑,而应该是对业务对象的裁剪和适配,所以可以新增一个新版本接口,没有业务层那种负担:

  • 创建订单对象:
      public class OrderCreateDTOV2 {
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnE;
    private String bizColumnF;
}
  • 订单响应对象:
      public class OrderCreateResultDTOV2 {
  private String orderId;
    private String bizColumnA;
    private String bizColumnB;
    private String bizColumnE;
    private String bizColumnF;
}

但是如果展示层不规范,包含大量业务逻辑,那么思考方式和业务层一样,也需要使用方案二。


2.2 分端思考

一个系统在业务上通常分三个端:

  • 面向B端用户
  • 面向C端用户
  • 面向运营用户

885b8456456f767450867978ddc90a62.webp


三端都具有BFF层,但是通常实现技术不同:

  • 面向B端和C端有APP端
  • 面向运营端通常H5实现

所以如果不存在APP端,为了接口不变得越来越臃肿,所以面向运营用户BFF层可以根据实际情况,考虑删除老字段。


3 技术系统为什么复杂

在《为什么需要生物学思维》这本书中提到复杂系统形成四个原因:

  • 吸积
  • 交互
  • 必须处理的意外情况
  • 普遍的稀有事务

3.1 什么是吸积效应

从字面上解读可以将这一过程理解为吸附和积累。如同一粒粒沙子,每次加入一点点,最终汇聚成一座沙山。在软件开发的世界中,无论每一次的代码迭代在表面上看起来多么独立和微不足道,它们都在客观上促使代码量不断增长。


3.2 吸积效应带来哪些挑战

吸积效应导致代码变得如此庞大和复杂,以至于没有人能够全面掌握这个系统。当系统出现问题或故障时,最熟悉这部分代码的人可能早已离职,消失在人海中。

面对这种情况开发人员往往只能添加一段段兼容逻辑,以期降低对原有系统的影响。然而这种做法反而加剧吸积效应。甚至在某些无奈的情况下,团队可能被迫选择容忍某些错误,因为修复这些错误的代价远大于容忍它们所带来的风险。这就是吸积效应在软件开发中带来的巨大挑战。


3.3 怎么应对

技术系统都是往熵增方向发展,从有序发展到无序,所以工程师要通过一些手段减缓这个进程,常见方案是:

  • 统一技术架构
  • 统一技术规范
  • 统一业务语言
  • 代码分享与审查
  • 技术与业务分享
  • 系统稳定性建设



JAVA前线 


欢迎大家关注公众号「JAVA前线」查看更多精彩分享,主要内容包括源码分析、实际应用、架构思维、职场分享、产品思考等等,同时也非常欢迎大家加我微信「java_front」一起交流学习


浏览 24
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报