﻿<?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-Jiangshachina-随笔分类-Methodology</title><link>http://www.blogjava.net/jiangshachina/category/35489.html</link><description>同是Java爱好者，相逢何必曾相识！&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;a cup of Java, cheers!</description><language>zh-cn</language><lastBuildDate>Thu, 13 Aug 2009 08:05:42 GMT</lastBuildDate><pubDate>Thu, 13 Aug 2009 08:05:42 GMT</pubDate><ttl>60</ttl><item><title>出错时的软件开发(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2008/10/27/236562.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Mon, 27 Oct 2008 00:44:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2008/10/27/236562.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/236562.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2008/10/27/236562.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/236562.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/236562.html</trackback:ping><description><![CDATA[<div align="center"><span style="font-size: 10pt;"><strong style="font-size: 14pt;">出错时的软件开发</strong></span><br />
</div>
<span style="font-size: 10pt;">
在开发的过程中有错误发生了，此时你该如何应对呢？<a href="http://weblogs.java.net/blog/johnsmart/">John Ferguson Smart</a>在他的<a href="http://weblogs.java.net/blog/johnsmart/archive/2008/10/software_develo.html">最新博客</a>中提出了一些想法，大家可以参考一下(2008.10.27最后更新)<br />
<br />
&nbsp;&nbsp;&nbsp; 现今比以后任何时候，都需要开发者更加高效。极度高效。组织需要提高从它们的开发项目中得到的附加值，并且它们也乐于寻找实现这一目标的方法。<br />
当然，你可以采用传统的方法--努力工作。为了消除项目中不可预见的症状，每天工作16个小时，还没有周末。但做的更聪明一点儿，会不会更好些？<br />
在引进新的实践方法及改进现有方法方面投入的相对多一些，以使组织能努力获得更多回报，这就是开发的过程。一般而言，事物中有许多方面都可以被改进，但此处有一些小窍门能使你的开发流程更加合理，只是为你开个头罢了。<br />
<br />
<strong style="font-size: 12pt;">持续集成(CI)通知策略的再思考<br />
</strong>&nbsp;&nbsp;&nbsp; 到目前为止，最通用的CI通知机制就是陈旧的邮件服务器。然而，你能肯定在你手边能完成这项任务的最合适系统就是电子邮件吗？尝试不使用电子邮件，而使用即时消息去完成你的CI通知。记住，电子邮件易成为一种干扰--如果你仅仅大约每两小时才查阅一次邮件，你就会变得十分高效。电子邮件只是，或至少是，用于构建失败--人们需要<em>快速</em>地知晓失败任务。<br />
<br />
<strong style="font-size: 12pt;">积极地优化构建过程</strong><br />
&nbsp;&nbsp;&nbsp; 构建度量(Build Metrics)是一种监控构建过程健康状况的极好方法。为什么过去3周中，代码覆盖率一直在下降？为什么单元测试的数量并未呈有规律的增长？为什么要花费很长的时间去修复这样的构建？运行单元测试需要多长时间--是否有一些测试需要执行过分长的时间？这些信息并非华而不实的东西--在不断改进构建过程的工作中，它们都扮演着关键的角色。现代CI工具，如Hudson，Bamboo和TeamCity，能为构建展示丰富的统计。Bamboo在这方面做的尤佳。无论你正使用何种CI工具，都要学习如何最大限度地使用它的报表特性，并使用这些特性去定位及修复开发过程中讨厌污点。如果你的CI工具不能给你所需要的全部信息，那就找一个能做到的。<br />
<br />
<strong style="font-size: 12pt;">合理化发布过程</strong><br />
&nbsp;&nbsp;&nbsp; 在发布过程中有许多必做的工作，如准备发行说明，确定该版本中哪些问题已被解决了，标记版本，等等。这些都是软件生命周期的重要部分，如果你忽略了它们，QA们和最终用户可能会很生气。但要尽量自动地去做这些工作。许多CI工具能很好地与问题追踪系统(如JIRA和Trac)进行集成，以便你能基于版本控制日志看到某个问题是在哪次特定的构建中被解决的。如果你在使用Eclipse，Mylyn能帮你将处理过的问题归总成逻辑变化组，并使用标准的模板列出在某项工作中已被解决的(或仅是影响到的)问题。或者你可使用Subversion的hook脚本去确保每次向Subversion做的提交都能对应到一个有效的问题编号。<br />
&nbsp;&nbsp;&nbsp; 这只是一些想法罢了--还有更多。底线就是--你不需要忍耐一个次理想的开发过程--相反，要进入其中，并做些能改进它的事情。祝好运! <br />
<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/236562.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2008-10-27 08:44 <a href="http://www.blogjava.net/jiangshachina/archive/2008/10/27/236562.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>编写好的面向对象代码(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2008/10/07/232942.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Tue, 07 Oct 2008 09:06:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2008/10/07/232942.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/232942.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2008/10/07/232942.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/232942.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/232942.html</trackback:ping><description><![CDATA[<div align="center"><span style="font-size: 10pt;"><strong style="font-size: 14pt;">编写好的面向对象代码</strong></span><br />
</div>
<p align="left"><span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 本文是<a href="http://www.java.net">java.net</a>上的一篇<a href="http://weblogs.java.net/blog/thedarksavant/archive/2008/10/writing_great_o_1.html">博客</a>，作者<a href="http://weblogs.java.net/blog/thedarksavant/">Curtis Cooley</a>对编写好的面向对象代码有些建议，希望对大家都有所帮助。(2008.10.08最后更新)<br />
</span><span style="font-size: 10pt;"><br />
获取经验没有捷径。编写好的面向对象代码需要经验，但这儿有三种做法能帮你在一开始就很顺利，即便你是老顽固：<br />
&nbsp;&nbsp;&nbsp; 1. 使用测试驱动开发(TDD)编写你所有的代码<br />
&nbsp;&nbsp;&nbsp; 2. 遵循<a href="http://xp.c2.com/XpSimplicityRules.html">简单法则</a><br />
&nbsp;&nbsp;&nbsp; 3. 告之而非问之<br />
<br />
</span><span style="font-size: 10pt;"><strong style="font-size: 12pt;">使用TDD编写所有代码</strong><br />
&nbsp;&nbsp;&nbsp; 按<a href="http://ponderingobjectorienteddesign.blogspot.com/2008/09/tdd-is-design-activity.html">测试先行</a>编写的代码与按测试后行编写的代码是极为不同的代码。按测试先行编写的代码是松耦合与高聚合的。当某个属性或私有方法需要暴露给测试程序时，按测试后行编写的代码常会打破封装，因为该类并不是为了测试而设计的。如果你首先编写测试代码，你的依赖将会更好，你的代码将是松耦合与高聚合的。后面会有更多关于测试能帮助你设计更佳代码的内容。<br />
<br />
<strong style="font-size: 12pt;">遵循简单法则</strong><br />
&nbsp;&nbsp;&nbsp; 代码是简单的，只要当它：<br />
&nbsp;&nbsp;&nbsp; 1. 执行了所有的测试<br />
&nbsp;&nbsp;&nbsp; 2. 不包含重复<br />
&nbsp;&nbsp;&nbsp; 3. 表达了所有的意图<br />
&nbsp;&nbsp;&nbsp; 4. 使用最少的类和方法<br />
注意到我用的是个被排序了的列表是很重要的。顺序是重要的。只有一个main()方法的的GodClass<sup>[1]</sup>不会是简单的。这个类可能执行了所有的测试，但在任何比"Hello, world!"更复杂的程序中，它肯定包含了重复，并且也没有表达出全部的意图。<br />
我努力使用简单法则去关注<a href="http://ponderingobjectorienteddesign.blogspot.com/2008/09/if-bugs.html">If问题</a>。我不知道如何使用简单法则去阻止某人编写重量级的If代码。有人可能会提出不同意见，我也尝试过，但这样的重量级If代码确实无法表达意图。但当你阅读如下代码时</span></p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 10pt; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(mobile.getType()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;MobileTypes.STANDARD)&nbsp;{<br />
&nbsp;&nbsp;alert();<br />
}</span></div>
<span style="font-size: 10pt;">确实难以看出其中的意图。这些代码无论处于哪个方法的上下文环境中，我们都能知道，如果mobile是STANDARD类型的话，那么就报警。而你所需要的更多意图呢？<br />
我还有一点儿灵感显现。如果有那样的代码，那么在其它地方肯定还会有更多那样的代码。这些代码可能就像：<br />
</span>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(mobile.getType()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;MobileTypes.GAS)&nbsp;{<br />
&nbsp;&nbsp;registerGasReading();<br />
}</span></div>
<span style="font-size: 10pt;">和</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 10pt; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(mobile.getType()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;MobileTypes.TEXT)&nbsp;{<br />
&nbsp;&nbsp;sendTextMessage();<br />
}</span></div>
<span style="font-size: 10pt;">和</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 10pt; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(mobile.getType()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;MobileTypes.LOCATION)&nbsp;{<br />
&nbsp;&nbsp;notifyLocation();<br />
}</span></div>
<span style="font-size: 10pt;">你看出来了吗？我是看出来了。它违反了规则2，有很多地方都违反了规则2，并且是一种最坏的情形。这段代码有多处重复。重复将极难发现。所以，请帮助防止这种情形的发生，我已包含其中了。<br />
<br />
<strong style="font-size: 12pt;">告之而非问之</strong><br />
简言之，<a href="http://www.pragmaticprogrammer.com/articles/tell-dont-ask">告之而非问之</a>意指不要先问一个对象的状态，然后才让它去工作。而应该告之对象如何去工作。这就意味着之前所有的那些If例子应该变为：</span> <br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">mobile.alert();</span></div>
<span style="font-size: 10pt;">和</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 10pt; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">mobile.registerGasReading();</span></div>
<span style="font-size: 10pt;">和</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">mobile.sendTextMessage();</span></div>
<span style="font-size: 10pt;">和</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 0);">mobile.notifyLocation();</span></div>
<span style="font-size: 10pt;">现假设遍布该程序中的一些If语句块有重复的实现。在"重量级If"版本的程序中，可能很难发现它们；但在"告之而非问之"版本的程序中，所有的实现都在Mobile中。所有的实现都在一处，这就便于察觉并根除问题。<br />
&nbsp;&nbsp;&nbsp; 倾听你的测试程序也能帮助你保持代码的简洁。</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);">&nbsp;Alarm&nbsp;{<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;alert(Mobile&nbsp;mobile);<br />
}<br />
<br />
</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;Siren&nbsp;</span><span style="color: rgb(0, 0, 255);">implements</span><span style="color: rgb(0, 0, 0);">&nbsp;Alarm&nbsp;{<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;alert(Mobile&nbsp;mobile)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(mobile.getType&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;MobileTypes.STANDARD)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;soundSiren();<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;TestSiren&nbsp;</span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);">&nbsp;TestCase&nbsp;{<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;test_alert()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;LocationMobile&nbsp;mobile&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;LocationMobile();<br />
&nbsp;&nbsp;&nbsp;&nbsp;Siren&nbsp;siren&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Siren();<br />
&nbsp;&nbsp;&nbsp;&nbsp;siren.alert(mobile);<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">assert</span><span style="color: rgb(0, 0, 0);">(sirenSounded());<br />
&nbsp;&nbsp;}<br />
}</span></div>
<span style="font-size: 10pt;">如果你密切地倾听测试程序，它可能会问你，"为什么你需要一个LocationMobile去测试Siren呢？"的确，为什么呢？看起来，Siren应该还不知道LocationMobile吧。</span><br />
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;LocationMobile&nbsp;{<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">&nbsp;Alarm&nbsp;alarm;<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;LocationMobile(Alarm&nbsp;alarm)&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.alarm&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;alarm;<br />
&nbsp;&nbsp;}<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;alert()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;alarm.alert();&nbsp;</span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">&nbsp;alert&nbsp;on&nbsp;Alarm&nbsp;no&nbsp;longer&nbsp;needs&nbsp;a&nbsp;mobile</span><span style="color: rgb(0, 128, 0);"><br />
</span><span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;}<br />
}<br />
<br />
</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;TestLocationMobile()&nbsp;</span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);">&nbsp;TestCase&nbsp;{<br />
&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;test_alert()&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;Alarm&nbsp;alarm&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;EasyMock.createMock(Alarm.</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">);<br />
&nbsp;&nbsp;&nbsp;&nbsp;alarm.alert();<br />
&nbsp;&nbsp;&nbsp;&nbsp;EasyMock.replay(alarm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;Mobile&nbsp;mobile&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;LocationMobile(alarm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;mobile.alert();<br />
&nbsp;&nbsp;&nbsp;&nbsp;EasyMock.verify(alarm);<br />
}</span></div>
<span style="font-size: 10pt;">好像我只是交换了依赖关系。Alarm不再依赖Mobile，现在是Mobile依赖Alarm。但如果你仔细地观察这个测试程序，你会发现真正的依赖关系是，Siren知晓了LocationMobile。一个具体类依赖另一个具体类，这违反了<a href="http://c2.com/cgi/wiki?DependencyInversionPrinciple">依赖反转原则</a>(DIP)。第二个例子就让LocationMobile依赖Alarm接口。具体类依赖抽象，这就满足DIP了。<br />
&nbsp;&nbsp;&nbsp; 如果你使用TDD，并遵循简单法则和告之而非问之原则去编写所有的代码，你就处于成为一个更好的面向对象程序员的道路上了。好的面向对象代码易于阅读和维护，但难以编写，至少，在开始时是这样的。你写的越多，你就会变得越好，也会获得更多的经验。同时，这些实践经验也会使你在自己的道路上受益匪浅。<br />
<br />
<strong>译注</strong><br />
[1]GodClass(上帝类)指包含了太多内容的类。<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/232942.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2008-10-07 17:06 <a href="http://www.blogjava.net/jiangshachina/archive/2008/10/07/232942.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>何时编写单元测试？(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2008/06/09/206812.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Mon, 09 Jun 2008 12:55:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2008/06/09/206812.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/206812.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2008/06/09/206812.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/206812.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/206812.html</trackback:ping><description><![CDATA[<div align="center"><strong><span style="font-size: 10pt;"><span style="font-size: 14pt;">何时编写单元测试？</span></span></strong><br />
</div>
<span style="font-size: 10pt;">&nbsp;&nbsp;&nbsp; 是在编写一个方法之前就编写它的单元测试，还是在写完这个方法，甚至是整个类之后才编写单元测试呢？John Ferguson Smart<sup>[1]</sup>在他的<a href="http://weblogs.java.net/blog/johnsmart/archive/2008/06/tests_first_or.html">blog</a>中再次提出了这个问题，并根据自己的经验给出了一些建议。(2008.06.10最后更新)<br />
<br />
&nbsp;&nbsp;&nbsp; 都别书生意气了。在你编写一个方法之前或是之后编写单元测试--根据我的经验，只要你在编写代码的<em>几乎同时</em>就考虑并编写单元测试程序，那么这就无关紧要了。过后再返回去(或者根本就不回去)写测试程序将导致问题。就我个人而言，我喜欢在编写少量代码之前或紧接着的之后就编写单元测试--这不会打破工作流程，因为<em>它就是流程的一部分</em>。<br />
&nbsp;&nbsp;&nbsp; 这需要一点儿实践经验--缺乏经验的开发者经常为要写什么样的测试程序而烦恼。但这可能也反映出一个事实：他们同样也不知道要写什么样的代码。一些人评说TDD能够鼓励进行微设计--一种非常底层的设计，它不需要考虑较大的场景。这会发生在缺乏经验的开发者身上；如果你教条般地应用这种方法，同样也会遇上。像行为驱动开发这样的方法在此处就会很酷。当你在写getter方法之前，你会写一个针对这个getter方法的单元测试吗？如果是的话，那么你的单元测试专注的层次就较高了，也会更接近于用户(或系统)的需求。<br />
&nbsp;&nbsp;&nbsp; 回到问题的本质，为什么我喜欢把单元测试放在最开始的位置？很简单！我的实践经验告诉我，那样可以帮助提高代码的质量，并且节约调试时间。在开始时写十个小的单元测试所花的时间比在以后修复Bug所花的时间要少，如果代码经过了正确的单元测试，那就不会有Bug了。<br />
&nbsp;&nbsp;&nbsp; 事实上，我屡屡见到，如果某些代码经过了适当的单元测试，那么就不会有编码问题。最近就有一个例子：花了一个小时的时间去搜寻Web应用中的一个问题，该问题出现在一个编写正确的Spring-MVC程序中。结果是由于一个检验器类忽略了一个异常。很容易就发现了这个问题，实际上，在看了代码(代码检查(Code Review)也很有效)之后立刻就发现了。但关键是，我们花了一个小时甚至更多的时间去找这个需要进行检查的类。如果这些代码经过了适当的测试，那么就能很快地发现并解决这个问题。<br />
&nbsp;&nbsp;&nbsp; 根据我的经验，当人们在编写完程序之后才开始编写单元测试，就如同事后才有这样的想法，他们很难写出这些测试了 ("我已经完成了所有的代码，此时我还得去写单元测试")。或者根本就不去做。在这种情况下，代码是否完成了呢？如果代码运行地很好，那就算是完成了。这样的话，再写单元测试就大大地丧失了它的价值。还不仅如此，事后编写的单元测试将是肤浅的，不会对代码进行良好地测试。或者，开发者已经耗完了时间，他们根本就不想再为单元测试伤神了。<br />
&nbsp;&nbsp;&nbsp; TDD与任何其它的编码实践一样。当你正在学习某个新的技术时，你会倾向于对学习指导亦步亦趋。类似地，当你学习一项武术时，你也会试着一步步地模仿大师的动作，而不必去理解其中的逻辑。一旦你熟悉了某个技术，能够熟练地使用它，并对它有了更深入地理解，<em>然后</em>，你就能改进它，并与你之前掌握的其它技术进行溶合了。<br />
<br />
<strong><span style="font-size: 12pt;">
译注</span></strong><br />
[1]John是<a href="http://www.javapowertools.com/">Java Power Tools</a>一书的主作者，也是<a href="http://www.java.net/">java.net</a>中一位活跃的<a href="http://weblogs.java.net/blog/johnsmart/">Blogger</a>。<br />
<br />
<strong><span style="font-size: 12pt;">译后</span></strong><br />
&nbsp;&nbsp;&nbsp; 上周在java.net上看到这篇Blog，再联想到自己在平时工作中的单元测试实践，有些感触，故将其翻译了出来，与大家共享。<br />
&nbsp;&nbsp;&nbsp; 事先就编写单元测试，还是事后才编写单元测试？这是一个老问题。按照TDD的思想，自然是要先编写单元测试，然后再编写能够通过该单元测试的方法。<br />
&nbsp;&nbsp;&nbsp; 但，单元测试并不是TDD的专属领地，很多不实践TDD的项目也在应用着单元测试。<br />
&nbsp;&nbsp;&nbsp; 我认为，在不实践TDD的项目中(我自己所处的环境就是如此)，事后编写单元测试仍有着其合理性：<br />
&nbsp;&nbsp;&nbsp; 1. 以消极的态度来看，既然项目本身不严格要求事先编写单元测试，那么就可以在事后去做了。这至少比不去做要好，聊胜于无嘛。(嘿嘿，是够消极的，但也拿你没办法)<br />
&nbsp;&nbsp;&nbsp; 2. 事后编写单元测试至少也是一种检验手段，当然，肯定比不上事先编写的单元测试。因为，事后编写的单元测试很可能会"将就"已经写好的应用程序，正如John所说"事后编写的单元测试将是肤浅的，不会对代码进行良好地测试"。但...仍然是聊胜于无嘛 :-D (哈哈，有完没完了)<br />
&nbsp;&nbsp;&nbsp; 3. 可以把单元测试，其中就包含事后单元测试，作为"后来者"了解、学习应用程序的手段。因为单元测试程序就是应用程序的"客户"，所以无论它是事先写的，还是事后写的，都能够表现出应用程序的行为。<br />
&nbsp;&nbsp;&nbsp; 4. 事后单元测试，也可能转化为事先单元测试。在应用程序的整个生命周期中，维护阶段是最长的。在"漫长"的维护过程中，"之前"所写的"事后"单元测试将会成为"后来者"(包括原始作者本人)的"事先"单元测试。在改进程序的过程中，这些单元测试仍然能起到监督的作用。(orz，有点儿诡辩)<br />
&nbsp;&nbsp;&nbsp; 虽然，事后单元测试明显不如事先单元测试，但它的作用仍然不可低估。只要编写了优秀的单元测试程序，无论是在哪个阶段，它都会对改进应用程序有莫大的帮助。(这可不是"聊胜于无"能够表达的)<br />
<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/206812.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2008-06-09 20:55 <a href="http://www.blogjava.net/jiangshachina/archive/2008/06/09/206812.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Design Patterns are Code Smells(译)</title><link>http://www.blogjava.net/jiangshachina/archive/2007/06/04/121731.html</link><dc:creator>Sha Jiang</dc:creator><author>Sha Jiang</author><pubDate>Mon, 04 Jun 2007 01:00:00 GMT</pubDate><guid>http://www.blogjava.net/jiangshachina/archive/2007/06/04/121731.html</guid><wfw:comment>http://www.blogjava.net/jiangshachina/comments/121731.html</wfw:comment><comments>http://www.blogjava.net/jiangshachina/archive/2007/06/04/121731.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jiangshachina/comments/commentRss/121731.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jiangshachina/services/trackbacks/121731.html</trackback:ping><description><![CDATA[<div style="text-align: center;"><span style="font-weight: bold;"><span style="font-size: 14pt;"><span style="font-size: 14pt;">Design Patterns are Code Smells</span></span></span><br />
</div>
<span style="font-size: 10pt;">上个月就在TheSeverSide中看到关于<a href="http://www.relevancellc.com/2007/5/17/design-patterns-are-code-smells">这篇文章</a>(实际是一篇简短的Blog)的消息，当时就觉得很有趣，因为自己正在学习设计模式，故将这篇短文保存了下来。昨天在自己电脑中又看到了此文，顺手就把它翻译了出来。<br />
这篇Blog的作者认为大部分设计模式在代码层都是code smell，在文末评论中有Google Guice项目的leader -- Bob Lee的评语。Bob对作者的观点表示了赞同，但也指出框架可以减轻对模式的需要。(2007.06.04最后更新)<br />
<br />
在原始的Gof的书中，作者清楚地指出当你在使用设计模式时，<br />
&nbsp;&nbsp;&nbsp; 程序设计语言的选择是重要的，因为它会影响某人的观点。我们的模式假设是使用Smalltalk/C++语言级特性，这种选择决定了什么容易/不容易实现(Design Patterns, p.4)。<br />
不幸的是，这条信息基本上被丢弃了，程序员们时常将模式当作处方。Martin Fowler解释了区别：<br />
&nbsp;&nbsp;&nbsp; 处方趋于更加特别，经常关联于一个特别的语言和平台。甚至当一些模式需要依赖一个特定的平台时，他们仍试图于用这些模式去解释更加一般的概念。<br />
如果你已经遇到一个Java或C#应用程序看起来像C++的处理方式，你就会知道这两个概念的混合将造成损害。<br />
不管你如何从处方中区分出模式，你所思考的程序设计语言就是你要为之所设计的程序语言。这也就是为什么Prags鼓励每个人每年学习一种新的语言。你将仍会为你所知道的这组语言进行设计，但至少你将不会没有希望。<br />
程序语言提前使模式不能成为药方。回到1998年，Petter Norvig争论道，大部分的原始Gof模式在Dylan或Lisp中都是无形或简单的。之后，Greg Sullivan对Scheme持同样的观点。Jan Hannemann也使用Java+AspectJ证明了相同的观点。设计模式不能如处方那样发挥良好。它们最多是周期性的。<br />
在代码级别，大部分的设计模式都是代码异味(code smells)。当程序员在代码检查中看到了设计模式，他们就会滑入到催眠般的熟悉场景中。醒醒！那是一个设计模式，或者说是一个来自腐臭程序语言的失效药方？<br />
<br />
<br />
</span>
<img src ="http://www.blogjava.net/jiangshachina/aggbug/121731.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jiangshachina/" target="_blank">Sha Jiang</a> 2007-06-04 09:00 <a href="http://www.blogjava.net/jiangshachina/archive/2007/06/04/121731.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>