标签归档:ThoughtBlogs

为什么TDD?

1. 反映真实需求

这里存在先写测试和后写测试的区别。

先说后写测试。根据很多经验,在直接写产品实现代码时,需要考虑需求,同时需要兼顾实现的细节,用什么算法和语法。在对需求和考虑和实现细节间来回,很容易让人产生对其中一方的疏忽,遗漏掉一些需求方面,甚至在实现上存在缺陷。

有人会说我可以通过后写测试来保证。第一经验是,很多人都不会在实现完成后,补充测试,因为还有更多的工作和需求需要实现。第二是开发人员很容易在后补的测试中,只是试图去测试他已有的实现,而不是需求本身,很容易遗漏掉一些边界检查之类,在测试时,已有的实现细节会在脑子里面先入为主,即使实现存在问题或有漏洞,也很难在后补的测试中测出来。我阅读过很多面试者的测试代码,很明显都是后补的,因为一些很明显的问题没有测出来,甚至已经实现的逻辑也是只测试了一部分。而这些面试者都承认。

结果就是,一旦代码签入,开始集成之后,暴露出问题,后补的测试起不到对于实现代码的保障需求的作用,开发者不能不借助调试工具,单步跟踪实现代码的每一行去寻找问题发生的原因。

再说先写测试。按照TDD的流程,先写失败的测试,再写恰好让测试成功的实现代码,最后重构,如此往复。这样的好处在于,每先写一个测试,都是在试图用自己对问题和需求的理解,来定义实现代码的架子。从测试的不同角度,范围、边界、大小、功能等等,来定义实现代码将来会是个什么样子。一个测试接着一个测试,利用TDD的过程,把实现代码恰好不多不少,正好驱动出解决这个需求和问题的实现代码来。

这里的重点在于,先写测试可以让开发者把重点放在理解需求和实现需求上,而不是一开始就陷入实现的细节中同时兼顾需求,掉入两者都兼顾不好的境地。先写的测试代码,作为副产品,可以作为验证需求的得力保障。

2. 设计在其中

先写测试对于设计的好处在于,先写测试先定义新的类,以及定义类与类之间的关系,就是在定义类与类之间如何交互,每个类如何暴露自己的接口,类和类之间的引用关系。这时,测试代码会逼迫开发者认真考虑如何分解类与类之间的耦合关系,这样产生的实现代码更容易利用了IoC和DIP的模式,实现面向接口编程。

这样实现代码的好处还在于,代码的可测试性很高,在加入更多的测试代码和新类的时候,同样借力于已有类的面向接口和依赖反转所带来的可测试性,达到新实现代码的面向接口和可测试性,这样进入良性循环。而这对于整体的代码和设计,获益良多。换句话说,测试即设计。

回头看后写测试的情况,因为从一开始开发者把重心放在实现的细节和功能需求的往复上,对于代码设计、类的关系和定义很容易疏于考虑,产生的结果可能是耦合紧,可测试性差。

3. 增强信心

在我看来,软件开发周期、软件交付最大的问题在于交付后的运行和维护阶段,正是这个阶段才是软件在持续交付价值的时期。在软件的可维护性,在这个阶段凸显价值。在软件交付后,包括软件开发周期期间,不可避免的就是开发者在根据新的需求,逐渐添加新的功能代码,或者修复一些已知的缺陷。

很多经验表明,在开发者按照需求添加一些新的代码进入系统,或者试图修复已有缺陷时,很容易导致既有功能出错,也就是新引入的代码打破了既有代码的逻辑,导致回归问题的出现。因为软件系统的可测试性差,无法做到快速频繁自动的回归测试,带来的可维护性自然也很差。

而作为TDD的副产品之一——可以快速频繁自动运行的测试代码,可以在开发者新引入代码之际,给予开发者足够的信心,每次添加一点新代码,一个方法,一个类,都已频繁运行已有相关的测试代码,来确保新引入代码不会打破已有的功能。

在持续集成中,这些测试代码可以帮助验证每次签入的代码都不会破坏掉已有的功能。这也是《重构》里面反复提到的在每个重构小步骤后都要运行所有的测试代码的原因所在。

4. 粒度和进度

