Day942.独立编译调试 -系统重构实战

news2025/6/9 23:07:46

独立编译调试

Hi,我是阿昌,今天学习记录的是关于独立编译调试的内容。

当组件做 独立的版本演进时,如果开发在本地每次修改代码时,都需要进行集成打包验证,反而会影响日常的开发效率。所以如果能够让组件独立进行编译调试,测试验证的速度就会大大提升。通过对比,来看看集成编译以及组件独立编译的区别。

集成编译时,开发人员每次代码提交都需要编译生成组件版本,然后再与基座集成编译,同时也需要集成其他的组件版本才能生成最终的测试版本。

此时如果其他组件还都是源码编译,那么每次修改自己的组件代码后都要连带编译其他组件代码才能进行验证,非常浪费时间。情况就像后面这样。

在这里插入图片描述

相比较集成验证,组件独立编译调试需要让组件能够进行自验证,避免每次都需要集成基座与其他组件才能进行验证。在日常的开发过程中,我们可以通过组件自验证来进行编译调试,最后再进行集成的验证,这样可以有效提高开发效率。思路是后图这样。

在这里插入图片描述
组件独立编译调试的 3 种常用的方式,分别为依赖基座进行测试、组件独立运行测试以及自动化测试验证。

掌握这 3 种独立编译调试的方法,可以帮助在日常开发中,更快验证代码功能验证和定位问题,避免每次修改代码都需要集成所有组件才能进行验证。


一、依赖基座进行测试

依赖基座进行测试

与集成测试类似,依赖基座进行测试是将目标组件与基座一同打包生成测试版本进行验证。

和完整的集成验证不同,这个时候打包不会集成其他的非必要组件,你可以结合后面这张图来理解。

在这里插入图片描述

前面 Sharing 项目经过兼容性改造以后,已经支持了依赖基座进行测试的方式。

假如现在只需要对账户组件进行测试验证,那么在编译时,可以只将账户组件以及支持运行必要的组件集成打包即可。

//implementation project(':file')
//implementation project(':message')
//只集成账户组件
implementation project(':account')

此时我们就可以独立集成账户组件进行测试,不用加载其他的组件,运行结果是这样。

在这里插入图片描述

采用这种独立编译调试的方法除了提高编译的速度外,在测试时也可以减少其他组件的干扰,因为此时集成的有且仅有目标的测试组件。

当然,如果要达到这种运行的条件,需要做好组件的兼容性,具体参考组件运行时兼容:让组件可以灵活插拔的内容。

不然就算组件能独立编译,但是如果无法独立运行也无法满足测试要求。


二、组件独立运行测试

组件独立运行测试。与方式一的区别是这种方式组件能支持独立运行,不需要集成基座

在这里插入图片描述

以 Sharing 项目的文件组件为例,来看看组件如何才能支持独立运行测试。

首先,组件要独立运行需要满足 2 个条件。

  • 第一个是以 “com.android.application” 插件的形式运行,这样才能够以 APK 的形式运行;

  • 第二个是要有主入口,能够展示相关的页面。

针对第一个条件,我们可以通过参数配置来控制 gradle 的插件集成形式,支持配置生成 application 插件。

def isApp = false
if (isApp) {
    //可运行
    apply plugin: 'com.android.application'
} else {
    //作为库
    apply plugin: 'com.android.library'
}

defaultConfig {
    if (isApp) {
        applicationId 'com.jkb.junbin.sharing.feature.file'
    }
}

增加了配置脚本代码后,我们就可以通过改变 isApp 参数来调整组件的打包方式。我们将 isApp 设置为 true 后,重新触发编译,此时文件模块就变成可以支持 APK 运行的模块,像下图这样。

在这里插入图片描述

接下来看第二个条件,需要增加入口来启动主要的页面。

这里有一个问题是要控制好调试的代码不要在集成的时候被打入到发布的二进制制品中。

测试代码需要隔离开,避免产生干扰。

此时,可以采用在工程的 src 目录中增加 debug 目录的方式,专门用于存放编译调试的代码,这样在构建 release 版本时这些测试代码就不会被打包进来,工程目录你可以参考后面的截图。

在这里插入图片描述

