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. 对于算法代码的实现,简单粗糙,还需要重构。
Share
 

2011 ThoughtWorks烽火传奇

Chapter1

树林外传来密集的枪声,由远及近,渐渐清晰。 山顶树丛后,迷彩的掩护下,几道焦急的目光投向了中心处的一位彪形大汉。

张凯峰队长抬手擦了擦额头上混在一起的血和汗,心中暗暗叹了口气,从枪声判断,敌人距离这里已经不远,这也就意味着一队高队长和二队月队长的防线已经溃败。时间已经不多,是时候来做最后的诀别了。

队长慢慢的抬头,沙哑的声音从干裂的嘴唇中缓缓吐出:“同志们,我想大家都明白,防线已被攻破,我们此次的失败已在所难免。”

说到这里,队长艰难的停下来,重重的喘息,仿佛“失败”二字就已经给了他巨大的负担。

身边的战士有人紧咬着嘴唇,有人摘下军帽,死死地攥在手里。

张队长用目光在所有人的身上环视一圈,然后继续开口:“很不甘心,是么?我也一样啊!一想到圣教的火焰或许会在此处熄灭,我的心就像被剖开一般疼痛。试问,还有什么,能比失去光明的指引更加痛苦!!!”

这样沉重的话语带给人们的是更深刻的悲痛,几个女孩子已经把持不住,相拥在一起低声的啜泣。

“但 是,我们的使命还未完结,如果死亡是我们注定的终结,我愿让这终结如烟花般绚烂,将我们不屈的斗志传达,哪怕只有一瞬间,也要照亮这黑暗的世间!!!同志 们冲啊!!!!!”张队长站起身来,大手一挥,从树丛中一跃而出,向着外漫山遍野的蓝色敌军冲去:“我愿将此身化为碉堡,在死后仍能为同志们挡去敌人的子 弹!日月神教!千秋永存!!!”

“啊啊啊!冲啊!!!”紧跟着张队长,付莹参谋也迎向了敌军。

“铁甲依然在~ ”江荣冲出去了。

“我们的敌人必将被消灭! ” 李斌冲出去了。

“女性!荣耀!梦想!”四眼冲出去了。

“啊啊啊啊啊啊~~~~~~”张桐也冲去了。

一点一点绿色的身影冲向了蓝色的防线,就像明亮的火焰冲进蔚蓝的大海。

这就是惊天动地的首次2011新员工真人CS第一战,史称红螺寺山体攻防战中,最为悲壮的一刻!天地为之变色,草木为之含悲,日月神教永垂不朽,荣光与我们同在!!!

 

Chapter2

天堂里,一群绿衣服的家伙蹲在地上,在角落里围成一个圈。中间还是我们熟悉的张队,正不耐烦的捻灭一只烟:“别吵别吵~ 死都死了,还不冷静。我们现在不是要推卸责任,而是要吸取经验,总结教训,从根部开始,源头开始,上起祖宗十八代,下数华夏五千年,深刻挖掘这次战争失败原因!怎么着我们就输了呢?!”

“老 大,我先说!”二队的月队长率先起身,“我们的敌军既优秀又强大,有三成以上以前就参加过各种战役,有着丰富的经验,是我们所不能比拟的。而且此次战役 中,敌军又启用了先进的生化武器,将徐晨,侯斌轶改造为僵尸战士作战,无法杀死。从而轻而易举,气势如虹的击溃了我们的防线。老大您明鉴,不是兄弟们不努 力,实在是敌军太狡猾啊!”

“去 去去,你这是给敌人开表彰大会呢吧!”张队长哄蚊子似的摆了摆手,“什么敌军太狡猾,分明就是我军太失水准。就说小月月你身为二队的队长,为了拉风非要穿 一件桔黄色的衣服,在绿色的树林里走到哪里都是活动靶,开场没三分钟就挂掉了,严重影响了我军的正常战略节奏,是导致最后失败的罪魁祸首。”

