SCMLife.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2152|回复: 0

[赏析] 流水先生新作《软件集成策略》赏析十

[复制链接]
发表于 2013-9-13 21:01:31 | 显示全部楼层 |阅读模式
4.4 提交前检测方法

' e) J& ~/ l! O" M0 ~# f1 d3 B1 r1 h: S/ S  Y# j4 G
在集成的第一阶段,有多种检测方法备选。在第1.7节我们曾经介绍了一系列检测手段:版本合并、源代码检查、构建、运行时测试四大类。那么,应该选用哪些检测方法,如何有效使用呢?
5 S7 ]2 h- }9 X9 Y; o  u% Y9 c1 \
在讨论具体检测方法之前,我们先要明确一个重要的原则,那就是,检测要尽量围绕本次改动,而不是泛泛地检测。本次改动,在改动相关的部分可能引入了缺陷,与改动相关的功能,在统计上其缺陷密度较大,发现单个问题的成本较低。同时,由于程序员对该地区熟悉,检测起来也比较有效率,能够更有效率地发现问题。在解决问题的时候更是这样,程序员解决自己的改动中的问题和附近的问题,其效率比较高。因为只有在这种情况下,程序员才比较熟悉相应的代码,才能快速地解决。' r4 L/ R6 `: |1 e

; r* ~% K2 h, l* ^0 F5 `
没有必要在提交前刻意去搜索并非本次改动带来的问题。与在集成的第三阶段做这样的事情相比,在此时检测,效率很低,因为不止一个程序员要检测相同的内容,为什么不放在第三阶段一次性完成呢?而修复工作同样效率不高,因为要修复的,并不是自己熟悉的改动。总之,一项检测工作,它越有针对性,就越值得在提交前完成,反之就要考虑是不是应该放到集成的第三阶段或第二阶段。
- k7 T  b* a$ ?1 n) _1 @* L9 J
除了这个重要原则外,还要考察具体某个检测方法在具体情景中的工作效率,考察它发现问题的能力。如果要增加的检测方法很费时间,而发现的问题又很少,或者发现的问题绝大多数已经被其他已有方法发现,那么就不值得增加该项检测方法。而如果新方法跟某个已有方法发现的问题差不多,但明显更省时或更省成本,那就值得考虑用新方法替换已有方法。而如果某个提交前采用的检测方法,能够有效率地发现不少在将来系统测试时很难发现的问题,那就特别值得考虑。' J* U2 g4 P. S! S

  x4 ]. g, m. d5 Q
下面我们按版本合并、源代码检查、构建、运行时测试四大类,分别讨论具体的检测方法。

  ]4 [! I- P8 Y首先讨论版本合并。如果进行了从基线或集成分支末端到工作区的更新操作,那么版本合并当然是被用到的检测手段。更新操作,其本质是合并。在版本合并的操作过程中,合并冲突得以暴露和解决。随后,更多的合并所导致的问题,将通过其他检测手段发现。$ I- P' I. Z- z" n5 B6 [2 ^

8 o' j# }9 A  B% ?
至于是否需要更新工作区,应在何时更新工作区,我们将在第 7章讨论。

7 ^# s& {: P1 [9 W5 n* z6 ^( N4 K从工作区到集成分支的提交操作,其本质也是合并。在这一过程中,新的合并冲突得以暴露和解决。但合并所导致的编译构建问题、运行时的问题,就只能流到集成分支上了。$ ]& U& m0 G- X" h
& q! w* Y$ M& a) B5 S
不少版本控制工具①由于其本身的设计机制,它禁止程序员在有(潜在的)代码合并冲突的时候提交。在这样的工具里,必须先用集成分支的昀新版本更新工作区,再立刻提交。也就是说,提交时要解决的代码合并冲突,转由更新时完成。
- ]: D/ W. r% Q3 y5 j# m: ?/ D
第二大类,源代码检查。这一大类中,代码自查显然是有效的,就好像考试的时候,做完题要自己检查一遍。) l6 l% ], K4 z- \* k1 D
而同行评审也是针对本次改动进行检查的有效的方法,推荐使用。它甚至能检测出不少在将来系统测试时也不一定能暴露出来的缺陷。
# X. ]; _! U+ W# Q# v3 Y
但也要注意评审的效率。比如,引入过多的同行进行评审,边际效用递减,而成本却显著增加。特别是,如果使用开会的形式逐项讨论发现的问题,那么人多的情况下,就可能难以找到大家都合适的时间,评审可能会一拖再拖。又如,由另一个站点、另一个时区、持另一种自然语言的同事来评审,由于工作时间不同、沟通效率低,常常会显著延长通过评审的时间,影响项目的进展。这需要审慎地权衡。
4 W0 L5 x( r0 X5 v; ~7 |9 K: D) Z9 g- c5 p6 A
近几年,类似 Gerrit这样的基于网络的代码评审工具日渐流行。
3 |0 }( v0 |* D! P& |
这样的工具通过网页形式展现待评审的改动,并且可以让评审者在(可能)有问题的改动旁边加上评审意见,而改动代码的人也可以用此方式与评审者交流。显然,这对于由分布在世界各地的志愿者一起完成的开源项目来说,是很大的方便。5 D9 O$ W+ P  w0 c
# Y, Y5 b! l3 H
而传统的评审方法,先由评审者各自查找并记录发现的问题,再开会逐项讨论的方法,也有其优势。一对一的交流沟通,面对面是昀有效率的方法。因此,当评审人数少,且都在一个站点时,仍值得使用这种传统方式。而当有些评审者因不在该站点等原因,不便面对面沟通时,可利用前面所说的评审工具做辅助。总之,两种方法,因地制宜,相互配合,能够发挥昀好的效果。
$ e- H* [; p# }  Z
一般来讲,应该等所有的评审意见都被妥善处理后,再提交改动到集成分支。但是如果由于种种原因,评审效率较低时,也可灵活处理。比如,当改动的质量已经比较高,而收集全部反馈意见尚需时日时,可以考虑不必等待全部的反馈意见就提交到集成分支,陆续到来的反馈意见可以在后续的提交中再体现。5 ~9 i. t' ^1 x2 V: z7 i- @, z$ e

+ ]8 |9 G: m0 ^+ `8 a7 h8 R" B! ~
也可以考虑把已经具有一定质量,但尚未通过评审(或其他检测方法)的改动,通过“胡志明小道”①送给急需它的程序员(们),让他们基于未通过评审的改动A,开始依赖于这个改动 A的新的改动 B。
) y4 g$ x, L% E8 ]6 x  \
如图4-1 所示。! m$ C0 k% _+ d# M( g, q5 {' I- y

