如今,IT世界里的发布已经变成几小时内的事情,甚至几分钟就能完成。所有的内容都要垂直伸缩、水平扩展。因此,有一个良好的监控系统是必需的。在很多IT组织里,应用是业务的核心。但监控却由不写应用的OPS(运维)团队单独去做。为什么会这样?如果是这样的话,为什么需要改变?又该如何去改变?怎样才能得到更好的结果呢?在这篇
文章里,我将分享我的想法和来自于我和DEV(开发)团队一起
工作的经验——让度量变得有意义。
本文描述的观点来自我在Adform公司任职IT架构师(联系开发团队和运维团队)的工作经验。Adform是一家数字广告公司,有自己的开发团队(65人)和运维团队(8人)。运维团队负责发布流程和开发环境,并负责准备和维护生产环境里的网络和服务器。开发团队则负责维护他们编写的应用,其中包括发布到生产环境里的应用。下面的内容基于我们的实际经验,这些经验有助于开发人员挖掘度量信息和监控信息,但在原来,大家都认为度量和监控应该是完全由运维团队关心的。
你可能听说过广为人知的TDD实践——
测试驱动开发,也可能听说过鲜为人知的BDD——行为驱动开发,或者可能听说过最不为人知的ADD——混蛋驱动开发(在Scott Berkunn的博文里可以看到一个不错的开发实践名称列表)。但度量驱动开发(MDD)是本文才提出的。
那什么是MDD呢?我认为MDD是用度量驱动整个应用开发的实践。在使用MDD的公司里,所有东西都是可以度量的,无论是性能和使用模式,还是收益。此外,开发人员、运维人员、甚至业务人员所做的每个决定都是基于度量结果的。度量用来监控团队的绩效、解决性能瓶颈、估计硬件需求,或者在开发生命周期的任意阶段达成其他目的。
度量驱动开发的主要原则有:
给度量拥有者分配度量项
创建分层的指标,相互关联、发现趋势
利用度量做决定
每个度量项都应该有一个拥有者,他/她要掌握一定的知识和方法来推行、维护确定的度量结果。度量拥有者负责应用、服务,设置运行应用和服务的服务器,确保能正常监控、收集结果。度量拥有者要获取现有度量项的最新结果,还要为新应用或功能设立新的度量项。
对度量进行结构化也很重要。按照一定标准分组或分层的指标能确保所有人(从业务人员到开发人员)更好地理解它们。而且指标分层后,能更容易相互关联、发现趋势,也能更快地找到、解决问题。
MDD让整个开发过程具备了可见性,所以大家能迅速而又准确地做出决定,错误也能被立即发现、修复。此外,可以度量的内容都能进行优化。换句话说,MDD能让你为应用“把脉”,并给你提供了一个持续改进的机会。
最后,利用度量给Sprint设置目标,MDD也能借此很好地和其他惯常实践结合起来使用,比如TDD、BDD或Scrum。度量也能发现问题和生产环境中的使用模式,这在验收测试过程中很难被注意到。一个例子是Lance Armstrong
Bug:代码在测试时永远不会出错,但还是有证据表明它和预期结果不一致。另一个例子是从不会被使用的功能的业务Bug。这些Bug相关的证据可以用度量来收集。MDD确实能实现集中、高效的开发过程,过程回顾可以提高应用使用率。
谁创建指标?
当我们从无到有开始做一件事情的时候,你会有机会重新思考一些概念,给流程加入一些创新,甚至完全修改流程。我们在Adform就做了类似的事情。我们写完需求、构想好完善的监控解决方案后,发现期望和现实很不匹配。我们本想收集更多应用和服务相关的信息,因为它们带来收入和竞争优势。但监控完全由运维团队去做,他们对基础设施有深入的了解,却不怎么了解应用和服务的内部工作原理。
公司不会因为他们的服务器运行稳定(尽管这很重要)和有10G互联网连接而赚钱。公司赚钱是因为他们的应用和服务提供的功能,以及功能运行稳定(这和“服务器运行稳定”是不一样的)。因此要快速发现问题,把真正编写应用的人引入监控流程是必不可少的。事实上,当应用和期望不一样的时候,开发人员能很容易看出来,因为产品就是他们开发的,他们掌握着产品相关的所有知识。
最重要的是,开发人员去监控还有更多好处:
开发团队能在开发过程中把监控点嵌入到应用里去
开发团队能从生产环境里快速获得应用相关的反馈(性能、Bug、使用模式)
开发团队能在开发过程中
学习基础知识,可以预见一些瓶颈
运维团队长久以来一直在做监控——CPU、内存和IO已经溶入到他们的血液里去了,至于应用和服务的指标,拥有者应该是开发团队。开发团队掌握着应用相关的所有知识,还有改进所需的所有技能。这就是运维团队为什么不能单独做监控的原因。开发团队应该和运维团队一起设立、维护指标。在接下来的部分里,我将介绍我们公司是怎么开始改变、如何把开发人员引入监控和度量里的。
在RTB(实时竞拍)项目中应用MDD
经过一个理解、学习、失败、最终成功的过程,我们才帮开发人员掌握了度量。情况并不简单,开发团队从来没用过度量,而且突然要依靠度量结果去做决策。这个是漫长而艰难的过程,很多因素都会影响最终结果,比如公司文化、员工态度、管理层、甚至工作习惯。为了让管理层和开发团队“买账”,先把度量的价值展示出来就很重要。我们偶然在一个名为实时竞拍(Real Time Bidding)的项目里完成了这件事情。
RTB是一种相对较新的买卖方法,会实时在线显示广告,每次显示一个广告。简而言之,为了在特定网站向特定用户显示横幅广告,我们通过一个叫“Ad Exchanges”的结构接收请求,了解客户愿意支付多少钱。我们收到、处理请求的时候,会给发送端的服务返回响应。这个项目的运营需求是每秒处理四万个查询(QPS),单个交易的往返处理时间不超过一百毫秒。
应用发布到生产环境之后,情况果然非常糟糕,因为我们每秒只能处理五千个查询。而且近30%的交易都失败了,因为我们满足不了一百毫秒的需求。更糟糕的是,性能如此之差却没什么明显的原因。我们搞不清楚问题是源自网络、服务器容量,还是应用层。
最终是度量帮我们找出了问题的真正原因,并扭转了局面。我们每秒能处理的查询最终有七万多个(比一开始多十四倍多),同时能保证失败交易数低于0.5%(大概比原来低五十倍)。但为了实现这样的结果,我们对数据进行了更多分析和结构化处理,在接下来的章节中我们继续说明。
分层的指标
由于在RTB项目开始的时候我们已经有一个度量项目了,所以我们就在RTB应用里嵌入了一些指标。而且我们已经有针对服务器和网络方面的度量。但在数据的海洋里很难辨别出必要的数据、了解趋势,并找出我们的性能远远低于要求阈值的原因。很显然,仅仅有数据并不会带来多大的价值。
所以我们决定在三个层面对数据进行可视化:
业务指标
应用指标
基础设施指标
分层的方法让度量更加结构化了,对所有人(从开发人员到业务人员)来说都变得可用、易于理解。Business Dashboard成为检查应用状态的公共入口点。任何人都可以访问它,检查当前的状况是否符合要求的SLA、使用趋势或收入。如果需要的话,大家还可以深入到Application Dashboard去检查不同应用组件的性能、不同服务器组的延迟及数据增长。事实上,Application Dashboard上的一些指标在Business Dashboard上也有,只是更为详细。举例来说,我们在Business Dashboard上绘制了应用性能,在Application Dashboard上则绘制了应用不同部分的执行情况(见图1和图2)。最后,我们在Infrastructure Dashboard上检查关于CPU、内存和I/O使用率的相关信息。
图1. Business Dashboard上的应用性能
图2. Application Dashboard上的应用性能
要找出问题的根本原因(不仅仅是看结果),接下来要做的就是把不同的指标关联起来。我们把显示关键指标的图形叠加了起来,从上到下依次是业务指标、应用指标和基础设施指标。这种方法有两种用途。我们从上往下看这些图形的时候,可以清楚地看到QPS的变化是怎样影响应用性能和服务器CPU的(参见图3)。相反,从下往上看的时候,则可以看出I/O的增加是如何影响SLA的。
图3. 关联的指标示例(自上往下依次是:QPS、SLA、竞拍服务的性能、CPU负荷)
分层和可用的指标能让开发人员了解项目业务方面的内容。事实上他们能看到我们从哪里赚了多少钱。当新特性或Bug修复发布到生产环境里后,开发人员立即就能在Business Dashboard的金钱图标里看到这些内容对收益产生了怎样的影响。反过来,业务人员也能理解项目技术方面的内容,看到开发人员所面临的问题和我们的负载局限。在现实中,我们还根据度量设置了目标,借此把MDD嵌入到了Scrum里。最终,参与项目的所有人员都对项目的各个部分都有了认识,结果很圆满。
利用度量做决策
在任何活动里,最重要的事情都是认识和理解目标及其背后的原因。你可以创建不同的Dashboard、收集大量度量数据,但如果不作为决策的输入,度量就没什么用处。我见过好几个例子,都是团队创建了多个度量项,但大家却不理解度量的含义和必须设置的原因。所以他们也没利用度量指导决策。还有一个不好的例子,团队做决策时甚至不知道他们的应用到底是怎么运行的(我宁愿说这是我猜的)。他们有一些指标,但还不足以从中获取价值。
MDD的美妙之处在于,它还能最低限度地减少误解。当基于度量做决策的时候,几乎不需要任何解释。决定变得明确、有逻辑、易于阐述,因此也就不易被反驳。决定做得更快更准确,团队的气氛也好转了很多。此外,这也能带来跨团队边界的级联效应。团队间的沟通更多由数据驱动,不再那么情绪化了。换句话说,开发团队和运维团队之间、多个开发团队之间以前会相互指责,这种情况现在则很少发生,甚至完全消失了。
需要注意的是,在某些情况下我们可能从现有的度量里找不到证据,只会去猜问题的真正原因。解决办法是再创建一些指标,来支持或否定最初的假设。
在决策过程中使用度量对大家来说是一个双赢的局面。MDD的主要目标是提供基础设施和应用各个方面的信息,除此以外,MDD还有助于改进团队内部和团队间的关系。
我们学到了什么
我们走了很长的路才在整个组织里应用了MDD实践。这不仅仅是技术的变化,更重要的是文化上的改变。每个人都需要转换观念、态度、对开发过程的理解。在达成愿景的过程中,我们发现了不同的结果。因此,我想和大家分享两个对你可能有益的经验教训。
我们学到的第一个重要经验是,你应该尽全力为开发团队创造尽可能顺利的体验,避免充当中间人。我们最初尝试的解决方案是让运维团队和开发团队共用一个度量服务器。但效果并不理想,对我们来说主要原因有两个。第一,开发团队受制于运维团队,开发团队做的每个修改都需要运维团队的授权。第二,运维团队不喜欢开发团队频繁修改内容。所以我们决定给开发团队专门提供一台服务器,让他们从中获取所有服务器相关的度量信息。开发人员在那台服务器上修改内容不需要按发布过程执行,也不需要特殊的授权。事实上,他们可以在这台服务器上做几乎所有的事情——甚至从监控里删除其他服务器。尽管让开发人员自由去决定、实施并负责变更看起来有些匪夷所思,但这确实是我们做过的最好的决定之一。
第二个非常实用的经验是,我们花费时间去写“监控愿景”或“监控工具的需求”,但都是浪费时间,因为我们的期望和实现在整个过程中变更了好几次。而且它们会继续变化。花费过多的时间去选择一个度量工具也是一种浪费。没有工具能满足你所有的需求,所以挑一个你用着顺手、适合你们愿景和公司的就可以了。我们选择了Zabbix——一个开源工具。尽管它有一些局限,而且导航复杂(我们甚至称它为“一点就死的工具”),但它能让我们迅速开始。最后,别忘了给最常见的用例准备几个收集数据、图形化展示数据的例子。
让MDD变得有趣些,而且让大家都能看到。把显示重要指标的电视放在门厅或工作空间里。如果可能,图形化显示不同项目的收益。给一定的成就设置奖励,比如连续成功发布的次数(参见图4)。大家一起度量最好的成绩,比如每天、每周、每月最高的访问量或交易数,并一起为之庆祝。这种方法会引发大家的好奇心,让大家提出问题,并参与到度量里来。通常情况下,你可以从添加一些简单的图形开始。同事们在门厅看到后,会立即提出一些很棒的改进意见。
图4. 成功发布的奖励
对参与MDD的所有团队来说,尤其是对开发人员来说,MDD要求的文化变化还是很冒险的。他们开始用自己的应用来观察问题,之前大家都不了解这种做法。Adform的思维模式完全发生了变化。原来的态度是,只要没人抱怨,就认为一切都正常。现在,所有人都知道这不是度量应用性能的好办法。开发人员现在都能很自如地处理度量了。出乎意料的是,开发团队原先看不到度量信息,对自己的应用倒是感觉良好,而现在只要指标不可用,他们就会觉得不舒服。
目前的工作重点和未来计划
我们要在整个组织里推行MDD,新的挑战会随之不断出现。当多个团队有不同的需要、愿景、对度量的理解,却在一起创建指标的时候,事情就会变得很混乱。我们要定期删除不用的指标,并以类似的方式让度量覆盖到新项目。
目前,我们正试着为开发人员创建准则,以确保所有开发人员达成共识。每个开发团队都要能回答下面三个问题:
你怎么知道你的应用运行正常?(Bug少并不够,必须提供进一步的证据,比如模拟)
应用的性能随着时间的推移会有怎样的表现?(比如说,和上一个版本相比,它是越来越快还是越来越慢?在高负载情况下是否仍能良好运行?)
你的应用的使用频率是多少?(比如有多少用户会在同一时间去生成报告?系统在白天会发布多少横幅广告?我们收到多少笔交易?)
这些问题有助于确保所有的应用在进入生产环境前都能被度量,并达到相同的度量覆盖水平。
至于以后的改进,我们现在正在做一个交通信号灯监控层(为了获得更快的反馈,最终达到外包一级响应等级——参见图5),还有度量驱动的硬件容量评估。
图5. 应用信号灯
总之,把度量加到开发过程里有很大的潜力。在整个组织内推行这种实践是很难的。但潜在的好处也很巨大:应用和业务表现对开发团队和业务人员来说是可见的,大家可以基于真实的数据更快、更准确地做决定,而且团队内和团队间的沟通也能得到提升。
关于
敏捷方法论的
文章已经很多了。其中,相当一部分文章讲述了敏捷方法技术方面的问题,比如
测试驱动开发和持续集成。同样,还有相当一部分文章讨论了敏捷 方法论的应用问题,例如发布计划,跟踪生产率,如何使用度量数据对过程“调优”,甚至让公司里的业务人员确信需要采纳一种特别的方法。读过这些有关敏捷方 法的文章后,很容易让人产生一种感觉,即通过购买一套工具并遵从一系列看上去很简单的实践,就算采纳了像极限编程和Scrum这样的敏捷方法。然而,现实 世界的经验表明,成功地采纳敏捷要比那复杂得多。它涉及到如何培养一些正确的做事态度来建立信任,鼓励交流与协作,最终让人们更加适应,并产生高效。
敏捷方法常常被描述为以人为中心,而不是强调技术,并有充分的理由来说明这一点。然而,虽然敏捷宣言强 调了“个体和交互胜于过程和工具”的重要性,但它并没有清晰地阐明如何处理这个重要的社会性维度。在强调技术的业务中,这些都太简单,无法概观个人态度在 项目团队中的强大影响力。要想知道哪种态度可以促进(或阻挠)敏捷的采纳,我们要问一个问题:“在成功的开发者和管理者之中,我们能发现那些与众不同的行 为吗?”,更重要的问题是 “这些行为是由什么态度驱动的呢?”
很多开发者习惯于独立
工作,花费大部分的时间来阅读规范,并完成设计和编码。在前敏捷环境(pre-agile environment)中,一些开发者甚至戴耳机听音乐,不听来自办公室的“噪音”。采纳极限编程的开发者发现其自身已经融入到更加社会化的环境了,在 这种环境下,成功依赖于与同伴和客户更紧密的协作。另外,经典的前敏捷开发是个体独自“拥有”那些设计和编码。在敏捷环境下,工作任务由团队共同决定: 没有谁能独自拥有某段代码。这种态度的调整可能特别具有挑战性。
刚接触敏捷开发的人可能习惯于在那种将自身划分成子系统再进行开发的项目。他们习惯于依据各子系统之间互联的高层次规范,独自负责某个子系统的设计。刚接 触集体代码所有制的开发者很容易被他们不得不掌握的代码的数量吓倒。与此同时,很少的技术文档(甚至没有技术文档)和快速变化的代码基线(包括那些熟悉的 类名和方法名都有可能在短时间内发生变化)很可能加剧这种情况。但是,敏捷方法论(特别是极限编程)要求编程人员有很强的编码能力。通过对缺乏经验和富有 经验的敏捷开发人员的观察,很容易就可以看出不仅仅是技能问题,态度也是非常关键的。
表1:传统团队与敏捷团队的对比
表一在代码级别上列出了一些传统团队与敏捷团队的不同。富有经验的敏捷开发者有不同的编码方法。他们倾向于灵活编码,而不是等到整个设计都很完善了再进行 开发。另外,他们还倾向于把编码视为
学习和探索的机会。例如,遇到一个问题时,他们总是通过编写一个小的概念验证模型或“技术原型(spike solution)”使问题具体化,而不是构建一个复杂的模型或者通过自然语言描述来说明各种行为。同样,敏捷开发者更愿意去阅读第三方的代码。有时候, 他们想做一些力所能及的改进;有时候他们这么做只是为了学习一种新的设计方法。最后,通过尽可能地让类、方法以及与潜在的方法调用链等相互独立,以便仅了 解局部代码就足够了,这样就不用去花很多时间去研究整个子系统或应用。所有这些差异能更好地使开发者发现并处理编码中出现的问题,而不是仅仅使用高超的编 码技能完成任务而已。
拿结对编程为例。对于采纳敏捷方法论(尤其是极限编程)的团队来说,结对编程是最有争议的几个问题之一,因为它需要两个开发人员共同完成同一段代码。虽然 一个开发者可能具有杰出的设计能力并精通开发平台,但作为一个高效的XP开发者,他还必须能够沟通思想,协作进行测试,提供可能的实现方案,并在某个实现 策略上达成共识。很多开发者不愿意进行结对编程,并不是因为他们不会编码,而是因为他们不熟悉结对编程。有个开发者在他的blog中写道:“结对编程会使 他们暴露他们真正的知识和技能水平”。独立编程时,别人只会看到编码结果。而结对编程时,不顺利的开始和早期犯的错误都会被别人看到。这时肯定会有一种压 迫感,甚至对高水平的开发者也是一样,要花上一段时间才能习惯。值得牢记的是:当你了解了其它团队成员,并且熟悉每个参与者的个性之后,结对编程就会变得 容易起来。
大多数成功的极限编程者对使用各种语言编程、学习新的设计方法都相当感兴趣,特别是阅读已存在的代码。这些成功的开发者愿意通过尝试做一些小的练习来“实 践”编码。他们可能会通过编写一些小工具或参与开源项目进行实验。在这里,着重强调“实践”是非常重要的。好的敏捷开发者常常通做一些事情来掌握知识和技 术,而不仅仅通过阅读了解它。
“极限编程是共产主义……”这就是某个开发者对结对编程的牵强解释。他提到,在XP中的编码使大家分享了的各自的经验,他嘲笑“集体代码所有制”,并对所 有开发人员可及接触所有领域的工作以便能够编写任意部分的代码这一事实嗤之以鼻。我与这个开发者聊过一段时间以后,才明白他的想法实际上是为了与他人竞争 以保住“饭碗”。他担心同一团队中以及不同团队间的竞争问题。与别人一起工作意味着允许别人看到他是怎样解决问题的,用了什么工具,这就使别人有机会学到 他的诀窍。他对结对编程的反感表明,在敏捷团队中需要解决个人英雄式开发和“饭碗”问题。结对编程很自然地使开发者向同事敞开胸怀,分享领域知识,并时刻 准备把你的方法与大家分享。
一个极度自信的开发者也可能会抛开结对编程这一方式。有时面对生产速率下降而一个成员独立工作可以使其提高的情况下会发生这样的事。另外,当一对开发者中 的某个人能力不济,而另一个人就会把“结对”变成“个人秀”。 还有一些时候,其中的一个开发者可能急不可耐地想完成任务,因为一些个人原因驱使他尽快完成用户故事,可能最显而易见的原因就是“野心”:试图通过展示技 术能力成为团队领导者,或得到其它晋升机会。这样的态度很容易使结对褪变成一个“得分比赛”,比赛的目标就是看谁能赢,而不是设法完成有意义的工作。
过少的发言权也可能是成为一个问题。一个开发者很少主动关心他的结对任务的话,很可能他就会被他的伙伴所领导。在这种情况下,这个开发者实际上是放弃了很多在设计和代码质量上的责任。
塑造敏捷教练
至此,我们仅讨论了在开发者中发生的常见实践问题。然而,创建和维护一个具有敏捷态度的开发团队也是教练和其他领导者最重要的责任。这些领导者必须为他们的团队建立一套好的样例并成为真正的教练,而不是成为只有“教练”头衔的团队成员。
最有效的领导技能之一就是建立一整套好的样例。开发团队会建立一整套规则,比如所有的产品代码要结对编写,所有的产品代码都要先写测试等等。只有团队成员 坚信这些规则是非常重要的,这些规则才会起作用。然而,“说了不做”真的是太容易了。例如,团队领导者向团队成员宣布:“构建失败了,我们现在最重要的任 务就是修复它。”刚听到时一定会信以为真,可是接下来的话却不是那么回事了,“我第一个发现了这个问题,原本应该由我来修复它,可是我太忙了。”他的行动 使其对这件事的重要性大打折扣。别人会认为,构建可能是现在最重要的事,也可能不是。作为一个团队领导者,让别人看到他正在与一个开发者一起修复这个构建 是很平常的事情。这么做可以向团队成员进一步表明,构建是一个非常重要的事。
好的教练并不仅仅是知道如何教开发人员技巧,还要鼓励开发人员务实思考,并高效协作。这有点与Ken Schwaber所描述的ScrumMaster 的角色相似,即该角色对鼓励团队协作负有责任。当教练拒绝解释而直接用自己的知识来解决问题或者以命令的口气来领导团队时,这就是一个不太好的信号。
我想,最好从外面请一个人来作为“教练”帮助团队,而不应该是团队的固定成员。如果教练是团队中的一个固定成员,那么会存在利益冲突:有时他要帮团队成员,以便提高团队能力和效率;而有时他要客观地评估团队,在团队成员之间做一些比较。就象Kent Beck在他的《Extreme Programming Explained》一书中所提到的,一个教练应该有一个目标,即帮助团队成长,最终达到不再需要教练。一个好的教练需要一定的自信和情绪控制力,也需要技术能力和经验。
铲除潜在的问题
有几个潜在的因素会对团队态度产生负面影响。一些团队成员很担心:他们的团队领导做改革只是为了进一步达到个人目标,而不是为了使团队做得更好。另一部分 成员不愿意面对变化的原因是怯于表达。另外一个特别麻烦的问题就是:谁不喜欢自己得到夸奖,并可以批评别人呢?可是我们真正需要的是虚心地接受批评和学 习。
在软件业,很多创新可以得到个人奖励。写东西和在会议上讲演显然都会提升个人形象。技术领导者、教练或处于同样角色的人就处于一种可以引入变化的位置上。 我们应当意识到,尽管我们鼓励创新,但变化也有可能带有破坏性或给已经高效工作的团队更大的压力。因此,和团队一起进行回顾找到解决方案要比由领导宣布某 种改进策略要好得多。
“激励整个团队拥抱变化要比使用权力来执行对他们自己及业务有利的某些变化好的多”。对于领导者来说,能认识到这一点是非常重要的。正如一个开发人员抱怨 说:“这么做只能使我们更伤心。他们只想通过会议来使他们看起来更有权力。”他认为在他的团队中,只是为了使团队中一两个权威人士显得更专业就将某种革新 强加在团队之上,甚至不顾这会使软件交付的每日任务更难完成。所以另一个关键之处就是要认识到每个人都需要稳定性和安全感,而过多的变化会使其很快动摇。
然而有时很明显的是,人们已经根深蒂固地反对那种尚未发现的变化。不管已经有多少人的担忧被巧妙地说了出来,还是会有更多的担忧不断涌现,这是经常发生的 事情。很可能那些提出个人担忧的人就有某种个人或动机问题需要改进,这是好事,但说出来以后并不一定会感到舒服一些。例如,很多人可能会对极限编程提出一 些技术和业务方面的异议。很少有人会坦言真正困扰他们的到底是什么。例如,你不可能听到:“使用XP意味着固定的工作时间,所以我不能到学校接我的女 儿。”
当团队成员发现他们可能要使用某种新的技术平台来构建一些产品时,同样的事情也会发生。一些开发人员强烈反对这样做,他们的理由就是“我们需要多考虑一些 技术问题,例如可扩展性、学习和维护成本、工具的质量等等”。几个月以后,我们就会发现,真正的原因是很多开发人员不想花时间去研究被提及的新平台,因为 他们感到学习新技术平台会证明他们的个人学习能力不行。从专业角度来看,尽管职业发展、就业能力和工作与生活的平衡都都是很正常的问题,但对于个体来说, 还是很难消除这种担心。
在培养敏捷团队中的最后一个潜在因素就是需要一点谦虚的品德。在敏捷团队中,谦虚有很多好处。其一就是它减少那种反生产力的“得分式(point scoring)”竞争的可能性。这正是与XP中的“做最简单的事”相吻合的心态,正象Steve McConnell在《Code Complete》中所指出的,它鼓励开发人员写可读性更高的代码。当你想批评别人,尤其是当他正努力采用敏捷方法的时候,你就该学习如何保持谦虚的心态 了。虽然别人有缺点,但当你看到了一个缺点并自问“我曾经犯过同样的错误吗”时,这才是重要的。你可能无法改正别人的缺点,但你肯定可以从中学到东西。
结论
在敏捷团队中培养高效的态度和工作方式是一个复杂而关键的活动。很多试图进行敏捷项目的人把焦点放在业务上。尽管业务很重要,但是一定要记住:项目干系人 都是人。他们也有他们的个人需求和关心的事情。一个成功的自组织的项目团队需要每一个参与者都能真诚地来推动各方面的改进。敏捷不是被“统治”出来的,但 是,假如给予那些具有能动性的团队成员进行自我组织的自由,那么敏捷是能培养出来的。
我们在
测试活动中,时常关注一些性能数据,这些数据从哪儿来?很显然,放在我们面前的第一道关卡便是
监控技术,我们需要合理的,可以高度扩展和集成的监控系统,可以实时监控性能数据,并将他们用漂亮的方式展现出来,云时代背景下诞生了这么一些给力的工具,他们中有一些名字已经让大家足够熟悉了,Nagios,Gmond等,他们中还有一个强大的身影,就是今天给大家分享的
Ganglia。
Ganglia
Ganglia是一个跨平台可扩展的,高性能计算系统下的分布式监控系统,如集群和网格。它是基于分层设计,它使用广泛的技术,如XML数据代表,便携数据传输,RRDtool用于数据存储和可 视化。它利用精心设计的数据结构和算法实现每节点间并发非常低的。它已移植到广泛的
操作系统和处理器架构上,目前在世界各地成千上万的集群正在使用。它已被用来连结大学校园和世界各地,可以处理2000节点的规模。
这几天
测试一个项目,上线时间比较紧,人手不够,白天都忙着测试功能了,对于 系统的一堆接口经常要迭代测试, 、并且性能基本没有时间去做,正急得头晕眼花的时候老大给了一个方案:写一些脚本 ,申请一台机器,做个定时任务 晚上去跑,白天来看结果,然后重点人工去测试。想法是不错,可以前没有高过脚本和定时任务,没有办法赶紧去补一下。
问题一:如何写访问接口的脚本,要保证接口正常,就要满足请求的接口是可访问的 ,同时返回的数据是正确的,我的乖乖,接口是否可以访问好弄 使用curl 命令访问接口接口以了。
例子:get接口:
curl "http://api.map.baidu.com/images/blank.gif?product=jsapi&v=2.0&t=66977464&code=5000"
post接口:
curl -d "user=nickwolfe&password=12345" http://www.yahoo.com/login.cgi
返回都是个json串。根据返回的json 来判断 返回结果有没有。但是我又该如何判断返回结果对不对呢?纠结了好久(肚子没有货,都这样),结果大神一个命令给解决了。贴一个脚本看看:
#! /bin/sh ##! 后面哟哟空格 sudo curl "http://===============" >> /home/url.txt #接口url cd /home if [ $((grep "ok" url.txt)| wc -l) -gt 0] then echo "ok" >>result.txt date +%y%m%d%H%M >>result.txt else echo "no" >>result.txt date +%y%m%d%H%M >>result.txt fi echo "end" exit 0 |
下面开始做定时任务:
sudo crontab -e
0 */1 * * * sudo sh /home/test.sh # 每个小时运行一次脚本
保存 退出
sudo /etc/init.d/cron restart #重启 定时任务脚本的配置
sudo tail -f /var/log/cron.log #监控 定时任务日志
好了定时任务搞定 ,这个是搞的一个 接口,多个接口 可以 把 所有的接口访问 url 写成一个文件 然后到文件中读取,再 用curl 去请求。哈哈,100多个接口 不用每个版本都去 看看 接口有没有问题 只需要一次测试没有问题,以后看运行结果就可以了。
版权声明:本文出自 huangzigang 的51Testing软件测试博客:http://www.51testing.com/?498111
原创作品,转载时请务必以超链接形式标明本文原始出处、作者信息和本声明,否则将追究法律责任。
近一年多一直在从事服务端的
测试工作,虽然之前也做过两年,但融合了
自动化测试和
功能测试以及
单元测试,所以精力有限,接触到的
白盒测试比较碎也比较浅。近期项目进入了调整期,有时间整理下对于项目测试中的代码测试一些感触。 顺便对未来的工作方向和计划做好准备工作。
2014年可能需要继续负责服务端项目测试工作,但到底白盒测试和功能测试以及模块测试,自动化测试之间应该如何进行抉择,如何进行搭配,相互补充,来达到项目高质,高效的目的呢? 站在整个项目的角度,从以下几个维度对白盒测试进行了一些思考:
1. 什么样的项目可以考虑做白盒测试
1.1. 大项目,周期比较长(因为需要前期介入review RD代码)
1.2. 功能测试不放心的项目,接口比较明确,重要函数做的修改
1.3. 对整个项目了解较清晰,时间要求较低
1.4. 新项目
1.5. 逻辑较复杂的模块
1.6. 通用类的
1.7. 异步的、多线程的程序
1.8. 函数用到的外部数据较多的不适合做,构造起来非常复杂,如大量的信令、词典等
2. 如何结合白盒测试和其它测试方法
首先,需要根据项目特点,比如项目周期,项目难度等来确定测试方法。
然后,如果满足做白盒测试的条件,则需要先确定白盒测试处于项目测试中的什么阶段,如果是迭代或优化类的项目,建议进行分层测试,重点对更新的代码进行白盒测试,其它的进行传统的自动化或手工回归测试。如果是周期比较长的全新项目,可以考虑在RD编码阶段介入,了解接口和底层内部函数构造,为白盒测试做准备。 为了避免白盒测试和功能测试的交叉工作量,可以底层库用白盒测试,上层功能测试用功能测试,在功能测试上就不再关注底层的测试,可借助分层测试思想。
3. 如何降低白盒测试成本
不管从技术还是从周期上,白盒测试成本比较大,所以站在高效和简易的基础上,尽量借助工具来尽量减少白盒测试范围,比如可以借助:
3.1. 手工测试+代码覆盖率测试来覆盖一部分代码
3.2. C代码可以用gdb(其它语言也有)来构造一些比较难引入的上层变量,再结合代码覆盖率来做
3.3. 单测工具,比如cppunit,gtest等来做
接口测试 3.4. 其它
我们之前的做法是将模块测试做成自动化CASE,然后新版本来后,进行自动化测试回归,并结合代码覆盖率来出一份覆盖报告(从分支和代码行两个维度),然后再对新升级的代码进行review,并拓展用例来覆盖,如果功能测试实在无法模拟,会采取gtest,最后仍不好模拟会采用gdb挂载的方式
4、 白盒测试收益和风险是什么
4.1. 功能测试无法深入到底层的测试上,白盒测试可以
4.2. 投入成本较大,收益较小
4.3. 通过白盒测试只能发现函数级的错误,较难发现函数接口之间的错误
4.4. 时间会增加,覆盖率会增加
4.5. 可促进rd的单元测试做的更充分
4.6. 短期收益不明显,长远会有收益
5、白盒测试方法
5.1. 最基层的函数做详细的测试(倾向于功能),策略较复杂的做详细测试(倾向于逻辑),通过自己写5.2. 程序去调用被测函数,外层的通过GDB的方式去测试
5.3. 自己写驱动去调用被测程序或构造上下层来验证被测程序
5.5. 通过程序包装被测程序,通过多线程的方式去实现多个动作之间的交互
5.6. cppunit去做,但调用关系较复杂的测试很难去实现,支持case的管理、验证
5.7. 可借助gtest去实现,扩展为和c++test类似的功能
版权声明:本文出自 800716 的51Testing软件测试博客:http://www.51testing.com/?359684
原创作品,转载时请务必以超链接形式标明本文原始出处、作者信息和本声明,否则将追究法律责任。
QQ登陆的输入项为QQ号码(长度为5到10位数)和QQ密码,登陆和退出按钮,一台机器可以同时登陆超过一个QQ号码,请设计
功能测试用例。
快捷键的使用是否正常:
1. TAB 键的使用是否正确
2.上下左右键是否正确
3.ENTER 键的使用是否正确切换时是否正常。
布局美感
界面的布局是否符合人的审美的标准
具体因人而依
输入框的功能:
输入合法的用户名和密码可以成功进入
输入合法的用户名和不合法密码不可以进入,并给出合理的提示
输入不合法的用户名和正确密码不可以进入,并给出合理的提示
输入不合法的用户名和不正确的密码不可以进入,并给出合理的提示
不合法的用户名有:不正确的用户名,,使用了字符大于用户名的限制
正常用户名不允许的特殊字符 空的用户名,系统(
操作系统和应用系统)的保留字符
不合法的密码有:空密码(除有特殊规定的),错误的密码,字符大于密码的限制
正常密码不允许的特殊字符,系统(操作系统和应用系统)的保留字符
界面的链接:
对于界面有链接的界面,要测试界面上的所有的链接都正常或者给出合理的提示
补充
密码框显示的不要是具体的字符,要是一些密码的字符
验证用户名前有空格是否可以进入,一般情况可以。
验证用户名是否区分大小写。(有的软件是区分大小写的)
验证必填项为空,是否允许进入。
验证登录的次数是否有限制。从安全角度考虑,有些安全级别高的软件会考虑这方面的限制。
单元测试的概念
单元通俗的说就是指一个实现简单功能的函数。单元测试就是只用一组特定的输入(测试用例)测试函数是否功能正常,并且返回了正确的输出。
测试的覆盖种类
1.语句覆盖:语句覆盖就是设计若干个测试用例,运行被测试程序,使得每一条可执行语句至少执行次。
2.判定覆盖(也叫分支覆盖):设计若干个测试用例,运行所测程序,使程序中每个判断的取真分支和取假分支至少执行一次。
3.条件覆盖:设计足够的测试用例,运行所测程序,使程序中每个判断的每个条件的每个可能取值至少执行一次。
4.判定——条件覆盖:设计足够的测试用例,运行所测程序,使程序中每个判断的每个条件的每个可能取值至少执行一次,并且每个可能的判断结果也至少执行一次。
5.条件组合测试:设计足够的测试用例,运行所测程序,使程序中每个判断的所有条件取值组合至少执行一次。
6.路径测试:设计足够的测试用例,运行所测程序,要覆盖程序中所有可能的路径。
用例的设计方案主要的有下面几种:条件测试,基本路径测试,循环测试。通过上面的方法可以实现测试用例对程序的逻辑覆盖,和路径覆盖。
版权声明:本文出自 沙场点兵 的51Testing软件测试博客:http://www.51testing.com/?535396
原创作品,转载时请务必以超链接形式标明本文原始出处、作者信息和本声明,否则将追究法律责任。
介绍
每个实行持续交付的项目,都有生产流水线的元素,如持续集成和
自动化测试。这些测试是在不同层面进行的,从
单元测试到冒烟测试再到
功能测试。自动化功能测试的优点之一是可重复性和可预测的执行时间。出于这个原因,它应该作为软件质量的每一个构建之后的指标。功能测试自动化往往会成为一个瓶颈,所以你应该熟悉一下如何创建这样的测试的基本原则。
首先设计你的测试
测试集合可以比作盆景树。
最初的时候,我们照顾树根和树干。我们选择会成长的主要分支,我们每天都细心照料这棵树并等待它长出健康的叶子。
我们可以以类似的方式继续测试。
我们建一个将负责应用程序主要功能(例如:开启)的基类。
根据说明,我们先明确将被测试覆盖的应用程序的主要功能,然后每天我们在执行测试的时候都添加更多平行测试。
每一个支持测试(例如创建一个新的用户)的方法都需要与测试分离——让我们在单独的类里面来实现。
你应该在包括了应用程序主要功能的目录里保持类。
去建一个规定很多功能共有方法的抽象类是很好的做法。
如果你正在测试Web应用程序,就用页面对象设计模式。该模式里,一个类及其方法对应了单个页面的功能或一个大型网页里单个页面上的一个元素。
无需事事自动化
自动化花费很多,所以你应该主要测试应用程序的主要功能。
某些测试可以快速轻松地手动完成,且潜在脚本可能难以实现。
值得用到自动化的是那些繁琐的需要被重复很多次的,和那些需要大量数据验证的测试
工作。
写短测试
在一个或多个测试失败的情况下,开发团队的任何成员都应该能够轻松地找到错误的原因。
出于这个原因,每个测试方法里应该最多有5个断言,并且每个方法都必须提供的测试操作的完整记录。
明智的做法是使用BDD(行为驱动开发)技术,但是当你没有用一个特定的测试框架时,你应该把接下来的测试步骤放在comments //given //when //then下。
创建独立测试
在测试类中的每个方法应该是一个独立的实体,而不是依赖于其他测试。我们应该能够在任何时间运行单个测试。否则,这样的
测试用例集将来维护起来就会很贵——必须定期跟踪和更新测试之间的联系。
很多时候,测试需要一定的前提条件来满足。这些条件不应该用外部方法,应该在试验开始时运行。如果这些条件和测试类的所有方法一样,它们就可以被放在一开始进行的方法里(例如:在
JUnit中被标记为@ BeforeClass)。
关注可读性
源代码应该是自我记录的,而写下以下几行代码的每个利益相关者应该明白测试在做什么,为什么它被这么写。尽量避免在源代码注释,因为它也必须被更新。这值得花比平常多一点的时间来命名方法,从而使你的代码更易读。
再看看行为驱动开发技术,每个测试方法都应以单词“应该”开始,而不是“测试”。
根据这一惯例,我们马上就可以明白一个特定的方法测试什么内容了,它在分析测试报告时特别有用。
测试必须要快
正如在本文开头所提到的,自动化功能测试应该是应用程序质量的一个指标。连续传递过程中的每一步都应指明最长持续时间;并且根据这个概念,开发团队应该尽快获得有关软件质量的反馈。自动化功能测试的持续时间应不超过几分钟。
对一个非常全面的测试集来说,有必要并行运行测试(经常在不同的机器上)。虚拟化在这里可能是非常有帮助的。
创建抗变测试
最常提及自动化功能测试的缺点是其对应用程序中变化的低抵抗性,尤其是在GUI中。
在Web应用程序中,测试应该能抵抗网站的内容的变化。测试应该只验证功能,这就使得它可以在不同的位置运行测试。这并不意味着我们不应该编写自动化测试来检查网页的内容。
如果你已经想创建这样的测试,你应该遵循DDT(数据驱动测试)技术。这意味着,检查内容是与源代码分离开的。
Web应用程序的页面布局变化非常频繁,这已经影响到了用户界面。
当你设计一个界面时,每个区段和每个页面你都应该有一个你可以用来测试的唯一标识符,即使一个网站的层次结构发生了变化。
自动化测试无法取代人类
功能自动化测试可以是项目中的主要测试技术,但绝不是唯一的一个。
自动化测试是可重复再生的,他们的覆盖范围总是相同的。
另一方面,虽然探索性测试是低再生的,但是它们能够覆盖自动化测试未触及的区域。
你还应该记住,自动化测试的“绿色”状态并不意味着你的应用程序是没有错误的。
这种情况往往会让测试员分心,而且有可能会影响测试的准确性。
一面(技术面)
栈和堆的区别
数组中第一个不重复的字符串(如AABBBC,则为C)
二面(技术面)
百度的
工作环境是
Linux,所以问了Linux常用命令的使用情况,问了一个查看进程的命令,是ps -aux | grep 进程名
问了hash map
介绍了下项目
三面(经理面)
1、自我介绍
3、你为什么在上海这家公司实习
4、你和你项目主管、师父的相处怎么样
5、你的优缺点(重点是确定)
6、对面试经理提问题
暂时记得这些,结果等待中
结果出来了,很幸运被录取了,哈哈,期待~
模糊
测试(fuzz testing)是一类
安全性测试的方法。说起安全性测试,大部分人头脑中浮现出的可能是一个标准的“黑客”场景:某个不修边幅、脸色苍白的年轻人,坐在黑暗的房间中,正在熟练地使用各种工具尝试进入某个系统。这种由安全人员“模拟黑客进入系统”的测试方法的确是安全性测试中的一种有效测试手段,名叫“渗透测试”。渗透测试方法完全依靠测试执行者的能力,能力强的“白客”能够发现有价值的安全性漏洞,而不具备很强的攻击能力的测试者就无法有效发现系统中的安全性漏洞。必须承认,渗透测试是一种有效的安全性测试手段,当然,前提是你要能够找到足够好的测试执行者。
渗透测试是一种有效的测试方法,但由于它对执行者的能力要求太高,因此很难被大规模应用。站在测试的角度,我们是否能够用“
自动化测试”这个强有力的武器帮助降低安全性测试的门槛呢?一个容易想到的“录制/回放”方法是:将渗透测试的执行者们的操作录制下来,形成脚本,期望这些脚本可以在不加修改或是稍加修改时应用在对其他应用的安全性测试中。但由于渗透测试的过程并不具有可重复的特点(测试执行主要依赖执行者的经验,类似调试),这种想法在真实的安全性测试环境下完全不可行。完全自动化的工具通常只能发现那些可被用标准化方式发现的特定安全漏洞(如简单的
SQL注入漏洞)。
模糊测试是一种介于完全的手工渗透测试与完全的自动化测试之间的安全性测试类型。它充分利用了机器的能力:随机生成和发送数据;同时,也尝试将安全专家在安全性方面的经验引入进来。从执行过程来说,模糊测试的执行过程非常简单:
测试工具通过随机或是半随机的方式生成大量数据;
测试工具将生成的数据发送给被测试的系统(输入);
测试工具检测被测系统的状态(如是否能够响应,响应是否正确等);
根据被测系统的状态判断是否存在潜在的安全漏洞。
显然,模糊测试的整个执行过程是依靠工具进行的自动化测试。但是,看起来它完全是一个类似MonkeyTest工具的随机数据生成器嘛,这怎么能和安全专家的经验结合起来呢?别着急,我们用一个例子来演示一下。
为了简单起见,假定我们要测试的应用是一个C/S应用的服务端程序。这个程序运行在Unix平台上,名字叫做TgServer。我们唯一知道的信息就是客户端和TgServer之间使用基于TCP/IP的自定义协议进行通讯。这种情况下,我们该如何尝试找到应用系统中可能的漏洞?
方法1:
如果我们手头上有TgServer的源代码,通过代码审查显然可以找到可能的漏洞。就算没有源代码,通过逆向工程方式,用代码审查的方式也可以达到找到漏洞的目的。当然,这必然要求审查者具有足够好的技能,而且,被测应用规模越大,需要付出的成本也就越高。
方法2:
尝试抓取到客户端和服务器之间的通信数据,根据这些数据分析出客户端与服务器之间的通信协议,然后根据协议的定义,自行编造数据发起攻击,尝试找到可能的漏洞。
方法2在成本上比方法1要低,而且由于方法2关注的是协议层面的攻击,效率会更高。但是,稍微想一下,方法2还是存在一些问题:
完整的协议分析难度很大;
人工编造数据的成本很高;
在方法2的基础上,我们尝试引入模糊测试的概念,由于机器生成和发送数据的能力足够强,因此我们完全可以把生成数据的任务交给机器去完成。当然,协议的分析主要还是依赖人工来进行,模糊测试领域内有一些自动化的协议分析手段(《模糊测试》一书中有专门的章节描述),但从效率和效果上来说,在面对复杂协议的时候,人工分析的方式更为有效。
假如根据抓取到的数据包,我们发现被测应用使用的协议如下(|仅表示字段间的分割,不是实际的数据内容):
|00 01| GET | 11 | user:dennis
2字节的包头(00 01)
10字节定长的命令(GET)
一个1字节的数据,表示命令参数的长度
不定长的命令参数
根据这些信息,使用模糊测试方法,我们就可以借助通用的模糊测试工具(如Spike),用模板方式将协议描述出来,并让模糊测试工具自动填充可变字段的内容,生成大量的测试用例并发送给TgServer。同时,通过模糊测试工具提供的功能监视TgServer,一旦TgServer出现可被识别的问题(如性能下降,不再响应,或是返回异常数据等),我们就可以停止模糊测试,并通过日志找到导致问题的请求,进而确认问题。
简单的说,模糊测试尝试降低安全性测试的门槛,通过半随机方式的数据发送来找出被测系统的漏洞。显然,测试这对被测应用越了解,模糊测试的生成就能越准确。但与渗透测试或是代码审查相比,模糊测试显然更加易于进行。而且,通过自动化工具,模糊测试可以把安全方面的经验积累到工具中,为组织持续的安全性测试提供帮助。
这是本系列的第一篇,后续还将写两篇来介绍不同类型应用的模糊测试,以及常用的模糊测试工具。
《模糊测试——强制发掘安全漏洞的利器》这本书全面覆盖了模糊测试这一技术。
jira是个bug跟踪管理系统,许多开源项目也使用它来进行bugtrac,如:jenkins。
用户可以把产品中的bug report到jira上,创建问题issue并进行跟踪。
issue的优先级(priority)和描述(description)如下: