阅读更多

1顶
0踩

移动开发
在iOS项目开发中,当实现新功能时如果忽略可维护性而引入技术债务,将会需要延迟解决它或导致增加维护成本。开发者需要设置什么才能自动监控代码质量?通过适当运用Gcovr等一系列工具,就能有效提高代码质量。

当实现新功能时,如果忽略可维护性而引入技术债务,那将会需要延迟解决它或导致增加维护成本。

最近我们已经思考通过哪些方式来提高代码的质量:
  • 当代码的质量下降时,通过设置一些工具来马上提醒开发者;
  • 文档化一些编码规范和思考在过去的几个项目中如何避免维护性差的问题。


我将会简单地概括我们需要设置什么才能自动监控代码质量。
基础

我们选择一个持续集成工具Jenkins,让它运行在一台放在我们工作室的Mac Mini。其实我不怎么喜欢Jenkins,但到目前为止,它是最稳定和最适合的工具来完成这些工作。

我们已经通过Homebrewrbenv来分别安装Jenkins和Ruby,而rbenv能够为我们提供一个最新和稳定的Ruby Gems环境。有个Homebrew和Ruby Gems两个包管理工具之后,我们就几乎能够安装所有我们需要的工具,但很少会破坏与原有OS X系统更新提供的Ruby。

单元测试

我们使用Specta和Expecta来测试我们的iOS项目。

Specta让我们采用行为驱动开发(BDD)风格的语法来编写测试,相比于XCTest的语法,它更加易读。它还有一个强大的分组测试功能,在测试之前或之后运行一些代码块,这样的话,能够极大地减少重复代码。

Expecta是一个匹配器框架,我们可以在测试中使用它来创建断言。它的语法非常强大,与此同时,它比内建的XCAssert套件更加易读。例如:
expect(@"foo").to.equal(@"foo");
expect(foo).notTo.equal(1);
expect([bar isBar]).to.equal(YES);
expect(baz).to.equal(3.14159);

我们在开发时,通过XCode来运行测试;而使用通过Homebrew来安装的Jenkins时,会借助XCTool。XCTool是一个可代替的选择来xcodebuild,它能让你通过命令行的方式来非常轻松地运行测试套件和生成JUnit风格的测试报告。
$ xctool -workspace Project.xcworkspace -scheme Project -reporter junit:junit-report.xml test

这些测试报告会发布在Jenkins上,而Jenkins会使用JUnit Plugin来根据时间的推移提供单元测试结果的图表,同时会向我们显示我们的测试是否稳定。



Unit Test

Pull Request测试

我们想我们的测试尽可能运行以至于如果我们破坏什么东西,我们就会马上知道。我们在feature branches做些修改,然后提交一个pull request到Github,那么代码就会被另一个开发者审查。只要被打开,我们就能运行所有的测试来确保没有任何东西被破坏。

当新的pull requst是开放状态时,为了管理这些,我们安装Github Pull Request plugin来将信息从Github发送到Jenkins。如果有任何测试失败,它将会显示在Github,然后我们就不将代码合并,直到代码被修复为止。

代码覆盖率

我们也会用Gcovr工具来生成代码覆盖率报告,Gcovr的安装方式也是Homebrew。你需要针对main target的debug congfiguration改变两个构建设置来配置项目。将Generate Test Coverage Files和Instrument Program Flow都设置为YES。


Code Coverage


当我们运行单元测试来生成代码覆盖率报告时,我们需要将OBJROOT=./build添加到XCTool命令行的尾部。
$ gcovr -r . — object-directory build/Project.build/Debug-iphonesimulator/Project.build/Objects-normal/x86_64 — exclude ‘.*Tests.*’ — xml > coverage.xml

Gcovr输出的代码覆盖率报告也会被插件Cobertura Jenkins plugin发布,这个插件会提供一种可视化的方式来根据时间的推移来显示代码覆盖率。

现在我们不仅可以看到测试是否通过,还可以看到代码的测试覆盖范围。

静态分析

在工具集中,其中一个强大并能够保持高质量的代码的工具就是静态分析工具。这些工具会扫描你的代码,然后生成一个报告,这个报告会告诉你破坏代码风格规则的代码位置。举几个规则的例子:
  • 未使用的变量或参数
  • 长变量名,方法名或代码行
  • 覆盖一个方法,但没有在这个方法调用super
  • 方法太长或方法过于复杂
  • 还更多的规格...

