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

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

欢迎大家关注公众号「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端用户
  • 面向运营用户
    变化多端_1.jpg

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

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

所以如果不存在APP端,为了接口不要越来越臃肿,所以面向运营用户BFF层可以考虑删除老字段。


3 技术系统为什么复杂

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

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

3.1 什么是吸积效应

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


3.2 吸积效应带来哪些挑战

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

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


3.3 怎么应对

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

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

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


http://www.kler.cn/a/155066.html

相关文章:

  • 2分钟在阿里云ECS控制台部署个人应用(图文示例)
  • 【Java语言】String类
  • JavaScript 观察者设计模式
  • 使用 unicorn 和 capstone 库来模拟 ARM Thumb 指令的执行(一)
  • Llama架构及代码详解
  • 曹操为什么总是亲征
  • vue项目node-sass^4.14.1 python gyp 报错解决办法
  • react-native实践日记--5.ReactNative 项目版本升级,0.61到0.72升级的问题记录(一)
  • SSH:安全的远程登录和数据传输工具
  • Mysql——》int(1)和 int(10)区别
  • python弹球小游戏
  • Claude2 -sdk java (非官方提供)开源计划
  • Python简单模拟蓝牙车钥匙协议
  • Linux周期任务
  • 将数据导出为excel的js库有哪些
  • linux简述进程
  • 程序员学习方法
  • 字符函数 和 字符串函数
  • asp.net core webpi 结合jwt实现登录鉴权
  • 金额到底应该用什么类型存储?
  • 基于单片机的多功能视力保护器(论文+源码)
  • SmartSoftHelp8,服务器,目标端口安全扫描工具
  • 单页面应用
  • 阅读软件OmniReader Pro mac功能特色
  • PostgreSQL对比Mysql
  • OpenSSL 使用AES对文件加解密