【Java开源代码栏目提醒】:网学会员--在 Java开源代码编辑为广大网友搜集整理了:[IT计算机]软件重构培训 - 技术总结绩等信息,祝愿广大网友取得需要的信息,参考学习。
目录1第一章关于软件
代码的新思考1.1源
代码-软件质量基石1.2
代码质量2第二章重构2.1重构概述2.2重构案例3第三章
代码坏味道3.121种
代码坏味道概述4第四章函数重构4.1函数设计第一原则—只做一件事情4.2复杂表达式4.3函数参数4.4重复5第五章类重构5.1面向对象重构-抽象数据类型5.2面向对象重构-职责驱动设计6第六章设计与重构6.1演化式设计6.2重构到模式重构-改善既有系统
代码与设计第 1 页20110411 北京朗讯请记录你的学习心得和反思培训的本质不在于记住哪些知识而是在于它触发了你的多少思考.一旦我们开始反思我们的工作工作将会不再一样.哈佛大学lt正义gtSandel教授1第一天
学习心得和反思2第二天学习心得和反思3第三天学习心得和反思重构-改善既有系统
代码与设计第 2 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase
代码新视角Topic
代码质量—软件系统基石软件设计与建模在最近的10年中很多人都在提倡模型构建包括IvarJacobson他宣称“软件开发就是模型构建”。
对于模型的关注阻碍了软件的开发。
构造模型不是项目的目的。
设计与施工的分离害了软件工程设计看做软件开发的关键环节而把编程看做机械式的低级劳动.设计就像画工程图纸而编码就像施工.但是这是错误的软件的可塑性更强而且完全是思想产品.一些项目中设计也许可能会详细到能够让编码工作近乎机械化但很少有如此完整的设计——程序员指编程通常也要对部分程序进行设计也许是正式的也许不是。
有了设计我可以编程更快但是其中充满小漏洞---AlistairCockburn重构-改善既有系统
代码与设计第 3 页20110411 北京朗讯木桶原理---
代码成为了我们的短板最好的设计经常是在编码阶段产生的建模来研究设计思路是没错的然而设计后不应该就认为该模型就是任务的最好设计.你会发现最好的设计是你在编码阶段一步一步逐渐形成的.什么是软件设计–源
代码是设计什么是软件设计--
代码也是设计??JackW.Reeves1992软件系统源
代码是它的主要设计
文档用来描述源
代码的图示只是设计的附属物而不是设计本身.你不应该认为设计就是一组和
代码分离的UML图.重构-改善既有系统
代码与设计第 4 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase编程的价值观Topic编程价值观百家争鸣EdwardYourdonampLarryL.ConstantineltStructureDesigngt30年前评价标准的背后动机--------------------关注开发总成本
软件系统维护
工作量所占的比重超出想象重构-改善既有系统
代码与设计第 5 页20110411 北京朗讯
代码要人能够读懂-MartionFowler任何一个傻瓜都能写出机器能懂的
代码好的程序员应该写出人能懂的
代码MartinFowler《重构》软件
代码3项职责---RobertCMartinlt敏捷软件开发gt第1职责:运行起来所完成的功能这是模块存在的原因.第2职责:要和阅读它的人进行沟通对模块不熟悉的人员应该能够比较容易理解.第3职责:它要应对变化因为软件要变化开发者保证应该尽可能的简单.编程价值观价值观是编程过程的统一支配性主题.有3个价值观:沟通---珍视与他人沟通的重要性简单—把多余的的复杂性去掉灵活-保持开放应对变化----KentBeck语。
随着年龄的增长我逐渐意识到编程不仅仅是让程序运行而已编程是创造一个易于理解的、可以维护的、高效的作品。
一般来说干净整洁的
代码往往运行起来更快。
这与流行观点正好相反。
而且即使它们不快也可以很容易地让它们变快。
正如人们所说的优化正确的
代码比改正优化过的
代码容易多了。
Google公司首席
Java架构师Joshua??Bloch重构-改善既有系统
代码与设计第 6 页20110411 北京朗讯Topic
代码质量的评价标准整洁
代码—百家争鸣BjarneStroustrupinventorofCandauthorofTheC我喜欢优雅和高效的
代码。
代码逻辑应当直截了当叫缺陷难以隐藏尽量减少依赖关系使之便于维护依据某种分层战略完善错误处理
代码性能调至最优省得引诱别人做没规矩的优化搞出一堆混乱来。
整洁的
代码只做好一件事。
GradyBoochObjectOrientedAnalysisandDesignwithApplications整洁的
代码简单直接。
整洁的
代码如同优美的散文。
整洁的
代码从不隐藏设计者的意图充满了干净利落的抽象和直截了当的控制语句“老大”DaveThomasOTI公司创始人Eclipse战略教父整洁的
代码应可由作者之外的开发者阅读和增补。
它应当有单元测试和验收测试。
它使用有意义的命名。
它只提供一种而非多种做一件事的途径。
它只有尽量少的依赖关系而且要明确地定义和提供清晰、尽量少的API。
代码应通过其字面表达含义因为不同的语言导致并非所有必需信息均可通过
代码自身清晰表达。
重构-改善既有系统
代码与
设计第 7 页20110411 北京朗讯MichaelFeathersWorkingEffectivelywithLegacyCode我可以列出我留意到的整洁
代码的所有特点但其中有一条是根本性的。
整洁的
代码总是看起来像是某位特别在意它的人写的。
几乎没有改进的余地。
代码作者什么都想到了如果你企图改进它总会回到原点赞叹某人留给你的
代码—全心投入的某人留下的
代码。
重构-改善既有系统
代码与设计第 8 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase
代码质量管理Topic是谁把
代码变烂技术债务与破窗效应
代码质量管理软件可维护性—残酷的现实程序员脑子里原先那些漂亮的设计随着时间的推移会慢慢“发出腐化的臭味”.去年才构建的漂亮小巧的系统到了今年却变成了由一堆纠缠不清的函数和变量搅和在一起的“
代码浆糊”.为什么会这样迄今为止人们构建出的几乎所有软件系统都遭遇了缓慢的.不可抗拒的腐化.这种现象是如此的普遍…Topic是谁把
代码变烂技术债务与破窗效应
代码质量管理重构-改善既有系统
代码与设计第 9 页20110411 北京朗讯破窗效应BrokenwindowstheoryBrokenwindowstheoryBrokenwindowstheoryBrokenwindowstheory破窗效应没修复的破窗导致更多的窗户被打破。
所谓“破窗效应”是关于环境对人们心理造成暗示性或诱导性影响的一种认识。
“破窗效应”理论是指一个房子如果窗户破了没有人去修补隔不久其它的窗户也会莫名其妙的被人打破一个很干净的地方人会不好意思丢垃圾但是一旦地上有垃圾出现之后人就会毫不犹疑的抛丝毫不觉羞愧。
这真是很奇怪的现象。
惯性定律简而言之好的
代码会促生好的
代码糟糕的
代码也会促生糟糕的
代码。
别低估了惯性的力量。
没人想去整理糟糕的
代码同样没人想把完美的
代码弄得一团糟.技术债务TechnicalDebt开发团队在设计或架构选型时从短期效应的角度选择了一个易于实现的方案但从长远来看这种
方案会带来更消极的影响亦即开发团队所欠的债务。
WardCunningham技术债务类似于金融债务它也会产生利息这里的利息其实就是指由于鲁莽的设计决策导致需要在未来的开发中付出更多努力的后果。
我们可以选择继续支付利息也可以通过重构之前鲁莽的设计来将本金一次付清。
虽然一次性付清本金需要代价但却可以降低未来的利息。
MartinFowler烂
代码对公司的伤害--1烂
代码对程序员的伤害--2quot破窗理论quot与quot变成惯性理论quot有着宏观的联系。
编程社区就好像一个现实社区。
每个作品都是一个开发者的缩影。
如果你不去努力编写优秀、整洁和稳定的
代码那你每天都将和糟糕的
代码相伴了。
从此养成的一种恶习到时你想改正的时间都很困难这是已经成为一种习惯.重构-改善既有系统
代码与设计第 10 页20110411 北京朗讯Topic是谁把
代码变烂技术债务与破窗效应
代码质量管理软件开发的过程的4个变量成本时间质量功能范围重构-改善既有
系统代码与设计第 11 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase重构思想内容重构成为必然-需求的不确定性重构成为必然-设计师经验的缺失重构基本概念预测软件变更基本法则软件不断变更法则:真实世界中使用的程序必须进行变更否则它在环境中的作用就会越来越小.软件复杂增加性法则:随着一个不断演进程序的变更它的结构会变得更复杂除非通过积极的工作来避免这一现象.LenhmanampBelady重构-改善既有系统
代码与设计第 12 页20110411 北京朗讯内容重构成为必然-需求的不确定性重构成为必然-设计师经验的缺失重构基本概念原来牛人也会犯错误希望软件设计师用一种理性的、不会犯错的方式从需求说明中推导出设计这画面根本就不现实。
没有哪个系统是这种方式设计出来的即便教科书和
论文的小型程序开发也是不真实的它们都是经过修订和修饰的直到作者让他们看到他想要的结果因而是不可能在实际中发生的过程.DavidParnasampPaulClement内容重构成为必然-需求的不确定性重构成为必然-设计师经验的缺失重构基本概念重构的定义使用一系列的重构准则对软件内部结构的一种调整目的是在不改变软件之可察行为的前提下提高可理解性降低修改成本。
重构-改善既有系统
代码与设计第 13 页20110411 北京朗讯重构是持续进行的不要先编写烂
代码再重构重构是持续进行的而不是在项目结束时、发布版本时、迭代结束时甚至每天快下班时才进行的.重构是我们每隔一个小时或者半个小时就要去做的事情。
通过重构我们可以持续地保持
代码玛尽可能干净简单并且具有表达力.重构是小步骤的重构就是在不改变
代码行为的前提下对其进行一系列小的改造旨在改进系统结构的实践活动。
每个改造都是微不足道的几乎不值得去做。
但是有了这些改造叠加在一起就形成了对系统设计和构架显著的改进。
重构面临的问题如何发现重构点如何去重构—重构方法如何知道重构的目标---去除坏味道or重构到模式如何保证重构的正确性-单元测试重构-改善既有系统
代码与设计第 14 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase
代码的坏味道内容
代码的坏味道概述坏味道
代码坏味道codesmell是指在
代码之中潜在问题的警示信号.
代码坏味道是需要重构的症状。
或者潜在的问题PotentialProblem或者缺陷Flaw.
代码坏味道CodeSmell-坏味道名称症状Symptoms-有助于找出
问题的线索原因Causes-对问题如何会发生的说明采取的措施WhatToDo-可能的重构收益PayOff-在哪些方面有所改善不适应情况-在哪些情况下不适用的情况二八原则意大利
经济学家帕累托提出的这个原则很简单任何一组事物中最重要的只占其中约20其余的80虽然是多数但是却是次要的。
重构-改善既有系统
代码与设计第 15 页20110411 北京朗讯21种
代码坏味道-第一级坏味道DuplicatedCode重复
代码 LongMethod过长方法 LargeClass过长类 LongParameterList过长参数
列表 Comments注释过多TemporaryField临时字段 PrimitiveObsession基本类型偏执 SwitchStatementsswitch语句 DivergentChange发散式变化 ShotgunSurgery霰弹式修改21种
代码坏味道-第二级坏味道DataClumps数据泥团 DataClass数据类 FeatureEnvy特性依恋 RefusedBequest拒绝继承 MessageChains消息链 MiddleMan中间人 InappropriateIntimacy过度亲密 LazyClass冗余类 21种
代码坏味道-第三级坏味道ParallelInheritanceHierarchies平行继承体系 SpeculativeGenerality理论上的一般性 AlternativeClasseswithDifferentInterfaces接口不同的等效类IncompleteLibraryClass不完整的库类 伟大程序员的标准“我不是什么伟大的程序员我只是一个有着很多好习惯的程序员”----KentBeck语。
重构-改善既有系统
代码与设计第 16 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase函数日程为什么需要函数/子程序函数抽象层次函数/子程序过长—万恶之源函数/子程序设计创建子程序的理由-1-降低复杂度/隔离复杂度降低复杂度/隔离复杂度降低复杂度创建子程序的一个最重要的原因就是为了降低程序的复杂度。
可以通过创建子程序来隐藏一些信息这样你就不必再去考虑这些信息了。
当内部循环或条件判断的嵌套层次很深时就意味着需要从子程序中提取出新的子程序了。
把嵌套的部分提取出来形成一个独立的子程序可以降低外围子程序的复杂度。
圈复杂度CyclomaticComplexityCC圈复杂度是一种度量方法由ThomasMcCabe于1975年定义。
圈复杂度是一个方法中执行路径的数量。
起始CC从1开始。
每一个条件如if、switch、while和for语句都被分配一个1值和异常路径。
一个方法的CC表明了它的复杂度。
过去几年的各种研究已经确定圈复杂度大于10的方法存在很大的出错风险。
重构-改善既有系统
代码与设计第 17 页20110411 北京朗讯创建子程序的理由-2-引入中间的易懂的抽象/隐藏实现细节引入中间的易懂的抽象/隐藏实现细节把一段
代码放入一个命名恰当的子程序内是说明这段
代码用意最好的方法之一。
ifnodeltgtNULLthenwhilenode.nextltgtNULLdonodenode.nextleafNamenode.nameendwhileelseleafNamequotquotendif读懂下面这条语句就更容易leafNameGetLeafNamenode创建子程序的理由-3-避免
代码重复避免
代码重复创建子
程序最普遍的原因是为了避免
代码重复。
??应该把两段子程序中的重复
代码提取出来将其中的相同部分放入一个基类然后再把两段程序中的差异
代码放入派生类中。
??你也可以把相同的
代码放入新的子程序中再让其余的
代码来调用这个子程序
代码改动起来也更方便因为你只需要在一处修改即可。
这时的
代码也会更加可靠因为为了验证
代码的正确性你只需要检查一处
代码。
同时这样做也会使改动更加可靠.创建子程序的理由-4-简化复杂的布尔判断简化复杂的布尔判断为了理解程序的流程通常并没有必要去研究那些复杂的布尔判断的细节。
应该把这些判断放入函数中以提高
代码的可读性因为??1这样就把判断的细节放到一边了??2–个具有描述性的函数名字可以概括出该判断的目的。
把布尔判断的逻辑放入单独的函数中也强调了它的重要性。
这样做也会激励人们在函数内部做出更多的努力提高判断
代码的可读性。
最终
代码的主流和判断
代码都变得更加清晰。
重构-改善既有系统
代码与设计第 18 页20110411 北京朗讯创建子程序的理由-5支持子类化subclassing覆盖override简短而规整的子程序所需新
代码的数量要比覆盖冗长而邋遏的子程序更少。
如果你能让可覆盖的子程序保持简单那你在实现派生类的时候也会减少犯错的几率。
提高可移植性可以用子程序来隔离程序中不可移植的部分从而明确识别和隔离未来的移植工作。
改善性能通过使用子程序你可以只在一个地方优化
代码。
把
代码集中在一处可以更方便地查出哪些
代码的运行能使用到该子程序的所有
代码都从中受益。
隐藏顺序把处理事件的顺序隐藏起来是一个好主意。
假设你写了两行
代码读取栈顶的数据然后减少stackTop变量的值。
你你应该把这两行
代码放到一叫PopStack的子程序中。
从而把这两行
代码所必须执行的顺序隐藏起来。
把这种信息隐藏起来比让它们在系统内到处散布要好很多。
日程为什么需要函数/子程序函数抽象层次函数/子程序过长—万恶之源函数/子程序设计
代码抽象层次流畅的
代码易于理解而跳跃的
代码的抽象层次破坏了
代码的流畅性.过分深层的缩进或者“嵌套”已经困扰了
计算机界达25年之久并且至今仍然是产生混乱
代码的罪魁祸首之一。
NoamChomsky和GeraldWeinberg做过一份研究表明很少有人能够理解超过3层的if嵌套Yourdon1986a很多究人员建议避免使用超过3到4层的嵌套.地图册重构-改善既有系统
代码与设计第 19 页20110411 北京朗讯函数的抽象层次-重构前Voidcomputeinputflags0x0080output单一抽象层次原则SLAPSingleLevelofAbstrctionPrinciple让一个方法中的所有操作处于相同的抽象层.建议:IF语句else语句while语句等其中的
代码应该尽量只有一行就是调用语句.所以函数的缩进层不应该多于一层或二层.ComposedMethod组合方法意图你无法迅速地理解一个方法地逻辑。
把方法的逻辑转换成几个同一细节层面上的、能够说明意图的步骤。
??动机绝大多数实现ComposedMethod的重构都涉及多次应用提炼方法重构直到这个ComposedMethod通过调用其他方法来完成自己大部分或全部的工作。
其中最难的在于决定提取出来的方法要包含哪些
代码。
如果在一个方法中提取了过多的
代码将很难给它起一个能充分描述它功能的名字。
那样的话就要应用将方法内联化重构把提取出的
代码放回原方法中然后考虑其他的分解方法。
??优点和缺点清晰地描述了一个方法所实现的功能以及如何实现。
把方法分解成命名良好的、处在细节的同一层面上的行为模块以此来简化方法。
可能会产生过多的小方法。
可能会使调试变得困难因为程序的逻辑分散在许多小方法中。
??实现ComposedMethod的重构的一些指导原则1、ComposedMethod都很小。
ComposedMethod的
代码很少超过10行一般都在5行左右。
2、删除重复
代码和死
代码。
除去明显的和微妙的
代码重复除去没有被使用的
代码以减少方法的
代码量。
3、表达意图。
清楚地命名程序中地变量、方法和参数使它们明确表达意图。
4、简化。
转换
代码使它尽可能简单。
为此可以思考组是如何编写某些
代码的尝试着使用其他方法重新编写。
5、使用细节的同一层面。
当把一个方法分解成一组行为的时候要保证这些行为在细节的相似层面上。
重构-改善既有系统
代码与设计第 20 页20110411 北京朗讯日程为什么需要函数/子程序函数抽象层次函数/子程序过长—万恶之源函数/子程序设计
代码过长是万恶之源几乎所有的问题问题都来源于Longmethod/longClass因为它们包含太多的信息这些信息又被函数错综复杂的逻辑掩盖不易鉴别.函数第一设计原则过去30年来以下建议以不同形式一再出现.函数应该做一件事做好这件事只做这件事.函数第一原则:是要短小函数第二原则:是还要短小函数第三原则:是必须短小过长的方法症状:存在大量的
代码行.超过100行以上的需要注意原因:自从方法开发过程之中作者从未考虑过将整个流程适当分解也未试图籍于某些辅助类的帮助而是一味增加.采取措施使用抽取方法分解更小的部分.对于有意义的
代码块请查找有关的注释或空格要抽取的方法有具体的含义而不是机诫抽取在开始分解前还可以找到其他一些帮助抽取类等收益:增加
代码的表达能力.有助于建立新的类和抽象.讨论方法调用的增多会不会影响性能不用机诫度量不适应情况有些情况下可能需要一个稍长的方法重构-改善既有系统
代码与设计第 21 页20110411 北京朗讯日程为什么需要函数/子程序函数抽象层次函数/子程序过长—万恶之源函数/子程序设计创建类和函数的过程重构-改善既有系统
代码与设计第 22 页20110411 北京朗讯??EvolvebycaseEvolvebycaseEvolvebycaseEvolvebycase函数参数与返回值日程函数参数函数返回值函数参数最理想的参数数量是零其次是一再次是二有足够的理由才能使用三个以上参数.过长的参数表症状:方法的参数过多比如gt3个以上原因:.采取措施如果参数值可以由已知的另一个对象获得可以将参数替换为方法ReplaceparameterwithMethod如果参数来自一个对象可以保持对象完整PreservewholeObject如果数据并非来自一个逻辑对象可以引入参数对象introduceparameterobject收益:增加
代码的表达能力.有可能暴露出重复性重构-改善既有系.