我们使用OCLint静态分析工具,这个工具能够支持C,C++和Objective-C语言。OCLint通过结合XCTool使用来生成json-compilation-database reporter,从而提供great integration特性。我们首先添加另一个reporter到我们的XCTool命令行,然后将那个report传递到OCLint来执行静态分析。
$ xctool -workspace Project.xcworkspace -scheme Project -reporter junit:junit-report.xml -reporter json-compilation-database:compile_commands.json test
$ oclint-json-compilation-database -e Pods -report-type pmd -o oclint-pmd.xml

这个report以PMD的方式来生成,然后使用PMD Plugin被发布到Jenkins。有了这些插件之后,你也可以在测试失败之前,设置每个警告的优先级(底,中,高)中一些限制。最初,我们设置这些限制为低,那么只要我们引入代码,就会被提醒,从而提高代码质量。



自动部署

最后一个问题不是如何提高代码质量,而是如何节省时间。开发者通常都会将编译好的代码通过Crashlytics发送到设计师来设计审查,或在sprint结束演示时发给用户。发送一个已经编译好的App通常花一个开发者的10分钟左右时间,但它需要他们来切换任务和干扰他们的心流。

最近我们已经配置一个在夜晚构建系统,它会在早上自动发送一个新版本的App给每个人。

为了做到这样,我们使用fastlane。fastlane是一个定义lanes的一些操作来执行的强大工具集。现在我们有三个已经定义好的lanes,一个是用来发布给ribot开发者,一个是用来发布给在ribot的每个人,最后一个是发布给用户。
before_all do |lane|
 cert
 sigh
end
desc “Deploy a new build to ribot iOS developers over crashlytics”
lane :dev do
 ipa
 crashlytics({ groups: ‘ribot-developers’ })
end
desc “Deploy a new build to people at ribot over crashlytics”
lane :internal do
 ensure_git_status_clean
 append_build_time
 ipa
 crashlytics({ groups: ‘ribot’ })
 reset_git_repo
end
desc “Deploy a new build to everyone over crashlytics”
lane :external do
 ensure_git_status_clean
 increment_build_number
 ipa
 crashlytics({ groups: [‘ribot’, ‘client’] })
 commit_version_bump
 add_git_tag
 push_to_git_remote
end
after_all do |lane|
 clean_build_artifacts
end

通过使用fastlane工具(通过Ruby Gems来安装)来运行一个lane。
fastlane internal

在开始使用所有的lanes之前,我们应该自动确保我们有一个有效的signing certificate和最新的provisioning profile。所有我们的配置都放在一个.env文件,它让我们有些默认配置,但当我们运行fastlane根据需要来覆盖它们。

在将来,我们会通过使用deliver操作来自动化App Store提交过程。

最后总结

到目前为止,我们已经尝试这些过程,并在工程中呈现出好的结果。我们期望看到只要适当地使用这些工具,就能提高代码的质量,这些报告将会让我们随着时间推移来量化代码质量。我们期待在下一个工程中适当地使用这些工具会发生什么。

文章来源:Medium 作者:Matt Oakes

译者简介:刘耀柱(@Sam_Lau_13),iOS Developer兼业余Designer,参与开发技术前线iOS项目翻译,个人博客:http://www.jianshu.com/users/256fb15baf75/latest_articles。
  • 大小: 7.6 KB
  • 大小: 14 KB
  • 大小: 8.4 KB