按照TDD的原则,先写测试,可以让开发者在同一时间只关注在功能需求的一小部分,把功能需求且分到一定小的粒度,用测试代码去表示这样的需求,用实现代码让测试通过,实现这样的需求,然后重构。

这样的好处在于,开发者自己的注意力和重心不用在整个功能需求内的小需求点之间犹豫,每次注重解决单个小问题,解决完一个进入下一个小问题的解决。在保证小粒度实现的同时,保证进度可以随时被打断,但同时被打断时已经做完的是完整可以运行,至少是实现了部分需求的实现代码。

而后写测试的代价是,首先实现代码很有可能包含设计上的问题,甚至含有缺陷,在完美的测试代码完成之前(事实上这是不可能的),可以交付的是可能存在严重缺陷,甚至是曲解了功能需求的实现代码。

Team的一次Code Kata

上周四的中午饭后,我们team坐下来完成了一次Code Kata练习。跟之前的几次邀请PwC team同事过来pair和coach不同,这次是我们组自己内部完成一次练习,题目来自Yuheng之前的一个练习:文曲星上的猜数字游戏。

题目规则很简单:

  1. 游戏开始后,系统会随机给出四个不重复的数字。由用户输入自己猜测的四个数字。
  2. 如果数字猜对而且位置也对,就是1一个A。
  3. 如果数字猜对但位置不对,就是一个B。
  4. 返回结果是如“2A1B”这样的字串。
  5. 猜错6次,游戏提示结束。重来。

开始提出的要求简单:用TDD驱动出实际代码。

大家抽签后开始pair,Yuheng还会一边计时一边催促,pair的气氛基本保持紧张有序。

在我和XuChen pair开始代码后,我们很容易写出第一个测试1,期望返回结果是”4A0B”,最简单的代码实现让测试变绿。

当我们试图写下第二个测试2,试图期望返回结果是“2A1B”时,我们发现不得不面对如何这个游戏规则的最核心算法,但可惜的是,猛然间对这个算法没有头绪。

局面一时僵住,停顿了有两分钟。

直觉和一点经验告诉我们,这时该拆解任务了。很容易想到,如果计算出几个A和几个B是很直白的拆分。

我们可以很容易写出一个测试3,测试猜测的四个数字跟事先给定的四个数字相比,有几个A类数字(循环比较),我们称之为perfect number。

也很容易写出另外一个测试4,测试猜测的四个数字跟事先给定的四个数字相比,有几个B类数字(在上个算法的基础上再循环比较),我们称之为good number。

写完针对测试3和4的实现代码,我们发现我们已经完成了最基本的算法,功能完成了。剩下的是重构代码。

从我们这次的经验看,我有一些收获和心得:

  1. 测试就是代码的设计,你看测试3和4导致的结果就是我们有了对应的两个计算方法。你打算怎么测,你的实现代码就会是怎样的。
  2. 印证了在Wikipedia中那段话,pair programming尤其适合面对一些challenging的任务(至少开始的时候是)。
  3. 分解任务是王道。我们在不同的level拆分任务,从story拆分成task,从大问题拆分成小问题,莫不如是。
  4. 囿于经验,不期望由端到端的测试能逐步甚至一下子推导出完整、完善的代码实现。而这样的练习,恰恰是我们锻造自己经验必不可少的过程。

我们在实现代码时,仍然欠缺的是:

  1. 对于测试方法名的命名,不够清晰直白。
  2. 对于算法代码的实现,简单粗糙,还需要重构。

为什么要结对编程?

以下内容摘自myThoughtWorks中对于结对编程(Pair Programming)的讨论。

结对编程与非结对编程相比那个效率会更高?

这个问题没有一个明确的答案,没有人可以很肯定的说结对编程就是会比非结对编程更有效率。效率不单单是时间,还包含效果。

