??xml version="1.0" encoding="utf-8" standalone="yes"?> 怿不只你我Q大部分的h都比较认同敏捷化的过E,希望使过E变得敏捗的,q是个好东西Q之前我也说q“敏捯E是三赢的”这L话?/p>
我所兛_的问题是“如何能够用好XPQ”?/p>
庄兄认ؓ“汤的味道,不需要什么过E控制”,我也会认同。ؓ什么?因ؓ你我都是中国人。大部分中国Z会认为汤的味道需要什么过E控制。但是想想看Q如果你在不同地方买到的肯d基炸鸡味道各异;同一Ҏ生的同型号的汽车Ş状各异;银行里取出来的一叠百元大钞大不一Q你不会觉得奇怪么或是有那么一点点愤怒么Q?/p>
西方人(甚至学习西方的日本hQ对品质的重视程度却完全不同。他们不允许肯d基炸鸡的味道有很大偏差(即便你觉得无所谓)Q?毫米工程”不允许整R的总装长度发生2毫米以上的偏差(即便你觉得无所谓)Q百元大钞……(我想谁都不会无所谓)?/p>
所以,一切质量都有标准,一切标准都应该被度量!q就是工E学的目标之一Qؓ了实现更严格的质量标准,需要过E控制和度量?/strong>
庄兄所_用测试用例保证代码的质量其实q是采用了“测试用例”作为度量的标准。唯一的问题是Q“如何确保测试用例的质量”。显Ӟ我们不能把一把不直的子度量出来的结果作为可靠的参考依据。怎么解决呢?“结对编E”么Q嗯Q这是一个不错的方式Q那么最l该信赖谁呢Q是Pair中的Aq是B呢?或者,是Leader么?那么又是谁提出的要求呢?是老板么?q是客户Q政府?法规Q市场?……问题没有终l了?/p>
不要学习哲学家的ҎQ提Z层又一层无法解决的问题。我们是工程师,应该试图解决问题才对Q解决问题的关键在于Q?font color="#ff0000">XP同样需要标准!Z制定标准Q必要的文档是不可以的。而且Q标准本w的质量是严苛的。因为,作ؓ标准Q他不可以含p其辞、模׃可。在标准的基之上Q我们才可以谈什么TDD、Pair Programming之类的实c?/p>
回到争论的开端。我引用了林先生的话“UP是正PXP是草书。要先学好UP才能学好XPQ先学XP会ؕ套。”我对这句话的理解如下:q句话ƈ没有批判UP或是XPQ只是指Z一个学习的序。我认ؓq句话是有实践依据的Q因为UP的是一U经典的工程Ҏ。Y件工E本来就源于其他行业的工E实늻验。UP利用大量的文档对开发活动进行约束和记录。正是这U重量的过E规范了规范了从PM到Coder的所有活动,有问题可以参照文档,看看自己应该怎么做。文档也可以作ؓ日后评估q个q程的依据。随着整个团队和每个个人的l验不断U篏Q开发活动中的日常行为渐渐Ş成了一U职业习惯。然后可以通过对UP的配|,逐渐减少文档的用量Q一些没有必要的文档可以省去,更具团队的实际能力调整过E?font color="#ff0000">UP是可配置的,不必要的文档没有存在的理由,q一点UP和XP没有什么两栗?/strong>当然Q随着大家的职业习惯越来越好,l验来丰富,个h和团队就可以采用更敏hM的过E,逐渐q渡到XP上去?/p>
反过来,如果一开始就没有详尽的文档,很多zdQ比如设计、版本控Ӟ往往会脱LӞq入一U无序的、q状态。没有文档可参考,意味着很多问题只能问hQ而不同h的回{可能各异,同一个h对同一个问题的两次回答也可能不同!当然Q如果整个团队的工程素养和个体的职业习惯都比较好的情况下可能不会发生cM的情c?font color="#ff0000">但是q种工程素养和职业习惯从哪里来,可能单靠的XP是不以培养出来的?/strong> “UP是正PXP是草书。要先学好UP才能学好XPQ先学XP会ؕ套。”这句话表明了UP和XP在一定程度上是存在冲H的Qƈ且提Z一条\U去降低和避免这个冲H?/p>
再次需要强调的是庄兄所提到的“XP是一U思想”,q点我认同。但是我认ؓq个除了思想之外Q还是一U“文化”。这U思想和文化也是出于Y件工E多q来的实践,其中也不免有UP{其他过E。不能简单地认ؓ“我们只要吸取历史的教训Q提出新的思想和文化就不会再犯同样的错误了。”很多时候历史L一ơ又一ơ地重演着?font color="#ff0000">新的思想和文化如果不能被准确地理解和q用Q它所带来的可能仍然是它原本想解决的问题。只有我们具备了引入q种文化的基Q才能把它变成自q文化Q否则这仍然是挂在嘴边行于表面的一U不求精髓只求模仿的伪文化、伪思想。这一点对于UP和XP的实践者来说没有什么两栗?/strong> 举个例子Q比如你做一锅汤Q?br />今天你状态很好,做完后尝了尝Q感觉很味Q你的家人尝了以后也有同感,喝完后感觉心情舒畅、意Ҏ?br />隔了一个礼拜,你做同样的汤l家里h喝。做完后你尝了尝Q感觉依然美呻I盼望着得到家h的赏识,然而他们却说味道咸了点。你很奇怪,Z么同栯己尝q了Q家里h却感觉不一样呢Q是不是最q加班多了,休息不好Q味觉不准了Q?br />一个月q后Q你要去国外出差Q给安请了个时保姆。一天,他也做了q么个汤Q做完后Q他也尝了尝Q感觉口呛_不错Q可是端上桌Q家里h说这汤太辣了。原来这保姆才从湖南老家出来不久…?/p>
因此Q只把焦Ҏ在最后的产品上往往是不够的。需要对“做汤的q程”加以控制。所以工E界会比较关注过E的理Q在软g领域也称作“Y件生命周期管理”?/p>
再来看看UP和XP。它们都属于软gq程Q只不过各有特色?/p>
再拿刚才那个做汤的例子: q个例子也许不太贴切Q但是可以联想一?德国人做汤們于UP;中国人做汤們于XP?/p>
UP和XP最l目的都是ؓ了保证品的质量Q不同的是,两个q程所的方法不同。我惻I没有Z说“UP的目的在于变态地q求文档的完”、“UP是ؓ了要E序员学会写各种各样文档”……之cȝ话。同Ӟ也没Z说“XP是不要文档只要代码”、“XP是要变态地q求完美的代码”……这L话?/p>
q些不正的看法Q只是h们对于这两种q程的误解。或许是来自于开发h员和目l理的那些“不堪回首的l历”?/p>
“UPx了整个Y件行业,让开发h员没完没了地写文档而忽略了代码QXP才是王道”这L话,我不敢苟同,仍然有很多企业用着UPq样的重型Y件工E,好比d国h依然喜欢把厨房弄得像个实验室?/p>
XP固然是个好东ѝ但是,不知道大多数人对于XP的热hZ对XP文化的理解,q是国h惯有的“一H蜂”似的行为?font color="#ff0000">不晓得一个“能够熟l阅M码的Leader”是不是能够真正q用好XPQ确保他的团队能够尽可能地出现"Over engineering"q种q背Agile_的东西,或是能够让他的团队保证“每周只工作40时”这L基本实践Q?/strong> 对于不同的技术和q程Q应该给予冷静的分析和慎重的选择。每个过E和技术都不能以“正”或“不正确”来定性,只能以“合适”和“不合适”来定性。因为正或不正是要严D明的Q而合适不合适是来源于工E实늚l果。所以,COBOL依然在金融领域v着举轻重的作用,U学家们仍不忘FortranQ汇~和C仍然健在…?/p>
另外不得不提的是文化上的差异。ؓ什么很多时候,我们学习国外的先q技术,购买了整套生产线Q引q了全套囄Q请国外专家做了详细的全E化培训Q国人生产出的品品质依然不如国外原产的Q这是每个中国h都应该思考的问题…?/p>
工具
在开展这些实늚时候,交流比较频繁。首推的工具?font color="#a52a2a">Mini white board?font color="#a52a2a">DC?br />选择Mini white board的原因ƈ不是因ؓ带有"mini"听上M?Mini Cooper 或?iPod mini 那么cool。因Z块A3左右大小的白杉K帔R合个h或者结对用,而且环保Q省M草稿U)。虽然整个团队也有用于大规模交流的更大的白板Q但那属于“竞争资源”,各自使用自己的白板更为方ѝ?br />交流l果产生后,Z不花不必要的旉d_的文档,一台轻便的DC往往是最合适的选择。当Ӟ如果_Q手Z的照相功能也可以完成同样的Q务。相比偷拍街上的MMQ这些电子品能够实现更大的价倹{?br />
关于l对
每天q行6时的结对编E,?ơ,每次2时。每ơ和不同的成员组队。在l队的时候充分利用了上面提到的工兯行交。如果出C个h不能解决的问题的时候,会立卛_整个团队提出Q这样可能导致一ơstand-up meeting。即佉K题不能马上解冻I臛_也能保每个人都知道q个问题?br />
]]>
]]>
大家都听说过德国人的厨房像化学实验室Q天q뀁计时器、量杯……装备齐全,再配上精的菜谱Q严谨的德国够确保不用尝那最后一口都做出口味基本一致的汤?br />换了中国人,大部分h都不会模仿d国h做菜的方式。解x案很单,让你的太太和孩子都尝那最后一口,再根据反馈调整几ơ,同样能做出全家h满意的汤?/p>
]]>
老师曾这么说。最q,对这句话有了深刻的体会?
软gq程是一个以Zؓ中心的活动。h是项目中最隄定和控制的因素。休息的质量、情l的起伏都会影响整个zd。ؓ了尽可能地约束这U个体的不确定行为和减少开发过E中不必要的误会?UP"采用了大量的文档来对整个开发过E进行控制。这些文档主要分Z下几c:
文档成了UPzd的主要部分。在UP中,往往大量的资源用于文档的制作。这些文档的目的是ؓ了尽可能减少不必要的沟通成本和误会Q也Z在发生问题的时候能够尽快确定原因找到解x法?
而正是因为如此繁重的资源消耗,D真正的设计和代码只占Cd销的很部分。这对很多h来说不可理解Q甚臌得本末倒置。于是很多敏h法诞生了Q最具代表性也是对UP思想最具颠覆性的属XP了?
对外QXP以快速的反应速度来响应客L需求;对内QXP以高质量的代码和设计来确保尽可能不生不必要的文档和资源开销?
从表面上看,在当今,XP实是一U非常理想的开发过E?
但是Q从没有q程到XP往往会非常失败。这是ؓ什么?问题的关键还在于人?
UP利用文档来约束和规范Z的开发活动。当一个没有经验的团队l历UP后,q于把性格各异、习惯差别不同的?font color="#a52a2a">l一成了“相对较一致的开发h员”?
他们有一致的~码习惯Q有共同的用语,有严格的规则。随着l验的积累,q个团队间的默契来高。此Ӟ如果q程由UP向XP切换Q付出的代h׃相对较低?
XPd快速反应。如果一个没有经验的团队在一开始就试XPQ那么后果可能是惨痛的。因Z个没有经验的团队其成员间的相互了解颇,对于一件事Q往往十个人有十种x。当~少文档U束Ӟ在以代码和设计ؓ中心的活动中Q成员之间往往因ؓ水^的参差不齐导致无休止的讨论甚至争论,代码被不必要地频J改动。这是因为,在团队徏设早期,成员之间往往q最基本的尊重和信Q都不存在?/strong> q种无意义的zd往往会严重媄响项目的正常q行?
所以,学习和应用过E不仅仅是个体的事,而是整个团队的事。只有当团队采用严格文档化的q程q且l过合后,才能渐渐向轻量的过E迁U,逐渐不必要的文档删减掉Q采用更灉|的过E。但是,此时q不是“没有文档”而是“心中有文档”?/p>
“抽象”是语言提供的功能。“多态”由l承语义实现?
如此Q问题生了Q“我们如何去度量l承关系的质量??
Liskov?987q提Z一个关于承的原则“Inheritance should ensure that any property proved about supertype objects also holds for subtype objects.”——“承必ȝ保超cL拥有的性质在子cM仍然成立。”也是_当一个子cȝ实例应该能够替换M其超cȝ实例Ӟ它们之间才具有is-A关系?
该原则称为Liskov Substitution Principle——里氏替换原则。林先生在上课时风趣地称之ؓ“老鼠的儿子会打洞”。^_^
我们来研I一下LSP的实质。学习OO的时候,我们知道Q一个对象是一l状态和一pd行ؓ的组合体。状态是对象的内在特性,行ؓ是对象的外在Ҏ。LSP所表述的就是在同一个承体pM的对象应该有共同的行为特征?
q一点上Q表明了OO的承与日常生活中的l承的本质区别。D一个例子:生物学的分类体系中把企鹅归属为鸟cR我们模仿这个体p,设计Lcd关系?
cZ鸟”中有个ҎflyQ企鹅自然也l承了这个方法,可是企鹅不能飞阿Q于是,我们在企鹅的cM覆盖了flyҎQ告诉方法的调用者:企鹅是不会飞的。这完全W合常理。但是,q违反了LSPQ企鹅是鸟的子类Q可是企鹅却不能飞!需要注意的是,此处的“鸟”已l不再是生物学中的鸟了,它是软g中的一个类、一个抽象?
有h会说Q企鹅不能飞很正常啊Q而且q样~写代码也能正常~译Q只要在使用q个cȝ客户代码中加一句判断就行了。但是,q就是问题所在!首先Q客户代码和“企鹅”的代码很有可能不是同时设计的,在当今Y件外包一层又一层的开发模式下Q你甚至Ҏ不知道两个模块的原地是哪里Q也p不上M改客户代码了。客L序很可能是遗留系l的一部分Q很可能已经不再l护Q如果因计出q么一个“企鹅”而导致必M改客户代码,谁应该承担这部分责Q呢?Q大概是上帝吧,谁叫他让“企鹅”不能飞的。^_^Q“修改客户代码”直接违反了OCPQ这是OCP的重要性。违反LSP既有的设计不能封闭!
修正后的设计如下Q?
但是Q这是LSP的全部了么?书中l了一个经典的例子Q这又是一个不W合常理的例子:正方形不是一个长方Ş。这个悖论的详细内容能在|上扑ֈQ我׃多废话了?
LSPq没有提供解册个问题的ҎQ而只是提Zq么一个问题?
于是Q工E师们开始关注如何确保对象的行ؓ?988q_B. Meyer提出了Design by ContractQ契U式设计Q理论。DbC从Ş式化Ҏ中借鉴了一套确保对象行为和自n状态的ҎQ其基本概念很简单:
以上是单个对象的U束条g。ؓ了满LSPQ当存在l承关系Ӟ子类中方法的前置条g必须与超cM被覆盖的Ҏ的前|条件相同或者更宽松Q而子cMҎ的后|条件必M类中被覆盖的方法的后置条g相同或者更Z根{?
一些OO语言中的Ҏ能够说明这一问题Q?
可以看出Q以上这些特性都非常好地遵@了LSP。但是DbC呢?很遗憾,L的面向对象语aQ不论是动态语aq是静态语aQ还没有加入对DbC的支持。但是随着AOP概念的生,怿不久DbC也将成ؓOO语言的一个重要特性之一?
一些题外话Q?
OCP的动机很单:软g是变化的。不论是优质的设计还是低劣的设计都无法回避这一问题。OCP说明了Y件设计应该尽可能C架构E_而又Ҏ满不同的需求?
Z么要OCPQ答案也很简单——重用?
“重用”,q不是什么Y件工E的专业词汇Q它是工E界所q的词汇。早在Y件出现前Q工E师们就在实践“重用”了。比如机C品,通过雉件的l装得到最l的能够使用的工兗由于机械部件的设计和制造过E是极其复杂的,所以互换性是一个重要的Ҏ。一辆R可以用不同的发动机、不同的变速箱、不同的轮胎……很多东西我们直接买来装上就可以了。这也是一个OCP的例子。(可能是由于我是搞机械n的吧Q所以就举些机械斚w的例子^_^Q?
如何在OO中引入OCP原则Q把对实体的依赖改ؓҎ象的依赖p了。下面的例子说明了这个过E:
05赛季的时候,一辆F1赛R有一台V10引擎。但是到?6赛季Q国际汽联修改了规则Q一辆F1赛R只能安装一台V8引擎。R队很快投入了新赛车的研发Q不q的是,从工E师那里得到消息Q旧车n的设计不能够装进新研发的引擎。我们不得不为新的引擎重新打造Rw,于是一辆新的赛车诞生了。但是,ȝ的事接踵而来Q国际汽联频频修改规则,搞得设计师在“赛车”上改了又改Q最l变得不成样子,只能把它废弃?
Z能够重用q辆昂贵的赛车,工程师们提出了解x案:首先Q在车n的设计上预留出安装引擎的位置和管Uѝ然后,Ҏq些设计好的规范设计引擎Q或是引擎的适配器)。于是,新的赛R设计Ҏp栯生了?
昄Q通过重构Q这里应用的是一个典型的Bridge模式。这个实现的关键之处在于我们预先l引擎留Z位置Q我们不必因为对引擎的规则的频频变更而制造相当多的Rw,而是可能地沿用和改良现有的车n?BR>说到q里Q想说一说OO设计的一个误区?BR>学习OO语言的时候,Z能够说明“扎쀝(或者说“is-a”)q个概念Q教U书上经常用实际生活中的例子来解释。比如汽车是车,电R是RQF1赛R是汽车,所以R是汽车、电车、F1赛R的上层抽象。这个例子ƈ没有错。问题是Q这L例子q于“Ş象”了Q如果OO设计直接可以将现实生活中的概念引用q来Q那也就不需要什么Y件工E师了!OO设计的关键概忉|抽象。如果没有抽象,那所有的软g工程师的努力都是徒劳的。因为如果没有抽象,我们只能L造世界中每一个对象。上面这个例子中Q我们应该看到“引擎”这个抽象的存在Q因R队的工程师们为它预留了位|,为它制定了设计规范?BR>上面q个设计也实C后面要说的DIPQ依赖倒置原则Q。但是请CQOCP是OO设计原则中高层次的原则,其余的原则对OCP提供了不同程度的支持。ؓ了实现OCPQ我们会自觉或者不自觉地用到其它原则或是诸如Bridge、Decorator{设计模式。然而,对于一个应用系l而言Q实现OCPq不是设计目的,我们所希望的只是一个稳定的架构。所以对OCP的追求也应该适可而止Q不要陷入过渡设计。正如Martin本h所_“No significant program can be 100% closed.”“Closure not complete but strategic?BR>
Q下一就要讲LSP了,我觉得这是意义最为重要的OO设计原则Q它直指当今LOO语言的Y肋,点出了OO设计的精髓。)
在学习和使用OO设计的时候,我们应该明白QOO的出C得Y件工E师们能够用更接q真实世界的Ҏ描述软gpȝ。然而,软g毕竟是徏立在抽象层次上的东西Q再怎么接近真实Q也不能替代真实或被真实替代?/P>
OO设计的五大原则之间ƈ不是怺孤立的。彼此间存在着一定关联,一个可以是另一个原则的加强或是基础。违反其中的某一个,可能同时q反了其余的原则。因此应该把q些原则融会贯通,牢记在心Q?/P>
1. SRPQSingle Responsibility Principle 单一职责原则Q?BR> 单一职责很容易理解,也很Ҏ实现。所谓单一职责Q就是一个设计元素只做一件事。什么是“只做一件事”?单说是管闲事。现实中是如此Q如果要你专心做一件事情,M人都有信心可以做得很。但如果Q你整天被ؕ七八p的事所累,q有心思和_֊把每件事都作好么Q?BR>
“单一职责”就是要在设计中为每U职责设计一个类Q彼此保持正交,互不q涉。这个雕塑(二重奏)是正交的一个例子,钢琴家和提琴家各自演奏自己的乐谱,而结果就是一个和谐的交响乐。当Ӟ真实世界中,演奏提琴和弚w琴的必须是两个hQ但是在软g中,我们往往会把两者甚x多搅和到一P很多时候只是ؓ了方便或是最初设计的时候没有想到?nbsp;
q样的例子在设计中很常见Q书中就l了一个很好的例子Q调制解调器。这是一个调制解调器最基本的功能。但是这个类事实上完成了两个职责Q连接的建立和中断、数据的发送和接收。显Ӟq违反了SRP。这样做会有潜在的问题:当仅需要改变数据连接方式时Q必M改Modemc,而修改Modemcȝl果是使得M依赖Modemcȝ元素都需要重新编译,不管它是不是用到了数据连接功能。解决的办法Q书中也已经l出Q重构Modemc,从中抽出两个接口Q一个专门负责连接、另一个专门负责数据发送。依赖Modemcȝ元素也要做相应的l化Q根据职责的不同分别依赖不同的接口。最后由ModemImplementationcd现这两个接口?BR>
从这个例子中Q我们不隑֏玎ͼq反SRP通常是由于过于“真实”地设计了一个类所造成的。因此,解决办法是往更高一层进行抽象化提取Q将Ҏ个具体类的依赖改变ؓ对一l接口或抽象cȝ依赖。当Ӟq个抽象化的提取应该Ҏ需要设计,而不是盲目提取。比如刚才这个Modem的例子中Q如果有必要Q还可以把DataChannel抽象为DataSender和DataReceiver两个接口?BR>
最q正在读q本书,喜欢影印版,是因Z中漂亮的插图。:Q惭愧,如此的好书到现在才去诅R?BR>准备边读边记录些心得Q今天先说些废话。:P
先粗略地概览了一遍全书。本书主要分以下几个部分Q?
之所以觉得这本书好,q与一个h有关。就是交大Y件学院的林d彰老师。林先生的课Q风幽默,能够用直观Ş象的语言让学生对讲课内容产生深刻的印象。(我可不是托儿Q网上能搜到些林先生讲课的片断,要是怀疑,可以验证一番)。记得在软g工程q门NQ林先生l我们讲了很多有兌计原则的内容Q其中就有“开闭原则(OCPQ”、“里氏替换原则(LSPQ”等……就把这本书当作是一本补充读物吧?
a归正传。个人感觉这本书的M风格Q就和所要讲的“敏捷”一Pq不带着厚重的学院派风味Q而是更注重实cƈ不是没有理论Q只是把理论融入C实践中,化了理论的复杂性。读h感觉很带劲儿?
废话说到q里Q下一步的计划是跟着自己的进度写M心得了。我x对书中内容的理解和以前在林先生的课上所学的l合在一P导出阅读此书时的大脑zd镜像?/P>