1
0
评论 共 1 条 请登录后发表评论
1 楼 kanme818 2015-05-28 16:10
收藏,这个有用

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 【java基础】——java虚拟机HotSpot

    一、前言 在自己电脑上输入java -version时出来:Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode),不知道是啥意思。查阅资料发现HotSpot是java的虚拟机。把前因后果写在下边。 二.、HotSpot历史 SUN的JDK版本从1.3.1开始运用HotSpot虚拟机, 20...

  • 一份深入解析Java虚拟机HotSpot手册,让我卷成美团架构师

    作为本书的开篇,本章将围绕Java的生态系统,简单介绍JDK、JVM、JEP,引导读者走进虚拟机的世界。1.1节介绍了各具特色的JDK分支和OpenJDK的子项目。1.2节介绍了Java改进提案,它们代表类Java社区最新的工作动向。1.3节简单描述了历史长河中存在或者曾经存在的Java虚拟机。1.4节讨论了HotSpotVM的组件、源码结构、构建、调试以及修改代码后如何回归测试。最后1.5节展望未来,讨论了Java的前沿技术Graal VM。

  • HotSpot虚拟机

    HotSpot VM

  • jvm中的Hotspot是什么

    jvm中的Hotspot是什么

  • 【Java虚拟机学习——对象相关学习】HotSpot虚拟机下对象的生命周期、对象的创建及在Java堆中对象的内存分配、布局和对象的访问

    HotSpot虚拟机下对象的创建及在Java堆中对象的内存分配、布局和对象的访问

  • JVM 中栈和堆的区别和联系,HotSpot详解

    JVM 中栈和堆的区别和联系,HotSpot详解

  • JVM(HotSpot)

    元空间的本质和永久代类似,元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。程序执行中当Eden放满之后会出发minor gc,清理内存,此时会清理所有区的内存,如果eden中的对象被标记为非垃圾,则分代年龄+1,并移到suivivor区, 本身就在suivivor区的如果依旧存或,分代年龄+1。指程序申请内存时,没有足够的内存供申请者使用,或者说,给了你一块存储int类型数据的存储空间,但是你却存储long类型的数据,那么结果就是内存不够用,此时就会报错OOM,即所谓的内存溢出。

  • java对象在内存中的结构(HotSpot虚拟机)

    一、对象的内存布局 HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。 从上面的这张图里面可以看出,对象在内存中的结构主要包含以下几个部分: Mark Word(标记字段):对象的Mark Word部分占4个字节,其内容是一系列的标记位,比如轻量级锁的标记位,偏向锁标记位等等。 Klass Pointer(Class对象指针):Class对象指针的大小也是4个字节,其指向的位置是对象对应的Class

  • Java各种规则引擎

    Aviator是一个高性能、轻量级的java语言实现的表达式求值引擎,主要用于各种表达式的动态求值。现在已经有很多开源可用的java表达式求值引擎,为什么还需要Avaitor呢?Aviator的设计目标是轻量级和高性能 ,相比于Groovy、JRuby的笨重,Aviator非常小,加上依赖包也才450K,不算依赖包的话只有70K;当然,Aviator的语法是受限的,它不是一门完整的语言,而只是语言的一小部分集合。其次,Aviator的实现思路与其他轻量级的求值器很不相同,其他求值器一般都。

  • JVM学习笔记002:垃圾回收

    三、垃圾回收 1、如何判断对象可以回收 引用计数法 一个对象被引用+1,一个对象不再引用-1,为0时可以回收 弊端:循环引用时,两个对象的计数都为1,导致两个对象都无法被释放 可达性分析算法 根对象:肯定不能被回收的对象 JVM中的垃圾回收器通过可达性分析来探索所有存活的对象 扫描堆中的对象,看能否沿着GC Root对象为起点的引用链找到该对象,如果找不到,则表示可以回收 可以作为GC Root的对象 虚拟机栈(栈帧中的本地变量表)中引用的对象。 方法区中类静态属性引用的对象 方法区中常量引用的对象

  • Java 11 到 Java 17 的最佳 HotSpot JVM 选项和开关

    一、前言 在本文中,你将了解 OpenJDK HotSpot Java 虚拟机 (HotSpot JVM) 中的一些系统知识,以及如何调整它们以获得最佳状态适应你的程序和运行环境。HotSpot JVM 是一项了不起且灵活的技术。它作为二进制版本适用于每个主要操作系统和 CPU 架构,从微型 Raspberry Pi Zero 一直到包含数百个 CPU 内核和 TB 级 RAM 的“大型”服务器。由于 OpenJDK 是一个开源项目,HotSpot JVM 几乎可以针对任何其他系统进行编译,并且可以使用选项

  • JAVA执行引擎详细介绍

    解释执行过程中,执行引擎会检查每个字节码指令的合法性,并根据需要加载相应的类、创建对象等。这就是JIT编译——在程序运行时,JIT编译器会识别并编译热点代码为机器码,之后再次遇到这些代码时,就可以直接查阅速查手册(已编译的机器码),从而大大提高执行效率。JVM执行引擎在JVM中,执行引擎是一个至关重要的组件,它负责将Java字节码转换为机器码并执行,从而确保Java程序的顺利运行。从架构的角度来看,Java执行引擎的设计有诸多值得借鉴的方面,这些设计选择为Java语言的性能和可移植性提供了坚实的基础。

  • Java --- JVM的执行引擎

    1、执行引擎是Java虚拟机核心的组成部分之一。2、“虚拟机”是一个相对于“物理机”的概念,这两种机器都有代码执行能力,其区别是物理机的执行引擎是直接建立在处理器、缓存、指令集和操作系统层面上的,而虚拟机的执行引擎则是由软件自行实现的,因此可以不受物理条件制约地定制指令集与执行引擎的结构体系,能够执行那些不被硬件直接支持的指令集格式。

  • JVM:Java程序的核心引擎

    JVM的作用是将Java源代码转换成可执行的字节码,并在运行时负责执行这些字节码。当程序要运行时,JVM会将字节码文件加载到内存中,并将其转换为机器码,然后执行它们。3.自动内存管理:JVM有垃圾回收机制,可以自动回收不再使用的内存,减少程序员的内存管理负担。1.跨平台性:由于JVM可以在不同的操作系统上运行,所以Java程序可以在多个平台上运行。4.高性能:JVM的执行引擎可以将字节码转换为机器码,提高程序的执行效率。2.资源占用:JVM需要占用一定的内存和CPU资源,可能会影响系统的性能。

  • 【架构】Java实现游戏引擎

    学过编程后,感觉所有的游戏都离不开两个方法,一个是画面更新,一个是指令输入。既然大多数的游戏都离不开这几步,那么为了便利游戏的开发,一些工程师就把这几个方法抽象出来,定义为一个规范,游戏开发者只需要根据这个规范实现游戏的业务逻辑就可以简单高效的开发出一个游戏。这个规范就是所谓的。这篇文章就用JAVA语言来实现一个简易的游戏引擎。

  • JVM技术细节: HotSpot的内存模型

    1、对象无句柄 在早期的JVM版本,例如 Classic VM 实现中,使用了 间接句柄(indirect handle) 来表示对象引用。 虽然使用这种方式使得垃圾收集器在重定位对象(relocating)时非常方便,但却导致了严重的性能瓶颈,因为每次访问Java对象的实例变量都需要两步操作。 HotSpot 推出以后,Java 代码就不再使用任何句柄。 对象引用使用 直接指针(direct p...

  • 代码三部曲,最全代码治理知识体系(上)

    1.问题1、代码管理是什么,包含哪些内容?2、如何建设合适的代码仓库,如何规范治理代码仓库?3、如何应用版本控制工具,选择合适的分支策略,适应不同的开发模式?4、项目开源需要注意哪些环节...

  • java三元运算符_推荐一款好用的Java表达式执行引擎

    最近在项目中需要根据不同的条件来做走不同分支的逻辑,那么就需要动态判断条件表达式结果(不想写一堆if else),研究了一番,发现了一个轻量级的Java表达式执行引擎:aviator,整个使用下来挺简单高效的,今天推荐给大家,下面介绍啊一下这款框架!二.aviator简介Aviator是一个轻量级、高性能的Java表达式执行引擎, 它动态地将表达式编译成字节码并运行,主要用于各种表达式的动态求值!...

  • java数据引擎(二):详细使用

    一、            详细用法 数据引擎的数据操作大体可分为两大类,一个是直接面对表的操作,一个是面对配置SQL的操作,两者可共存,根据方便程度及业务复杂度,可灵活选择。 1.     单表操作 当需要访问的对象只涉及一张表时,就属于单表操作。数据引擎使用两种对象进行表的自动映射,即Map对象和实体对象。当使用Map时,是将库表的字段及值映射为map的key-value;当使用实体对象

  • 265行代码实现第一人称游戏引擎

    本文由 伯乐在线 - Jaward华仔 翻译自 playfuljs。欢迎加入技术翻译小组。转载请参见文章末尾处的要求。 今天,让我们进入一个可以伸手触摸的世界吧。在这篇文章里,我们将从零开始快速完成一次第一人称探索。本文没有涉及复杂的数学计算,只用到了光线投射技术。你可能已经见识过这种技术了,比如《上古卷轴2 : 匕首雨》、《毁灭公爵3D》还有 Notch Persson 最近在 l

Global site tag (gtag.js) - Google Analytics