其中 DebugActivity 就是用来展示文件主页面,其代码也很简单,就是直接展示 FileFragment 的页面,代码是后面这样。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout  
xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <fragment
        android:id="@+id/fragment_file"
        class="com.jkb.junbin.sharing.feature.file.FileFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

完成这些准备工作以后,就可以独立运行账户组件的内容,下图展示了运行结果。

在这里插入图片描述

组件独立运行的好处是可以脱离于基座做到真正的独立运行,特别是当基座的代码也比较庞大,编译需要耗费一定时间的情况下,对于效率的提升就更加明显了。

但缺点就是需要额外增加编译调试的代码,而且如果长期没有和基座及其他组件集成,将可能导致一部分集成问题更晚发现。

通常情况下,独立编译调试一般在本地开发时使用,当代码提交时会有流水线来做集成的验证检查,保证最终的代码提交质量。


三、自动化测试验证

自动化测试验证。其实在前面的基础篇和解耦重构篇中,都大量地运用了自动化测试验证的手段。那么为什么说自动化测试验证是比较好的编译调试手段呢?

2 个优点。

  • 第一个优点是自动化测试测试的粒度可以精确类及方法。在日常的开发过程中,很多时候修复一个 bug,或许就是对某个方法的表达式的修改,如果每次修改验证都需要打包验证,这个过程效率就非常低下。有了自动化测试验证就不一样了,可以在毫秒级别测试验证这段逻辑。这里结合 Sharing 项目来举一个例子,在文件组件的代码中,有一个展示文件大小格式化的代码逻辑。
public static String formatFileSize(long fileSize) {
    DecimalFormat df = new DecimalFormat("#.00");
    String fileSizeString = "";
    if (fileSize < 1024) {
        fileSizeString = df.format((double) fileSize) + "B";
    } else if (fileSize < 1048576) {
        fileSizeString = df.format((double) fileSize / 1024) + "K";
    } else if (fileSize < 1073741824) {
        fileSizeString = df.format((double) fileSize / 1048576) + "M";
    } else {
        fileSizeString = df.format((double) fileSize / 1073741824) + "G";
    }
    return fileSizeString;
}

假如现在产品增加了一个新需求,由于存在大量的数据,需要展示 T 的转换,需要扩展该方法,代码是后面这样。

else if (fileSize < 1099511627776L) {
    fileSizeString = df.format((double) fileSize / 1073741824) + "G";
}else {
    fileSizeString = df.format((double) fileSize / 1099511627776L) + "T";
}

这个时候,修改完代码以后有 2 种选择来验证,一种就是通过上面介绍的方式,进行打包验证。可以通过配置服务下发有 T 级别的文件数据,然后确认数据格式化展示是否正常。另外一种方式就是就是通过自动化测试来验证,增加对应的用例来覆盖增加的代码逻辑。后面是具体用例。

@Test
public void should_return_T_unit_when_file_size_in_its_range() {
    //given
    long fileSize = 1199511627776L;
    //when
    String format = FileUtils.formatFileSize(fileSize);
    //then
    assertEquals("1.09T", format);
}

该测试用两个 i 运行结果如下图所示,从运行结果可以看出,只需要 3ms 的时间就可以完成这个功能的验证。

在这里插入图片描述

  • 第二个优点是测试也支持进行 debug 断点调试,当用例运行失败时,可以通过断点查看对应的运行逻辑及数据。就像后面这样,可以在对应的被测试代码打上断点,在运行用例时选择 Debug 模式即可。

在这里插入图片描述

相比前面的验证方式,通过自动化验证的优点能够精确到类及方法,实现更加精准的测试,而且反馈的时间更快,通常在毫秒到秒的级别。

但缺点就是需要投入时间去设计,编写用例有一定的前期投入成本。


四、总结

3 种组件独立编译调试的方法。

传统的集成编译需要我们将所有组件一起打包进行测试验证,如果开发每次修改代码都需要进行集成验证,那么效率会比较低。

采用组件独立编译调试的方法,能够在开发阶段帮助更加高效对功能进行验证。

一张表,总结了这 3 种调试的优缺点对比,供参考:
在这里插入图片描述