如 果对于一个技术难度不高,一个人几天就可以搞定,后期不需要维护的一个小项目来说可能结对编程在效率上会低于非结对编程。但是我们twer是关注代码质量 的,面临的项目一般都是需要持续发展,而且是具有一定规模的。对于这样的项目和我们,从长远来看,结对编程会带给我们长足的发展和更高的效率。对于这点我 总结了如下几点(欢迎补充):

  1. 代码质量。结对编程与非结对编程相比,往往更加容易写出更短 的代码,做出更好的设计,产生的更少的bug。俗话说三个臭皮匠顶过一个诸葛亮,每个人的思维 都是有瓶颈的,两个人的合作通常会考虑更多的设计选项,达成更简单,更易维护的设计。研究发现结对编程bug率降低会15%到50%,这个会根据程序员的 经验以及任务的复杂度而不同,这样就会大大减少以后修bug的时间,降低维护成本。这样我们才敢一个项目只有一个QA或者没有QA呀!
  2. 互相督促。 在结对编程的过程中我们可以相互督促,比如严格去TDD减少裸奔,提高注意力避免一个人注意力不集中或者花时间上网处理个人事宜,避免偷工减料 等等,从而也可以在某种程度上保证我们的代码质量。而且人们更不愿意打断两个结对编程的人,而单独工作的人却容易被打断,这样也增加了我们专注工作的时 间。
  3. 知识共享。在结对编程我们是知识共享的,还有我们会不停的switch pair,轮流与团队中的所有其他程序员结对编程,而不是仅与某个程序员编程,使得系统的知识在整个团队中传播,减少了程序员休假或者离开团队带来的风险,从而可以保证我们项目的可持续发展。
  4. 新人成长。 这是结对编程很重要的一个作用。曾经听大大说过,他和大熊发现,在别的公司毕业刚刚一年的毕业生在项目中可以承担的还很少,但是在我们公司很多 人已经成为了项目的骨干。这很大程度上要归功于结对。当新员工进入一个项目的时候,我们往往会安排有经验的老员工去跟他们结对,这样新员工可以更快熟悉项 目情况,更快的进入状态,更快的发现自己的不足,也可以学到更多的东西,更快的成长起来为项目做出贡献。
  5. 沟通能力。结对编程需要两个人一起讨论,一起把一件事情做完,也是对我们沟通能力的一种锻炼。让我们不再是很多人眼中只会闷头写代码的木讷的程序员了。
  6. 结对可以省钱http://www.infoq.com/cn/news/2009/06/dollar-value-of-pair-programming
  7. 徐昊说结对还可以Simple Designhttp://blog.vincentx.info/2007/03/agile-101-pair-programming-simple-design/

Mock, Stub, Fake

上次郑晔给大家做游戏,徐昊问到台上的咨询师,Mock、Stub和Fake的区别是什么?

自己虽然心里有点印象,但还是下来搜了一下:

Wikipedia的解释是这样:

Some authors[1] draw a distinction between fake and mock objects. Fakes are the simpler of the two, simply implementing the same interface as the object that they represent and returning pre-arranged responses. Thus a fake object merely provides a set of method stubs.

In the book “The Art of Unit Testing”[2] mocks are described as a fake object that helps decide if a test failed or passed, by verifying if an interaction on an object occurred or not. Everything else is defined as a stub. In that book, “Fakes” are anything that is not real. Based on their usage, they are either stubs or mocks.

Mock objects in this sense do a little more: their method implementations contain assertions of their own. This means that a true mock, in this sense, will examine the context of each call— perhaps checking the order in which its methods are called, perhaps performing tests on the data passed into the method calls as arguments.

这里还有StackOverFlow的回答

扩展阅读:

SAI项目小结

