《Google软件测试之道》—第2章2.3节SET的招聘

2.3 SET的招聘
优秀的SET在各个方面都很出色:是一个编码能力很强的程序员,可以写功能代码;也是一个能力很强的测试者,可以测试任何产品,有能力管理他们自己的工作和工具。优秀的SET不仅可以看到树木而且可以看到整个森林,在看到小段函数原型或者API的时候,就能想到各种使用这段代码的方法以及怎样破坏这段代码。

在Google,所有的代码都存放在同一个代码库中,这意味着任何人可以在任何时间使用里面的任何代码,所以代码本身一定要可靠且稳定。SET不仅仅要发现功能开发人员遗漏的代码缺陷,而且还要去关心其他的工程师是如何使用这些代码模块,并确保这种使用方式是没有问题的,甚至还会去关心这些代码未来适用的功能。由于Google前进变化的速度非常快,所以代码一定要保持干净、连贯一致。在最初的代码作者都不再关心这些代码的时候,仍要保证这些代码可以正常工作。

在面试的过程中我们如何考察这些技能和心态呢?这可不是一件容易的事但幸运的是,我们已经找到了上百个满足条件的工程师。我们期望有这样的混合型人才:对测试有强烈兴趣和天资的开发人员。一个通用且有效的招募优秀SET的方法是,给候选人和其他开发角色一样的编程问题,并考察他们在处理质量与测试方面的方法。在面试过程中,SET有两次回答错误的机会。

常常通过一些简单的问题就可以识别出哪些是优秀的SET。在一些棘手的编码问题或功能的正确性上浪费时间,不如考核他们是如何看待编码和质量的。在SET的一轮面试中会有一个SWE或SET来考察算法方面的问题。对于候选者,最好去考察如何思索问题的解决方案,而不是解决方案本身的实现上体现得多么高雅。

注意
SET的面试重点在考察候选人如何思索问题的解决方案,而不是解决方案本身的实现上有多么高雅。
这里有一个例子。假如这是你第一天上班,你被要求去实现一个函数acount(void* s),返回一个字符串中大写字母A出现的次数。

如果候选人上来就直接开始写代码,这无非在传递一个强烈的信息:只有一件事情需要去做而我正在做这个事情,这个事情就是写代码。SET不会遵循这样的世界观。我们希望先把问题搞清楚。

这个函数是用来做什么的?我们为什么要构建它?这个函数的原型看起来正确吗?我们期望候选人可以关心函数的正确性以及如何验证期望的行为。一个问题值得更多的关注!候选人如果没头没脑地就跳进来编码,试图解决问题,在对得测试问题上他同样会没头没脑。如果我们提出一个问题是给模块增加测试场景,我们不希望候选人上来就直接开始罗列所有可能的测试用例,直到我们强迫他停下来。其实我们只是希望他先执行最佳的测试用例。

SET的时间是有限的。我们希望候选人能够回过头来寻找最有效的解决问题的方法,为先前的函数定义可以做一些改进。优秀的SET在面对拙劣的API定义的情况下,在测试的过程中也可以把这个API定义变得更漂亮一些。

普通的候选人会花几分钟通过提问题和陈述的方式来理解需求文档,例如以下几点。