在实践中,一般在本地开发进行验证时采用组件独立编译调试的方式,但当代码提交时会有流水线来做集成的验证检查,保证最终的代码提交质量。


·

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/412415.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Object方法

私人博客 许小墨のBlog —— 菜鸡博客直通车 系列文章完整版&#xff0c;配图更多&#xff0c;CSDN博文图片需要手动上传&#xff0c;因此文章配图较少&#xff0c;看不懂的可以去菜鸡博客参考一下配图&#xff01; 系列文章目录 前端系列文章——传送门 JavaScript系列文章—…

Node.js -- 模块化

1.模块化的基本概念 模块化是指解决一个复杂问题时&#xff0c;自顶向下逐层吧系统划分成若干模块的过程。对于整个系统来说&#xff0c;模块是可组合&#xff0c;分解和更换的单元。 将代码进行模块化拆分的好处&#xff1a; 提高代码的复用性提高代码的可维护性可以实现按…

元宇宙:新的数字模式——元宇宙会场

一、引言 元宇宙是一个充满无限可能的虚拟空间&#xff0c;人们可以在其中创建和参与各种虚拟场景和体验。元宇宙技术的兴起&#xff0c;为传统的会场提供了一个新的方向。元宇宙会场将线下会场的物理空间转化为虚拟空间&#xff0c;通过数字技术和互联网实现了人们在虚拟环境…

我的第一台电脑的故事

第一台电脑啊&#xff0c;多么遥远的故事了&#xff0c;又似乎就在眼前。今天重回往事&#xff0c;就简单记录一下吧。 &#x1f331;缘起 那是初一&#xff0c;至今已13年&#xff0c;遂觉遥远&#xff0c;而又是立志我学习的起点&#xff0c;至今还在校园&#xff0c;又觉就…

断开连接图的 BFS

在上一篇文章中,仅对特定顶点执行 BFS,即假设所有顶点都可以从起始顶点到达。但是在断开连接的图或所有顶点都无法访问的任何顶点的情况下,之前的实现将不会给出所需的输出,因此在这篇文章中,在 BFS 中进行了修改。 所有顶点都是可达的。因此,对于上图,简单的BFS就可以…

【消息队列】细说Kafka消费者位移机制

什么是位移 位移说白了就是消费者消费对应的Topic的分区的消费位置&#xff0c;之前存储到ZK中&#xff0c;后来转移到Kafka默认的Topic中。结构是采用keyvalue形势存储的&#xff0c;key是groupIdtopic分区号&#xff0c;value是offset的值。 而上述的存储就在_consumer_offse…

微信小程序02

小程序tabBar 普通页面跳转到 带有tabBar页面的时候不能使用 wx.navigateTo() 小程序中跳转到选项卡页面使用 wx.switchTab()跳转 到底部 onReachBottom() 函数 &#xff0c;&#xff0c; 在下拉刷新显示取消loading &#xff1a; wx.showNavigationBarLoading() wx.hideNavi…

深入讲解Linux内核中常用的数据结构和算法

Linux内核代码中广泛使用了数据结构和算法&#xff0c;其中最常用的两个是链表和红黑树。 链表 Linux内核代码大量使用了链表这种数据结构。链表是在解决数组不能动态扩展这个缺陷而产生的一种数据结构。链表所包含的元素可以动态创建并插入和删除。链表的每个元素都是离散存…

【网络原理】网络通信与协议

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; 目 录一. 网络发展史二. 网络通信基础1. IP地址2. 端口号3. 认识协议&#xff08;核心概念&#xff09;4. 五元组5. 协议分层6. 封装和分用一. 网络发展史 独立模式&#xff1a;计…

C++入门demo(从最简单的案例学习C++)

通过案例学习Cdemo01 在屏幕上输出内容demo02 规格不同的箱子&#xff08;变量&#xff09;demo03 物品存放&#xff08;变量赋值&#xff09;demo04 交换物品&#xff08;变量之间交换数值&#xff09;demo05 消失的重量&#xff08;隐式类型变换&#xff09;demo06 游泳池的容…

Melis4.0[D1s]:7.lvgl添加物理按键