其实这个我在TW的第一个项目还没结束,现在就总结还为时尚早。但我担心我会遗忘,而且既然有心思写下来,为什么要等那么一个时机呢?

  1. JS代码组织结构和单元测试。按照客户要求,我们使用SmartClient作为客户端RIA库,这个库的优点是丰富的UI控件,但逻辑和视图耦合很紧。当我们发现JS端代码日渐庞大臃肿时,耦合紧导致维护很难,而这时已经过了第一个Release。在第二个Release中,我们讨论过用MVP来解耦,引入Jasmine作单元测试,讨论尽可能将代码做M、V、C三个角度分离并有了尝试,但仍未引起足够多的重视。我们是侥幸的,因为这个项目并不复杂,不管从技术上还是业务上,所以这个方面的技术债感受不深。我们知道我们应该做的。
  2. 代码静态分析和质量控制。我们直到第二个Release的后期,才试图引入cobertura和sonar来分析我们的所有代码,结果可想而知,一些测试没有覆盖,代码的逻辑有问题,有些是多余的分支,有些是永远不会走到的逻辑。这样又方便又能让我们学习的工具,为什么没能早点采用呢?
  3. 成熟框架。因为Team半数以上是新TWer,从一开始team并未引入Hibernate和Spring等重量级框架,但在Domain Model分析上下了功夫,这样一直平静发展到Release 1结束。Release 2开始,因为团队学习的需求和客户要求架构统一,我们同时引入Spring和Hibernate,用到的多是框架最核心和基础的技术,除了遇到个别问题比如双向关联、继承和Proxy Bean,一切都还正常,业务和技术的双重相对简单性决定也用不了多复杂的框架技术。只是在临近Release 2结束时,客户要求集成双方的系统时,我们发现引入Hibernate和Spring在这时是一种风险,或者说累赘,我们不得不合并或者修改一些配置,以期避免冲突,这个过程不那么平滑。
  4. 代码合并。最后关头时间紧,我们却发现我们要merge一个超过一万两千行代码的类,这个类基本是一个Release才merge一次。过程痛苦,IDE自作主张的分析合并让我们无法相信它,我们能做的只是纯文本的手工对比,这时Beyond Compare帮了大忙,但即使这样也消耗了我们近半个下午的时间,这还只是不到十个类文件。我在想,如果能前瞻一点再果断一点,我们定不会在这个一万两千多行的类里面再添加我们全部的实现的代码,而是挪到自己的实现类里。
  5. 管理客户期望。系统集成,是客户在Release 2还剩一个半迭代时,强烈提出的。这个问题似乎从项目开始时可以预期,甚至中途客户也是偶尔提及,但我们似乎没有足够重视。我更认为这是业务理解和管理客户期望的问题。我还没有更好的想法,期待跟团队一起回顾。

ThoughtWorks有什么不同?

仅仅入职两个月时间,就试图看清楚说明白新入职公司的不同,注定是浅陋的。但是这并不妨碍我说出目前我心目中的ThoughtWorks。

昨天和前同事聊天,被问起了ThoughtWorks跟之前公司有哪些不同的地方。我想了想说,你所知道的敏捷的全部,在ThoughtWorks都能找到;没有拖沓碎叨更像是status update的standup; 我看到了自组织的团队,每个人都在团队中承担自己的职责,自信且淡定;扁平的层级文化,没有看不到头的title层次,可以把精力聚焦在项目上和自己感兴趣的事情上;可以向整个公司发邮件,表达自己的担心和困惑,评论社会现实,公司的老大也会加入进来讨论;可以让自己承担起公司主人的角色,为公司的发展做出自己的努力和影响;还有ThoughtWorks对于利用软件和技术改善人类生活的社会责任的担当;ThoughtWorks一直致力于用最先进的技术和方法来帮助客户,这会让做技术的人很high。这些在别的公司都是很难见到的。

我之前的工作经历很有代表性,先是一家国内大型软件企业,然后是一家大型外资企业,这样的经历让我有在不同企业背景和文化下的体验,也让我现在有了相对的参照系,来比较现在所在的环境——ThoughtWorks有什么不同。

如果答案仅仅止步于上面那些不同,我想这是肤浅的。是什么造就了这些以及更多的不同?有一些线索可以帮助理清楚:

在TWI上徐昊提到了Martin Fowler写的一篇博客,讲的就是ThoughtWorks是Roy的社会化实践。Roy希望借这场实践来证明那些认定下面结论的观点是错误的:

  • 你的公司不可能只由能力强的人们组成,必须存在能力差别
  • 能力强的人往往无法合作
  • 大型公司必须有强有力的管理结构,以避免分崩离析
  • 不可能为考虑长远而做事
  • 成为国际化公司是为了利用欠发达国家的人才
  • 不能暴露自己的弱点,尤其对于公司外
  • 不要赋予员工权利,否则会被滥用而伤害公司
  • 文化是次要的,你需要一个优越的商业模型

“社会化实践”,是不是挺震撼的?事实是,ThoughtWorks的确在全球网罗到了一批才能很高的人,在共同致力发展这个公司,守护这样的文化。我们成为了Roy的实验品,但软件这个特殊的行业,工程师这个简单又复杂的职业,这样一群人,的确在印证着Roy的实验趋向成功。