“所以说不怕神一样的对手,就怕猪一样的队友。”角落里,平素最爱吐槽的四眼儿政委接着张老大的话茬,持续进行毒舌攻击。

“你也好不到哪儿去!”张老大没好气的开始数落小政委,“在背后开冷枪误伤一个顶仨,真正面对敌人了,子弹射程还没有唾沫星子喷的一半儿远。一场下来三条命全送出去了,可一枪都没打到敌人!”

听到老大点名自己,四眼哭丧着脸站起来:“老大,我我我,我错了。同为政委,蓝军的Magen那是战神加护雅典娜附体,上场先杀死4人。我是刚刚亮相就被人乱枪打死。我愧对祖国愧对党。为表羞愧之心我决定以死谢罪,大家你们都不要拦我啊啊啊~”

说罢,四眼儿政委不知从哪里变出一根半指来宽的麻绳,笨手笨脚地在身旁的歪脖树上打了个圈,抻着脖子想把那颗大脑袋套进去,作势要去见马克思。

“算了算了,又不是盗梦空间,你当能在死亡状态下再死二回啊。”张队长最不待见这种苦情戏,赶紧招呼旁边的娴静军长把四眼儿拦了下来。

几个人七首八脚的把四眼弄下来,这才发现不知什么时候起,四眼儿已经进入了发呆状态。张队长心说不好,该不会是刚才批评的太狠了给小孩儿整自闭了吧。

众人正琢磨着要不要弄个电击疗法刺激刺激四眼儿政委的时候,这边四眼突然大叫一声:“我知道了!”然后从地上一跃而起,跑到张队长面前,一把拉起张队的手:“队长,我知道了!我可以先复活,这样就可以继续死了。”

“额?你是说我们可以复活?”张队长问道。

“是啊是啊,队长你没听过信春哥死后原地满血满状态复活的!!”小政委乐颠颠的说。

“哇呀呀呀呀~ 有这等好事,那还等什么?!”张队长一把抄起地上的抢,举起高呼,“小的们,跟着我,复活继续跟他们拼一场啊!!!!!!”

 

Chapter3

“怎么又死了呢!!”张队长的咆哮惊走了山林上飞禽走兽,“你们不是自称攻无不克战无不胜全灭敌军胜利手到擒来的无敌日月神教么!!!!!!怎么水平一个一个的比我还菜呢?身为军人却大脑壳小细脖还全带着眼镜!我要去军事法庭投诉征兵水平!”

“队长息怒,”旁边的杨锐狗腿的凑了上来,“虽然我们的战斗力可能有一点点的不够合格,但是我们这次从教官那偷来了秘密武器,你看~”说罢,神秘兮兮的从背包里掏出一个黑色物体。

“咦?复活遥控器!” 九强凑了上来,一看是好东西,两眼放光的在杨锐肩上拍了一下。

“老大,据说只要我们队里还有一个人活着,就能用这个遥控器无限次复活队友。” 胡悦也凑过来,献宝似的说道。

“哇哈哈哈,这次我们就无敌了!”终于得到了终极武器的张队长双手叉腰,仰天大笑。

“队队队长~~不好了!!”那边还没笑完,这边四眼就上气不接下气的冲了进来,“队长!龙珠队杀回来鞭尸了!”

话音未落,只见蓝队的先锋史磊和文迪踢开房门冲了进来,紧接着龙珠队长唱鑫一袭蓝衣飘然而至,后边跟着小虫、庆法、王健、王彪、徐晨、魏广程等众人。

但见狙击手肖然抬手一梭子弹打在唯一还生还的张队长身上。只听“啊~”的一声惨叫后,绿队里最后一个幸存者也被记入了死亡名单。

“我死不瞑目哇~~~~”张队长的怒吼声,伴随着落日的余辉,缓缓沉入地平线下。

Share
 

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还剩一个半迭代时,强烈提出的。这个问题似乎从项目开始时可以预期,甚至中途客户也是偶尔提及,但我们似乎没有足够重视。我更认为这是业务理解和管理客户期望的问题。我还没有更好的想法,期待跟团队一起回顾。
Share
 

