-
Yesterday, I watched a movie name Wanted. It is about a killer's story with some fantastic actions. This is the introduction of the movie which published on Youku(one duplication of Youtube in China).
The story is kind of old, but one thing interested me. The whole story is telling the man wanna figure out who he is and who he wanna be. This is similar with one story put on www.kaixin001.com by one of my friends who is a ThoughtWorker, too. That story is telling about one business man tried to change one fisher's life. Both of the stories ask me one question:"Who are you? Who you wanna be?"
I think I'm lucky, I have my plan, and I exactly know what I wanna be. But some people can't, especially those young people(sorry, I'm young, too) , they just lost their destination. Their lives are not what they want, they work because they need to. This maybe not only happenning in China, also in other countries
If you are not happy, and you don't know why you should live in this way, So you may find what you wanna be. Ask yourself, nobody can answer instead of you. But only one thing more, don't lose your confidence
everyday is a new day close to your dream
OK, too much philosophy. That's not my style, to be honest
-
ThoughtWorks University 取经记 - [心情/记事]
2008-08-09
This is another article written by me published on the local IT magzine Programmers. Sorry my freinds in other countries, it is written in Chinese. It is about our stories in TWU. To be honesy(yeah, again and again), I miss you guys.
这篇文章可能与程序员上的略有不同,因为后来L MM 帮我改得更好了,不过这是我的Blog 所以贴出来的自然是原文
四月份我加入了ThoughtWorks公司,由于是应届毕业生的缘故,紧接着就被派到印度班加罗尔分公司进行了六周的公司培训。六周的生活是紧张、繁忙而 又非常开心的,不但与敏捷开发方法进行了亲密接触也结识了许多聪明、勤奋富有激情的外国同事。在这六周的生活中,前两周主要是进行公司文化和敏捷开发思想 的培训,后三周就主要进行技能的培训,最后一周是给所有培训的ThoughtWorker一个项目,来评估整体培训的结果。培训这些内容的主要目的是让新 员工尽快的融入到公司文化中,成为公司的一份子;还有就是理解敏捷软件开发的原理并亲身体验真正的敏捷软件开发方法,从而体会到这种开发方式的种种好处; 最后的一个目的当然就是增强新员工的技术水平。本文会分为两部分,第一部分介绍ThoughtWorks对公司文化和敏捷开发思想的培训,第二部分介绍 ThoughtWorks针对具体的团队开发技能是如何进行培训的,全文中会穿插一些真实有趣的小故事以及我对相应培训的一些感想。ThoughtWorks University 取经记
公司文化的传承
对ThoughtWorks有所了解的人都知道,公司的文化都是围绕人与人之间的平等、尊重和加强沟通这几个方面的。作为一个新员工,给你带来的最大感受就是公司自由平等的氛围和人与人之间和谐友好的关系。
这些平等、自由的思想当然会渗透在培训课程的点点滴滴之中。第一天的课程中,我们就做了很多的游戏,其中有两个很有趣的游戏,第一个游戏是老师们给每个人发 了一份表格,上面写了二十多条内容,每一条内容会对应一位老师或学员,例如会有这样的内容“有一个人拥有iPhone”,“有一个人的体重小于50公斤 ”,或者“有一个人要坐超过二十小时的飞机才能来到班加罗尔”等等,这些问题每一个都是特别设计的,而你的任务就是要在五分钟之内将所有的内容与人对号入 座。游戏开始的时候,大家跑得跑,叫得叫,笑得笑,整个大厅沸腾了,好不热闹,最终有一两个学员将所有人对号入座,然后大家就集体将所有匹配的结果大声朗 读了出来。其实到底谁赢了游戏,并不重要,真正重要的是在这个过程中,大家增进了了解,进行了有效地沟通,如果你都不了解你的团队,那如何进行软件开发 呢?从这一个简单的游戏,我们所有学员和老师,就从陌生人向朋友迈进了一大步。第二个游戏叫做“人人都会犯错误”,传达的人人平等的理念更加强烈一些。游 戏规则类似于中国饭桌上经常玩的报数字(遇到含七的数字和七的倍数要说Pass),只不过我们加了一条,就是在你犯了错误后,要大声地说“YES”,同时 手脚并用的摆一个姿势,然后站到圈的末尾。结果在游戏的过程中一位印度裔的老师Reshema经常出错,长相可爱的老师Reshema再加上大声吼叫的 YES以及怪异的手脚并用姿势,把所有人逗的前俯后仰。这个游戏使我们明白了,犯错误是很正常的事情,你没有理由去责怪别人,ThoughtWorks也 是允许你犯错误的,关键是犯了错误你从中能学到什么,以及帮助别人怎么从错误中进步。
其实公司的第一堂课根本与敏捷软件开发和技术无关,可能大家根本无发猜出是讲什么的,连所有的学员都很惊讶公司培训的第一堂课,竟然是告诉我们什么是公司认为 的歧视和不平等,在这一堂课中,老师会提出一些问题来让学员投票,让我们分辨什么是歧视和不平等,然后再给出公司的答案,如果大家有疑问可以充分的表达自 己的意见,然后再投票。从这第一堂课的内容就可以看到ThoughtWorks是何等的重视人与人之间的平等和尊重了。注重人与人的沟通也体现在公司文化 的各个方面,最简单的一个例子就是宿舍的安排,我本想着可能是不同分公司的员工会住在一起,没想到刚下飞机就得知自己会和一个澳大利亚的同事还有一个印度 的同事住在一间公寓里,这对于英语不是母语的中国人来说,也真的是捏了一把汗。但是仔细想想,这样的住宿方式,不但会加强不同学员之间的交流,而且可以更 好的了解不同区域的文化,了解你将来可能一起工作的同事,了解他们的想法和行为方式,这样才可能达到真正的尊重和平等。
了解ThoughtWorks的人可能都知道,平等和尊重在公司的极致体现不能不说是那些公司的领导层了,每一期学员培训,Roy(不要说你不知道Roy是 谁啊)都会单独做一次演讲,其中的主要内容包括创建ThoughtWorks的原因和历史,公司经历过哪些困难以及他本人的一些传奇经历。Roy的演讲是 很有趣的,不过学员们提的问题更加有趣,我和我的舍友就提了一个“假如你被绑架了,你会怎么办?”的离奇问题。结果Roy的回答让人瞠目“其实我是被绑架 过的!”然后他就娓娓道来那一次班加罗尔分公司的ThoughtWorker是如何乔装成绑匪,然后在飞机场对Roy实行了一次“绑架”,之后Roy又爆 料出许多被ThoughtWorkers戏弄的故事。从这些Roy的小故事中,你可以发现公司的头头脑脑们,喜欢和员工打成一片,有的时候他们会上来拍你 的肩膀然后叫你的新外号,有的时候他们会跟你谈论他们最近的尴尬经历,甚至吃饭的时候他们也会被员工灌醉。可见平等和尊重的理念已经深深的植入 ThoughtWorks的文化精神之中。
ThoughtWorks公司的平等和尊重还体现在公司的管理很透明,甚至包括财务收益、开销等信息都会公开的呈现在新员工的面前。印象中关于管 理很透明有两个小故事很深刻,其中之一就是第一周一门课程的内容就是将公司这几年的收益和开销完完整整的展现在所有员工的面前,包括总共有多少收入,总共 有多少支出,这些支出用在培训、新建分公司、股东收益等等方面的具体支出数目,并且在课程的最后每个学员还要扮演公司财务部门的角色,模拟体验一下公司财 务部门是如何进行资金运转和保证现金流的。第二个故事就是Roy在他的演讲中提起了2001-2003年公司曾经裁员的事情,原因就是当时IT产业大萧 条,公司处于窘境,Roy说那时是他最为困难的时期,直到现在都很内疚,仔细想想在绝大多数的公司中,这些内幕消息哪是一个刚进公司还不到十天的人可以接 触到的,但是ThoughtWorks确毫无保留的给我们展现在眼前。其实管理的透明在回国后,也时时刻刻都可以体验到,ThoughtWorks 北京分公司每月都会做一次月报,让全公司的同事都知道这个月我们分公司的经营状况。对于我们这些新员工,在短期内就对公司的各种状况有了一个整体的了解, 从而很快的建立起了一种强烈的主人翁精神。
敏捷软件开发思想的传承
对于前两周敏捷开发思想的培训是非常有趣的,几乎每节课都有互动的过程,每节课都会有生动的实例让你体验到什么是真正的敏捷软件开发,为什么要使用敏捷软件开发。
在介绍整体培训的过程之前,首先介绍一下ThoughtWorks敏捷软件开发团队的构成。一般一个开发团队主要有以下几种角色:PM,Project Manager项目经理;BA,Business Analyst业务分析员;DEV,Developer 开发人员;QA,Quality Analyst测试人员。PM对项目进行全局掌控(有的时候,还会有IM,Iteration Manager对具体的迭代开发进行掌控);BA,主要与客户进行沟通和业务分析,与开发人员进行交流,与测试人员对整体功能进行讨论等等;DEV,主要 就是开发应用程序,但同时也要协助业务分析员和测试人员进行工作;QA,主要对开发人员开发出的系统,进行全方位的测试,包括功能测试、性能测试等等。对 于团队整体的开发流程,是一个有序、小步、渐进的过程。ThoughtWorks对敏捷软件开发思想的培训也主要针对如何了解用户需求,团队共享代码,迭 代开发,总结与回顾。
在软件开发的过程中,能够准确的理解用户的需求,将用户的需求转变为开 发团队理解的用例,是一件紧迫而重要的事情。但是,如何才算好的理解用户的需求呢?如何能让我们这些从没与客户打过交道的毕业生尽快的学会与客户沟通的方 法呢?这就是我个人非常喜欢ThoughtWorks University的一个方面,在敏捷软件开发的所有课程,包括对需求理解的课程,设计的非常精妙,不但能够让这些观念深深地扎根人心,而且能让你体会 到真正的软件开发其实就是应当这样做得。我们上过一堂用橡皮泥做电话的课程,老师们把大家分成许多小组,每个小组由3-4个学员和一位扮演客户的老师组 成,老师们扮演的客户是非常的苛刻的,我们的任务就是要做出让客户满意的电话来,每一次开发的过程只有十五分中,分三次开发完成一部完整的电话。在整个开 发的流程中,我们体会到客户的需求是随时改变的,当他们看到了原型系统,甚至可能推翻之前的所有需求,这时候作为一个开发人员或者业务分析人员,在你了解 客户的需求过程中,不但要求你具有能够充分理解客户需求的技巧,更需要你能启发客户思考一些它们没有想到的方面,从而少走一些弯路。在制造电话的过程中, 我们几个小组在第一个开发周期的行动,几乎都是闷头造电话,完全忘记了我们有一位客户坐在我们的桌字旁,当我们有疑问的时候,为什么不去直接找客户进行沟 通呢?老师向我们提出了这样的问题后,我们在后面两次的迭代中,和客户进行了频繁的沟通,最终做出了让客户满意的电话系统。下图就是我们做出的橡皮泥电话 系统之一,你看Reshema老师拿着电话,多么高兴。
在有些人的眼中,ThoughtWorks是一群拿着卡片到处贴,到处走的奇怪人群组成的软件咨询公司。其实为什么使用卡片作为理解用户需求的主要机载体, 在我去TWU之前也很疑惑。后来,在一堂介绍如何使用卡片理解需求的课程中,终于了解到原来其中包含了这么多奥妙。首先卡片很小,这就迫使业务分析员不能 将太多的内容放在同一张卡中,由于一个迭代周期通常是两到三周,需要给用户展示一些能用的系统功能出来,这样就会引起整个团队思考许多有价值的问题,什么 是最紧要的?什么是系统的核心?我们要用多长时间来完成这些卡片上的内容?第一个迭代周期能完成多少卡片?我们的团队开发速度是多少?等等。其次,卡片在 卡片墙上是可移动的,因此它很灵活,就如下图所示,可以将卡片放置在不同的队列中,通常我们用“在分析中”、“在开发中”、“在测试中”、“结束”等一些 状态表示卡片所处的不同状态。这样,当所有团对人员,需要了解当前项目的进度状况时,只要站到卡片墙前,就可以一目了然,如果处理不同卡片的小组需要彼此 沟通,在卡片墙上,可以用最快的速度找到相应的人员,甚至,当你有疑惑的时候,卡片可以拿下来仔细研究,只要记得最后放回去就好。卡片的最后一个优点就是 对当前项目进行评估,举一个简单的例子,当一个团队的开发状态是绝大多数的卡片都集中在“在开发”的队列中,就表示当前开发团队处于业务分析员和测试人员 无事可干,但是开发人员又过于繁忙的不健康状态。什么原因导致的呢?可能是开发速度过慢或者是业务分析员写的卡片粒度过大,导致开发人员无法及时的完成。 由此,当我们站到一个团队的卡片墙之前,我们看到的不仅仅是一些简单的卡片,更是整个开发团队的开发状态的展示。一张张小小的卡片却包含了如此多的内容, 这真的是我们始料不及的。当然卡片并不是完美无缺的,对分布式团队开发就是卡片墙的致命弱点,但这些问题在ThoughtWorks的Mingle软件中 都得到了很好的解决,卡片对我们来说更是一种以用户为中心,以团队沟通为中心的开发思想,而不仅仅是一种开发方法。
针 对眼前的需求,小步前进,不做过多的设计,也是敏捷软件开发的核心思想之一。ThoughtWorks University通过一个早上的摆积木课程(Lego Game)让我们充分的理解了过多设计的弊病。这次课程的整体任务是创造未来物种,类似于造电话课程,同样分为三个迭代周期,有一位老师作为客户伴随着我 们进行开发。这一次,老师们一下给了我们许多点数不同的需求,每个需求对应一张卡,每张卡上有不同的分数表示这张卡的难度,每次迭代有五分钟的讨论,需要 确定这次迭代都要完成哪些功能,有十分钟的设计,还有十五分钟的开发过程,每次迭代后大家要讨论哪些做得好,哪些做得不好的地方。第一次的迭代往往是犯错 误最多的地方,我所在的小组向客户许诺了总共加起来十分的卡片,在设计过程中又做了许多不必要的假想,过多的专注于给未来的需求留下余地,而将自己开发的 过程束缚住。最后仅仅搭起来了动物的头和身体,可是客户要求的是一个完整的动物,所以第一次迭代我们只有零分,客户非常的失望。ThoughtWorks 就是这样,通过学员的犯错误,让我们自己体会,然后通过讨论,让我们自己总结出具体的方法,老师们则是在旁边指引,这样的感受怎么能不深刻呢?经过讨论, 我们制订了自己的方针:少许诺,少设计,好好做核心模块。就这样,最后我们创造出了未来的一个物种(还有它的孩子)。
迭代的过程也是ThoughtWorks进行敏捷过程培训的一个重要方面。还是继续我们的游戏旅程吧:这一次老师让我们分成三个小组,分别从培训大厅的一端 将气球搬运到另一端,每一组有两个人负责装运,两个人负责撑袋子,一个人负责搬运,哪一组能在最短的时间内,将最多的气球从一个口袋中运到另一侧的口袋中 就算胜利,如果过程中任何气球掉在路途中,则不可拾取。第一次的规则是只能运一次,整个过程给人的感觉就是搬运的人花了很多的时间,承担了过多的责任,而 其他的四名队员起不到任何的作用,只能边喊边焦心的等待。第二次的规则几乎与第一次一样,但搬运人可以多次的运输。结果第二次,我们不但出色的运输了所有 的气球,而且还比第一次所花的时间更少。玩完游戏的讨论过程中,我们逐渐的明白了,第一次运输就好比传统的瀑布式开发,开发人员承担了许多的压力,缺少沟 通和其他人员必要的帮助,闭门造车造出来的东西,往往并不是客户心目中想要的东西;而第二次运输就好比多次迭代的开发过程,开发人员得到更多的信息回馈以 及业务分析员和测试人员的帮助,因此能够开发出更好的软件产品。就这样,我们不但理解了迭代开发的原理,更通过亲身的体验明白了这样做是行之有效的。
不得不提起的回馈信息
加 入ThoughtWorks以来,发现回馈信息是公司非常注重的一个方面。在TWU的生活中,不但学员之间两周会互相给一次书面的回馈信息,每周需要对这 一周发生的小到食物好吃与否大到老师的培训方式等都要提供回馈信息,平时课堂上即使给出的回馈信息更是数不胜数了。由于我们中国学员的母语不是英语,因此 在前两周培训的过程中,我们有的时候跟不上老师们的语速。结果在第一周五的回顾课程中,不光中国学员,还有许多我们新认识的朋友帮我们提出了这个问题,讨 论的结果就是我们不但在墙上挂起了“说慢点!”的大幅标语,还发明了一个手势用于提醒老师讲话慢点。回馈信息其实确保了大家都在尽自己最大的努力去做好每 一个方面,同时也培养出一种公正公开的气氛,让我们都朝着自己所树立的目标前进。
总结
现在想想,公司的一系列生动的培训课程,不但让我们了解公司文化的本质,更重要的是让敏捷软件开发思想深深的扎在了我们心中,我们看到了原来软件开发的过程 可以这样的丰富多彩。TWU的洗礼其实只是带我们入门,不过这些课程在我们真正进入项目后,才会逐渐发挥出一步步深远的作用,例如我现在从事的项目,就时 常让我想起TWU的课程中老师说的方方面面,再结合当前的亲身体验,可谓是获益匪浅。希望本篇的内容也能够对读者有所启迪。 -
Textmate 快捷键总结 - [技术]
2008-08-04
This blog will be my first English blog, cause my friend Matty who is living in Chicago and aslo a ThoughtWorker asked me to write some blog in English that he can read.
This blog is about my frequently used Textmate shortcuts, and I will keep adding to the list when I find something new
Since I have joined Mingle team for more than 2 months, now I can remember some shortcuts and also shortcuts can improve your development speed. But the most import benefit of using shortcuts is that when you are used to it, you can esaily keep on thinking about how to write code instead of stopping for a little while and click mouse to find the code in your IDE project. Now the below is my summary of Textmate's shortcuts for Ruby on Rails.
ctrl + shift + < : input html tags
ctrl + shift + < : input <% %>
cmd + ctrl + atl + p : preview html
ctrl + alt + cmd + v : show the recent copies
cmd + ctrl + r : show file localtion
ctrl + shift + v : show syntax error
ctrl + shift + k : delete one line
ctrl + shift + a : show context menu
ctrl + shift + f : search in project
cmd + t : find file
cmd + shift + t : find method
ctrl + shift + d : copy one lineSecond part is the most frequently used shortcuts I found, and the first part is the diffcult ones that I can't remember at first. Haha, I'm slow. Enjoy ! Hoping this can be a little helpful to you
-
接触敏捷相关的知识也快有两个年头了,但是真正体会到敏捷开发或者说真正的软件开发流程,是最近的这四个月。这四个月(精确点来说还不到四个月)是我人生的第一份工作(以前在学校勤工助学和在外面作项目不算的吧),在ThoughtWorks 度过的这几个月让我真真正正体会到软件开发的正确流程,远远不是书本所能够教给我的
记得当初在实验室,由于老师的信赖,手里同时管着几个项目,平时又喜欢拿书本上才看到的软件技术和开发方法做试验,因此在实验室是应用过敏捷的。可是效果那就真得不敢说了,第一次毫无经验的去尝试敏捷,的确吸取了不少经验教训,经过这几个月的锤炼,逐渐发现自己曾经错在哪里了。趁这篇Blog 好好总结一下经验
先说一下现在从事的项目情况:Mingle 项目是ThoughtWorks Studio 的第一个产品,历时已经超过两年了,获得广泛的好评,是很注重用户的体验和实用性的一个软件。不是我夸张,这绝对是我做得最令自己自豪的软件产品了,产品的质量控制和用户体验可以说是发挥到了极致!当然对一个新人来说,一个做了两年多的软件产品,几十万行的代码量的确是有挑战性的。Mingle 的团队是典型的分布式团队,一个团队在美国San Francisco,一个团队在北京,7 个Developer,3个Quality Analysts,2个Business Analysts 1个Project Manager 共13 个人组成。人员构成 Senior Devs 4个,Junior Dev 就我一个(汗呀),Senior BA 2 个,Senior QA 1个,Junior QA 2个,其余的都是Middle Level 的。这就引出了我的下一个敏捷重要的特点,团对人员组成,和工作方式──人的因素很重要
Mingle 团队在我看来是一个健康的敏捷团队,在上述的分析中,可见Senior人员占绝大多数,这就使得放进去少数的几个新人,在同一时间内既可以保证项目的进度,同时也可以让新人得到很多的帮助,从而让新人非常快的成长,从而尽快的对项目作出贡献。其实这也是我这两年多接触敏捷软件开发以来一直坚信的一个原则,就是敏捷软件开发对人的素质要求非长高。一个从未有敏捷软件开发经验的团队,如果自身团队构成又是新手居多,是绝对不可能获得成功的。我想这就是为什么,有的软件公司应用敏捷软件开发喜忧参半的最终原因。这里不得不提到一个敏捷的最佳实践原则,Pair Programming,我在Mingle 团队的这两个月(其实还不到)每天都会写代码,但是不是我单独写,身边总会有一个Senior Dev 跟我一起Pair,他们不但会给我介绍一些技术上的最佳开发实践,同时也会给我介绍敏捷开发的一些思想,还会给我介绍项目本身的代码结构,同时我们还能完成项目的正常进度,真的是一举四得。跟这些Senior Pair 的同时,我不仅学到了技术相关的知识,更学到了他们的工作方式,最重要的还学到了他们遇到问题和解决问题的思考方式。这些Senior Devs 总会启发我,假如我遇到这样的问题,我自己会怎么做,然后再告诉我他们是怎么做得。这样的后果就是,导致我每天都很累(大脑高负荷运转,哈哈),当然每天也都很有趣。其实,这还只是开发者的部分,仔细想想,团队中Senior BA 和QA 给Devs 的支持是非常有效果得,例如我们在做一个Story 的时候,我们小组的Senior BA 给我们分的任务就很清晰,考虑很周到,系统什么最重要,要多长时间来完成,具体的细节要注意哪些,都非常清晰,这就使得我们总是知道下一步要做什么,而Senior QA 总能即时的发现Bug,从而减少了代码发臭变腐的周期,使得代码和软件总是处于一种比较健康的状态。仔细思考一下,在学校作项目的时候,我和师弟师妹们Pair 的时候,有的时候总是不知道如何下手,一方面这真的跟经验有关,另一方面,由于团队的构成基本上任何人都是BA、QA同时又是Dev,所以划分Story的能力实在是不敢说,总是处于,一种不知道什么重要,不知道下一步该怎么办的状态,大部分有价值的时间都被困惑过去了。果然呀,21世纪啥最重要?人才!同样适用于敏捷团队的构成
对开发流程使用正确的控制手段也非常的重要。以前在学校开发的时候,一个团队坐在一起,先划分用户素材,我们使用Mind Map 作为记录头脑风暴结果的工具,但是记录后的结果就是放在那里,照模照样的开发了,忘记了这些素材是有状态的,它们是可以在不同的状态之间进行迁移的,我们也需要对这些状态进行控制。加入ThoughtWorks 之后,发现大家都使用卡片作为载体,卡片通常分为New, In Analysis, In Dev, In QA, Ready for sign off 等一些状态,这就是把一个庞然大物的软件,分成许许多多细小的部分,而每一个部分都是可以展示,都是可以运作的。非常的合理也非常的巧妙,而这些卡片在迁移的同时,也表示了你这个团队当前的状态,及时的反映了团队健康与否。在开发流程的控制中,还有一点给我印象非常深刻,就是持续集成。在学校的时候,SVN就意味着持续集成,现在才逐渐明白了什么才是真的持续集成。最简单的持续集成是什么?是你每次将你的测试通过后,提交的那些代码,这个流程通常是这样的(以RoR开发为例),我们从Story 中找到一小块功能,像播洋葱一样,从外到里,先写一个Controller 测试,描述或暴露出需要完成的问题,这就导致了Model 层会引起一系列的变化,这时候我们添加Model 测试来继续细化这个问题,好了,到此测试部分完成,但是都没通过,剩下的任务就是写代码来通过测试了。当所有测试通过了,你可能修改了以前的代码,怎么能保证软件仍旧处于可用的状态呢?你需要从SVN(或者别的版本控制工具)下载当前最新的代码(注意,服务器上的一定是能工作的),然后在你本地跑测试,确保原本的功能,和你新增的功能都正确无误,那么可以将你的系统同步到服务器上了。这是最基本的持续集成,其实还包括对数据库的持续集成等等。持续集成的下一个环节,是使用Cruise来进一步运行测试。这时候就有疑问了,我们本地测试都通过了呀?为什么在服务起上还要运行一次?正确答案是,你的开发环境并不代表使用环境,我们开发环境都是Mac 的开发环境,可是用户很可能使用Windows;我们使用的浏览器是Firefox,但是偏偏那么不好用的IE 占据市场绝大多数的份额,还有人喜欢使用Safari;如果你的软件又要支持多种数据库,那么就有更多的运行环境了(这就2*2*2=8 了不算Safari)。所以,我们怎么能让21世纪最重要的人才来手动处理这些事情呢?当然使用自动Build 的软件啦!这就是持续集成很重要的第二个环节,其实在Cruise 上还会运行你本地所无法跑得Acceptance 测试,比如说Selenium 的测试,这些是利用行为方式来进行测试的,很费时间,却代表了用户最终的使用价值,因此重要而必须,我们完全可以让服务器来帮我处理这件费时费力的事情。持续集成的第三个环节其实就是短期的Showcase 和Swich Pair 保证团队每个成员的知识体系也是持续集成的──代码共有和对系统的整体认知。
健康敏捷团队的最后一点──回馈信息。无论是在TWU 的日子,还是回国后的工作,回馈信息绝对是敏捷开发团队健康发展最重要的因素之一。软件开发是高脑力劳动,也是当前世界上聪明人最多的一个行业,大家对一个软件开发的流程和技术,都有很多思考,也有很多的价值,及时地团队交流和信息回馈,就会创造一个大家乐于工作,乐于开发的环境,人开心了,代码质量自然就上去了,是不是?
看吧,这篇Blog 就不是一个持续集成的好例子,长时间不总结自己,结果要说得东西太多,步子太大,又都没讲清楚!哈哈哈!
好了,今天就写到这里吧!
-
FireFox 快捷键总结- MacOS 版 - [应用]
2008-05-11
这几天的Project Simulation 是Web Apps ,所以老要用到FireFox , 总结下FireFox 的快捷键
在TW 的日子,大家都尽量使用快捷键,个人觉得快捷键最大的好处是使你注意力集中,而且使用快捷键对于有些功能真的是非常方便的,做任何事情效率第一嘛!我将我个人关注的几个快捷键方式标记为红色的了。嘻嘻。哦,对了,Cmd 表示Mac 的Command 键,为啥Mac 要有这个键呢?功能明显和Ctrl 重复了么,难道就是为了和微软区分一下Windows 键?真是奇怪呀!!!
添加至收藏夹: Cmd + D
打开收藏夹:Cmd + B
增大页面字体 : Cmd + +
减小页面字体 : Cmd + -
恢复页面字体大小:Cmd + 0
刷新页面 : Cmd + R
停止载入页面: Cmd + . 或者Esc
打开页面源代码: Cmd + U
打开Dom Inspector : Cmd + Shift + I
打开Home 页面: Cmd + Home(可惜我的Mac Pro 键盘没有Home 键,555555)
后退一个页面 : Cmd + Left
向前一个页面 : Cmd + Right
打开新标签 : Cmd + T
关闭当前标签: Cmd + W
重新打开最新关闭的标签: Cmd + Shift + T
下一个标签 : Ctrl + Tab
前一个标签 : Ctrl + Shift + Tab
选中地址栏: Cmd + L
选中搜索栏 :Cmd + K
查找: Cmd + F
继续查找 : Cmd + G
快速查找文本: /
快速查找连接 : . -
I'm in India - 续 - [心情/记事]
2008-05-07
来印度一个多月了,和大家基本上都混熟了。先后也去了不少地方,其中印象最深刻的要数Mysore Palace 和上周末去野外郊游了
Mysore Palace 是班加罗尔附近,比较有名的皇宫,不知道为什么印度的皇帝搬了出去,风景不错,就是小了一点点。比起北京和西安的皇宫是小了很多,但是异国风情吗,还不错滴,只可惜不让在里面照相,我只能在外面狂拍照片,给你们秀一下吧

这是我到印度第二周的事情了,在这里的生活是紧张而充实的,平时白天是没有多少时间的,除了上课,还要自己准备一些session。晚上呢,大家吃完饭,如果有homework,还要写写homework,还要学习一下project simulation 要求的技术。周末又要参加各种各样的活动,所以基本上没啥私人时间,所以请不要责怪我这个月没有更新很多Blog
上周末大家玩的很开心,但是Xiaona 带的防晒霜实在太糟糕了,害的我现在脸还是红红的,555555,身上和脸上都在蜕皮。。。。。。
我们玩了攀岩,独木舟,印度垒球还和大家一起游泳
放出一些照片
这是Jai 在攀岩,可惜就是太短暂了,不过很刺激
这是我的Coach 和Elena 在玩独木舟
我们一直在湖边玩到晚上,趁机照下这美丽的傍晚景色
还有很多事情值得纪念,我就在这里简单的说说吧
第三周去了孤儿院
照片中的小孩叫Christian,旁边是最受欢迎和技术不错的Canadian boy Matt。看到这些孩子,觉得自己真的是很幸运的,当得知ThoughtWorks 一直在资助这些孩子的时候,心里对公司也产生了一层崇高的敬意。

这是去Mysore Palace 那一天去了Bangalure 附近一个有名的天然野生公园,那里有很多漂亮的鸟,当然最让我开心的是近距离接触鳄鱼,哇哈哈

当然还有运动啦,那就是保龄球
最后就是狂欢啦,嘿嘿,Dancing 啦
好吧好吧,透漏一点课程中很有趣的部分,Lego Game,这个游戏让我充分的理解了迭代开发的重要性(Trainer 就喜欢算计我们。。。。。。)

好啦,今天就写到这里吧,基本上也把这一个月的事情都塞到这篇文章里了。这边都十一点多了,北京那边都2点多了,回宿舍洗洗睡觉啦
-
开发你自己的XMPP IM 续 - Openfire 插件开发 - [J2EE]
2008-05-05
继续上一篇的内容,本篇文章介绍开发Openfire 的插件
这篇文章拖了很久了,呵呵,真是千呼万唤始出来呀。Openfire 服务器端是支持插件开发的,开发过程可能会涉及到数据库的操作,本篇文章专注于Openfire 插件的部分,对服务器端涉及到数据库的开发只做简单介绍。
Openfire 是一个用Java 实现的XMPP 服务器,客户端可以通过IQ 的方式与其进行通信(其实就是XML),客户端和服务器之间的通信是依靠底层Smack 库提供的各种功能来完成的。其实利用插件方式来扩展Openfire 服务器端主要有两种扩展方式,一种是对服务器控制台页面进行扩展(不是本文的主要内容),其实就是遵循Openfire 页面的布局方式,进行相应的页面扩展和功能扩展;另一种是对通信功能进行扩展。本文主要针对后者进行具体的描述
本篇文章的结构如下:
1、创建plugin.xml(这是整个插件最关键的文档)
2、创建服务器插件实例(实现Plugin 接口的一个类还有一批IQHandler)
3、打包插件(Openfire 插件也有自己的打包方式)和部署插件
好滴,实刀实枪的来动手做吧
1、创建plugin.xml
初次开发Openfire 和Spark 插件的时候,很容易把二者搞混,千万记得,这里是Openfire 的plugin.xml 不是第二篇文章说的那个啦!
<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<!-- Main plugin class 这里是最重要滴-->
<class>com.im.server.plugin.GroupTreePlugin</class>
<!-- Plugin meta-data -->
<name>GroupTreePlugin</name>
<description>This is the group plugin.</description>
<author>Phoenix</author>
<version>1.0</version>
<date>14/03/2008</date>
<url>http://localhost:9001/openfire/plugins.jsp</url>
<minServerVersion>3.4.1</minServerVersion>
<licenseType>gpl</licenseType>
<!-- Admin console entries -->
<adminconsole>
<!-- More on this below -->
</adminconsole>
</plugin>
最重要的那一行我已经标记出来啦,就是你这个插件的初始化和垃圾清理类,例子中是在com.im.server.plugin 包中的GroupTreePlugin 类,下文会对这个类进行详细描述。其余的都是描述信息,只要你提供了正确的描述信息,一般都不会出错。建议初次开发者,在写完plugin.xml 文件后,写一个简单的Plugin 实例,并打印出一些信息,如果重新启动Openfire 信息成功显示,恭喜你,你已经迈出一大步了!
2、实现Plugin 类和IQHandler
Plugin 类主要起到的作用是初始化和释放资源,在初始化的过程中,最重要的的注册一批IQHandler,IQHander 的作用有点类似于Spark 中的IQProvider,其实就是解析XML 文件之后,生成一些有用的实例,以供处理。下面分别给出一个Plugin 类的实例和IQProvider 的实例
GroupTreePlugin 类
/**
* 服务器端插件类
*
* @author Phoenix
*
* Mar 14, 2008 11:03:11 AM
*
* version 0.1
*/
public class GroupTreePlugin implements Plugin
{
private XMPPServer server;
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.container.Plugin#destroyPlugin()
*/
public void destroyPlugin()
{
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.container.Plugin#initializePlugin(org.jivesoftware.openfire.container.PluginManager,
* java.io.File)
*/
public void initializePlugin(PluginManager manager, File pluginDirectory)
{
PluginLog.trace("注册群组树IQ处理器");
server = XMPPServer.getInstance();
server.getIQRouter().addHandler(new GroupTreeIQHander()); //1
server.getIQRouter().addHandler(new UserInfoIQHandler());
server.getIQRouter().addHandler(new DelUserIQHandler());
server.getIQRouter().addHandler(new CreateUserIQHandler());
server.getIQRouter().addHandler(new AddGroupUserIQHandler());
server.getIQRouter().addHandler(new SetRoleIQHandler());
}
}
上例所示,在初始化中先找到IQRouter,然后通过IQRouter 注册一批IQHandler,这些IQHander 会自动监听相应命名空间的IQ,然后进行处理;由于这个Plugin 不需要做资源释放的工作,所以在destroyPlugin() 方法中没有任何内容。具体的IQHander 类如下
GroupTreeIQHander
/**
* 处理客户端发来的IQ,并回送结果IQ
*
* @author Phoenix
*
* Mar 14, 2008 4:55:33 PM
*
* version 0.1
*/
public class GroupTreeIQHander extends IQHandler
{
private static final String MODULE_NAME = "group tree handler";
private static final String NAME_SPACE = "com:im:group";
private IQHandlerInfo info;
public GroupTreeIQHander()
{
super(MODULE_NAME);
info = new IQHandlerInfo("gruops", NAME_SPACE);
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.handler.IQHandler#getInfo()
*/
@Override
public IQHandlerInfo getInfo()
{
return info;
}
/*
* (non-Javadoc)
*
* @see org.jivesoftware.openfire.handler.IQHandler#handleIQ(org.xmpp.packet.IQ)
*/
@Override
public IQ handleIQ(IQ packet) throws UnauthorizedException
{
IQ reply = IQ.createResultIQ(packet);
Element groups = packet.getChildElement();//1
if (!IQ.Type.get.equals(packet.getType()))
{
System.out.println("非法的请求类型");
reply.setChildElement(groups.createCopy());
reply.setError(PacketError.Condition.bad_request);
return reply;
}
String userName = StringUtils.substringBefore(packet.getFrom().toString(),"@");
GroupManager.getInstance().initElement(groups,userName);
reply.setChildElement(groups.createCopy());//2
System.out.println("返回的最终XML" + reply.toXML());
return reply;
}
}
可以看到主要有两个方法,一个是getInfo() 这个方法的目的是提供要解析的命名空间,在本例中,这个IQHandler 对每个命名空间为"com:im:group" 的实例进行处理;还有一个最重要的方法:handleIQ() 该方法对包含指定命名空间的XML 进行解析,然后返回一个解析好的IQ。其实我认为,这个IQHandler 和IQ 的关系就是Controller 和Model 的关系(如果你了解MVC 的话,那么你一定知道我再说什么),只不过这里并没有指定什么View,你完全可以把IQ 当成Model 类进行理解。在这里,我用了GroupManager 进行了XML 的处理,因为我返回的IQ 内容中要从数据库读取所有群组信息,所以转交给GroupManager 进行处理,你完全可以在这个方法中进行具体的XML 处理,在这里,解析和创建新的XML 主要用到的是JDOM(如果你对Java 解析XML 有所了解,那真的太好了!)。程序//1 处主要是获取创建返回的IQ,并获取原来IQ 的子元素(用于创建我们返回的IQ);程序//2 处很关键,如果你不调用createCopy 方法,程序会出错(程序会死锁还是什么,忘记咧,不好以西)。
这就是程序的主体部分,我在这里有一个建议,能不用Openfire 原始的程序函数,就不要用它们。我的提取数据库方式都是自己写的Bean,这样有利于你自己对程序的掌控,其实更有利于快速开发(这世道不是啥都讲究敏捷么,哇哈哈)
3、打包插件
打包依然遵循二次打包的原则(如果你不了解啥叫要二次打包,请看上一篇)
这是我的ant 文件,由于Eclipse 帮我做了build 等很多工作,实际我的ant 工作就是在打包,并放入插件目录下的plugin 文件夹下
<?xml version="1.0" encoding="UTF-8"?>
<project name="IM" default="release" basedir=".">
<property name="openfire.path"
value="E:/workspace/europa/openfire_src/target/openfire" />
<property name="classes.dir" value="classes" />
<property name="lib.dir" value="lib" />
<target name="jar">
<jar jarfile="${lib.dir}/grouptreeplugin.jar" basedir="${classes.dir}" >
<fileset dir=".">
<include name="*.jar"/>
</fileset>
</jar>
<jar jarfile="${openfire.path}/plugins/groupTreePlugin.jar">
<fileset dir=".">
<include name="lib/*.jar" />
<include name="plugin.xml" />
<include name="logo_small.gif" />
<include name="logo_large.gif" />
<include name="readme.html" />
<include name="changelog.html" />
<include name="build.xml" />
</fileset>
</jar>
</target>
<target name="release" depends="jar">
</target>
</project>
好了,至此XMPP+Spark+Openfire 的插件开发三部曲彻底结束了,希望你们对这个开发流程有了系统的了解。
在此声明,你们如有问题请留言,我会挤出时间尽量回复你们的问题。如果我不小心忘记了,请原谅我,因为现实生活中,我也是一个大忙人。我会尽量给你们回 信,还有请使用email 的方式联系我,我会把我知道的内容发到你们的信箱中,还有,告诉你们一个事实,其实我很菜的,年龄也不大,别把我叫老啦! -
I'm in India - [心情/记事]
2008-04-09
今天总算可以说闲下来一些了,所以上来更新自己的Blog,自从四号来到了印度,就一直忙于认识其他的TWUer,倒时差,处理一些在印度生活的事宜和苦练英语口语中
先谈谈对印度的整体印象吧,来之前,不知道是不是那帮中国Office 的故意吓我,说什么班加罗尔是牛车与宝马并行,咖喱everywhere。来了之后才发现被骗了,都快一个礼拜了,在大街上就没见什么牛车么,倒是蹦蹦蹦everywhere。都说中国的出租车司机很彪悍,那是你没倒印度来,你要是来了就会发现,印度的司机那才叫技术高超,马路上很少有红绿灯,司机开车狂飙,还能让一辆车和另一辆车的距离不到一米 ,人想在两辆车之间插进去,想都别想!我们出去吃饭,经常是过马路的时间比走路的时间还长,还是祖国的traffic 更好一些啊~~~~~
班加罗尔是这样的一个城市,城市很大,交通堵塞,超过十层的楼房很少,商业还挺发达的,不过远没有中国的规模,感觉像是十几年前的西安,发展中的城市,但是有些乱。不过值得一提的是,这里的人很好,可能是印度教的原因吧,偷窃抢劫,很少发生,只要你对本地居民客气,他们一般都很客气,对你也很友好和热情,这一点在中国是很少可以看见的
来的第一天,就被安排到一个三室一厅的房间,有厨房,洗衣间,还有三个洗手间,由于我的客气,把一间洗手间在卧室里面的房间让给了Raph~~~后悔呀~~~我咋就那么大肚呢


(哈哈,开玩笑呢,其实Raph 最近正在帮我练习英语口语呢)。冰箱里天天有专门的housekeeper 给塞的满满的,衣服也帮我们洗。哎,生活实在太惬意了。这就是我的Dear Roomate Raphael 帅吧,长发的呦?中国MM 不要流口水呀!
第二天,trainer Khali 和Reshma 带我们十几个人去班加罗尔旅游啦,哇哈哈,公费旅游呀,后来还去了班加罗尔的酒吧,见识了印度美女呀,就是不敢拍照片呀,因为trainer 说,要尊重人家呀!
这里貌似是市政府
这里是印度大大神的神庙,具体的名字忘记啦,叫Ka啥啥的 ,印度人名太难记啦,索性忘记算啦,还是往脑子里装更多英语单词和程序的东东吧。说到这里,奇怪的是这里的神庙都不允许拍照的,所以只能出来照一些小的啦,毕竟咱去过了,不能白去啊!
后来去了班加罗尔的一个公园,这个公园好小呀,难道是这个城市最好的么?不知道呀不知道。比起西安的兴庆公园可差远了呀
然后又去了Tipu Sultan's Palace 好小的Palace,简直和中国的Palace 不能比呀
最后,公费去书店和酒吧,哇哈哈,这就是在酒吧外面呢,看到没,BARTON,好多酒吧类~~~
奇怪的水烟,味道一点也不重,被他们逼的尝了一口
现在我正在边写Blog ,边让我的roomate 听中文歌呢(反正他们根本看不懂我在干啥,是不是欺负他们了?


我好邪恶哦,哇哈哈),哦,对了忘了说了Sanjay 是我另外一个dear roomate ,是个很年轻的印度男孩 ,有前途呦后面几天的日子过的很快,shopping ,上课,这周据说trainer 要带我们去看电影和吃饭,估计又要去酒吧吧,呵呵,后面的故事慢慢告诉你们呦,my dear friends
对了,忘了说了几件,重要的事情,印度的蚊子很凶猛,简直要吃人了,还好公寓有防护罩,印度消费很便宜,一天消费平均下来最多200 Rupys,也就是不到40人民币的样子吧, 生活很充实,印度英语超级难懂,可是我就不明白,为啥欧美人能听懂呢?好好加油练英语吧,我觉得现在,英语反而是最大的障碍了,技术反而成强项了......在中国office,技术菜菜,英语还不算差的呀,55555555
好了,今天就写到这里啦,以后有空,再继续。
下一篇要写完有关XMPP 的了,隔久了,就不能好好总结了
-
今天是正式工作来北京的第一天,肯定要记录下来了。
早上6点就起床了,和爸爸妈妈告别,在机场还挺依依惜别的,心里真的很舍不得他们,希望他们好好照顾自己的身体,我会好好的生活,好好照顾自己的,在这个纷乱的城市我会努力拼搏,不迷失自己,我保证!

这是西安机场的候机室,要回去也要一个半月呀,走的时候真的是强忍眼泪的,舍不得爸爸妈妈,看着爸爸妈妈年龄都大了,我却不在身边,心里老大的不放心,记得去年得病的时候妈妈对我的悉心照顾,这份恩情,这辈子什么时候才能报答呢?
哎,伤感了~~~
然后,飞机飞呀,一路颠簸,感觉坐飞机起飞和降落的时候就像海盗船,还挺好玩的

这是首都国际机场的长廊,还真是比咸阳机场大多了,豪华多了

机场大巴外的景色还挺好看的,让我不停的按动快门

今天很幸运,机场大巴在东直门下的时候,没赶上,结果跑过去跟司机说要下车,被司机白了一眼,最后竟然刚好把我放在了公司楼下,我赶紧拍下来,可惜下午去公司一个人都没有,有些失望。听小龙说公司最近很忙,大家看来都很累了,周末都不想去公司了,这可不好呀,搞软件的不能高负荷的!

来到了公司给我定的旅馆,暂时的小家,供我住四天的,简单的布置了下,看起来还有那么回事么,(*^__^*) 嘻嘻……

没想到我的午餐是麦当劳,竟然吃出来了咖喱味,神哪~~~你这不是给我暗示吧!!!中午胃被辣的那个狂叫呀!

又幸运的事情发生了,吃麦当劳的时候,竟然遇见了一整队的外国美女,个顶个的漂亮,金发碧眼,身材修长。难道世界小姐班来了?哎呦呦~~~养眼呀,口水呀,那个流呀~~~~~
后面的事情就是买生活用品了 ,让我好好利用了Google Maps 和朋友资源,后来掐指一算,用漫游的不划算,赶紧跑去办电话号码!以后真正的生活开始了,我要好好努力了,我也开始记账了,你不理财,财不理你呀。加油吧,小子!
-
开发你自己的XMPP IM 续 - Spark 插件开发 - [J2EE]
2008-03-29
继续3月18日介绍基于XMPP IM开发的那篇Blog,今天主要总结一下如何基于Spark 的插件架构来新增客户端的功能,这里列举出一个获取服务器端群组信息的实际例子,实现后的效果如下图所示:
Spark 是一个基于XMPP 协议,用Java 实现的IM 客户端。它提供了一些API,可以采用插件机制进行扩展,上图中,“部门”部分就是使用插件机制扩展出来的新功能。要想实现你的扩展,首先要了解 Spark API的架构,其中最关键的是要了解它的工厂类,这些工厂类可以获得Spark 提供的诸如XMPPConnection、ChatContainer 等实例,从而你可以实现获取服务器的信息,与另外的Client 通信等功能。最核心的类是SparkManager,这个类是一系列工厂类的工厂类(呵呵,还真拗口)。它的getChatManager()、getSessionManager ()、getMainWindow() 、getConnection() 等方法分别可以获得聊天管理器、会话管理器、主窗口、与服务器的连接等等非常有用的实例。基本上可以说SparkManager 是你与Spark 打交道的衔接口。其实,每一个Manager 都使用了单例模式,你也可以不通过SparkManager 来获取它们,但笔者建议你从单一的入口着手,这样有利于代码的开发和维护。
接下来描述一下插件的开发流程:
1、创建插件配置文件 plugin.xml
2、实现你自己的Plugin 类的实现(如果你需要实现自己规定格式的XML 发送、接收和处理,那么你需要在这里注册你的IQProvider,关于IQProvider 你可以查询Smack API,简单的来讲是处理你自定义的IQ 处理器。)
3、打包你的插件(Spark 有自己的打包机制,我研究了半天才发现其中的玄机,后面介绍)
4、部署你的插件(其实3、4两步可以糅合在一起,当然要利用Ant 啦)
好滴,下面结合一个实际的例子讲述上面的四个步骤
1、plugin.xml
<plugin>
<name>Enterprise IM Client</name>
<version>1.0</version>
<author>Phoenix</author>
<homePage>http://phoenixtoday.blogbus.com</homePage>
<email>phoenixtoday@gmail.com</email>
<description>Enterprise Client Plug-in</description>
<!-- 关键是这里,这里要定义你的Plugin 类 -->
<class>com.im.plugin.IMPlugin</class>
<!-- 这里定义你使用的Spark 最低版本 -->
<minSparkVersion>2.5.0</minSparkVersion>
<os>Windows</os>
</plugin>
这是一个 plugin.xml 文件的内容,插件体系会自动调用你在此文件中定义的Plugin 类,从而完成你自己扩展的功能。最关键的部分我用红色标识出来了,要声明你的插件扩展类,采用完整的命名空间方式(包括包名),其余的部分结合我的注释, 大家应该都能理解,就不做详细的描述了。要注意的是plugin.xml 文件要放在项目的根目录下,这是严格规定好的。
2、Plugin 类的实现
你的类首先要实现Spark 提供的Plugin 接口,然后实现它的一些方法。其中最主要的是实现initialize() 发放,在这里注册你的的IQProvider
ProviderManager providerManager = ProviderManager.getInstance();
providerManager.addIQProvider("groups", "com:im:group", //1
new GroupTreeIQProvider());
System.out.println("注册GroupTree IQ 提供者");
requestGroupTree();
上述的代码,就在该类 就是我实现的IMPlugin.initialize() 方法中的一小段,大概的含义是,先获取ProviderManager(这个貌似不能从SparkManager 直接获取),然后注册一个GroupTreeIQProvider(自己创建的)这是一个IQProvider 的具体实现,它用于解析像下面这样的一个XML 文件:
<?xml version="1.0" encoding="UTF-8"?>
<iq type='result' to='domain@server.com' from='phoenixtoday@gmail.com' id='request_1'>
<groups xmlns='com:im:group'>
<group>
<groupId>1</groupId>
<name>西安交通大学</name>
<upGroup>ROOT</upGroup>
<isLeaf>0</isLeaf>
<description>xjtu</description>
<user>
<userGroupId>1</userGroupId>
<userName>phoenix_test</userName>
<role>normal</role>
</user>
</group>
<group>
<groupId>2</groupId>
<name>电信学院</name>
<upGroup>1</upGroup>
<isLeaf>1</isLeaf>
<description>xjtu info</description>
</group>
</groups>
</iq>
可以看到,在注册 IQProvider 的时候(代码中标注的1部分),需要你提供名称和命名空间,我的XML 文件中的iq 下的第一个子节点是<groups> 所以我的名称就写“groups”,命名空间对应于groups 节点的xmlns(XML Name Space)所以是“com:im:group”,其实IQProvider 中最关键的方法是parseIQ(XmlPullParser parser) 该方法就是解析XML,完成你的功能,并返回一个相应的IQ 实例(这里可以把IQ 看做一个回馈的Model 类)。说到底实现基于XMPP 协议的IM 就是解析XML 文件,而这正是客户端的IQProvider 和服务器端的IQHandler(下一篇文章会涉及到)所做的事情。
3、打包你的插件
现在该有的功能都实现了,那么就是打包了。这最好利用Ant 来完成,因为每次你都要打包,要部署,如果纯手动的话,那也太不敏捷了,大大影响开发效率。
<?xml version="1.0" encoding="UTF-8"?>
<project name="IM" default="release" basedir=".">
<property name="src.dir" value="src" />
<property name="dest.dir" value="bin" />
<property name="lib.dir" value="lib" />
<property name="im.path"
value="E:/workspace/europa/spark_new/doc/spark/target/build" />
<target name="clean">
<!--
<delete dir="${dest.dir}" />
<delete dir="${lib.dir}" />
-->
</target>
<target name="init" depends="clean">
<!--
<mkdir dir="${dest.dir}" />
<mkdir dir="${lib.dir}" />
-->
</target>
<target name="build" depends="init">
<!--
<javac srcdir="${src.dir}" destdir="${dest.dir}" />
-->
</target>
<!-- 最重要的是这里,打两次包 -->
<target name="jar" depends="build">
<jar jarfile="${lib.dir}/eim.jar" basedir="${dest.dir}" />
<jar jarfile="${im.path}/plugins/eim.jar">
<fileset dir=".">
<include name="lib/*.jar" />
</fileset>
<fileset dir=".">
<include name="plugin.xml" />
</fileset>
</jar>
</target>
<target name="release" depends="jar">
<!--
<exec executable="cmd.exe"
failonerror="true">
<arg line="/c e:"/>
<arg line="/c cd workspace\europa\spark_new\doc\spark\target\build\bin"/>
<arg line="/c startup.bat"/>
</exec>
-->
</target>
</project>
这是我的这个项目的 build.xml 文件中的内容。因为Eclipse 其实帮我自动完成了编译的任务,所以我也就省去了这写编译的步骤,最重要的是大家要看到“jar” 部分,Spark 打包的神秘之处也就在此,打两次包首先把你的项目打包到本项目lib 文件夹下,比如说你的项目目录是MyPlugin 那么,你就将你的类打包到MyPlugin/lib 目录下,然后再次的打包,将所有的lib 文件夹下的内容打包起来,记得这次要包含plugin.xml。也就是说,最后Spark 插件体系会读取你的项目下的lib 文件夹下的内容。这里我也有个疑问,我本来想每次打包后自动执行bat 文件,启动插件,看看效果,为啥死都调用不了呢,那段代码在最后面,注释掉了,谁能帮我解决,我请他吃饭滴!
4、最后就是发布了
其实我的发布很简单,就是将这个打包好的jar 文件拷到Spark 本身的plugins 目录下,每次启动Spark 的时候,它会自动调用自定义的插件的。我这里用Ant 第二次jar 的时候,就自动拷贝过去了,这里用的是绝对路径,所以你不能直接拷贝就用滴呦(是不是很丑陋呀,这段Ant 代码)。
基本上客户端的实现原理就是这样的,只是有些地方需要特别注意,还有就是应该利用像Ant 这样的工具大大简化开发步骤,加快开发效率。还有就是,我建议你在开发自己的插件的时候,多利用MVC 模式,尤其是在IQProvider 解析后,生成的部分可以实例化Model,然后你可以编写自己的Manager 进行这些Model 的处理。多写Log,当然Log4j 貌似不太起作用,那就System.out.println() 吧,哈哈!今天就写到这里啦,偶有点累啦。