另外还有一篇文章《为什么我要把公司做成扁平型》,作者是37signals的创始人之一,他讲述了公司确实发生过的事情,当试图为一些资深员工创造一个管理职位和职务来发展时,遇到的问题和冲突。经验证明,让团队自己管理自己是效率更高的方式,因为的确有这样的一些人,不介意有那样垂直发展的梯子供自己攀爬。

最后是今天看到的米高写的一篇《全面成功》,这跟我在团队同事那里听到的一样。怎样定义项目的成功,只顺利结项拿到款是肤浅和单薄的。客户满意,项目质量高,团队得到发展,不一而足。ThoughtWorks的文化追求,也导致了全面成功是每个项目组的诉求。在这样的环境下,团队才会是自组织的,个人最后也才是充实和成功的。

DevOps是什么?

DevOps是什么?

devops is an emerging set of principles, methods and practices for communication, collaboration and integration between software development (application/software engineering) and IT operations (systems administration/infrastructure) professionals. It has developed in response to the emerging understanding of the interdependence and importance of both the development and operations disciplines in meeting an organization’s goal of rapidly producing software products and services.

— from Wikipedia, http://en.wikipedia.org/wiki/Devops

简单的说,DevOps是一组原则、方法和实践的集合,用来改善软件研发和IT运维之间的沟通、协作和集成,从而让软件产品和服务以更快的速度发布。

这里的快不是真正的目的,真的目的在于终端用户不会察觉到快速交付带来的不爽(质量、性能、安全性变差),而是享受到版本变化带来的更优质服务,这样才能让软件企业立于不败之地。至于为什么要快,我不说,你懂的。

一边要快,一边要稳定。说到稳定,就没法把运维避开不谈了。所以DevOps就是试图消除软件研发和运维之间的壁垒,让二者结合为更高效的软件交付团队。

DevOps涉及到什么?

DevOps是基于Agile的理念,并试图用Agile去影响其他部门、团队和实践。这里涉及到Agile和Lean中各式各样试图提高效率、消除浪费而采取的过程式、理念式、工具式的实践。可以包含但不限于以下内容:

  • 让开发人员和运维人员交叉参加部门会议
  • 让开发环境与运维环境保持一致
  • 自动化任何运维过程可以自动化的过程

如果有人或者公司说,用了我们的blabla产品,就是DevOps了,这只会引来明白人的窃笑。这个效果,基本和说我们每天都Stand Up所以我们就是敏捷也可以跳舞一样可笑。

在我看来,实施DevOps最后要面临和解决的依然是组织和人的问题,这是文化和价值观信奉的差别,与具体的产品和项目无关。我甚至预见,DevOps因为会涉及到不同业务部门,而不像敏捷只会局限在研发单一部门内,反而更难实行。所以,可以想象,在怎样的情形甚至逼迫下,会有怎样类型的企业会去追求真正意义上的DevOps。

扩展阅读:

IFrame带来的Session问题

客户原来有个Web App系统A,我们要基于A开发一个系统B,但不希望B对A依赖太重,所以B被实现为一个独立的Web App(war)。A和B部署在同一个Weblogic server上,在A中可以导航到B,两个系统看起来像是一个系统。

有个小需求是,在B中希望显示一个页面,根据参数能展示出不同的信息。这个页面在A中已经存在,所以自然而然最快的方法就是在B中创建一个iframe来指向那个A中的页面,配以不同的参数,多快好省!

问题很快出来了,QA发现那个iframe中的A页面很快就会session timeout,然后会提示用户输入登陆用户名和密码,而iframe外的B session并未过期的。

问题在于A和B实际上还是两个Web App,各自有各自的session。因为不能简单地修改A的页面,让它保持session不会timeout,所以剩下的办法只好是控制B的session timeout时间要早于A了。还有什么更优雅的方法呢?

如果给我一次重新实现的机会,我宁愿自己画一个属于B的页面,而扔掉iframe。