ThoughtWorks有什么不同?

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

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

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

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

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

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

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

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

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

Share
 

Experience Design初体验

打酱油的结果,就是有机会两次经历ThoughtWorks的Experience Design。一次是针对Climate Action的Social Impact Project,一次是Beijing Design Night。

在过程中,我领略到了跟之前的经验和了解完全不同的设计体验:如何拨开层层需求迷雾,抛弃虚妄的需求,找到潜在系统用户的真正痛点,实现和改进系统的功能,提升用户的内在体验。

我们会首先设计出目标系统的使用者——Persona,一个虚拟的用户,但有明确的生活和职业背景。

然后是依据这个Persona设计他/她的Empathy Map和User Journey。会根据模拟和假设Persona的所听所见所闻所想来发现Persona对系统的(甚至是潜在的)期望,模拟一个尽量真实的故事历程来找出Persona的痛点,从而找到可以实现和改进的地方。这个设计过程是整个团队和客户共同参与,进行头脑风暴的过程,合作的过程可以避免对Persona的误解以及以偏概全。

最后会用笔和纸快速地在纸上画出Sketching,也就是UI的原型,充分体现出设计过程产生的系统改进并解决痛点。

Experience Design会是ThoughtWorks未来很重要的一个Offering。

扩展阅读在这里

Share
 

ThoughtWorks需要怎样的人?

想知道如何才能做好软件的人
想学习最新前沿技术并应用在项目中的人
想在项目中自己做主承担责任的人
想跟大牛成为同事一起工作的人

厌恶大公司繁文缛节的人
厌恶低效无谓加班的人
厌恶没有进步空间的人
厌恶盛气凌人的老板的人

想用上最新版MacBook Pro甚至Air的人
想每天吃到新鲜水果喝可乐的人
想每天可以打PS3和街机的人
想每天都有session听的人

不想把薪水放在第一位的人
不一心追求升职的人
不沽名钓誉的人
不畏惧变化的人

Share
 

DevOps之Puppet

Puppet在一款自动化系统配置管理的工具,它可以让你在很短的时间内对大量硬件和系统基本类似的系统,进行统一的系统配置管理。

说的简单点,就像开网吧,你需要对网吧的每一台机器安装操作系统,配置完全一样的软件,比如QQ和360,供网友上网,在系统和软件有损坏时,很简单的一个恢复操作就可以让机器回到刚刚安装好操作系统和软件的状态。

Puppet就是可以干这个事儿的,不同在于,Puppet是给网络管理员用的,而针对的系统多是*nix系统,因为Puppet目前对Windows支持的很少,但这不妨碍Puppet成为DevOps实现过程中的利器,另外一个类似的工具是Chef

Puppet本身基于Ruby实现,但即使没有Ruby的经验也没甚大碍。Puppet自己提出了所谓Puppet Language,是一种DSL(Domain Specific Language)语言,用直白而描述性的语言,定义系统应该具有的状态,比如一个简单的例子tmpfile.pp:

file { 'testfile':  
    path => '/tmp/testfile',
    ensure  => present,
    mode    => 0640,
    content => "I'm a test file.",    
}

在安装了Puppet了机器上运行:

puppet apply tmpfile.pp

结果就会在/tmp下新增加一个testfile,内容是This is a test file。
这个例子太简单。除了file这种类型外,Puppet提供了大量的资源类型,供对系统的状态进行描述,比如打开(如果不存在会自动下载)某项服务,自动增加一个用户。当管理的机器成百上千,这样的自动化服务达到的效果就很可观了。

puppet apply是Puppet在单机上运行和测试的工具,真实的使用情景会是,一台机器(master)专门保留所有机器配置管理的状态信息,而每台机器(agent)会在指定的时间向master发起查询,从而更新自己的系统状态,以期与指定状态保持一致。

 

 

Share