传入的字符串编码是什么:ASCII、UTF-8或其他的编码方式?
函数名字比较槽糕,应该是驼峰式(CamelCased)的?需要更多说明描述,还是这里应该遵循其他的什么命名规范?
返回值类型是什么(或许面试官忘记了,所以我会增加一个int类型的返回值在函数原型之前)?
void是危险的。我们应该考虑更合适的类型,如char。在一些编译时刻类型检查中可以为我们提供一些帮助。
如果只有一个A的情况,计数结果是多少?它对小写字母a也计数吗?
在标准库中不是已经有这样的函数了吗(为了面试的目的,假装你是第一个实现这个函数功能的人)?
更好的候选人则会考虑的更多一些。
考虑一下扩展性:或许返回值的类型应该是一个64位的整形,因为Google经常涉及海量数据。
考虑一下复用性:为什么这个函数是针对大写字母A进行计数的?一个好的办法是参数化,使得任意的字符都可以被计数,而不是使用不同的函数来实现。
考虑一下安全性:这些指针都是来自于可信任的地址吗?
最佳的候选人会这样考虑。
考虑扩展性。
这个函数会在Shared data(译注:数据分区,是数据库存储分割(partition)的一种方式。水平分割是一个数据库的设计准则,数据以记录行的方式存储在不同的物理位置,而不是通过不同列的方式存储。(database_architecture))上被作为MapReduce(注:MapReduce是分布式计算编程模型)的一部分运行吗?或许这才是调用这个函数最有用的形式。在这个场景需要考虑一些什么问题吗?针对整个互联网的所有文档运行这个函数,该如何考虑性能和正确性?
如果这个子程序被每一个Google查询所调用,而且由于外部的封装层面已经对参数做了验证,传递的指针是安全的,或许减少一个空指针的检查会每天节省上亿次的CPU调用周期,并缩短用户的响应时间。最少要理解全部参数验证带来的潜在影响。
考虑基于常量的优化。
我们可以假设输入的数据是已经排好顺序的吗?如果是那样,我们或许可以在找到第一个大写字母B之后就快速退出。输入的数据是什么结构?多数情况下都是A吗?多数是字符的混合,还是只包含字母A和空格?如果那样,在我们比较指令的地方或许可以做些优化。当在处理大数据,甚至小数据的时候,在代码执行的时候对于真实的计算延迟也会有比较显著的亚线性变化。
考虑安全性。
在许多系统上,如果这是一段对于安全敏感的代码,可以考虑更多的非空的指针做测试。在某些系统上,1是一个非法的指针。
增加一个字符长度的参数,用以保证代码不会运行到指定字符串之外的部分。检查字符串长度,这个参数的值是否正常。那些不是以null结尾的字符串是黑客们的最爱。
如果指针指向的数据能被其他的线程修改,这里就有潜在的线程安全问题。
我们是否应该使用try/catch来捕获异常的发生?或者如果未能如预期那样正常的调用代码,我们或许应该返回错误代码给调用者。如果有错误代码的话,这些代码经过良好的定义并有文档吗?这意味着候选人在思考大型代码库和运行时刻的上下文环境方面的问题,这样的思索可以避免错误代码的重复和遗漏。
基本上,最佳候选人会有针对性地提出一些新观点。如果这些观点比较明智的话,它们都是值得考虑的。

注意
一个优秀SET候选人不应该被告之要去测试代码,这应该是SET自然要考虑的地方。
所有这些面试问题,无论是针对问题本身还是针对输入参数都有一个关键之处,那就是任何通过入门级别编程课程的工程师都可以针对这个问题写出简单的功能代码。优秀的候选人和普通的候选人在提问和思路上的表现会迥然不同。我们要确保候选人能够感觉足够舒适地去提出问题,如果没有问题,我们就引导他们去提问,确保他们不会因为当前是在面试就直接去写代码。Google的人应该质疑几乎所有事情,但仍然会把问题解决掉。

在这里,如果把这个面试问题的所有正确实现与常见错误都罗列一遍,肯定会招人讨厌,毕竟这不是一本关于编程或面试的书。但为了讨论的需要,让我们使用一个简单且常见的代码实现方式来做讨论(译注:在下面代码中,第6行代码中的‘a’应该是大写字母‘A’,原书有误)。注意,候选人一般都会选择使用自己喜欢的编程语言,如Java、Python等,但这经常会引起一些问题,例如垃圾收集、类型安全、编译和运行时刻的不同关注点等。我们同时要确保候选人可以正确理解这些问题。

int64 Acount(const char* s) {
    if (!s)
    return 0;
    int64 count = 0;
    while (*s++) {
        if (*s == ‘a’)
        count++;
    }
    return count;
}

