2008年11月16日星期日

讲演培训中学到的

自信,从来都是说时有,用时无的。很少有人在开始讲演的时候就信心满满。大多数的情况下,讲演者都是从听众的反馈中不断积累信心的。这些反馈包括了卖关子时看见的期待眼神,听众赞同的点头,适时的提问等等。 有几个简单的实践可以帮讲演者源源不断的从观众中汲取信心。

* 合理的站姿,身体的姿态会在潜意识里影响观众对于演讲的印象,一个僵硬的站姿,会让人觉得压抑,抖腿,双手交叉等都是内心觉得不安全,想逃跑的表现。轻松站姿两年前就有人教过我,可惜境界一直没到,没领悟。 教我的人是我太极拳的师傅,老师说要“中正,安舒,沿路缠绵,静运无慌,肌肤骨节处处开张”,用在讲演中也是没错。

* 声音,洪亮的声音大概是抓观众注意力最简单的方法了,任谁也没法忽略台上站着的大喇叭。

* 适当的停顿,头至尾一直以相同的速度来进行,听众会被催眠的,譬如说我当年的政治老师就是此中高手。

* 目光接触,没有目光接触的观众会觉得被冷落,自然没兴致听下去。你也甭想得到任何正面的反馈。 如果台下都是dark look,就找几个脾气好的人目光接触吧。

* 诚实,其实是给自己减压的法门,讲演的时出错很正常,承认了,然后用备用方案就好了,没人会在意。越想掩盖,越多人会注意到。到时候大家就完全抱着看你出糗的态度了。当然如果你没准备备用方案,就不是诚实不诚实的事儿了,而是个大傻瓜。

2008年11月12日星期三

不同的思考方法

前几天产品发布,项目经理“Jez.谦虚” 同志要求我们审查一下2.0版本中有没有添加不能用于商业目的类库。因为类库很多,并且有很多的更新,删除,添加操作,很难一下找出到底在新版本中添加了那些文件。

于是我和哈达写了这样一个shell:

hg log -r 4281:tip --template '{node}\n' localivy |xargs -I % hg glog -p -r % | grep -A 1 '.*diff.*jar' | grep -B 1 'new file mode' > ~/Desktop/newlyAddedJars.diff

哈达和我都很欣赏使用shell来解决问题的方式, 所以写这段代码的时候,先想到了利用管道,以及grep过滤出所有在上次发布后和最新版本间添加的所有jar文件并把它们输出到文件中。

同时克里斯也在解决这个问题, 他把代码首先更新到上一个发布版本,然后利用meld将两个版本的ivy文件比较,人肉分析添加了哪些文件。 这个方案很简单,速度也很快。克里斯关注点在快速解决问题上,而不是“自动化的解决问题”


同组的李教授看到我们这么热闹,也饶有兴趣参与进来,他最近一直在研读mercurial宝典,对各种tip烂熟于心,他看到我们的解决方案后,写了另一段shell

hg log -r v1.0:tip --template '{file_adds} is added at revision {node}\n' localivy

这段shell充分利用了mercurial在template中定义的关键字做到了简单而强大,它可以打印出所有从上一个发布版本到最新版本间添加的文件以及相应的版本号。

解决这个问题的过程让我觉得很有兴趣, 同一个问题,由于解决者所关注的点以及知识域的不同出现了千差万别的解决方案。这些方案间的成本和收益也有着巨大的差别。

在日常工作中,我们都希望“简单而强大”的解决方案,单凭自身不断的宽展知识面是不够的,因为我们面临的问题多种多样,个人精力有限,个人的兴趣也限制了对于某些问题的深入研究,敏捷方法中的结对编程是一个很好地解决方案,更多拥有不同知识领域的人可以来共同解决一个问题,增加了我们找到“简单而强大”解决方案的几率,而开放空间可以让更多的人有机会参与到讨论中,贡献他们的聪明才智。爱凑热闹的李教授就是一例

2008年11月3日星期一

在Junit测试中使用 “前提”

在Cruise团队,QA经常会提交这样的bug, "某某功能在Windows上不工作 ",当然我并没有歧视Windows的意思,Windows在这句话里可以被替换为OSX, LINUX,乌龟SVN, Collable SVN,等等。在这样的团队中,面临着更多的不同平台(不仅仅是操作系统,还有不同发行版)带来的挑战。即便是Java这样号称“一次编写,随处运行”的语言,也必须常常去处理不同平台之间的些许差异。

作为一个TDDer,我们修复上述的bug的步骤是:

* 找到一台Windows机器
* 对上述Bug编写测试
* 运行测试得到“Red bar”
* 修改产品代码
* 运行测试得到"Green bar"


但是这样一个好的测试,却很可能无法提交,因为这特定平台的补丁可能会让别的测试失败。

这时候的无奈之选就是

@Test
public void featureShouldWorkOnWindows {
if (OSUtil.isWindows()) {
//Run the test.
}
}


这样,我们修复了bug,也编写了可靠的测试,除了测试代码有一点ugly. 这样的代码多了 ,也终究是一件恼火的事情。

前几天,写了一个对Junit的扩展,对于上面的测试,
可以这样来写
@RunWith(PrerequisiteAwareClassRunner.class)
public class TestCasesOnDifferentOS {
@Test
@Prerequisite(checker = OSChecker.class, arguments = OSChecker.LINUX)
public void shouldPassOnLinuxPlatform() throws Exception {
}
}

在这里,引入了前提条件@Prerequisite, 只有当前提满足的时候才会运行测试。

在项目里一个真实的例子是我们使用了ab(apache出品的性能测试工具,可以通过命令行调用)来进行性能测试,但并非所有的平台都能方便的安装ab。并且这个测试也无需在所有的平台上运行,通过使用前提,可以写下测试:
@RunWith(PrerequisiteAwareClassRunner.class)
public class TestCasesOnDifferentOS {
@Test
@Prerequisite(checker = AppsInstalledChecker.class, arguments = "ab -V")
public void shouldRunPerfWhenABIsInstalled() throws Exception {
}
}

在这里AppsInstalledChecker通过运行“ab -V”,并利用返回值判断是否当前平台上安装了ab,从而相应的运行或者忽略测试。


@Prerequisite中的Checker是一个接口
package com.googlecode.junit.ext;

public interface Checker {
boolean satisfy();
}
任何人都可以通过继承这个接口在扩展出适合应用场景的Checker。

@Prerequisite不是用于解决产品代码中的平台问题,作为junit的扩展,可以使用它让测试代码更干净,可读。

如果有兴趣,可以访问 http://code.google.com/p/junit-ext/来尝试一下。

Feedback或者Feature Request请发到:

iamkaihu@gmail.com
zee.ho.81@gmail.com