2008年1月27日
题外话:我其实想说的是一个被人所忽视的问题。形式有没有价值?我承认,形式化是不好的。但是这个世界有个东西,叫做仪式。
举个例子,在国外,有种组织叫兄弟会,(电影里很常见)他们的有些会设置很多可笑的考察仪式来考察你够不够入会的资格。有些会有危险,有些只是纯粹搞出些恐怖气氛吓你看你会不会被吓退。这种东西有价值吗?心理学告诉我们,设置准入门槛可以提高组织成员的忠诚度。如果你觉得这玩艺太可笑了,给取消掉。你会莫名其妙的发现后来加入的人对组织的认可度忠诚度都不高。这就是仪式的价值。
今天说的是Retro,全名retrospective,中文名“回顾会议”,网上有很多相关文章,就不再这里赘述了。这里提到的Retro是最常见的一种模式,分Well, Less Well, Puzzle三个维度的模式。该模式的Retro的特点是会让我们更多的关注less well,关注我们做的不好的那些。这点有好有坏。本文只揭示它好的一面。做为补充,还有一种海星图的模式,感兴趣的人可以自己查询。
我个人认为retro是敏捷开发中很重要的一道防线。是团队健康度的晴雨表,是沟通的桥梁,是共识建立的契机,是改进的开始。
对于团队本身就存在大量问题,而这些问题可能都在敏捷方法的问题域里时。Retro是一个很好的发力点。他的效果可能没有持续集成那么立竿见影,往往是润物细无声。他可以帮我们把痛点暴露出来,但是不一定是根本问题。就像医生看病也得先问你哪不舒服。而Retro就能帮团队说出来哪不舒服并达成共识。某种意义上讲,它是个报警器。
如果已经采用了大量敏捷实践的团队呢?比如我们团队,在我们团队的开发中,我们一直推进着各种改进,期望让我们的工作更有效率,交付更多价值,同时也让我们的生活更美好一些,这是一件双赢的事情。 可是我们也要看到改进是需要成本的,而且也是有风险的,所以有的时候难以推动。对于客户( 有时是PM等内部角色)来说,他讨厌一切成本和风险,而更感兴趣的是新功能,当碰到短视的负责人,或者交付压力占了上风的时候,难以推动这点感觉尤为明显。不过商业社会里竞争如此激烈,这也无可厚非。虽然我们也知道出来混,欠下的迟早是要还的。
不过这不是我们今天讨论的角度。今天我们站在推动改进的角度来看这个问题,开发时,在开发第一线的我们往往是第一个了发现开发中的问题,然后我们会发现改进最困难的是沟通,明明这是个问题,但是让各方都接受这个问题并改进它需要证据,需要沟通,需要资源,最重要的需要时间。我曾眼睁睁得看着客户只是加几台机器提升持续集成的构建效率这件事竟然推动了近一年才成功,那么在这个问题被发现但不能改进的时间里,团队会怎样呢?首先士气会被打击,接着如果问题长期不能解决并影响了工作效率,一种不愿追求卓越的气氛会渐渐感染团队成员,进而使得大家会在其他实践上表现渐渐变差。( 相对于每个人自己,而不是团队其他成员)改进的意愿也会不同程度的变低。这符合
破窗效应。
这时候,很容易出现的一个倾向会是干脆我们不要retro了,反正也改进不了,完全是浪费时间。 这就成了自毁长城。不能干因为报警器老响就把报警器拆了的事。出来混欠下的始终要还,学鸵鸟是没用的。当retro不能给我们提供更多实际改进价值的时候,它还能提供最后一个价值:忏悔的仪式。
曾经一直不明白西方人为什么定期去教堂忏悔,周周去,周周都有值得忏悔的,甚至犯过的错还有很多类似的。看起来没什么用。但这就像房间,天天打扫天天都有的打扫的,心灵的房间也是一样。一位有信仰的朋友告诉我,定期经常向神忏悔会更愿意改进自己,如果一段时间不去对自己的要求就会放松。人的心理就是这么奇怪。这揭示了一个道理,人是会逐渐放松对自己的要求的,所以需要一种手段让我们保持对自己的高标准。
我个人认为retro就是一个很好的手段。尤其我前面说过了,这里讨论的这种Retro的模式的特点就是让我们更关注于Less Well。定期,经常,回顾,反思。当我们无法变得更好的时候可以帮助我们反观团队自身,不要变得更差。让破窗效应难以发生。
(本来只是想写一个敏捷团队碰到让人沮丧的情况时Retro提供的价值,结果越写越多,有点跑题了⋯⋯)
在我们的开发中,有些实践的价值是容易感受到的,比如重构,比如TDD,比如持续集成。
有些实践的价值则不容易感受到,比如Retro(回顾会议),比如IPM(迭代计划会议)。
以IPM为例,在我们的IPM上我们一般会做两件事Kick off cards和Estimation。也就是选择下个迭代要做的卡和评估每张卡的点数。这两件事情似乎第一件事没必要所有人都参与,第二件事感觉一定程度上是瞎蒙,尤其是一群人来蒙,显得尤为的不靠铺。而且似乎我们IPM就是为了选出下个迭代能做完的卡,就是为了知识传递,就是为了给客户可视的数据和计划,让他们心理好过。
假设说我们不必所有人都参与就能保证选出适合下个迭代做的卡,我们通过每日Code Review等实践使得每个人都不会缺少相关卡的知识,而客户也不特别在意我们的进度(或者说我们的进度他们总是满意),是不是我们就不需要IPM了?是不是我们就不需要集体Estimation不需要集体Kick off了?
实际上,我们的项目就符合前面的假设,在项目的最后,我们真的取消了IPM。这时,才感觉出来IPM的价值。
整个团队的效率慢慢开始下降。对于目标的理解开始不一致。虽然团队整体的表现并不差,虽然没有出现任何实质的问题,但容忍度低的人开始不舒服。跟团队自己以前的状态比,确实有点退化的感觉。怎么会这样呢?
每当说到这种状态出现在敏捷团队中的时候,我最常听到就是人的问题,态度问题等等说法。其实我一直觉得,如果追究态度,空谈人的问题有用的话,我朝应该是世界第一而不是那个人人自我的美帝。人一直是有问题的,不然要管理学干什么?敏捷里提倡自组织团队,自我管理。但决不是松散组织,不管理。自组织它也需要组织,自我管理它也是管理。像IPM这样的活动,就是管理的一部分。
IPM上做的两件事,看起来完全不靠铺,实际上却非常有价值。整个IPM活动就是一个承诺的仪式。像古代行军打仗前的誓师大会一样,可以调动起团队在下一个迭代中的士气。通过集体参与评估和制定计划,通过各个角色的共同作用,使得每个人都参与到整个计划制定中来。自然而然的对下一个迭代许下承诺。而承诺一旦许下,就会像一个耳语的恶魔,暗中催促着人们的行为与其保持一致。
生活在我朝的人们,似乎对承诺这个东西的效果是完全不相信的。这也难怪,不过出于众所周知的原因,咱不谈我们为啥不信任承诺。从心理学的角度,承诺是有实际意义的。《影响力》“第三章 承诺和一致”中就讲了这个极为简单却极为有用的心理学原理:人人都有一种言行一致(同时也显得言行一致)的愿望。
其中有很多很有趣的实验,揭示了承诺的力量。 感兴趣的人推荐读一读。里面有个小例子提到,两个星期前一个愿意在自家的草地上插一个小牌子为交通安全做点贡献的小承诺,使得该社区76%的人都在两个星期后接受了在自家草地上插一个挡风景的大牌子的请求。而对照社区只有17%。巨大的反差可以让我们看到承诺的力量。
当然我们对承诺的不信任也是有道理的,当承诺真的难以完成的时候,几乎所有人都会违背承诺。在传统的瀑布式开发过程中,使得计划这种承诺难度大大上升,而可信度也就大大下降。这也是为什么我们需要迭代的原因。
一个成功的企业需要积累。当你坐在电脑旁,看着一个运行达十年之久的软件的源码时,相信我,你一定会更深刻的感受到积累这个词,确确实实是个中性词。
软件多种多样的功能支撑着一个企业帝国的运转,它源源不断的在为这个帝国创造着财富,毫无疑问它随着时间积累了很多挣钱的能力。可是如
同历史上其
他的帝国一样,在繁华的背后,很多黑暗的东西同样随着时间积累了下来,临时性的策略被固化在核心流程中,为扩展留下的空白成了每次扩展必须绕行的弯路,精妙的手法随着时间的变迁显得复杂过时,分工协作使得同样事情得处理方式大不相同,预先的设计又使得本不相同的东西硬造成了相同的样子,管理的疏忽使得简单的功能用了复杂的模式实现。
坐在代码面前,仿佛在读一本被囚禁了灵魂的魔书,你能在注释中读出兴奋与痛苦,你能在代码中看到骄傲与彷徨。每当完成一次重构就像解救了一个被困的灵魂。那代码又仿佛一个人的脸,你可以看到各个技术历史阶段在它脸上留下的岁月痕迹。畅游在代码中,有些时候我们好像穿梭在时光的河流中,你能看到一个愚昧的风格是如何从一个有价值的需求中演变而来。如今再看,仿佛一群羊在不断的跳过一个早已不存在的栅栏一样诡异。而有些时候,我们只能看到一些遗迹,原野中矗立的大石柱根本无法自己告诉我们他们到底是为何矗立在那里的。以及移动他们会不会带来什么灾难。
能力很强,问题很多。是任何一个已经有历史的公司都会有的。软件不过是公司的一个表现方面。就像一个拥有完整公司基因的细胞。准确的说,任何时候,任何公司都不可能没有问题的。但是何时解决?这个问题就跟什么时候重构一样,答案也是一样,随时。解决问题的时机会影响解决问题的难度。越晚解决,就越难解决。说起来容易,做起来谈何容易。是的,解决问题总是需要鼓励的,但是谈何容易四个字却很容易瓦解我们前进的意志。低下头埋到土里,是可以让一切都清静了。但不管我们做不做,甚至于即便我们在做,问题也永远不会停止它产生并进化的脚步。面对问题,只有应战,没有第二条路可以走。经济危机教会了很多企业只顾赚钱而忽略企业的问题会有什么后果。我相信有很多人会选择遗忘并在遥远的未来继续重犯同样的错误,但是我也相信,也会有很多人会选择记住并把教训提炼成一种知识或制度,让后世人学会警惕。
进来听闻最大的CMM堡垒DNV要搞敏捷。大票的猎头纷纷出动,四处搜罗敏捷咨询师。使敏捷这个本来只有小众在实践的一类开发方法陡然变得要大众化了。本来以为是件好事。却在昨天看到z叔大喊,敏捷要倒。当时只是觉得有点道理。晚些时候却切身体会到了。
收到某非知名公司举办的scrum培训的邮件。顿时心里一紧。在这个时间,用这个操作手法有点可怕,各培训公司都找到了敏捷里面最好切入的一个点---Scrum。
Scrum是个筐,什么都能往里装啊。为什么这么说呢,他并不能算是一个完整的开发方法。只是一个框架。不领会敏捷的精神,没有其他具体的开发方法,他只能是一个大面的东西,如果用上这种东西就号称敏捷了。那真是可怕。而且,scrum证书也在这波浪潮中量产。一个人,花几千块钱,上两天的课,拿着一张纸就号称敏捷了。没办法,谁让咱们崇拜证书这种看得见摸得着的东西呢。但这样大量量产出来的敏捷项目经理。一实践肯定不对劲,就会用自己的理解去曲解敏捷。然后大家认为敏捷就是早晨开个会,月末开个会。最后的结果就是你在骂敏捷,我在夸敏捷,可是你嘴里的敏捷和我嘴里的敏捷根本就不是一个东西。
记得曾经见过一个CMMI的咨询师,张口闭口卡耐基梅隆,一付兄弟当年在英国的时候的样子。生搬硬套的CMMI流程。最后搞的那套流程根本不可操作,大家都为流程凑数据。当下如果大家都从CMMI倒向Scrum,这种人咋生存呢?会挂掉?错,摇身一变,举起敏捷大旗开始摇旗呐喊。没这两下子怎么能在忽悠界纵横这么多年呢。像这样的人都来搞敏捷了。敏捷不臭,那除非老天开眼了。那原来搞敏捷的人呢?本来就是小众,在这大浪里面,估计很快就看不见了。。。。从今开始,我还是少说两句敏捷了。。。
我习惯于在午饭后午睡一下。上班时午睡,只能是趴着睡。最近才注意到,写字楼的空调大多是从上往下吹得,所以这个时候整个后背是暴露给空调的。从中医上讲,背上主要是两条经络。督脉和膀胱经。其中膀胱经主人体一身之阳气。号称人体最大的排毒通道。膀胱经不通的人可能会怕风怕冷,容易得湿疹等病,常年排毒不畅,可能会导致更多疾病。
体的经络不管哪一条,都怕六邪,风湿热火燥寒。对于处处空调的现代人,火燥热远不如风湿寒需要担心。比如像这样天天把后背暴露给空调,而且是在睡觉这种放松状态下。就等于天天让空调的风寒入侵膀胱经。加上很多办公室都有加湿器。那湿也是跑不了。当然,人体自身有防御的能力,肯定不会马上出问题的。但是天天这么搞,难免不出问题。上个礼拜加了几天班觉得左肋靠近腋窝的地方疼。周末好一点了,今天下班前又痛了。引起我一点警惕。所谓猝死,大概就是这么一点点演变来的。干咱们这行撑不死可也别累死。
温热可以驱寒,我想把背紧靠一会靠背取暖。这时发觉我的椅子后背只到肩胛骨中部。好像很多公司的椅子都是这样的,不能很好的护住背部(除了老板椅。老板椅上面似乎还要往前多出一块来,连后脖颈子都能护住。倒是很养生。)
所以,办公室可以放一件外衣,睡觉的时候披上来防风防寒。另外,可以偶尔的去做一些保健。比如拔罐,刮痧等。基本上背部拔罐就是在疏通膀胱经。背部刮痧也是。不过要注意的是:
一,拔罐的话,频率不宜过高,拔罐是排毒比较猛的一种方式,体内毒多的时候倒是在排毒,毒少了以后,排的就不只是毒了。有一种说法,拔得太频繁反而会有损阳气。我比较认可这种说法。一个月一次或者隔一个月一次为宜。拔罐后六个小时不能洗澡。
二,刮痧倒是可以频繁点,但最好找干净的地方或让自己家人做。肉少的地方尽量少刮。最近发现一种叫魔蝎刷的东西,个人感觉比刮痧板好用,可以替代刮痧板刷背。刮痧后半小时不能洗澡。从时间上也能看出哪个比较猛。
最后,多多运动是最好的保健方法。自我锻炼总是要胜过别人伺候。愿程序员们都能度过一个健康的夏天。
没“贡
献”的田鼠
在田野里,住着三只田鼠。
秋天到了,三只
田鼠开始准备过冬的东西。
第一只田鼠每天都到田野上运粮食,准备冬天食用。
第二只田鼠每天都到田野上运野草,准备冬天取
暖。
而第三只田鼠每天都跑出去游玩,对粮食和野草一点儿也不关心,好像冬天永远也不会到来一样。
前两只田鼠劝它为即将到
来的冬天多准备一些必要的东西,但它只是笑笑,仍然每天都出去游玩,经常玩到天黑才回来。
寒冷的冬天很快到来了,三只田鼠住在洞里,饿了
就吃第一只田鼠运回来的粮食,冷了就用第二只田鼠运回来的野草取暖,而毫无贡献的第三只田鼠自然也得到了前两只田鼠的嘲笑。
然而日子一
天天地过去,每天都无所事事地待在洞里,做着同样的游戏,吃着同样的粮食,三只田鼠渐渐厌烦起来,感觉到了无聊的空虚。
这时,第三只田鼠
开始为前两只田鼠讲故事,讲它在秋天出去游玩的时候见到的许多新鲜有趣的故事,前两只田鼠听得津津有味,生活开始重新变得充实而有意义。
作
为感谢和报答,前两只田鼠经常把自己的粮食和野草挑出一些送给第三只田鼠。
原来,有些贡献并不是从一开始就能看得出来的,然而我们却经常
因为暂时看不到它的“用处”就舍弃了它。
这篇文章是受启发于要求我写一些设计和spec的文档的面试要求。趁这个机会整理整理自己的思路。
什么是软件开发呢,最常见的一种说法是,软件开发是一门艺术。我觉得更现实的讲,软件开发应该是一种生产。跟其他所有的生产一样。要考虑成本和收益。收益这块,跟其他很多外部因素相关,对开发者或者说开发者的管理者来说无法控制,开发者从职业的角度出发更多需要考虑的是成本。这也是我们职业的目标。
软件这种产品的生产,材料本身的损耗也就是电脑,电费,基本属于沉没成本。不会因为咱们任何努力而改变。(也不是完全不能改变,只能是变多。。。。)那么,最大的成本损耗在时间上。一方面,程序员都属于高薪人士(相对,相对)。每一天的损耗都意味着大量的钱打水漂了。另一方面,随着时间的推移,商业价值在降低,风险却在增加。
对软件开发来说,需求实现速度,应该说是很重要的,但是实现速度本身并不是考量的标准单位。作为最大成本考量标准的时间,从对她的消耗来看:除去简单的功能点实现需要,需求的变化浪费的时间则更客观。而无数实例证明,我们在需求分析阶段投入时间诚然可以减少需求的变化,但是并不能达到我们满意的高度,所以对需求变化的反应也是我们的重要标准。
敏捷这个词,我觉得非常好。做为一门方法学,从名字上就说明了软件开发需要关注的两个重要的点:需求实现速度和对于需求的反应速度。当然,说到这里有点虚了。我想,回归到不太实际的本质,能更好的指导我们的实践。Rails框架为什么这么火热,恰恰因为它做到了这两点。我们想想,为什么要设计?我读过让人舒爽的代码,也读过看着让人想吐的代码。抛掉个人的感情因素,这两种代码有什么区别呢?大部分让我想吐的代码里出现的是一些重复的代码,看起来稍有不同,却不肯费点心思除掉这些“坏味道”。重复代码的问题在哪里呢?最大的问题就是随着代码量的增多,工作量的与日剧增。维护量也会增大。而且,复杂度绝对不是O(n)。其实我常常觉得,我们最早学程序的时候要学算法与数据结构。其实这个课程很早就告诉了我们编程最重要的两块:算法,结构。好的设计就是好的结构。可扩展,可维护,最起码,可以分工。
好的设计可以大量的减少代码。减少代码就意味着成本的降低。也就是文初说的,我们职业的目标达到了。但是现实往往不是那么美好,虽然我们有很多OO的设计模式,我们有很多最佳实践。但是在现实中,我们往往需要妥协。一般是三个原因:性能、稳定性、各种接口,在左右着我们。其实,很多时候,这也是最考验一个程序员的功力的地方。如何在这三个沼泽上跳舞,才是软件开发真正可以被称之为艺术的地方。而怎么做,则只能靠一行一行的代码锻炼,一篇一篇文章和文档整理经验,没法一句半句说得清楚的了。
晨会是Scrum里的一个实践。
最近才意识到,这种东西一点都不时髦。很多理发店,饭店,他们早晨都有这个。今天在大鸭梨看到他们的晨会,颇有感觉。看着他们都站在那里,觉得跟站立式晨会差不多。不同的是他们的员工,年龄层比较低,处于还比较毛糙的年龄。也就是说,不仅需要教育怎么做事,还得教他们怎么做人。所以在这个晨会上,经理教育他们说,不要混日子,十年后,你们如果没做出什么来,一生就这么过去了。跟他们说,要当面说坏话,背后说好话。也就是进行人性和行事风格上的教育,也可以说是一种文化上的教育。经理教育完,几个像老员工的来说加单要写名字,不要怕写了名字会怎么着等等。虽然是端茶倒水送饭,但是需要注意的还真是不少。前台,服务员,后厨,这之间也是需要沟通规范,任何一个沟通不符合规范,就会出乱子。
比较起来,敏捷的实践只是要求个人说自己做过什么,要做什么,有什么问题。不过我发觉,有些话,其实是应该在晨会的时候应该强化与灌输,不见得是每天,但是隔三差五的就该讲讲。关于工作态度,配合。这是员工培训的最好时机。在这里用力,虽然不会有奇迹般的效果,但每隔一段时间肯定会有一点切实的进步。企业与企业都是不同的,有自己的氛围,那所谓的文化,就是企业的性格。员工与员工更是不同。但是企业喜欢的员工其实都很相似。不喜欢的员工却各有各的不同。所以企业经常培训员工。但我是不相信给员工搞一两次课可以改变一个人的。有天在快餐店,听到一个老销售教育一个新销售说,鸭子听鹰讲怎么飞。上完课,鹰飞回家了,鸭子还是走回家的。不能飞的鸭子又不缺什么,野鸭就能飞。所以,仅仅几天的员工培训能改变什么呢?不能指望着几天就能给公司制造出好用的员工来。公司对教育的重视不够说小了是不把自己的钱当回事,说大了其实是社会责任的缺失。
你们10年后还一事无成,这是给员工灌输的一种危机意识。要当面说坏话,背后说好话,这是对员工进行人性的教育。这像是领导说的话,有人说,领导两个字是领袖+导师。身为导师不引导人光明磊落,就不能怪人言可畏。有喜欢以流言御人的领导才有大量到处嚼舌头的下属。现代企业不是古代的官僚衙门。该专心搞的是经营而不是政治。
散会后,员工继续去工作了。你说这个晨会有什么作用吗?不知道,就像一颗石头扔进了平静的水里。一阵激荡过后我们什么都看不到了。但是,我想,日积月累,石头扔得多了。在你不注意的时候,水面会悄悄上升的。
敏捷作为方法学,其实还是比较虚的。哪怕是其中比较实的最佳实践,也是非常难以掌握运用的。原因其实很简单。人要想通过敏捷偷懒是绝对不可能的。敏捷的实施,在最初肯定是非常累的。因为改变总是痛苦的。回顾丰田的历史,他们在创造TPS的时候,工人们也是想把大野耐一的那些破烂东西都给砸咯。
不过很多时候,痛苦是幸福的开始。一个人完成很多人合作完成的工作,咋看起来是非常劳累的。但是习惯了,也就那样了。TPS里面基础就是让一个工人具备两项以上的技能。程序员也是一样。不能为自己的懒惰找理由。大家都是人,都想懒,但是今天懒了,总会有一天被逼着勤快。就好像没有时间锻炼,就有时间生病一样。只有每个团队成员都变得敏捷了,敏捷的方法才有意义。
时间。。。曾经是我最害怕的东西。。。如今却变成了最喜欢的东西。。。
这个世界纷纷扰扰有那么多的真实与虚假
只有时间能把它们分离开来。
时间,跟所有自然的伟力一样,从来都是缓缓的,慢慢的显示着自己的力量。
人可能等不及看到它的效果,可它却一直履行着自己的职责
一切浮于表面的虚幻,终会在时间的侵蚀下消逝,只留下最真实的东西。
google上搜这个词,搜到的很多是征文,和一些扯淡的文章。
跟这篇文章一比就差的比较远咯:
http://www.dapenti.com/blog/more.asp?name=xilei&id=15410
节选精华“中国梦”解释如下:
如果有人问什么是中国梦?我说,只要你看看这个国内的精英怎么选择的,你就知道了:
【1】读书,考上清华北大,然后,到外企工作,出国,拿绿卡;
【2】唱歌跳舞,不惜一切代价成名,出国,变更国籍;
【3】当官,贪污腐败,找机会逃跑到国外,躲起来过一掷千金的日子;
【4】做生意,赚到足够的钱,然后,出国定居,想生几个孩子就生几个孩子,让小孩都在国外上大学。
BlogJava,应该是一个技术博客。倒回来看自己写的东西,却感觉离题越来越严重。
对技术的热情在衰退。所写的技术相关的东西越来越少。
从Java到Flex到Grails。技术照理增长了不少,人却越来越迷茫。
对文科的兴趣在增长,已然超越了对程序设计的兴趣。
可是做的工作又不得不继续从事程序设计的学习,不然一旦失业了,我又能做什么呢?
所以每当看一些文科的书,就会有一种罪恶感。人活成这样,不得不说是一件悲哀的事情。
其实心里明白,所谓悲哀在旁人看来不过是一种吃饱了撑着的心态。
买了域名和空间,准备换一个独立博客了。到时想写些什么就写些什么了,也不用担心站方有问题。
最近一直在看跟丰田生产体系有关的书,得到一些很有意思的知识点
- 刚明白原来这些个名词他们是JIT->TPS->Lean->Agile这么一个关系。
-
丰田老总一拍脑袋提出3年之内超越福特。这种感觉就像好像有一家中国软件公司一拍脑袋说,三年之内超越微软一样。我要是执行人,只会觉得上边又发神经了,这不是疯了吗?结果大野耐一到底是大野耐一,竟然真的找到了方法。
- 生产过剩的浪费
- 制造不良品的浪费
- 停工等活的浪费
- 动作上的浪费
- 搬运的浪费
- 加工本身的浪费
- 库存的浪费
-
丰田的思路其实简单到了不能再简单,利润=销售价格-成本。那么在经济增长无望的时代,减少成本就等于创造利润。过去的时代是一个经济高速发展的时代。就像日本泡沫经济时代一样。但是泡沫破裂的时候,丰田反而崛起。类似的如学习TPS的佳能,在5年内销售没有增加的情况下,利润增长十倍。
- 面对一个即将来临的经济增长放缓的时代,成本开始成为管理者嘴上流行的新词应该是下一步的趋势。
-
软件开发中的浪费有哪些呢?我现在想不到太多。但是跟朋友聊天我突然意识到,犹豫也是一个巨大的浪费。作为一项脑力劳动,开发时的犹豫就如同停工等活的浪费和动作上的浪费。这种事情其实可以避免,我开始明白TPS这样一个强调变化与改进的过程,为什么还如此强调标准化。应该就是通过整理最佳实践并确定为标准流程来减少重复犯错与犹豫造成的浪费。那么结对对效率造成的改进,别的不提,减少了犹豫的时间应该是很重要的一点。而这也是在水面以下最不容易被发现的浪费。因为犹豫和谨慎,从表面上看,似乎是一样的。
通往天堂的轮船和通往地狱的轮船烧得都是同一种燃料,那就是人类的欲望。
记得小时候看《读者》这本杂志,里面有一个故事,上帝带一个人去参观地狱,地狱里支着一口大锅,锅周围坐着一群人,每个人拿着一个很长的勺子,因为勺子太长了,想要吃东西,经常会碰到别人,所以互相之间总会打起来,结果所有人都吃不饱,人人脸上充满着愤怒和痛苦。然后上帝带他又去参观天堂,结果天堂里跟地狱的摆设一模一样。但是人人脸上洋溢着幸福,原来,这里的人会用长勺子喂对面的人,所以,每个人都能吃饱。
同样的配置,同样的人,同样都有吃饱的欲望。一处是天堂,一处是地狱。现实中也是如此,一个好的游戏规则,游戏中便是天堂,一个不好的游戏规则,游戏中便是地狱。
相传,有两个嫌疑犯,合谋杀死了一个人,之后被警察抓住,警察将他们分开审讯。并告诉他们说,如果你们两个人都不说的话,以我们现在的证据,我们可以让你们坐一年的牢。如果你招供了,而你的同伙没有招供,那么我们将当庭释放你,你的同伙关20年。如果你和你的同伙都招供了,那么我们也就没有必要照顾你们任何一个,你们一人关10年。
这就是著名的囚徒困境。处于困境中的囚徒,该如何选择呢?
如果我是那个囚徒,我不说,你说了,我被关20年。你说了,我也说了,我关10年,只有你不说我不说的情况下,我还要关1年。这里还有一个极大的诱惑,那就是我说,你不说,我可以当庭释放。人性如此不可靠,综合判断的话,还是说最保险,保不齐还能当庭释放呢?不如赌一把。
这就是我全部的如意算盘,可惜,另一个囚徒他又不傻,他也会这么想。于是,利益最大化的可能性变成了永远不可能达到的彼端。而10年这个选项变成了我唯一的下场,也是我们双方唯一的下场。这个次坏的结局被称之为双输。我们追求的利益最大化的那一点被称之为单赢。而每人都得到次好的那个看起来更不可能的选项被称之为双赢。
这个故事中其实并不虚幻,现实中的我们都是这样的囚徒。想想日常中遇到的一些类似的情况,真的是非常的熟悉。
现实中的情况复杂一些,可是道理相同。我们每个人都追求自己的利益最大化,可是长远来看,最大化的利益或不曾降临,或稍纵即逝。我们最终得到的只有那个次坏的选项。不过还好我们还可以合理化,安慰自己说,总算没有到最坏的结果。但实际上我们明明可以到达双赢的结局。
从刚知道这个故事的时候,我就发觉工作中的情况与此非常类似,于是我想,应该找办法摆脱这个困境,远离双输,通往双赢。我觉得,凭借敏捷方法我可以不用陷入这个困境。可是我错了,以前的困境拼图并不完整,敏捷方法恰恰是补完了这个困境通向双赢的那最后一块拼图,至此一个完整的囚徒困境才算是建立完成了。有诱惑,有陷阱,有希望,于是也就有了困惑。于是,困境始成。
在这个困境里,企业那点道道,就不说了,大家都很熟悉,可是作为我们程序员,就多么高尚吗?
敏捷要求全能小团队,可对于程序员来说,只干自己擅长的那一摊事,然后拿工资是利益最大化的选择。抽空还能自己学点东西提升一下自己。或者聊聊天、泡个论坛、玩个网游什么的。我们自己做出了并不比企业高多少的选择。通过双方的不懈努力,终于,企业和我们达到了双输的结局。简直就是悲剧。悲剧一再上演着,却没多少人太在意,至少大家都可以安慰自己说,总算没有到最坏的结果,一定是哪里做的不够好,再改进一些会好的。可惜,自然规律是很无情的。你做了这个选择,就只有这个结局,于是悲剧一再上演。
没有解决的办法吗?有,当囚徒困境不是模型里的单次博弈而是多次博弈时就有解。可以采用一报还一报的方式,当一方选择个人利益最大化的选择时,那另一方也选,直到对方放弃。也就是不停的双输,并且沟通,直到大家一起回到双赢境地下。这就是囚徒困境的唯一破解之法。只可惜这个方法也有问题。第一个选择个人利益最大化的人会在这个方法中获利。如果利益比较大的话,反复几次,他就可以有机会破坏这个平衡,将双赢博弈再次变为零和博弈。所以,惩罚机制也是很需要的。
方法有了,可是模型毕竟是模型,现实比这复杂得多。在囚徒困境之外,你会发现,还有团队这个群体存在。当一个人做选择很容易,当一群人做选择的时候,就很难了。按照大众心理学的说法,群体几乎是没有意识的。所以这个时候,我是只能感慨个人的渺小了。
价值,所有的方法学都会指向这个词。
可是所谓的价值,有的时候说得清楚,而有的时候很难说得清楚的。客户说出来的清楚,但有可能根本不是他最需要的。如果天下的人都清楚的知道自己要什么,也许也就不会有什么方法学了。
就考虑我们自己吧,我们想要什么?钱,没错,谁都需要钱。但要钱干吗呢?在钱的背后是我们追求的价值。大家都想让自己的价值得到体现。可是这简单的一句话在每个人身上却有不同的含义。
客户提出需求的时候总是欲求不满的,仿佛跟上帝许愿一般。可是我们毕竟不是上帝,只是勤劳的工匠。工匠是一种介于艺术家与科学家之间的职业,是兼顾感性与理性的一群人。在我们的身上有像艺术家一样追求超越自我的性格也有像科学家一样锲而不舍追求真理的性格,制造出对人们有用的工具是我们最大的价值体现吧。可复杂的现实,让我们这么利他的追求也难以实现。
红警、星际、暗黑。还有人记得当年的这三个伟大的作品同台竞技的那个时代是怎样的情景吗?
不记得也没关系,因为这个时代又要来临了!
这次是红警3、星际2和暗黑3.哇咔咔,未来的几年不会太无聊了。不要太沉迷于游戏中才好,呵呵。
昨天,盖茨离开了微软。对我来说那一天只是一个普通工作周的结束,对微软来说,却是一个时代的结束。
用盖茨大叔的操作系统的历史跟我接触电脑的历史一般长。从最早的dos到win32到win95、98、me、xp、2000、2003、vista。我几乎用过微软的每一代操作系统。经常会骂微软垃圾,可我也从来没掏钱买过正版操作系统,这种骂多少有点龌龊。
时隔若干年之后,总算我也用上了正版的windows(笔记本送的Vista)。回想起来,一些往事不由得浮上心头
最早的时候接触的dos已经记不得是哪个版了,286时代的,而那个286电脑大概长成这样:
但是开始正式学的dos应该是6.22的:
那个时候装机只需要一张5存盘:
后来才有的3.5寸盘:
那个时候盘经常坏,所以3.5寸盘的塑料盒和5存盘的纸袋是很重要的东西。
后来,接触到的第一个图形化的操作系统是windows 3.2,那个时候我并不知道apple是什么:
操作起来大概是这么个感觉:
没有任务栏、没有开始菜单,非常诡异。再后来的,就是windows95了吧:
win95的界面比较经典,可以看出来现在的windows界面相比win95其实没有太大的变化:
当时的游戏大多都是在dos下的,机器内存又小,为了玩游戏需要切到dos下,关掉95。即便在这么困难的环境下,依然有伟大的作品诞生:
。。。。
那个时候,很多游戏的安装需要靠一个叫arj的解压工具:
中间还有一个改进版的95,被称之为win97,至今我也不知道到底有没有那么一个正式的97出现过,反正很快,98就诞生了:
回想起来,那年开始,我接触的游戏开始变多,我永远忘不了我看到星际的时候的感受:
在那个时代,还有一个称得上传奇的病毒---CIH,以其可以对电脑造成物理伤害而闻名:
98是一个及其不稳定的操作系统,解决98里一些较大问题的唯一法宝往往就是重装,也许正是因为他如火凤凰一般的再生能力,一直到2000和xp诞生之后都有人选择他做自己的操作系统。
而win me。。。很多人根本就不知道他的存在:
不知道现在有几个人知道win me安装完第一次启动时必须忍受那个开机动画的事。再后来就是2000了,其实在win32时代就有windowsNT,微软用它在服务器市场里战斗,不过我个人并没有用过,windows 2000是我接触的第一款微软的服务器级别的操作系统:
到了windows 2000之后我对微软的怨言已经少很多了,呵呵。之后微软家族的产品越出越好,只不过漏洞和病毒依旧多不胜数。XP和2003就不回顾了,反正他们还不算历史。看看前面的这些东西,想想盖茨大叔的退休,该说些什么呢?私底下骂了微软若干年了,反过来看,微软也给我带来了很多乐趣。也许,应该对他说一声,谢谢。
前些天跟朋友聊天,聊得很激烈,我也收获很多。
中间聊到过程,朋友认为,管理的最高境界应该是没有过程,但仔细一问发现,还是有过程的,只不过是一些更人性化的过程而已。结合我另一些朋友的观点,看来“过程”这个词有点招人恨了。(当然如果是瀑布式的过程的话,我会第一个跳出来恨的,:P)
我一直认为过程这种东西,做不好就是枷锁,做好了就是铠甲,让你在工作中左冲右时保障你的安全。这次敏捷大会跟o6z聊天时,他说,虽然他老说敏捷,但他
其实是一个很偏好重型过程的人。其实还是我的那个比喻,只不过重型的铠甲也是铠甲,更适用于直线冲锋陷阵的重装骑兵,但是你要是随便找个步兵团队来配上重装骑兵的铠甲,估计还没打就被压死了。
关于过程这个东西,很有趣。既然想到这了,就像抽取一些自己的零散思维放上来。
我琢磨XP有很长一段时间了,Scrum也看了一段时间,就个人来说,不是很喜欢Scrum。总觉得这个东西天生带有一点滋生官僚这种细菌的潜质。常听说
XP没有管理的内容,Scrum在这方面做的更好。可我还是觉得Scrum没提供什么东西,完全可以把Scrum的一些东西吸收到XP中,结合自己的团队
实践搞一些混合敏捷(Hybrid
Agile)。因为Scrum在管理方面做的东西并没有多少,实在算不上盔甲,顶多是个盾牌。比较起来,XP的话,倒是有丰富的价值观和配套的实践,在吸
取了它的一些本质的东西之后集合公司实际做一些定制化的管理框架更好。
下一步准备研究一下FDD,再考虑跟前面俩方法混搭一下。我感觉这搞过程越来越像J2EE开发了:Struts + Spring + Hibernate一样的玩法。
第110集的银魂非常的搞。桂入狱了,而且是号称从未有人逃出来过的监狱,里面关的都是罪大恶极的人,但是入狱的领袖到底还是领袖,很快他就成为了监狱中的老大,并且给这些终生无望的人带来了改变,每天的劳改变得不再无聊,人人都有了目标,脸上都洋溢着希望,乏味的人生从此有味道起来。。。。。当然,这终究是一部搞笑的动画片,前半截不管铺垫的怎么热血,最后一幕还是抖出包袱:前面只是阴错阳差得演了一场各怀鬼胎的阴谋闹剧。。。囧rz
虽然是搞笑的,但是那些洋溢着希望的脸,却在脑海中怎么也驱之不去。监狱是人生的地狱,那里的色彩只有一种---灰色。如果是终生监禁,这种颜色还会伴随你一生,成为你余生的主色调。进入监狱的人,在第一夜关灯的刹那开始明白,自己的人生从此完了。彩色的世界已经离自己远去,剩下的时间里只有单调的监狱生活,不会再有希望。在那个世界里,几乎不会有那样的神情、那样的脸,只有充满戾气的脸才跟那个环境般配。当这个动画以夸张搞笑的手法把一张张这样的脸呈现在我眼前的时候,我的第一感想竟然是羡慕。。。。
是啊,羡慕。我惊奇的发现,希望在我的词典里被挤到某个小角落很久了。感谢一些人,让我看透了一些事情。同样也亏得他们,我开始不再抱有幻想,变得更加理性,虽然人生不再有明确的方向,却敢于迈出自己坚实的脚步。这种没有方向感的自信我不知道是什么,但是在这种自信的世界里,没有希望的存在。偶尔升起的希望很快会被我的理智所设下的“幻想侦测系统”预测到并驱散。(目前这个系统的误杀率还真不是一般的高啊。)
走在地铁站中,看过往的人群,有各式各样的脸,有幸福的、有木讷的、有暴戾的、有冰冷的,也有洋溢着希望的,对于见过的部分人们,说实话,真的有很多看起来充满希望的,不过有些是因为没心没肺,有些不好说是因为勇敢还是无知,或者说不准是因为无知而勇敢,更多的是让通过一种眼不见为净的手法,让自己的人生有希望起来,可是当真想到未来时,总会有一阵阵恐慌。
我想,希望这种若有似无的东西,看起来很没有价值,实际上却可以很有价值。一个人生活中充满希望,那么他是幸福的,他就会有安全感,工作也会卖力许多。有什么理由不给人们带来更多的希望呢?如果我们的团队被希望所笼罩,我们的团队就会有更大的活力。对于软件这个行业,非常需要注重人。希望,是对人非常重要的一个东西。那么我们的团队建设者们,是不是也应该注意一下这个东西呢?
早在工作之前,就有学长们、老师们谆谆教导说,语言不要贪多,学一门语言学到精,其他语言再学就很容易了。
我是这么做的,而且,做的有点过。很长时间里都扎在Java的世界里不肯出来,找开源工具也一定要找基于Java的。最早找一个Wiki都执意要找Java的,找到了JSPWiki。也因此认识了BeanSoft和Java Ajax群的朋友们,呵呵。
但是,随着开发任务的变化,不得不去学一些其他的语言。没办法,人在江湖身不由己啊,所以,也就开始了多门语言的学习之路。javascript可以说是我学的第一门“外语”。最早的时候对js的应用,也就简单用一下得了。后来随着时间的推移,觉得将来脱不了要靠它吃饭,也就主动买了几本JavaScript的书,慢慢的去啃,甚至啃到了很多对我没什么用的高级的特性,再后来工作需要,接触了Flex,js用的就少了,也就慢慢的放下了。
ActionScript是我接触的第三门外语。也是用心比较大的,呵呵,很长一段时间里甚至热情超越了Java。中间根据个人兴趣还看了点Ruby。
随着实践的增多,对语言的恐惧心理下降了。反而发现了各个语言所在世界的优势。每个语言所在的世界里都有非常优秀的东西。最早想做一个手脚架,看了一下Rails,是基于Ruby的;为了测试Flex,研究了FunFX,也是基于Ruby的;前不久在部门里搭建了一个wiki,是基于PHP的;这段时间又研究了一下Trac,是基于Python的;研究Trac的时候发觉它可以跟Bugzilla集成,而Bugzilla是基于Perl的。这么多优秀的东西,让我觉得学习多门语言的困难变得无所谓了。
上次去OpenParty,参与了郑晔的那个session。他讲了自己在项目中使用多种语言的经历。其实很有趣,作为只会一种语言的人来说,他觉得学多门语言会让自己泛而不精,然而真正掌握多门语言的人却发觉,他山之石可以攻玉,当你学会别的语言之后反过来在使用以前的语言的时候,思路会变得异常开阔。不管是对设计模式的领悟上还是对架构的组织上,都达到了一个更高的高度,反而更加精深了。
回来后,我也想了很多。记得早前看o6z一个帖子讲,SOA之所以风行,很大原因是因为企业已经积累了一些设备和软件。因为金融风暴也好,因为经济衰退也好,因为成本考虑也好,因为这这那那也好,不想统一成一个,需求决定供给,所以SOA才风行起来。那么这样一个环境对我们开发人员的会不会有什么影响呢?而且开源风行的今天,我们的软件行业也已经积累了一批财富。我们业内的人,也是不想统一替换成一类语言的,那么市场上的需求会不会慢慢变得要求我们程序员必须掌握多种语言呢?其实现在已经这样了,我就是一个例证,我的变化不是我主观想这么做的,而是一只看不见的手---市场推动的。不过我个人预测未来可能会更严重,如果JVM成功变成一个可以跑各种动态语言的超级平台的话。
疯泉的故事一直困扰着我---相传,有一个国家,有一口疯泉,喝了泉水的人都会疯,很快全国人民都疯了,只有国王是正常的,在国民眼中看来国王是不正常的,其结果就是国王被灌下疯泉水,成为了疯子,全国狂欢。作为旁观者看来,你告诉我,国王是对的?还是国民是对的?
可是跟所有的故事一样,故事总是只强调问题的一方面,我反过来讲这个故事,如果全国人民都没疯,就国王疯了,国王认为,不行,全国人民得跟我这样,于是想法设法让全国人民喝上疯泉水。那么现在作为旁观者你告诉我,国王是对的?还是国民是对的?
现在有一个国家,有两口泉,一口是疯泉,一口是醒泉。喝了疯泉的人会变成疯子,喝了醒泉的人会变成正常人。最早国家的人全变成了疯子。机缘巧合,国王喝下了醒泉。清醒过来的国王想让国民都醒过来,想让国民喝醒泉。而国民发现了国王与自己不一样的地方,于是将国王灌下疯泉水,国王再次疯了。那么现在作为旁观者,你告诉我,国王是对的,还是国民是对的?
其实三个问题都挺简单的,第一个:国王是对的,第二个,国王是错的,第三个,还是国王是对的。可是,我现在再给旁观者的你一个新情报,三个故事是一件事,只不过是三个人讲的,所以出现了三个版本。其实我还能讲一个故事,就是把第三个故事反过来讲,大家自己想去吧,相当于第二个故事的扩展版。如果是这四个故事一块看,你说谁是对的呢?是“群众的眼睛是雪亮的”呢?还是“真理掌握在少数人手中”呢?
如果到现在你还没有被我绕晕了的话,应该心中还能响起柯南的那句话:“真相只有一个”。没错,所以你只要找到那两个泉,搞清楚到底哪个是醒泉哪个是疯泉就好了。真理,自然就知道是掌握在谁手中了。继而也就可以证明国王是对的,还是国民是对的。
可是,事情没有那么简单,你率领的观察队发现,两个泉水是两口魔泉,你喝下一口泉水的水,你就有拥有了一种价值观,喝另一口泉的水,就拥有了另一种价值观。两种价值观是对立的,但是,谁知道哪种是疯的呢?事情变得更复杂了。。。难道在这个事件中我们无法证明什么吗?诶,还真有一个,你证明了,这个国家有两口魔泉,不是一口。
这世界上有很多事情就是这样,扑朔迷离的,就算最终谜底揭晓,发觉反而不知道对错了。可是如果我们一开始就知道这些,我们就能知道对错了吗?还是不知道啊。不过呢,这种问题,我们苦恼,精英们比我们更苦恼。早在我们考虑之前,精英贤者们就在考虑这些问题了,并得到了一些结论。最早的时候,老子就说,有错才有对。这说法比较言简意赅,乍一看就是句废话。我以前也觉得他是句废话,知道有一天看到了另一句话,才明白他老人家的微言大义。这句话就是:“可以被证伪的命题才是科学的命题”。这话听着跟我们日常里对科学的印象不太一样呢,我们常说,你这个说法不科学,那意思就是不对。科学当然是对的,证伪,证明是错误的,那种东西怎么能算是科学的呢?可惜,事实正是如此,所有科学的命题都是可以被证伪的。科学也正是因为信奉这一条原则,所以才可以自我修正,自我进化,以致今天的高度。
所谓可以被证伪不是说这个东西有错误,而是说,你这个命题天生带着可以被推翻的情况出生的。比如,曾经有人怀疑进化论的科学性,说你这个东西无法被证伪,进化论的拥护者就说,你只要找到一批侏罗纪的兔子或者猩猩化石什么的,那么进化论就被证伪了,因为进化论说物种的进化一定是从低级到高级。这种情况,我们称之为可被证伪。指一个命题能够被推翻。什么是不可被证伪的呢?比如说什么是美的,我们常说情人眼里出西施,那美自然是无法被证伪的东西。艺术的东西,大都是无法被证伪的。无法被证伪的东西,自然没有错误,没有错误的东西自然就没有正确。像这样的东西,就不要追求什么对错了,硬要追求,只有自讨苦吃。
前一阵跟一做企业文化咨询的哥们混了一阵,从他那瞅见一书,挺有意思。叫《公司基因》,看着不错就买了。
这OpenParty是不兴推荐书了,下次再有机会就推荐这个。
这书里认为企业文化不管怎么变,他的DNA都是由四个元素组成的,即:组织架构(原词是structure)、决定权、信息、激励机制。
它根据这四个元素把企业分成了七种类型
- 消极进取型
- 时进时停型
- 过度膨胀型
- 过度管理型
- 随机应变型
- 军队型
- 韧力调节型
其中前四者看名字就知道不是什么好东西,书中也定义为不健康的企业。后三者,虽然都算是健康的,但最好的其实是最后一个。
敏捷常常被说是一种文化,我也这么觉得。所以,我最近一直让自己从这四个角度看敏捷的方法学。分析来分析去,反而搞不清敏捷应该塑造一种文化,还是某种文化是维持敏捷的土壤。有点鸡生蛋蛋生鸡的意思。不过不管哪个生哪个,如果目的是养鸡,那谁先谁后就不是我关心的了。
这本书前面部分写了太多关于案例的内容。没有足够形象的讲解Scrum。也没有充分描述Scrum的假设、适应情况和不适应情况。讲Scrum的风格跟微软的讲师讲座倒是真挺像。
书中的Service1st公司的案例跟我们部门的情况极其相似。最后他也没解决,只是说Scrum在现有的形势下带来了什么好处,有些失望。不过仔细想想,这个团队的问题不是软件开发方法的问题,而是企业文化的问题。所以Scrum解决不了是意料之中的。
但是这本书,说实话,不是特别经典的一本书,大概看看吧。
敏捷是以消除浪费、提高质量为目标的。但是有些时候总能见到一些原教旨主义者指出,重构也是浪费、结对也是浪费、讨论也是浪费。然后呢,又有人提出,XX是必要的浪费这种说法。
想了一下,XX是必要的浪费这个说法其实不确切,只能说,这些东西是必要的成本支出。所谓浪费,必须从经济学角度讲才行。不然世间一切都可以带上这个难看的帽子。
从牛博网最近新来的骗银老师那里学来一个概念:“经济学上有个奇怪的概念叫‘冤死的损失’(deadweight loss),英文的直译是‘未被释放出来的能量损失’,那是说,有一部分损失,...”谁也没拿走,“...但因为效率原因,它就那么凭空损失掉了。”
因为听起来很玄,为了让大家更好理解,骗银老师在后面讲的一个非常耳熟能详的例子:
“
我雇了一帮人,天天就负责刨坑,刨了然后填上,然后再刨开,再填上(这例子不荒谬,中国随处可见),我发给他们工资,这一来一往国民生产总值(GDP)就上去了。看起来谁也没损失什么,对不对?只是简单的财富转移。其实不然,这里面有巨大的浪费,因为这些钱、这些劳力本来可以用在其他更为有效的生产上,可都用来刨坑了,那就是浪费。”(其实个人这个例子还不够形象,如果挖坑和填坑的不是一批人,他们自己根本就不知道自己做的是浪费的事情,就知道干了活,拿钱,而且还为挖坑和填坑做了很多过程改进,提高工作效率。那就更形象了。)
所以说,您不能因为某些工作做了您能看到效果了,就不称之为浪费,而有些工作做了您看不到效果就称之为浪费了,应当反思一下是不是自己眼界不到。
离职将近,我在交接工作之际,因为我最熟,所以要我把依赖我负责模块的其他模块的适配器类改至新版。自己搬着Mingle写了一些故事卡,又用CC写了一
些持续集成的脚本。接下来,我还会去写测试用例。整个过程中,没有一行有效代码的产出。在以代码计绩效的角度看,我的工作就算是浪费。可是,大家应该知
道,没有这些东西,先不说我会不会在开发的时候保证质量。就说我离开以后,当产品质量出问题了,谁来保证?我可以根据异常一眼看出问题可能出在哪里,新接手的人能吗?如果他改了程序,能保证不会按下葫芦起来瓢吗?他需要时间去犯错去学习,这个时间,没有产生新的价值,这才是真正的浪费。而且这也就成了挖坑-填坑的模式了。
问题反过来了,我做好这个CI的环境走了,来了一个新人接手,会怎样?一天,系统报异常了。他有我的测试环境,而且,还是可以运行的。他可以很快的写一个测试用
例,并开始调试,即便他无法理解整个设计,那不妨碍他快速的修复Bug。而且,因为以前的测试用例可以自动运行,他还可以保证自己的修改不会导致之前的功
能出现问题。一个为产品而组织的团队,离开了某个特定的人,产品仍然可以自我完善,能完成这样的目标的手法才是最有价值的。
很多人担心前期花费的时间太多,后期就更没时间,问题又来了。前期花费的时间多,是浪费掉了,还是合理的用掉了?如果是浪费掉了,自然不应该,如果是合理的用掉了,那是必须的。我们学软件工程的时候都学过,一个问题发现的越晚,改正他的成本就越高。后期所谓的没时间,就是因为前期太多问题没有修正。
说道这个前后期的问题就不得不提最近一次结对的经历。在我的坚持下,总算完成了一次与同等水平开发人员的结对编程。持续时间有三天。与同等水平的人结对,感觉是不一样。也发现了很多以前没有发现的问题。这都是个人问题,脱离我本人就没有意义了,所以也就不说了。主要说一下心得。这三天的时间里做了一件什么事呢?推翻以前分成两个模块的应用,合成一个。两个人做一件事,大家可以随时根据今天剩余的时间做工作的调节,精确到小时。因为了解的信息不同,可以快速传递,合作互补,当他提出一方案的时候我可以快速告诉他,我这边没有问题,减少了尝试造成的时间浪费。因为两个人一起做,脑子根本停不下,一个人停了,另一个人还在转,带着你不得不进行。一天的有效工作时间在6小时以上。而分开的话,基本上能有3个小时就不错了。
(中间发生的一点插曲。因为结对开发从不了解的人看来,是一件很浪费时间的事情。所以出现干预结对的现象出现,理由是担心做不完。我觉得,如果不是坚持的话,就真的做不完了。从现实中看来,强调浪费,很容易被偷欢概念。而偷换概念的人很多人都没有做过仔细的考虑。纯粹的想当然。)
今天公司过了CMMI 4级,5级没过,听老外讲述什么是5级也就是说什么是持续改进以后,感觉到CMMI的持续改进和Agile的消除浪费其实是一枚硬币的两面,持续改进就是消除浪费,为什么这么说呢?CMMI的持续改进本来就是高级别的过程域,那个时候指望重大变革基本就不靠谱,所以这个时候,看不管哪个行业,都会走向消除浪费的方向,软件开发也不例外。CMMI的持续改进要求一直做一直做,那跟敏捷要求的追求精益的观点是一致的。
CMMI认为通过4级的度量形成了稳定的过程之后,5级就应该是对4级过程的不断改进,什么时候看,都是不满足的,值得修改的。那种精神不正是敏捷的世界观吗?CMMI给出了一堆过程域和目标,并没有告诉我们怎么实现,Agile就更粗狂,不过大家提到Agile其实想到的是XP。所以觉得Agile就是一堆实践而已,没关系,不去争辩这个问题。我就看XP,XP的那12个最佳实践,跟CMMI的思想一点都不矛盾。(细节不可考,因为很多时候我很难清到底是CMMI里面就定好了这细节还是我们的EPG定的)。以前的时候只是粗略的感觉这两者可以不矛盾,现在培训过后,更证实了这点。
============
缩写解释:
Agile 敏捷
CMMI 能力成熟度模型集成
XP 极限编程
EPG 企业过程小组
不知不觉做这个产品已经一年了,其实除了技术积累,对这个产品的概念基本是处于原始阶段。虽然早已经过了企业内容管理与网站内容管理的疑问阶段。但是内容管理本身是对企业有什么价值,问了很多人。很多人的回答都不让我们满意,因为他们回答的其实是工作流有什么价值、OA有什么价值、文档管理有什么价值、ERP有什么价值。
昨天听一位曾经实施过FileNet的同事说了一句话才明白过来这个东西的价值在于“提供一种海量非结构化异构文档的查询服务”,其余的都是在其之上的附加价值。
价值有了,可是越看越没底:“海量”、“非结构化”、“异构”仅一个关键字就够麻烦的了,三个拼一块。。。很好,很强大。。。。。
这两天为了Fluorida的closePopUp功能,读了点Flex框架的源码,对Alert,TitleWindow以及Flex的PopUp功能做了简单的分析。
【Alert和PopUp】
Alert内部其实是调用了PopUpManager.在parent参数为null或者为Application的时候,弹出的窗口将跟当前Application在一个容器下。Alert在最顶层,Application在最底层,中间那层是一个称之为modalWindows的控件,其实就是Alert后面那个磨砂的层。为了点到Alert上的按钮,写了一个小程序分析Alert的结构,不是很好读,但是可以运行一下,看看分析出的Alert的内部结构:(大略说一下,Alert的Child有一个AlertForm,而AlertForm的Child除了第一个是TextField以外,都是按钮)
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
<mx:Script>
<![CDATA[
import mx.core.IChildList;
import mx.core.UIComponent;
import mx.core.IFlexDisplayObject;
import mx.managers.ISystemManager;
import mx.managers.PopUpManagerChildList;
import mx.managers.PopUpManager;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.core.Singleton;
import mx.managers.IPopUpManager;
private function showSimpleAlert():void{
Alert.okLabel="oKey";
Alert.show("Hello, World!","",15,null,alertCloseHandle);
var myTimer:Timer = new Timer(1000, 1);
myTimer.addEventListener("timer", timerHandler);
myTimer.start();
}
private function alertCloseHandle(event:CloseEvent):void{
simpleAlertShower.label = event.detail.toString();
}
private function timerHandler(event:TimerEvent):void{
var text:String = "elements:";
var sm:ISystemManager = (Application.application.root as ISystemManager);
text+=sm.numChildren.toString();
text+=";\n modalWindows:";
text+=sm.numModalWindows.toString();
for(var index:int = 0; index < sm.numChildren; index++)
{
text += "\n" + index + " : ";
text += sm.getChildAt(index).toString();
}
var alert:Alert = sm.getChildAt(sm.numChildren - 1) as Alert;
text += "\n buttonFlags : "+alert.buttonFlags;
text += "\n alertChildren:" + alert.numChildren;
for(var index:int = 0; index < alert.numChildren; index++)
{
text +="\n" + alert.getChildAt(index).toString();
}
var alertForm:UIComponent = alert.getChildAt(0) as UIComponent;
text += "\n alertFormChildren:" + alertForm.numChildren;
for(var index:int = 0; index < alertForm.numChildren; index++)
{
text +="\n"+index+":"+ alertForm.getChildAt(index).toString();
}
popupChildText.text = text;
alertForm.getChildAt(1).dispatchEvent(new MouseEvent(MouseEvent.CLICK));
// var popupContainer:IChildList = (application.root as IChildList);
// PopUpManager.removePopUp(popupContainer.getChildAt( popupContainer.numChildren - 1 ) as IFlexDisplayObject);
}
]]>
</mx:Script>
<mx:Button id="simpleAlertShower" click="showSimpleAlert();" label="Click Me"/>
<mx:Text id="popupChildText"/>
</mx:Application>
【关于TitleWindow】
TitleWindow作为弹出窗口的时候,跟Alert处的位置没什么区别,我想说的是TitleWindow的closeButton在哪里。下面这个同样不好读的程序可以帮助你分析TitleWindow或者说Panel里面都有用什么,以及closeButton在哪,其实就是在rawChildren的最后一个。
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="horizontal">
<mx:Script>
<![CDATA[
import mx.containers.TitleWindow;
import mx.core.IChildList;
import mx.core.UIComponent;
import mx.core.IFlexDisplayObject;
import mx.managers.ISystemManager;
import mx.managers.PopUpManagerChildList;
import mx.managers.PopUpManager;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.core.Singleton;
import mx.managers.IPopUpManager;
private function showSimpleAlert():void{
var popUpWindow:TitleWindow = TitleWindow(PopUpManager.createPopUp(this,TitleWindow,true));
popUpWindow.width = 400;
popUpWindow.height = 300;
popUpWindow.visible = true;
popUpWindow.showCloseButton = true;
var myTimer:Timer = new Timer(2000, 1);
myTimer.addEventListener("timer", timerHandler);
myTimer.start();
}
private function alertCloseHandle(event:CloseEvent):void{
simpleAlertShower.label = event.detail.toString();
}
private function timerHandler(event:TimerEvent):void{
var text:String = "elements:";
var sm:ISystemManager = (Application.application.root as ISystemManager);
text+=sm.numChildren.toString();
text+=";\n modalWindows:";
text+=sm.numModalWindows.toString();
text+="\n top children: ";
for(var index:int = 0; index < sm.numChildren; index++)
{
text += "\n" + index + " : ";
text += sm.getChildAt(index).toString();
}
var titleWindow:TitleWindow = sm.getChildAt(sm.numChildren - 1) as TitleWindow;
text += "\n popUpWindowrawChildren:" + titleWindow.rawChildren.numChildren;
for(var index:int = 0; index < titleWindow.rawChildren.numChildren; index++)
{
text +="\n" + titleWindow.rawChildren.getChildAt(index).toString();
}
var titleBar:UIComponent = (titleWindow.rawChildren.getChildAt(2) as UIComponent);
text += " has " + titleBar.numChildren;
text += "\n" + titleBar.getChildAt(3).toString();
popupChildText.text = text;
// var popupContainer:IChildList = (application.root as IChildList);
// PopUpManager.removePopUp(popupContainer.getChildAt( popupContainer.numChildren - 1 ) as IFlexDisplayObject);
PopUpManager.removePopUp(titleWindow);
}
]]>
</mx:Script>
<mx:Button id="simpleAlertShower" click="showSimpleAlert();" label="Click Me"/>
<mx:Text id="popupChildText"/>
</mx:Application>
最近的一个月事情真不少,公司内:要过CMMI,公司外:活动接连着就有俩。接连参加了OpenParty和RIAMeeting之后觉得自己应该总结一下了。
上次的OpenParty质量奇高。从那里学到了很多知识,从gigix那里学到基础的价值,在session的学习中还顺带自己想明白了迪米特法则的价值,了解了坏的制度是如何作用于公司氛围的,亲眼目睹到设计欠债的后果,以及补救仅能做到的程度有多高。从Tin哪里学到界面开发过程方面的一些非常优秀思路,今天参加RIAmeeting的时候还讨论了更细节的开发人员和设计人员配合的问题。这次的好topic太多了,只能挑着最感兴趣的听了,次感兴趣的其实也很想去听得,比如精益、CMMI & Agile、巨富客户端,这一说起来好像哪个都想听了,但只有在好看簿上看了,这种不完美别有一番吸引力,还有些没选上的topic其实也不错的。希望下次有机会听到。Open Party给我的东西太多了,每次想说的时候就被教育一次自己的语言能力有多贫乏。
这次RIAmeeting也不错,见到一些老朋友,也见到了没有见过面的朋友。而topic呢,说实话,我已经过了对技术普及的topic感兴趣的阶段了。所以两个主要的topic都不是很吸引我,而这半途蹦出来的一位90后的小兄弟贡献的topic给了我不小的震撼,他的作品虽然还有点稚嫩,但是可以看到很多创新点和一些真正的产品级设计。看到了一个如此鲜活,没有被教育体制的“压模机”残害过的头脑,感觉真是不错。(脑子中闪过“炸学校”短片里的那个压模机)一年、3万行代码,高二,这几个关键加在一起,让我觉得这个小兄弟的时间管理能力应该不错,于是问了一下,他还真给出了一个时间表,很有意思。会后的讨论也很有趣,大家就美工与开发人员如何配合展开了很深的讨论。那对美工与程序员的搭档给我留下深刻印象,他们说的一些话体现出来态度让我仿佛看到了一个优秀的团队,尤为欣赏,尤其那位美工那种追求更高效交流以期减少浪费的“敏捷”态度在美工中真的是非常少见。(说实话,程序员中这种态度也不忒多见)
两个活动都参加之后,个人比较来看,Open Party比RIAmeeting精彩,大概是因为RIAMeeting更像是Flex的传播活动,偏向普及,缺乏高级点的交流,而OpenParty则是从业人员的经验交流,门槛稍微高一点。其实对于线下的交流我还是比较喜欢门槛高一点,那样比较过瘾。
【花絮】
在OpenParty上我们讲解了FunFX之后。熊节跟我说他刚才也做了一个自动化测试的框架。虽然我已经把敏捷和熊节这两个词关联起来很久了,但是这等速度还是让我吃了一惊(导致现在我还在怀疑是不是我听错了,
已经证实。。。我听错了)。那个框架当天就被熊节发到了google code上,当时他的名字是:
Fluorine,还写了一句很有趣的话:Fluorine makes your teeth FLASH。可惜这个名字有人用过了,现在改名为Fluorida。
Fluorida的原理说白了很简单,使用dispatchEvent的方式模拟操作,若干个月之前我也这么干过,当时是对这种方式的可行性表示怀疑的。在后来在Google code上下载了代码并阅读一遍之后,我开始觉得这个做法没啥问题。而且相比FunFx,他不需要Flex程序员再去学Ruby。今天很荣幸的加入到这个项目组中。
如今预览版--0.0.1版已经发布,广泛征集回馈和建议中,有任何建议可以到
http://code.google.com/p/fluorida/wiki/Announcement001 发表评论
======
主要相关报道及文章:
http://www.matrix.org.cn/resource/news/7cf0239a-ebe6-11dc-91da-b599c3ba16ef.html
http://dreamhead.blogbus.com/logs/16533990.html
http://gigix.thoughtworkers.org/2008/3/6/announcement-fluorida-0-0-1
项目地址:
http://code.google.com/p/fluorida/
这世界上有很多界限,有些是看的见得,有些是看不见的。看得见的界限我们想办法总能突破,而看不见的,则无法可想。
最可悲的是当看到本来看不见界限的时候,刹那的无力感会将自己的一切骄傲粉碎。
我很喜欢《亵渎》的一个词--位面。不一样强大的人们就像活在不同的位面。在一个位面里,没什么障碍是无法突破的,可位面间的界限,有时候你连他在哪都不知道。何谈突破。
像我这样从Java平台进入Flex平台的人经常会为ActionScript不容易实现某些设计模式(比如单例)而烦恼,跟我一样烦恼的人有福了,这里有一本很棒的书:
http://www.blogjava.net/Files/tj19832/flex/Adobe.Press.Advanced.ActionScript.3.with.Design.Patterns.Nov.2006.rar
这本书一定要读,一定要读,一定要读,不然开发的时候会犯很多错误,走很多弯路,产生很多错误的认识。后果很严重的:P
从来没有想过把“炫”这个词跟诺基亚的产品联系在一起,通常这个词都是给apple之类的公司的,但是在开始看这个视频不到30秒,我的观念就被彻底颠覆了。据说,七年之后,这款手机将上市。期待啊。。。。。
这就是我参加完第二次OpenParty的感觉,这次的topic有十几个。很可惜最后进行的只能有9个。我跟Thoughtworks的韩锴一起准备了一个关于Flex的session。没想到还得到最多人的支持。虚荣心得到极大满足,咔咔。
坐在里面,参与或主持Session,感受知识的传播与再造,那真的是一件非常快乐的事情。我可以感受到自己的成长和别人的成长。往大了说可以感觉到中国的软件界的成长,因为大家都是来自不同的公司,等大家带着知识回到公司,又会对公司成长产生作用也就一点点得对业界产生了作用。就像蝴蝶效应,虽然这是一只颇大个的蝴蝶。(PS:但是出了门没多远就看到Police坐着车慢游,顿时紧张是不是查证的,唉有推动力就有障碍么)
整个活动是idea的碰撞、搅拌。这种感觉遍布各个角落,经常看到session已经结束,但是思维的碰撞仍在继续。甚至这一期的OpenParty结束了,他的效果却才刚刚开始,一直绵延到很久以后。在那种氛围下,头脑在一刻不停的思考、汲取知识,同时不自觉的就想去跟人交流。这半天过得是非常充实的。
也正是因为前面的原因,等回到家中,兴奋劲稍微过去之后,大脑似乎才刚刚意识到累了。其表现就在于一回想白天的某一个topic,脑子里就爆炸式得蹦出一堆东西,有自己的想法,有别人的话,甚至当时的场景,一遍遍像过电影一样闪现,最终崩溃,所有的画面连不成一个有序的思维。于是打开优酷看美剧,同时上网跟人聊天,让大脑停止思考。这招百试百灵,这次也不例外。直到现在,好象才从中稍微的恢复过来。可也想睡觉了。。。。。。
我的操作系统是Vista Home Basic版,Adobe网站上有两个地方下载Flex Builder。我从http://www.adobe.com/go/flex_trial下载的怎么也装不上。而从https://www.adobe.com/cfusion/tdrc/index.cfm?product=flex下载的就能装(这个地址需要你有Adobe的id,注册一个就好)。虽然解压出来也是前一个的文件,但就是能装,实在是有点晕。不知道是不是vista都这德行,反正跟我一样装不上Flex Builder3的话,去后一个地址下载就可。
最近,Adobe发布了Flex 3和AIR 1.0。宣布一个新时代的正式来临。Flex的时代。
回顾多年以前,当它仅仅是Flash的时候,那时的它也可以运行在网页中和桌面上,大家觉得它很漂亮,仅此而已,那时的它只是个非常可爱的小玩具。不要说巨人微软没有注意到它身上隐藏的潜力,就连他现在的主人Adobe也对它不感兴趣。也正是这样,他在每一个平台上都很好的生存了下来。
在这个世界上,有另外一个技术,叫做Java。它以跨平台为理念,努力打造一个统一的软件世界。在后台,它取得了无与伦比的成功,可是在前台,它总是不那么顺利。我,就生活在这样的世界里。
日子一天天过去,Flex迎来了3.0。FlashPlayer9也占据了世界上94%的PC(如果算上以前的版本,这个占有率逼近100%)。而相比只下,JRE之占据了84.6%,在苹果和其他操作系统的冲击下,windows也降到了90%以下。毫不客气的说,FlashPlayer已经是世界上覆盖率最大的运行环境。昔日的星星之火开始呈现燎原之势。
今年,毫无疑问会有很多的开发人员转向或者开始接触Flex,中国的Flex资源还比较贫乏,不过已经有一群人在努力了。虽然已经有了AnyFlex,RIAchina之类的论坛,但是相比较传统的论坛,下面的几个更有特色:
以
Kenshin为首的人做的
RXNA是一个非常棒的Flex相关RSS信息整合站,类似国外的mxna
而
闲云野鹤则建造了一个Flex搜索引擎计划:
http://blog.eshangrao.com/index.php/2007/02/27/352-googleflex
以及同样是他搞得Flex Wiki计划:
http://blog.eshangrao.com/index.php/2007/05/12/390-flexwikiflex
还有促进线下交流的
RIAmeeting
有声有色的活动和网站正在一点点多起来,今年将是Flex星火燎原的一年。我对此充满信心。
所有关注Flex的博客上都在写这个,那我也跟风好了。
Adobe发布Flex 3和AIR 1.0的正式版。
在这个日子里我在干啥捏?配CruiseControl,尝试将持续集成引入我们部门,顺便,考虑CI in Flex的解决方案。
我人生的道路上,我在做的事情有意义吗?不知道。我的幸福是什么呢?不知道。我如此努力会不会是无谓的付出呢?不知道。我只知道,有一种力量在逼迫我行动,我不知道是在向前还是在向后。它让我很累,很充实,同时很失落。我今天的努力可能在明天被证明是无谓的。我正在做的事情也可能会在将来被我意识到是没有意义的。我的幸福,可能早已被我错过。但是我依然不能停止我行进的步伐,向着幻想中的希望前进。这,就是我的人生吧。
今天应用维基百科的程序搭建了一个wiki,想架设知识库的伙计们可以参考
部署方式如下:
下载Apache2.2,相关地址:
http://httpd.apache.org/ windows下要下载msi那个版本。双击将其安装在机器上,我选择的目录是:C:\Apache2.2。如果不想使用80端口,在安装过程中设置
下载php5,相关地址:
http://www.php.net/downloads.php 我下载的是windows的zip包那个版本,将其解压在c:\php下。
下载mysql,这个就不废话了。
安装完后,将C:\Apache2.2\conf下的httpd.conf打开,在LoadModule一组处加上LoadModule php5_module "c:/php/php5apache2_2.dll",在AddType处添加的
AddType
application/x-httpd-php .php 在LoadModule下面加上PHPIniDir
"C:/php"。把"c:/php"下的"php.ini-recommended"文件复制一份,改名为"php.ini",在php.ini中将
extension=php_mysql.dll
extension=php_mysqli.dll
两行前的;去掉。
将extension_dir = "./"改为extension_dir = "C:/PHP/ext"
下载wikipedia:
http://sourceforge.net/projects/wikipedia/
将所有文件拷到"C:\Apache2.2\htdocs"下
运行开始菜单里Apache Http Server下的Start Apache in Console
打开浏览器,输入:http://localhost:8080/index.php,在页面上点击 set up the wiki,页面跳转到:http://localhost:8080/config/index.php
输入wiki name,和Admin username的名称(默认是WikiSysop)和密码
配置mysql的属性,Database name,Database host,DB username,DB password还有超级用户的用户名密码
全部设置完毕后点击 install mediaWiki
完成之后,系统会提示你
Installation successful! Move the config/LocalSettings.php file into the parent directory, then follow
this link to your wiki.
将"C:\Apache2.2\htdocs"下的config/
LocalSettings.php拷贝到父目录里即可
===================
以上部署过程在vista下测试通过。那些安装路径都可以换掉,但是不要安装在Programe Files下。如果系统安全性设置太高的话,最后可能不生成LocalSettings.php
硅谷创业公司 BeyondMedia 高薪招聘 (北京)
BeyondMedia 是位于美国硅谷的一家提供媒体服务的互联网公司, 主要为美国所有的媒体和客户提供一个中间平台.
现在公司处于快速成长期, 希望在国内发展一个研发中心, 目前正在招聘研发人才.
本公司是一家正在快速发展的互联网公司, 公司为员工提供良好的工作环境, 具有吸引力的薪水以及股票期权, 履行正规的保险权益.
有意者,请发送中英文简历到
cnscud@gmail.com 邮件, 并请注明期望薪水,外语情况等, 谢谢.
以下要求仅供参考.
==============================
====
高级Flash工程师
主要工作职责:
* 和整个开发/设计团队协作
* 完成相关的Flash设计, 制作, 维护
* 其他相关的设计工作
* 编写相关文档
基本要求:
* 3年+工作经验
* 美术设计专业或有相关从业经验
* 熟悉Flash制作
* 熟悉Flash编程 (Flex, ActionScript等)
* 熟悉JavaScript, Html, XML
* 有网站设计经验更佳
个人:
* 能熟练阅读英文文档, 能编写英文文档更佳
* 良好的沟通能力, 能与团队紧密协作
* 富有责任感
* 能积极主动完成工作
* 善于学习
===============================================
高级网站美术设计师
主要工作职责:
* 和整个开发/设计团队协作
* 了解整个平台网站的结构, 对网站进行设计, 实现和维护
* 编写相关文档
基本要求:
* 3+年工作经验
* 美术设计专业或相关从业经验
* 熟悉Photoshop, Dreamweaver等相关软件的使用
* 熟悉网页的制作编辑, Html, CSS. (Div+Css方式)
* 了解欧美网站风格者优先考虑
* 熟悉Javascript更佳
* 熟悉Flash制作更佳
个人:
* 能熟练阅读英文文档, 能编写英文文档更佳
* 良好的沟通能力, 能与团队紧密协作
* 富有责任感
* 能积极主动完成工作
* 善于学习
高级J2EE软件工程师
工作职责:
* 和开发/设计团队进行协作, 了解系统需求,架构和设计
* 设计, 实现和维护系统平台
* 编写相关文档
技术要求:
* 4年+ 的J2EE应用开发经验
* 熟悉Struts2, Webwork或类似MVC框架
* 熟悉Spring和Hibernate
* 熟悉Javascript, Html, Jsp
* 有Ajax的使用经验更佳
* 数据库方面的经验, 例如数据库设计和SQL
* 熟悉Mysql, Oracle或者其他数据库
* 有Web services的使用经验更佳
* 熟练使用Java IDE, 例如Idea, Eclipse
* 了解Weblogic, Tomcat, JBoss或Resin的部署
* 熟悉Linux系统更佳
* 有网页制作编辑(美工)经验更佳
个人要求:
* 能熟练阅读英文文档, 能编写英文文档更佳
* 良好的沟通能力, 能与团队紧密协作
* 富有责任感
* 能积极主动完成工作
* 善于学习
===============================================
J2EE软件工程师
工作职责:
* 和开发/设计团队进行协作, 了解系统需求,架构和设计
* 设计, 实现和维护系统平台
* 编写相关文档
技术要求:
* 2年+ 的J2EE应用开发经验
* 熟悉Struts2, Webwork或类似MVC框架
* 熟悉Spring和Hibernate
* 熟悉Javascript, Html, Jsp
* 有Ajax的使用经验更佳
* 数据库方面的经验, 例如数据库设计和SQL
* 熟悉Mysql, Oracle或者其他数据库
* 熟练使用Java IDE, 例如Idea, Eclipse
个人要求:
* 能熟练阅读英文文档, 能编写英文文档更佳
* 良好的沟通能力, 能与团队紧密协作
* 富有责任感
* 能积极主动完成工作
* 善于学习
目前Flash是不支持运行时加载SVG的。必须使用Embed的方式。
已经有人向Adobe提出了请求,不知道什么时候才能实现了:
http://bugs.adobe.com/jira/browse/SDK-11619
目前来说,使用SVG就会增Flash的体积,用来做些Logo之类的小东西还可以,做别的还是免了吧。
用了twitter之后这些小小的心得都有点不想往博客上写了。
这两天用BlazeDS做个小软件,在用BlazeDS的时候发现,服务端的异常会被直接抛到客户端,去了我心里一个疙瘩。虽然我还不知道他给抛哪去了,是去了回调函数,还是在调用代码那里。不过他既然能抛回来,我就能处理咯,这都是小问题。
另外服务端返回的Java中的List,在BlazeDS中,都是给映射成了ArrayCollection。以后可以放心的处理了。
BlazeDS的文档还只有在线的,看着十分不方便,尤其是公司那个网速,整个就是拨号时代的速度啊。
BlazeDS文档地址:
http://livedocs.adobe.com/labs/blazeds/html/index.html
最终确定,这个东西是用flexmdi做的,而不是用的ventanas。不管用哪个,我都郁闷了一天,想不明白他是怎么做的旋转,结果看了代码发现,他把Flexmdi给改了。把人家的MDIWindow改成继承ViewStack的了,恍然大悟。。。。。
【前言】早在半年前的项目之处就想采用TDD的开发方式,最起码也要做到较完备的自动化测试。当时调研了很久找到一个叫FunFx的开源框架。可惜这个框架的试用之路并不平坦。最初找到的只有文档,照着文档做,失败了。看到文档上还是Flex2的,换成Flex2,编译都通不过,原来Flex2需要lcds的license只好回到flex3。被逼无奈去看代码,我的Ruby水平是二把刀,尽管改代码了,但还是通不过。怀疑是不是不支持Flex3,而且项目进度又容不得我们慢慢研究,只好自己写了一个功能有残次的测试框架,凑付着用,后来因为框架的扩展速度慢慢跟不上开发的速度,最终连写自动化测试用例的计划也放弃了。随着FunFx出了0.0.2,又对这个测试框架产生了一点希望,再次搭建的结果还是一度失败,经过不懈努力,总算在大年三十的下午运行了第一个Hello World!。
【正题:搭建TDD测试环境】(下面我说的过程是我个人运行的过程,应该是运行FunFx的充分条件,但不保证都是必要条件,如果有人发现哪个步骤是不必要的。请在回复中指出。)
FunFX是一个基于Ruby的自动化测试框架,所以,我们必须要装Ruby,我安装的Ruby版本是Ruby-186-26。我的Ruby IDE是eclipse上的RDT插件。我的操作系统是笔记本自带的Vista Home Basic,因此我的IE是ie7。我的Flex IDE是Flex Builder 3 beta3。
运行环境就这些,那么开始讲解搭建过程吧。我们从下载开始说起,首先,我们要去
RubyForge下载FunFx 0.0.2,那是一个zip文件,记得要把Source包也下载下来,在后面我会说到它的用处。
下载完毕之后,将其解压,我们可以看到三个文件:
- AutomationGenericEnv.xml
- FunFX-0.0.2.gem
- FunFXAdapter.swc
接下来,我们在FlexBuilder3中新建一个工程:LearnFunFx,在libs文件夹里加入下面三个swc文件:
- automation_agent.swc
- automation.swc
- FunFXAdapter.swc
这里面的前两个swc文件来自flex的sdk里面。后面的一个就是FunFx里面的swc,但是这个swc有可能是无法使用的,因为它是为flex 2编译的,这时就需要我们前面下载的源代码文件了。源代码文件解压开之后可以找到FunFXAdapter文件夹。里面就是FunFXAdapter.swc的源代码(包括测试代码)。将其编译成swc(如果你不会编译成swc,请查阅相关文章或自己琢磨,给你个提示,可以用library project)。将我们自己编译出来的swc文件拷到libs里。这样我们就收集全了所有的类包。
接着将AutomationGenericEnv.xml拷贝到src文件夹下,然后在LearnFunFx.mxml中加入如下代码:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
import mx.controls.Alert;
]]>
</mx:Script>
<mx:Button id="test" x="255" y="146" label="Button" click="Alert.show('Hello World!');"/>
</mx:Application>
代码实现的功能很简单,单击按钮,弹出Hello World!的对话框。
代码准备完了,接下来是编译了。下面我们在我们的工程:LearnFunFx上点击右键:选择Properties,再选择Flex Compiler,在Additional compiler arguments文本框中输入:-include-libraries "XXXX\LearnFunFx\libs\automation.swc" "XXXX\LearnFunFx\libs\automation_agent.swc" "XXX\LearnFunFx\libs\FunFXAdapter.swc"
XXX表示工程根文件夹,自己补齐。
接下来,一个囫囵的swf文件就被编译出来了。这里还有一个问题,html文件里面的Object标签一定要有一个name属性,其值要跟id一样,这就需要我们改html-template文件夹下的index.template.html了。我的做法是把body标签里的js代码删掉,只留下html标签版本的,然后在Object标签里面加上一个属性:name="${application}"。再次编译一个,将 bin文件夹下的所有文件拷到一个web应用中。
flex端的处理完毕了,接下来是Ruby,还记得那三个文件吗?
在三个文件所在的文件夹中地址栏里运行cmd(这是vista的小技巧,其他的windows可以通过传统的方式进入cmd窗口,并进入该文件夹),在命令行上输入:
gem install FunFX-0.0.2.gem等待一小会儿,屏幕上提示:Successfully installed FunFX,
version 0.0.2,表示已经安装成功。
然后进入Eclipse 新建一个ruby项目LearnFunFx,也将AutomationGenericEnv.xml拷到源文件同级目录下,新建LearnFunFxTest.rb,输入代码:
require 'test/unit'
require 'funfx'
class LearnFunFxTest < Test::Unit::TestCase
def setup
@ie = Funfx.instance
@ie.start(true)
@ie.speed = 1
@ie.goto("http://localhost/.../LearnFunFx.html", "LearnFunFx")
end
def test_control
@ie.button("test").click
end
end
“...”是web应用的名字,自己补齐。代码非常简单,功能是打开网页,找到名为LearnFx的swf,点击id为test的按钮。在运行之前,我们还要做一件事,不然的话,我们之前的所有努力都白费了。打开IE,按下alt,选择“工具”-> “Internet选项”,点击“安全”tab页,将“本地Intranet”安全级别设为低,将http://localhost加入可信站点,并将可信站点的安全级别设为低。(这里是我不确定是否多做了什么的地方之一)。做了这些之后,ruby调用js就不会被浏览器阻拦了。(刚才试了一下,运行完测试用例之后再改回去也不会被阻拦了,搞得我很郁闷,但是在我修改这里之前,确实是无法运行的。)
然后我们运行该测试用例,我们就会看到一个浏览器窗口被弹出,swf中的按钮被按下,一个Hello World!的对话框弹出。一切成功:)
(完)
因为二把刀的Ruby水平,导致我反反复复研究FunFX,最后问题居然出在IE的安全性上。不管怎么说,终于在今天测试通过了。新年里,这是一个非常鼓舞我的事件,终于可以给自己一个交代了,Flex对TDD是友好的。
最后,新年新气象,跟所有看到这篇blog的朋友们拜个年。
今天在首页看了一篇很有意思的博文:
谈一谈在家办公的利弊
其实在家办公对我来说是一个很遥远的梦想。但是人总不能放弃梦想啊。也来一个假想吧。
说是假想,其实这些手法也是来源于一些分布式开发的讨论。而在家办公在一定程度上构成了分布的情景。
最早听说分布式开发是一篇讲分布式敏捷的文章,之后一直对这种神奇的开发模式十分向往,也看过一些讨论贴,借着这个话题也来写一些东西,主要考虑一下Web2.0产品对分布式开发可能会有的一些帮助。在那篇文章曾说到分布式开发的基本原则:
(注:可以接触到实际客户的一端一般称为on-site,另一端可相应的称为off-site)
原则说得很到位,总之,无条件的提高交流的效果。在手段上我觉得在web2.0时代,我们有很多更好的工具可以帮助我们进行交流。
首先,对那个MSN和Y!的做法我就不是很同意,相比较的话Twitter不是更好吗?项目组成员一人注册一个Twitter帐号,所有人互相Follow。制定一个制度(先不考虑制度的建立过程)每隔一个小时写一个正在干什么。Twitter不就是干这个的吗?就像Twitter输入框上面写的:“What are you doing?”Twitter还能对话,而且所有的对话都是公开的,方便每个人加入进来,天生是个开放的环境。Twitter还能发到手机上,外出有事也能接到小组成员的工作动态。并且随时插入讨论。当然Twitter毕竟是国外的,可能会有很多问题,比如哪天被盾掉,那么叽歪,饭否也是可以选择的。相传矶歪的功能比Twitter更强大。
接下来我说的更多像是给Google做广告了,但是不管你承不承认,Google这些工具确实很有帮助。
第一个,Google日历,Google日历可以拿来做计划和工作日志,每个人一个日历,项目组再做一个计划日历。每个人的日历写自己的计划和日志,项目组的日历写项目计划和日志。可以帮助项目组跟踪计划和统计工作量。甚至项目经理或组长可以拿日历分配任务。拿任务日历和日志日历跟踪进度情况。
第二个,Google Group,google的这个论坛可以拿来做项目组讨论的地方,每一个发起的讨论都可以记录下来,还避免了平常口头讨论时不容易回溯的问题。但是单纯的GoogleGroup还是比较麻烦的,只有在结合了Google的另一个拳头产品之后,这个手段才是可用的。那就是Gmail。
第三个,没错,Gmail,Gmail中可以直接对Group发帖或对讨论贴进行回复,并且每一个讨论贴都可以折叠和展开起来。同时各个Gmail用户可以直接聊天,聊天记录也可以被保存在Gmail中。一切都是便捷且可回顾的。
第四个,Google Doc,不管我们怎么讨厌文档,大多时候文档是逃不掉的。大家分布的情况下,文档的管理和共享是个问题,但实际上,即便是不分布的时候,我们的文档的管理共享也是问题(我总是在飞鸽上收到大量的文档,导致我的文件夹中文件膨胀速度太快,产生大量垃圾,每次到找的时候总也找不到需要的文档。)。为啥不使用Google Doc呢?文档可以轻松共享,且大家可以协作完成一份文档。且支持版本控制。
第五个,Google NotePad,这是一个很有趣的记事本工具,他有很多种用途,在我看来,他可以做能够共享的TODO List,而且一些点子可以随手记在上面,当哪天差不多了可以导出到Google Doc,我们可以用它来制定自己的计划,并共享给组长或组员。
Google的广告做完了,再来吹吹Adobe的,Adobe推出了一款在线会议室:BRIO,目前还是测试版。
我申请了一个个人会议室试用了一下,还是挺不错的。可以共享桌面、聊天、语音对话、视频,上传文件。这些对于帮助在家办公的人开会是很有帮助的。不过因为外国服务器的关系,速度有点慢。
即便这个东西因为网速等人力不可战胜之原因跑不了,我们还有qq嘛,虽然因为众所周知的原因,用QQ一般是降低工作效率的,不过我们可以申请一个工作用QQ嘛,这样聊天、语音、视频、共享桌面也都全了。而且在twitter的帮助下,配上TDD和持续集成的手法,偷懒应该是很容易被发现的。
以上就是我想到的可以辅助我们在家办公或者说分布式开发的web2.0产品。
===========================
写完之后我到回来想,其实有些用在办公室里也未尝不可。
FunFX是flex平台下的一个开源自动化测试工具,可以对Flex进行TDD开发,目前,我已经进行了三次尝试,可FunFX总也搭建不起来,心情极度恶劣。
最近突然想回顾一下设计模式,很多东西是要回过头来总结一下的。今天先回顾一下单例吧。
很多时候觉得挺搞笑的,去面试的时候如果人家问你设计模式,一般都是要你写个单例模式。去年来北京好几家面试都是问我这个。当时我就想这个能反映出一个人的水平来吗?还是说更多的是反映出这个公司的水平呢?
随着一年的应用,很多地方都用过之后觉得,单例这个东西虽然简单,可是现实是复杂的。所以单例这个简单的模式也不能太小瞧咯。
单例其实有很多种实现,这是其中的一种,延迟加载的(好像英文叫Lazy?):
[下面代码中所有的构造器都是私有的,这里我就省略不写了。]
public class ClassName {
public static ClassName getInstance(){
if(instance == null)
{
instance = new ClassName();
}
return instance;
}
private static ClassName instance;
}
这种的好处是我们的单例使用时才进行初始化,这样方便我们在系统启动时做些小动作。但是这个方式不是线程安全的,想要完成一个线程安全的单例,有几种方式:
(一)
public class ClassName {
public static ClassName getInstance(){
return instance;
}
private static ClassName instance = new ClassName();
}
这种方式,可以保证我们的单例是线程安全的,毕竟我们唯一的实例在系统初始化的时候就构造了。可是Java的机制是static级别的变量初始化时互相调用是会报异常的。所以随着系统的扩展,尤其还会有一些新手或者粗心大意的家伙(比如说,我)会乱用你的方法。一不小心就造成问题了。而且,你也失去了第一个方式中的一个小优势,不能在系统启动时做点小动作了。
(二)
public class ClassName {
public static synchronized ClassName getInstance(){
if(instance == null)
{
instance = new ClassName();
}
return instance;
}
private static ClassName instance;
}
这样倒是线程安全了,也可以延迟加载,但是从今以后这个getInstance方法就是
synchronized的了,那绝对是很影响效率的。我跟朋友讨论提出了几种写法,以期既能使单例可以在系统启动不至于数据已经煮成熟饭又是线程安全的:(少数人讨论结果,代码可能会比较丑陋,仅供参考,欢迎拍砖)
public class ClassName {
public static ClassName getInstance(){
if(instance == null)
{
instance = ClassName.createInstance();
}
return instance;
}
private static synchronized ClassName createInstance(){
if(instance == null)
{
return new ClassName();
}else{
return instance;
}
}
private static ClassName instance;
}
这种写法就很好的解决了这些问题。
还有一种写法是这样的,这个不是延迟加载的。而是采用了一种取巧的方式。
public class ClassName {
public static ClassName getInstance(){
if(!instance.isInit)
{
instance.initSingleton();
}
return instance;
}
private synchronized void initSingleton() {
if(!isInit)
{
reset();//这名字是有点怪异,我没时间想太好听的名字
isInit = true;
}
}
public void reset(){
//.....真正进行数据初始化的地方
}
private boolean isInit = false;
private static ClassName instance = new ClassName();
}
将所有的初始化代码搬到构造器之外。这是专为数据初始化和复位进行的设计。所以我把reset开放了出来。
(【转载者按:】虽然不是技术文章,相信对我们很多人都有教育意义,所以发到了首页)
=========
刚在天涯看见一个HR的文章,总结他的经历,以一个面试官的角度看求职者的种种。
不能不说写的很好,总结得相当全面,而且非常体现细节决定成败的观点。
但是,一如一个网友所说的,这些东西对刚毕业的学生比较有用,对于打滚过几年的人,就帮助不大甚至相反了。
当你的能力处于同一水平线的时候,一家公司要你不要你,开多少价钱,你选择去哪家公司,都是很随机的事情。只要没有严重出格的行为,那么几乎就是运气主导一切。
就像《太傻十日谈》中所说的那样,各种各样的面经都是成功者归纳的,也许他们注重了某一方面,在某个地方做得比别人好,所以他们就将自己的成功归功于哪一方面。
而实际上呢?可能和他们总结的原因南辕北辙。
同样,经验都是失败者总结的,心有郁郁者对自以为的某一失策耿耿于怀,于是将自己应聘失败的帐算在这头上,实际上也可能根本不是这么回事。
运气,真的是运气而已,一切都是命运的随机。
唯一提高自己应聘成功可能的只有能力而已。
当你是不可取代的一员的时候,你可以穿任何一件衣服应聘,甚至可以以任何态度来对待面试官,无他,硬营销而已。
当你的水准超过其他应聘人员,足矣让对方眼前一亮的时候,一些细节可以忽略。
当你水准和别人差不多的时候,你必须三分人才七分打扮,才有十足的力气去拼。
当你远远不适应这个职位的时候,再熟读面经也是无用,就算是对方一时眼花招了你,且不说对他,光是干一份自己不适合的工作就够痛苦了。
那天和朋友聊起她最近的一次面试,很平淡地谈着,虽然也积极展现自己,但是不再扭曲,懒得伪装,也不会激动甚至忘形。而她看见一个小男生面试,激动地面红耳赤,一如我们当年。
呵呵,我第一次应聘失败,把原因归结于我要回学校写论文和答辩;
第一份实习工作面试,我连自创营销学派的狂言都说得出口;
第一次辞职,差点掉眼泪;
对于一个有着试用期女郎名声和作为职业跳蚤的我来说,面试过无数公司,拿到过无数个OFFER,也被无数个公司拒绝过,回想起来,其实自己的成功和失败,选择与放弃,都是相当随机的事情,并没有什么很确定的理由。
而对于公司,选择我还是选择别人,为什么拒绝我,大多数时候只怕也是很随机的事情吧。
而我在哪家做,做得如何,同样也是这个词语可以概括了。
成功的经验也是那么多,名人们写着出,飞来飞去地演讲。比起来,我更喜欢他们的人生态度而不是具体到某个公司的工作经历,或者自己总结的一些职场励志类东西。
所处的环境不一样,成功的方式怎么可能复制?
病症不同,难道乱吃药?只怕就是好了,也是撞大运罢了。
以前我一直觉得自己混得不够好的一大原因是因为自己不够坚持,不会忍耐,求成心切。当然,这也的确是我的毛病,但是并不能就将失败归结于此。
曾经想过要改,但是看看兢兢业业踏踏实实的人混得还不如我的时候,又迷茫了,到底该如何?
如今,我只做我自己,除了努力提高自己外,个性上的东西,不再做什么强求了。
也许这错了,但是谁又能确定地说什么是对呢?
当你的能力有所局限的时候,你所能达到的高度也有了瓶颈,这是所有的技巧都不能弥补的。无论你如何在面试中伪装,在工作中积极,能力缺陷始终会是你的天花板,即使偶尔冲破这层玻璃,但是碎玻璃一样会划伤自己,一旦跌落,体无完肤。
的确,一个好的平台会给你很多,甚至有可能从此在职场上一帆风顺,但是这真的只是运气而已。我们敢用自己的一辈子去赌运气吗?
这个轮盘上唯一能增添获胜几率的,还是能力。至少,有能力的时候,你可以多一些选择机会,这家不合适,换一家,还可以选择自己做老板。相反,则是你必须去适应公司。
扭曲自己是很痛苦的,也会影响发挥。当然,很多成功人士说适应环境的重要性,但是同样我们可以找到大量的案例说明扭曲自己不但没有获得成功反而弄得自己痛苦不堪。
然而时间是单程的,所以我们永远不会知道自己如果选择了另外一家公司,换了另一种做法,会是什么样的结果?更好,更差?
想多了那个问题,只会给你带来现实的困扰。
都是不确定的未来,为什么非要扭曲自己呢?有礼有节,不卑不亢,就足够了。
也许,只是因为我老了,累了,懒了,开始给自己找一个玄乎乎的借口罢了。
但是真的不愿在为什么而扭曲自己,不想再去拼命考虑自己该如何做如何说,除非这不会违背我的本性,并且我知道这么做有一个很确定的好结果。
其实十多年前我就明白一件事情,为什么这么多年我却忘记了?
当你知道该说什么的时候,就说;当你不知道该说什么的时候,就说实话。
回忆起来每当这么做的时候,事情也许没有变得更好,但是的确没有变得更糟。
祝我们好运!
=================================
转自非著名作家--白水加冰的博客,更多精彩文章请移步:
http://blog.sina.com.cn/gyy101081
过去的半年,因为对于Flex的认识较浅,全部采用的HttpService的方式构建的我们程序的通信,这里面java对象与as对象的映射与解析是一份工作量不小的工作,不是没考虑用DataSerive的RPC,因为考虑到收费就放弃了,前不久从InfoQ上一篇新闻得知,有开源的DataService:GraniteDS,而Adobe自己也在去年12月14日开源了一个:BlazeDS。
这下清除了我们成本和许可的障碍。前天下载了BlazeDS,稍微研究了一下,部署了一个应用。
结果非常的成功,一切都变得那么简单了,我们可以轻松的调用后台的Java方法。就好像调用flex本地的方法一样。而且不用写Java类和as类的映射(还是要写两行代码的,在映射的类上写这些:[Bindable] [RemoteClass(alias="Java全类名,自己替换")]),我昨天试了,非常好用。传参和返回值都是跟直接调flex的函数一样(除了是异步的。这里我们看得出Flex对Java是非常友好的),还没试异常。而且配置也是非常简单的,在WEB-INF/flex/remoting-config.xml 下配置一个类似这样的标签就可以了:
<destination id="product">
<properties>
<source>flex.samples.product.ProductService</source>
</properties>
</destination>
调用也非常简单(以mxml中的调用为例): <mx:RemoteObject id="srv" destination="product"/> destination属性的值就是配置文件里<destination>标签的id属性的值,之后我们就能像使用as对象一样使用他了。
前后台的对象保持一致的办法也只是有一个什么样的Java对象就写一个什么样的as对象。
部署也非常简单,将BlazeDS下载到之后,解压完毕我们可以看到三个war包,三个文件夹,和一个license,其他的不看,三个文件夹分别是:
顾名思义,第一个是文档(现在还不全,想看全的还得去网站上看在线的);第二个是一些可能会用到的资源,比如Jar包什么的;第三个是保存有例子的tomcat,webapps里面有三个web应用,分别对应那三个war包,但其中最有用的就是blazeds-samples这个了从里面我们可以看到所有丰富的例子,而且单击右键选择View Source还能看到代码,而blazeds就是我们部署一个基于BlazeDS的web应用的空文件夹,所有该web应用需要的Jar包和配置文件都全了,而且都在他们该在的文件夹里。不过你要真的跑起来,在你的tomcat里还要部署些server级的东西,那个就在我们的resources/security/tomcat里,参照该文件夹下的readme.txt部署。
另外,即便是对HttpService和WebService的应用方面他都有一个很好的框架,他还有一个message框架,目前我还不清楚是干什么用的,猜测也许像JMS。
在对J2EE的支持方面,GraniteDS号称已经支持EJB3.0,Spring,Guice,Seam,BlazeDS我还不知道,不过GraniteDS的作者对BlazeDS是持一个开放的态度的,且两者的开源协议是同一个,可以互相拷贝代码,所以我相信将来两者都会更强大。
简单的配置,清晰的结构,强大的功能。在试用之后,我坚信Flex中J2EE开发的王道一定是各种Data Service。
=========================
BlazeDS的网址:
http://labs.adobe.com/technologies/blazeds/
题外话,推荐一个Flex for Java的网址,希望对Java程序员有帮助:
http://flex.org/java/