文章目录1.lvgl注册keypad驱动1.1 在melis的ADC按键中发送消息1.1.1 创建消息队列&#xff0c;并初始化1.1.2 扫描按键时&#xff0c;发送按下和松开消息1.2 编写读取按键的回调函数1.3 lvgl按键驱动注册2.在gui中测试物理按键效果2.1 测试效果参考资料&#xff1a; 1.韦东山老…

第七章 基于 RNN 的生成文本

目录7.1 使用语言模型生成文本7.1.1 使用 RNN 生成文本的步骤7.1.2 文本生成的实现7.1.3 更好的文本生成7.2 seq2seq 模型7.2.1 seq2seq 的原理7.2.2 时序数据转换的简单尝试7.2.3 可变长度的时序数据7.2.4 加法数据集7.3 seq2seq 的实现7.3.1 Encoder类7.3.2 Decoder类7.3.3 S…

静态时序分析Static Timing Analysis3——特殊路径(多周期、半周期、伪路径)的时序检查

文章目录前言一、多周期路径1、建立时间检查2、保持时间检查二、半周期路径1、建立时间检查2、保持时间检查三、伪路径前言 2023.4.12 一、多周期路径 对于建立时间&#xff0c;要设置为N&#xff08;向后移&#xff09;&#xff1b;对于保持时间&#xff0c;要设置为N-1&…

9.8.0.32:ProEssentials数据可视化2D和3D图表:Crack

下面是我们的Winforms、Wpf、C MFC、VCL、ActiveX图表组件示例项目中的屏幕捕获。 有关下图&#xff0c;请参见我们的示例项目和演示中的030。 ProEssentials Winforms 图表, WPF 图表, C/MFC/VCL 图表. Gigasoft拥有20多年帮助企业开发大型客户端和嵌入式图表项目的经验。图…

JavaScript基础-02

常量&#xff08;字面量&#xff09;&#xff1a;数字和字符串 常量也称之为“字面量”&#xff0c;是固定值&#xff0c;不可改变。看见什么&#xff0c;它就是什么。 常量有下面这几种&#xff1a; 数字常量&#xff08;数值常量&#xff09;字符串常量布尔常量自定义常量…

传输线的物理基础(九):N 截面集总电路模型

理想的传输线电路元件是一种分布式元件&#xff0c;可以非常准确地预测实际互连的测量性能。下图显示了 1 英寸长传输线在频域中的实测阻抗和仿真阻抗对比。我们看到甚至高达 5 GHz 的测量带宽也能达成出色的协议。 1英寸长、50欧姆传输线的测量&#xff08;圆圈&#xff09;和…

Java实现hdfs的8个api操作

Java实现hdfs的8个api操作一、预处理准备1. 配置本地hadoop3.1.3目录文件2. 配置环境变量二、Maven项目依赖三、Java源代码四、api操作的实现1. 实现前的准备2. 创建hdfs上的路径3. 删除hdfs上的路径4. 创建hdfs文件并写入数据5. 删除hdfs上的文件6. hdfs上的文件移动路径并改名…

算法笔记:Frechet距离度量

曲线之间相似性的度量&#xff0c;它考虑了沿曲线的点的位置和顺序 1 概念 1.1 直观理解 主人走路径A&#xff0c;狗走路径B&#xff0c;他们有不同的配速方案主人和狗各自走完这两条路径过程中所需要的最短狗绳长度 &#xff08;在某一种配速下需要的狗绳长度&#xff09;&a…

MySQL-高可用MHA(二)

目录 &#x1f341;通过keepalived方式 &#x1f342;安装keepalived &#x1f343;防火墙策略 &#x1f343;keep配置文件 &#x1f342;MHA应用keepalived &#x1f343;停止MHA &#x1f343;启动MHA &#x1f343;检查状态 &#x1f343;测试 &#x1f341;通过脚本实现VIP…

数据结构——线段树

线段树的结构 线段树是一棵二叉树&#xff0c;其结点是一条“线段”——[a,b]&#xff0c;它的左儿子和右儿子分别是这条线段的左半段和右半段&#xff0c;即[a, (ab)/2 ]和[(ab)/2 ,b]。线段树的叶子结点是长度为1的单位线段[a,a1]。下图就是一棵根为[1,10]的线段树&#xff1…