* Y" N. f* t4 w将来这个改动A提交到集成分支后,再同步新的改动 B,让新的改动 B基于集成分支的新的末端(或包含了 A的基线)。如图4-2所示。" A- i9 a& S$ X9 |9 |4 B' L; S' b
" K0 W8 h% n5 l- ]7 ?7 M
与同行评审相比,结对编程可以让“评审者”在“被评审者”编程过程中,并行地思考,实时地提供反馈。把串行变成并行,因此可以减少等待,降低项目时长增量。如图 4-3所示。: p5 F4 C- z0 z+ H  n! ^2 [

  e# T: |" w! B; X1 q+ w
源代码检查这一大类中,自动的方法,也就是静态程序分析,与人工的代码评审相辅相成,发现人工代码评审容易漏过的问题,并保证程序遵循已制定的各项规则,值得使用。但要注意,受具体技术的限制,在一些情形下,静态程序分析无法针对本次的改动,进行小范围的检查。它必须对程序全部源代码进行检查。如果因此造成检查时间格外的长,比如数个小时,那么就要重新思考是否要在集成的第一阶段使用它了。可以考虑把它挪到第三阶段,多攒点问题再检测,以期待一次多检测出一些问题,并显著降低对项目时长的影响。
5 f( M' s8 b) X# d/ y/ ~# F/ m9 \
当然,这意味着分析和解决静态程序分析所发现的潜在问题的成本将有所增加,因为要再走一遍改动代码再检测再提交的流程。此外,由于潜在问题流入集成分支,可能将烦扰开发工作和质量保证工作,需要权衡。0 Z! ^" A( h! ^1 J, ]0 g) ]
; {. n6 a( W1 k2 h, [( f
第三大类检测工作是构建。显然,构建是必不可少的检测手段。因为不进行构建,就无法进行测试。并且,如果源代码中尚有令构建失败的问题就提交,将严重干扰后续工作。

) }: u& C: K" ?/ C( J  }' E# O5 E程序员通常采用增量构建①来大幅缩短构建时间。增量构建尽可能利用已有的构建成果,只构建与上次构建时相比,源代码的改变所导致的必须重新构建的部分。我们说过,检测要尽量围绕本次改动进行。增量构建体现了这一点。当然,增量构建可能不够可靠,增量构建失败不一定是因为源代码本身有问题。如果这种情况过于频繁地发生,严重干扰程序员,那作为权益之计,就要重新考虑全量构建了。同时,要寻找构建方面的专业人员,解决增量构建不稳定的问题。! p3 e% f9 f/ D: w. f

1 s7 M9 r6 Q% O& L+ k' R
第四大类,测试。测试这一大类当然也是必不可少的检测手段。测试要围绕本次改动进行,才能有效率地发现和解决问题。适当的单元测试,是很有效率的检测方法。并且,它能够轻易查出一些系统级测试不易覆盖到的问题。

! z) y( R$ w9 G3 u: v+ J' ]3 H单元测试有清晰的边界。本次改动了哪个或哪些模块,就做针对哪个或哪些模块的(一部分或全部测试用例)单元测试用例。本次改动没有碰的模块,就不用做该模块的单元测试,因为测试结果跟本次改动之前比,不会有任何变化。% S6 w, o; e# s
' ]9 T+ _- O' A$ l1 s7 s
此外,不仅要做模块级的单元测试,一般还要做更高层级的测试,直到测试系统整体表现出来的功能符合预期。我们将在第 5章详细讨论测试的层级。
& D7 B/ C3 J+ a1 o" H* X- v
除了测试功能,对于可能将给性能带来较大影响的改动外,也要考虑在提交前就有针对性地测一测性能。
' z- V. }6 T. x
& C, H+ [& p# l/ ~& R
要格外重视确保程序不会出现严重问题,因为提交严重问题,将严重干扰后续工作。因此针对可能出现的严重问题,要做好相应测试,即便是预计这样的严重问题发生的可能性不高。为防止这样的严重问题,应该做一些粗略测试,确保程序具备基本功能。
$ \$ I2 `( J% l3 w% y) U
这样的粗略测试,其测试用例的挑选,应基于以下原则:首先,测试应该是系统级的,而不是模块级的。因为测试的目的是保证程序外在的基本功能。其次,粗略测试是为了确保那些基本功能,因此针对细节的测试不在此列。昀后,即便是不太可能被影响到的基本功能,也应该测一测,因为万一出问题,影响很大。当然,几乎肯定没有问题的基本功能,也就不用测了。& g/ R7 k4 w7 e

' P& [' y2 Y6 }) D' t* n; a
有些项目中,强制要求提交前必须进行一个固定的测试集的检测,确保提交不会出现测试集所覆盖的严重问题。这是否合适,也要依实际情况而定,关键是检测的效率。如果这个测试集挺大,内容不少,纯人工测试,而某次提交跟这个测试集里绝大部分测试用例都没什么关系,几乎不可能因为这个提交而出问题,那使用这样的固定的测试集,就不合适。比如修改手机软件中某个游戏中的字幕提示,就几乎不可能影响打电话、发短信等功能。硬性规定进行这样的测试,并无意义。

2 b1 B: h1 P6 n) O
( C3 U. C9 r; T" l
一般来说,自动测试是件好事情,因为一个自动测试用例一次写成后,可以反复多次使用,每次成本很低。这样,就可以做更多的测试,让提交质量更有保证。举例来说,在某个改动之后,要进行针对所在模块的单元测试。在过去,由于测试是人工的,有些不太可能出错的测试用例,就被权衡下去了,不测了,有问题只好等集成的第三阶段再说。而现在,测试是自动化的,因此很轻松就把该模块上的所有单元测试用例再运行一遍,确保没问题。这使得在不增加甚至减小了提交前检测成本的基础上,让提交质量更高,进而减少了多日后在第三阶段暴露出问题时,要付出的代价。
3 E$ ]# f  I& A3 I
另一方面,由于自动测试用例反复运行时的低成本,就可以在每完成很小的一块改动后,就进行与之相关的全面测试,然后提交。包括自动测试在内的各种自动化,能够有利地促进频繁提交,持续集成,进而享受持续集成带来的好处(详见第7章)。
4 y* U9 O- K# W6 }2 n4 U
+ O. P: q( \0 R; t+ d7 T; J* o
然而自动测试也有其弱点,自动测试用例的编写需要一次性的投入,这个投入可能不低。有些自动测试需要频繁地维护,投入也不小。因此,有些测试适合自动化,有些就不适合。在第8.3节我们将详细讨论。举例来说,单元测试的自动化,已经比较成熟,有比较广泛的应用。

8 }- m4 k- Q# I5 Y- @在测试这一大类中,测试驱动开发( TDD)正在获得越来越多的理解和支持,在第1.7节我们已有所介绍。- _- C" ]( y/ s2 K3 X. }2 j9 K
4 \* N6 K% j5 K) ]
GitSubversion都是这样。: ?5 }# g( f4 \1 ]/ a) p
①胡志明小道是越南战争期间,胡志明领导的军队在崇山密林中修建的通往南方前线的秘密运输通道。
①详见第 8.4节介绍。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|手机版|无图版|SCMLife.com ( 京ICP备06056490号-1 )

GMT+8, 2018-1-20 12:08 , Processed in 0.069923 second(s), 8 queries , Gzip On, MemCache On.

Powered by SCMLife X3.4 Licensed

© 2001-2017 JoyShare.

快速回复 返回顶部 返回列表