另外一个需求是,A和B是各自独立的Web App对于用户是透明的,用A的用户登陆进来可以直接进入B,反之则不可以。解决办法有点tricky,A的contextRoot设为/,B的contextRoot设为/XXX,这样二者的servletContext为同一个,即可实现A把自己的loginToken放到servletContext中后由B访问到,从而在请求B页面时,检查是否能取到servletContext中的loginToken,如果不能则转向到A的登陆页面,这点由Filter来实现。

事关挪卡(Moving Story)

最近我的team频繁遇到关于挪卡与否的事情。

可能会包括下面其中一种情况:

  1. 一个Story在前一个迭代做完了,但是客户没有及时sign-off,导致后一迭代中客户发现Sotry实现有问题,不是自己想要的东西,需要重新实现。
  2. 一个Story在前一个迭代做完了,客户已经sign-off,但在后一迭代中我们发现实现中设计有问题,会引发其他的bug。
  3. 一个Story在迭代中实现完毕,进入In QA,但发现有重要的AC没有事先提出来,导致需要补充实现。

可能还会包括其他可能的情况,不一一列举了。

我们team的对策分别是:

  1. 新开一个Story卡,对有问题的部分重新实现。这里的问题在于没有及时从客户那里取得反馈,原因自然有多种,你懂的。
  2. 新开Defect卡,对发现的问题进行修复。
  3. 直接在当前迭代中,把Story卡挪回In Dev,补充实现。但不会修改点数。

Pair的节奏

这篇只想说说我对Pair节奏的理解。

Pair是需要节奏的,为什么?最简单的回答是,没有节奏,两个人都会很累。我有体会,跟team另一个新TWer一起pair,两个人会不由自主地坐在屏幕前,切分任务,你写测试我写实现,一动不动坐了整个下午,除了上厕所的时间。可想而知,离开办公室的时候那个疲惫。

不是说Pair就会比一个人“裸奔”轻松,恰恰相反,Pair就会比较累,这是无数人经验证明的。但是我们仍然需要在Pair时控制一定的节奏,不仅仅是为了减轻疲劳。

最直觉的反应是,疲劳会影响对问题的考虑,测试的覆盖度,代码的质量,这在一对Pair都疲劳的状态下,也不能免俗。当疲劳把Pair能带来的那些个好处统统赶跑后,Pair还有何存在的意义?

一般来说,对Pair经验比较少的人,节奏可以由Pair经验多的人来控制,如何划分任务,粒度以及驱动测试开发的频度如何,都可以依据Pair的双方的能力和经验对比进行安排。在划分任务和思考时,可以以提问的形式,互相提问回答,推动进度。实现代码时,可以以乒乓的形式,由一方来编写测试,另一方编写实现,并跨任务轮换,让双方都感觉到Story的实现在有条不紊地前进,充满自信。双方可以约定在一个小时左右的时间,进行一次短暂的休息,切换context,以确保有持续的精力投入后续的Pair。

因为Pair是两个人的事情,当一方因为某种原因感觉到疲劳,或者被第三方事情打扰,不能集中精力在pair中时,可以主动跟对方提出中断,以换取集中的注意力在Pair上。

如果Pair对于某个问题或技术都不熟悉,并且在可遇见的时间内无法解决,应该立即寻求有经验同事的帮助,或者暂时放下留待后期解决,坚持钻牛角尖无疑是破快Pair节奏的杀手之一。就我的经验看,Pair时钻牛角尖的几率很小,在一方出现端倪时,对方会明显感觉到并主动提出来跳出这个圈子,这应该时Pair时一个小小的好处吧。

至于可能破坏Pair节奏的另外一个杀手——两人就问题或技术有争执,一般会发上在没有较多Pair经验的人身上,这会是另外一个话题,涉及到Simple Design,徐叉教导我们,要用代码证明自己的观点,要反过来关注问题本身。

Pair时的心态

为什么我们需要pair programming,以及pair有什么好处,不是这篇文章要说的内容,关于这些方面,网上能找到的太多太多。这篇只是想说说对于pair中心态的问题,我在pair时的体会。

对于有过开发经验的人来说,离开几年来一直专属自己的那个格子间,坐到一张开放会议桌边写代码,旁边还坐着自己的pair,度过半天甚至一天的开发旅程,并不见得都是一帆风顺的过程。