候选人应该可以走查他们的代码,指出程序中出现的指针或计数器的值在测试数据输入之后在代码运行时刻是如何变化的。

一般来说,普通的SET候选人会做到以下这些。

在通过编写代码解决问题的过程中很少遇到问题。在编码时,函数重写没有麻烦,很少出现基本语法错误,也不会混淆不同语言的语法和关键词。
在理解指针方面没有明显错误,或者没有分配不必要的内存。
在代码开始的地方做一些输入验证,避免由于取值到空指针等引起比较麻烦的程序崩溃。若在被问到为何不做参数验证的时候,则可以很好地解释为什么要这样做。
理解运行时刻效率或程序代码的大O(译注:大O表示法描述了函数在运行时刻需要消耗的时间,参考See http://en.wikipedia.org/wiki/Big_O_notation)。在效率上,任何非线性的运行时间虽然说明程序可用,但都有可提升的空间。
在被指出代码中有小的问题时,可以修正它们。
写的代码干净易读。如果使用了位操作或把所有的代码都写在一行,则绝对不是一个好现象。代码即使在功能上可以正常工作,读起来也会令人呕吐。
在输入为一个A或null的时候,走查代码确保能正常工作。
更优秀的候选人会做的更多一些。
考虑使用64位整型int64作为计数器变量和返回值的类型,为了以后的兼容性和避免用户使用非常长的字符串而导致溢出。
针对分布式的计数计算而准备一些代码。一些对MapReduce不熟悉的候选人,会针对大字符串并行计算使用自己的简单变量来提高响应速度。
在代码注释中对条件假设和常量做解释说明。
在有很多不同的数据输入时可以走查代码,修复所发现的错误。不懂得如何发现和修复缺陷的SET候选人不是合格的候选人。
在被要求去做功能测试之前就去做相应的测试。测试不应是被要求了才去做的事情。
在被要求停止之前,不停地尝试优化解决方案。在经过区区几分钟的编码和简单测试之后,没人敢说他的代码就是完美的。程序的稳定性和韧性比功能正确要重要的多。
现在,我们想看候选人是否可以测试他们自己写的代码。令人费解或复杂棘手的测试代码是世界上最差的代码,但这也比没有测试代码强。在Google,如果测试运行失败,需要清楚地知道测试代码在做什么。否则,这个测试就应该被禁止掉,或是被标记为怪异的测试,或是忽略这个测试的运行失败。如果这样的事情发生了,这是编写出坏代码的SWE的责任,或是代码审查时给予通过投票的SET/SWE的失误。

SET应该可以用黑盒测试方法做测试,假设其他人已经实现了功能;也可以用白盒测试的方式,考虑其内部的实现可以知道哪些用例是无关的。

通常情况下,普通的候选人会这样做。

他们会比较有条理地或体系化地提供特定的字符串(如不同的字符串大小)而不是随机的字符串。
专注于产生有意义的测试数据。考虑如何去运行大型测试和使用真实环境的数据做测试。
更优秀的候选人会这样做的更多一些。

在并发线程中调用这个函数,去查看在串扰(cross talk)、死锁和内存泄露方面是否存在问题。
构建长时间持续运行的测试场景。例如在一个while(true)循环中调用函数,并确保他们在不间断地长时间运行过程中保持功能正常。
在构建测试用例、测试数据的产生方法、验证和执行上保持浓厚的兴趣。
优秀候选人的例子

by Jason Arbon

最近有一个候选人(后来被证明他在实际工作上的表现也确实令人吃惊)在被问到如何针对这个返回值为64位整形的API做边界测试时,他很快地意识到由于时间和空间的限制,不可能使用物理的方法做测试。但为了做完这个题目和出于好奇心,在思考这个级别的扩展性时尝试使用非常大量的数据来做这个测试,并提出使用Google的网页索引作为输入数据来源。

他是如何验证这个结果的呢?他建议使用一个并行来实现,从而保证产生两份相同的结果。他也考虑到使用统计学上抽样的方法:大写字母A在网页上出现的期望频率。由于我们知道网页索引后的数量,计算后的数字应该比较接近。这正是Google思考测试的方式。即便我们不会真的构建这样庞大的测试,思考这些解决方案一般也会对正常规模的测试工作提供有意义或有效的借鉴。
在面试中需要另外考虑的是文化上是否匹配。SET候选人在面试过程中是否在技术上有好奇心?当面对一些新想法的时候,候选人是否能够把它融入到解决方案里呢?又是如何处理有歧义的地方的?是否熟悉质量方面的理论学术方法?是否理解质量度量或其他领域的自动化?例如土木工程或航空工程方面的自动化。当你发现在实现中存在缺陷时,是否心存戒备,思路又是否足够开阔?候选人不必具备所有的这些特质,但仍是越多越好。最后还要考虑在日常的工作中,我们是否愿意和这个人一起工作。

需要着重强调的一点是,如果某人在应聘SET岗位的时候没有具备足够强的编码能力,这并不意味着此人不是一个合格的TE。我们已雇佣到的一些优秀的TE,之前都是来应聘SET岗位的。

一个有趣的现象值得我们注意,Google在SET招聘过程中经常会与优秀的候选人失之交臂,原因是这些人最后成为非测试类的SWE或对测试过度专注的TE。我们希望SET的候选人具有多样性,他们可能会在以后工作上成为同事。SET是一个真正的混合体,但有些时候这也会导致一些令人不悦的面试得分。我们想确保的一点是,这些低分是由于我们的面试官在使用严格的SET考核标准而导致。

正如Patrick Copeland在序言中说的那样,关于SET的招聘目前还有一些不同的观点。如果SET是一个优秀的编程者,他就应该只去做功能开发的工作吗?SWE也是很难雇佣到的。如果他们擅长做测试,就应该只是专注于解决纯粹的测试问题么?事实总是存在于两者之间。

招聘优秀的SET是一件很麻烦的事情,但这是值得的。一个明星级的SET能够对一个团队产生巨大的影响。

时间: 2024-10-26 20:42:13

《Google软件测试之道》—第2章2.3节SET的招聘的相关文章

《Google软件测试之道》—第2章2.1节SET的工作

第2章 软件测试开发工程师 Google软件测试之道 C:\Documents and Settings\Administrator\桌面\页面提取自- 9780321803023_book.jpg 在理想情况下,一个完美的开发过程是怎样进行的呢?测试先行,在一行代码都没有真正编写之前,一个开发人员就会去思考如何测试他即将编写的代码.他会设计一些边界场景的测试用例,数据取值范围从极大到极小.导致循环语句超出限制范围的情况,另外还会考虑很多其他的极端情况.这些测试代码会作为产品代码的一部分,以自检

《Google软件测试之道》—第2章2.2节测试认证

本节书摘来自异步社区<Google软件测试之道>一书中的第2章2.2节测试认证,作者[美]James Whittaker , Jason Arbon , Jeff Carollo,更多章节 2.2 测试认证 Patrick Copeland在本书的序中强调了让开发人员参与测试的难度.招聘到技术能力强的测试人员只是刚刚开始的第一步,我们依然需要开发人员参与进来一起做测试.其中我们使用的一个 关键方法就是被称为"测试认证"(译注:Test Certified)的计划.现在回过头

《Google软件测试之道》目录—导读

内容提要 Google软件测试之道 每天,Google都要测试和发布数百万个源文件.亿万行的代码.数以亿计的构建动作会触发几百万次的自动化测试,并在好几十万个浏览器实例上执行.面对这些看似不可能完成的任务,谷歌是如何测试的呢? 本书从内部视角告诉你这个世界上知名的互联网公司是如何应对21世纪软件测试的独特挑战的.本书抓住了Google做测试的本质,抓住了Google测试这个时代最复杂软件的精华.本书描述了测试解决方案,揭示了测试架构是如何设计.实现和运行的,介绍了软件测试工程师的角色:讲解了技术

《Google软件测试之道》—第1章1.2节角色

1.2 角色 为了保证"解铃还需系铃人"这句名言成为事实(译注:"you build it,you break it",摘自"you build it,you break it,you fix it".原意指在构建实验室(Build Lab)的人永远不会去修复构建失败(build break)的问题,只有开发人员自己才能修复.这里的意思是开发人员自己要对自己写的代码负责,比专职的测试人员更适合做测试工作.在传统的开发岗位之外我们又增加了几种角色.

《Google软件测试之道》—第1章1.5节测试类型

1.5 测试类型 Google并没有使用代码测试.集成测试.系统测试等这些命名方式,而是使用小型测试.中型测试.大型测试这样的称谓(不要和敏捷社区发的那些T恤型号混为一谈),着重强调测试的范畴规模而非形式.小型测试意味着涵盖较少量的代码,其他的测试类型以此类推.Google的三类工程师都会去执行其中的任何一种测试,无论是自动化的还是手动的.测试的规模越小,就越有可能被实现成为自动化的测试. 提示 Google并没有使用代码测试.集成测试.系统测试这些命名方式,而是使用小型测试.中型测试.大型测试

《Google软件测试之道》—第2章2.4节与工具开发工程师Ted Mao的访谈

2.4 与工具开发工程师Ted Mao的访谈 Ted Mao是一位Google的开发工程师,但Ted的主要工作专注于测试工具的开发方面.特别要提到的是,Ted制作的Web应用程序方面的测试工具,所有的Google内部应用上都在使用.Ted本身在SET这个圈子里也很有名气,一般情况下SET都对优秀工具有需求,否则效率就会非常低下.Ted可能是Google内部对通用Web测试基础框架最熟悉的人员. HGTS:你是什么时候加入Google的?是什么吸引你来这里工作的? Ted:我是2004年6月加入G

《Google软件测试之道》—第1章1.3节组织结构

1.3 组织结构在我过去曾经工作过的多数组织中,开发人员和测试人员都一起隶属于同一个工程产品团队.从组织架构上讲,开发人员和测试人员汇报给同一个产品团队的管理者.这样看起来,同一个产品.同一个团队.所有参与的人都在一起,应该可以做到平等相处.患难与共. 但不幸的是,我还从来没见过有团队能真正做到这样.资深管理者一般都来自产品经理或开发经理,而不是来自于测试团队.在产品发布时,优先考虑的是功能的完备性和易用性方面是否足够简单,却很少考虑质量问题.作为同一个团队,测试总是在为开发让路.为何我们这个行

《Google软件测试之道》—第1章1.4节爬、走、跑

1.4 爬.走.跑在拥有如此少量测试人员的情况下,Google还可以取得不错的成果,核心原因在于Google从来不会在一次产品发布中包含大量的功能.实际上,我们的做法恰恰相反,在一个产品的基本核心功能实现之后,就立刻对外发布使用,然后从用户那里得到真实反馈,再进行迭代开发.这也是我们在Gmail产品上的经验,Gmail带着beta标签在线上运营了四年,这个标签用以警示我们的用户,Gmail仍处于改良之中.对于最终用户,只有该产品达到99.99%的可用性时,我们才会把beta标签去掉.在Andro

微软的软件测试工程师——《微软的软件测试之道》

   好多人极力推荐<微软的软件测试之道>这本书,于是在网上搜索了一番,英文版的阅读起来有难度,在51CTO上发现了前第二章和第三章中文的内容.     在这个世界顶级的企业里,软件测试工程是的测试是怎样的. ------------------------------------------------------------------------------------------------      一.职位名称含义: 即使你给玫瑰花起不同的名字,它闻起来可能还是同样的香.但是,如果