﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-常高伟的专栏-随笔分类-它山之石</title><link>http://www.blogjava.net/chgaowei/category/42132.html</link><description>思考、分享、交流、进步——为了自己的、公司的、中国的、世界的软件技术</description><language>zh-cn</language><lastBuildDate>Mon, 12 Oct 2009 12:32:45 GMT</lastBuildDate><pubDate>Mon, 12 Oct 2009 12:32:45 GMT</pubDate><ttl>60</ttl><item><title>代码的坏味道</title><link>http://www.blogjava.net/chgaowei/archive/2009/10/12/297963.html</link><dc:creator>常高伟</dc:creator><author>常高伟</author><pubDate>Mon, 12 Oct 2009 12:15:00 GMT</pubDate><guid>http://www.blogjava.net/chgaowei/archive/2009/10/12/297963.html</guid><wfw:comment>http://www.blogjava.net/chgaowei/comments/297963.html</wfw:comment><comments>http://www.blogjava.net/chgaowei/archive/2009/10/12/297963.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/chgaowei/comments/commentRss/297963.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/chgaowei/services/trackbacks/297963.html</trackback:ping><description><![CDATA[<p>《重构》第三章学习笔记  <p>我们必须培养自己的判断力，来决定在什么时候进行重构。  <h4>1.1&nbsp; Duplicate Code（重复代码）</h4> <p>如果你在一个以上地点看到相同的程序结构，那么将他们合而为一会更好。  <h4>1.2&nbsp; Long Method（过长函数）</h4> <p>拥有短函数的对象会活得比较好，比较长。  <p>间接层所能带来的全部益处：解释能力（可读性），共享能力（重用性），选择能力（？）。  <p>现在OO 语言基本解决了函数调用所产生的开销。  <p>“ 你应该更积极进去的分解函数。我们遵循这样一条原则：每当感觉需要以注释来说明点什么的时候，我们就把需要说明的东西写进一个函数中，并以其用途（而非实现手法）命名。我们可以对一组甚至短短一行代码（拥有复杂逻辑，难以理解）做这件事。哪怕替换后的函数调用动作比函数自身还长，只要函数名称能够解释其用途，我们也该毫不犹豫的这么做。关键不在于函数的长度，而在于“做什么”和“如何做”之间的语义距离。 ”  <p>“如何确定该提炼哪一段代码？一个很好的技巧是：寻找注释。它们通常是指出“代码用途和实现手法间的语义距离”的信号。如果代码需要用注释来说明其用途，那么就要考虑把这段代码提炼成独立的函数，并且用注释来为此函数命名。”  <p>复杂条件式和循环液常常是提炼的信号。  <h4>1.3&nbsp; Large Class（过大类）</h4> <p>如果想利用单一的class 做太多的事情，其内往往会出现太多的 instance 变量。  <p>如果class 中拥有太多的代码，也是“代码重复、混乱、死亡”的绝佳滋生点。  <h4>1.4&nbsp; Long Parameter List（过长的参数列表）</h4> <p>过长的产生导致程序难以理解。  <h4>1.5&nbsp; Divergent Change（发散式变化）</h4> <p>“ 一个class 受多个外界变化的影响 ”，则把这多个变化封装成一个新的类。即“ 将总是一起变化的东西放在一起 ”  <p>针对外界某一变化所有相应的修改，都应该只发生在单一的class 中，而这个 class 的所有内容都应该反映该外界变化。总的思想就是，封装变化。这个地方和设计模式的想法是一致的。  <h4>1.6&nbsp; Shotgun Surgery（散弹式修改）</h4> <p>和发散式变化不同，每次遇到变化，都要在多个class 中进行小的修改以响应之。他们分散在多处，很容易出错。  <p>这里的主要思想是集中变化。  <p>散弹式修改指的是，“ 一种变化引发多个class 的修改 ”，发散式变化指的是“ 一个class 受多个外界变化的影响 ”。  <p>这两种情况下，通过重构， 使“外界变化”和“待修改类”呈一对一关系 的理想境地。  <h4>1.7&nbsp; Feature Envy（依恋情节）</h4> <p>某个函数对其他类的数据的兴趣，高过对host class 的兴趣。即对其他的类的数据的依赖十分大。  <h4>1.8&nbsp; Data Clumps（数据泥团）</h4> <p>数据泥团指的是总是绑定在一起出现的数据。  <p>一个好的评断方法：删除众多数据中的一项数据，其他数据是否是因而失去了意义？如果他们不再有意义：你应该为他们产生一个新的对象。  <p>形成新的对象后，可以根据Feature Envy 将一些操作移至此对象中。  <h4>1.9&nbsp; Primitive Obsession（基本型别偏执）</h4> <p>建立多个很小，但是很灵活的对象。  <h4>1.10&nbsp; Switch Statements（ switch 惊悚现身）</h4> <p>使用面向对象编程，要少用switch 和 case 语句。而是用多态来替换它。  <h4>1.11&nbsp; Parallel Inheritance Hierarchies（平行继承体系）</h4> <p>每当你为一个class 增加一个 subclass 的时候，必须为另一个 class 增加一个 subclass 。一般这两个 class 的前缀相同。  <h4>1.12&nbsp; Lazy Class（冗赘类）</h4> <p>类显得多余，没有价值。  <h4>1.13&nbsp; Speculative Generality（夸夸其谈未来性）</h4> <p>这个往往是过度设计的结果：对某种变化的应对，而这种变化没有发生。  <h4>1.14&nbsp; Temporary Field（令人迷惑的暂时值域）</h4> <p>变量只在特定的情形下有效，而并不是所有的情况下有效。很多情况下，这些值域应该不属于此class ，而应该单独的提取成新的类。  <h4>1.15&nbsp; Message Chains（过度耦合的消息链）</h4> <p>用户向一个对象索取另一个对象，然后在向后者索求另一个对象，然后在索求另一个对象——客户与查找过程的航行结构紧密耦合。  <h4>1.16&nbsp; Middle Man（中间转手人）</h4> <p>对象的基本特征之一就是封装——对外部世界隐藏实现细节——封装往往伴随委托。委托的过度运行，就导致了Middle Man 。  <h4>1.17&nbsp; Inappropriate Intimacy （亲密关系）</h4> <p>两个class 之间的关系过于亲密。比如，花大量的时间探究彼此的 private 成分。  <h4>1.18&nbsp; Alternative Classes with Different Interface（异曲同工的类）</h4> <p>类名不同，但是功能相似。  <h4>1.19&nbsp; Incomplete Library Class（不完美的程序类库）</h4> <p>基础类库无法满足实际的需求。  <h4>1.20&nbsp; Data Class（纯稚的数据类）</h4> <p>它们拥有一些值域，以及用于访问（读写）这些值域的函数，除此之外一无长物。  <h4>1.21&nbsp; Refused Bequest（被拒绝的遗赠）</h4> <p>子类不像继承父类的函数和数据，这往往是继承体系的错误。  <p>如果子类复用父类的行为，但又不愿支持父类的接口，这种情况下Refused Bequest 的坏味道会很强烈。  <h4>1.22&nbsp; Comments（过多的注释）</h4> <p>注释其实是一种香味，更多的情况下它被用作除臭剂：即代码中出现坏味道（设计糟糕的代码），然后用注释“除臭”。这个时候我们应该对这些坏味道的代码进行重构，然后，你会发现注释变成了多余的。  <p>当你感觉需要注释，请先尝试重构，试着让所有的注释都变得多余——代码本身就是自注释的。  <p>注释可以用来记述“为什么做某事”、“打算做某事”、“无十足把握的区域”，而不必记录“怎么做”。</p><img src ="http://www.blogjava.net/chgaowei/aggbug/297963.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/chgaowei/" target="_blank">常高伟</a> 2009-10-12 20:15 <a href="http://www.blogjava.net/chgaowei/archive/2009/10/12/297963.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>重构&amp;mdash;&amp;mdash;构筑测试体系</title><link>http://www.blogjava.net/chgaowei/archive/2009/10/12/297958.html</link><dc:creator>常高伟</dc:creator><author>常高伟</author><pubDate>Mon, 12 Oct 2009 12:11:00 GMT</pubDate><guid>http://www.blogjava.net/chgaowei/archive/2009/10/12/297958.html</guid><wfw:comment>http://www.blogjava.net/chgaowei/comments/297958.html</wfw:comment><comments>http://www.blogjava.net/chgaowei/archive/2009/10/12/297958.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/chgaowei/comments/commentRss/297958.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/chgaowei/services/trackbacks/297958.html</trackback:ping><description><![CDATA[<h3>1&nbsp; 构筑测试体系</h3> <p>如果你想进行重构，首要前提就是要拥有一个可靠的测试环境。  <p>“编写优良的测试程序，可以极大的提高我的编程速度，即使不进行重构也是如此。”  <h4>1.1&nbsp; 自我测试代码（Self-testing Code ）的价值</h4> <p>“Class 应该包含他们自己的测试代码。”  <p>“每个Class 都有一个测试函数，并用它测试自己这个 Class 。”  <p>确保所有的测试都完全自动化，让它们检查自己的测试结果。  <p>只要写好一点功能，就立即添加测试。  <p>一整组（a suite of ）测试就是一个强大的“臭虫”侦测器，能够大大缩减查找“臭虫”所需要的时间。  <p>“实际上，编写测试代码的最有用时机是在开始编程之前。当你需要添加特性的时候，先写相应的测试代码。听起来离经叛道，其实不然。填写测试代码其实就是问自己：添加这个功能需要做什么。编写测试代码还能使你把注意力集中于接口而非实现上头（永远是件好事）。预先写好的测试代码也为你的工作按上一个明确的结束标志：一旦测试代码运行正常，工作就可以结束了。”  <p>构建自我测试的代码。  <h4>1.2&nbsp; JUnit测试框架（ Testing Framew ）</h4> <p>频繁的运行测试，每次编译请把测试也考虑进去，每天至少执行每个测试一次。  <p>单元测试和功能测试  <p>“每当你接获臭虫提报，请先撰写一个单元测试来揭发这只臭虫。”——如何揭发？这里需要根据报告准确定位。单元测试会对此有帮助吗？  <h4>1.3&nbsp; 添加更多的测试</h4> <p>“观察Class 该做的所有事情，然后针对任何一项功能的任何一种可能失败的情况，进行测试。”  <p>“测试应该是一种风险驱动（risk driven ）行为，测试的目的是希望找出现在或未来的可能出现的错误。”  <p>“测试的诀窍是：测试你最担心的部分。”  <p>这点和我目前的想法不大相同。我目前的想法是，测试要对程序做100% 的保证，所以，要测试程序可能行为的每一种情况，保证其正确性。按照我的想法，值域的设置和访问函数也是要测试的。作者的意思是，测试代码要用最低的成本，获取最大的收益。这一点，要我在实际的环境中进行抉择。  <p>“编写不是十分完美的测试并实际运行，好过对完美测试的无尽等待。”——我持怀疑态度。  <p>运用测试用例前后执行的函数：tearDown 和 setUp ，保证测试用例之间相互隔离，而非相互影响。  <p>做一个懒惰的程序员——。  <p>考虑可能出错的边界条件，把测试火力集中在那儿。  <p>“测试（优先）可以调高编程速度”，这一点我要在实践中验证一下，如果真是这样，那我就要尝试在我们部门推行这种方法。  <p>“当测试达到一定的程度后，测试效益会呈现递减态势。”所以，你不要期望通过测试找出所有的bug ，而是要通过测试，找出绝大多数的 bug 。  <p>这个地方其实也符合“二八定律”：即20% 的测试可以找出 80% 的 bug ，其余的 80% 的测试可以找出剩下的 20% 的 bug 。我们要做的，就是写这 20% 的测试，而非 100% 的测试。  <p><img alt="" src="http://p.blog.csdn.net/images/p_blog_csdn_net/chgaowei/EntryImages/20091009/test%20case.jpg"><img src ="http://www.blogjava.net/chgaowei/aggbug/297958.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/chgaowei/" target="_blank">常高伟</a> 2009-10-12 20:11 <a href="http://www.blogjava.net/chgaowei/archive/2009/10/12/297958.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>