每个人有自己的开发经验、背景和知识,成为pair就要为Story的代码质量负责。怎样合力以解决问题产生代码,是需要彼此Open心态,针对问题解决问题,而不是:

  1. 妄自尊大,容纳不下对方的观点
  2. 对对方不闻不问自顾自操作机器
  3. 炫耀自己的知识面而鄙视对方
  4. 甚至出言不逊,伤了对方还浑然不知

这是一个成长的过程,也是一个自我剖析让自己更open的过程。所以我们一般会安排由具有丰富pair经验的老同事带着新同事一块来pair,还会有乒乓和keyboard-mouse方式来控制pair的节奏。在知识传递的同时,逐渐打开每个人闭锁自我的心态,逐步提高pair的效率从而提高team的velocity。

从小处看,这是个人心态改变的过程,从大处看,这是开发文化不同导致的诉求。

Automation Training For TW QA

今天作为酱油党之一(徐X语,还有小刀和LeoShi同行)参加了徐X为TW QA开的Automation Training。

对于Ruby小白的我,跟着QA一起学了一把。

  • Ruby的包机制,应用的配置环境
  • Selenium RC的原理,包的四个变种。
  • 在07年就提到过的Page Object

自动化测试具备怎样的特质,才能最大限度的减少QA手工测试的工作量?

  1. Effective
  2. QA manageable

最后,徐X介绍了几个月前他研究出的Data Flow大法。简言之,测试不是要去测试事情本身,而是要测试事情结果的确发生。听着象废话,但那张精美手绘图却惊艳得不行。用以作为切分并归纳测试案例的依据。很受用,争取撺掇一篇文章出来。

OO训练营第二三课

这两节课徐X给出的问题是,用代码表达在停车场停车的模型和逻辑。

首先,还是任务分解。分解出任务列表的样子,取决于对程序架构的理解。理解不同,导致划分出来的任务列表也不一致。但要保证每个任务能够衍生出1-2条可以测试的子任务,变成代码。对于测试任务的设计,既可以从状态变化上来考虑,也可以从行为上来考虑。而且,由分解出来的任务列表,可以反推出需求是什么。

课上有一对pair最后没有完成测试及实现代码,原因在于双方对各自的实现方案争执不下,被徐X拿来教导我们:在这种情况下,要放下争执,去还原真实的业务场景和需求是什么,来解决实际的问题。

总会有分别都是正确观点的双方在争执,就像民主之于正义。这个时候我们要evidence over opinion,通过代码来表达自己的观点。

最后,徐X再度施展重构神技。

OO训练营第一课

今天下班前,开始第三届OO训练营的第一课。

本来觉得应该没什么,结果课堂上大家窘态尽出,会写代码不代表面向对象代码写的好,事先不写测试,直接上实现,情何以堪呐。

一些重点:

  • 代码是写给人看的,不是给机器的。代码是用来表达和传递知识的。
  • 对于可度量的对象,有几个属性(比如相等性和可描述性),可以作为分解任务的依据,并据此编写测试。比如长度(Lenght)的Equality,如何判定是同一个长度对象,如何比较不同的长度对象。
  • 测试优先开发,划分出可测的任务是关键,即所谓Testability Driven Tasking。
  • 模块化最重要的是封装实现的细节,对类细节的访问要封装在类上下文中,这是最最容易忽视的bad smell。

TWI is Over

Today, we finished 3-day TWI(ThoughtWorks Immension) in ThoughtWorks China, which is also the sixth TWI here.

4 people from Xi’an office also came with us, and we spent a good time together. I have now a deep impression on the company culture, Agile Methodology, and a more closer observation on the story things and xp practices. All of what we saw and heard differentiate a lot from what we did before in a more traditional way. This introduced too much dicussion and questions, which even blocked the progress of courses.

Good to see this happened, when TW China grows up and attract more and more experienced people, it has to embrace and absorb those who are willing to join after survived from bad software engineering career, with its own special culture. I believe these people are here not wishing to get satisfying salary or anything, but to see how and why software engineering works here and people are happy at the same time.

I am shocked totally when teacher told ThoughtWorks company is actually a social experiment by Roy Singham, founder of company. I believe I will be shocked time and time when I understand more about company.

I am very pleasure to be the witness for this experiment is ongoing, and hopefully it will be successful.