<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Absolutely No Machete Juggling</title>
	<atom:link href="http://www.nomachetejuggling.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.nomachetejuggling.com</link>
	<description>Rod Hilton's views on programming, technology, and life.</description>
	<lastBuildDate>Wed, 07 Jul 2010 18:46:52 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Finding High-Impact Areas for Refactoring</title>
		<link>http://www.rallydev.com/engblog/2010/07/06/finding-high-impact-areas-for-refactoring/</link>
		<comments>http://www.rallydev.com/engblog/2010/07/06/finding-high-impact-areas-for-refactoring/#comments</comments>
		<pubDate>Tue, 06 Jul 2010 22:35:06 +0000</pubDate>
		<dc:creator>The Rally Software Engineering Blog</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[Code Reviews]]></category>
		<category><![CDATA[complexity]]></category>
		<category><![CDATA[Continuous Integration]]></category>
		<category><![CDATA[crossposted]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[metrics]]></category>
		<category><![CDATA[quality]]></category>
		<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false">http://www.rallydev.com/engblog/?p=705</guid>
		<description><![CDATA[At Rally, we&#8217;ve stayed committed for the last 7 years to never telling the business that the product has to halt active development to pay down technical debt.  For us, the &#8220;big rewrite in the sky&#8221; has always been off the table.  Instead, we prefer to incrementally refactor and improve the existing elements [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.rallydev.com%2Fengblog%2F2010%2F07%2F06%2Ffinding-high-impact-areas-for-refactoring%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.rallydev.com%2Fengblog%2F2010%2F07%2F06%2Ffinding-high-impact-areas-for-refactoring%2F" height="61" width="51" /></a></div><p>At Rally, we&#8217;ve stayed committed for the last 7 years to never telling the business that the product has to halt active development to pay down technical debt.  For us, the &#8220;big rewrite in the sky&#8221; has always been off the table.  Instead, we prefer to incrementally refactor and improve the existing elements of the codebase, gradually getting it to where we want it to be without ever halting feature development completely.</p>
<p>This has never been an easy task.  The truth is, the codebase is quite old by engineering standards, many parts of it written before standards emerged in the industry.  Our entire persistence layer, for example, was created by hand well before libraries such as Hibernate existed (or at least, before they became standard practice).  This means that there are many, many areas of the code that we&#8217;d like to attack and improve.</p>
<p>One thing we&#8217;ve started doing is holding lunchtime &#8220;refactotums,&#8221; where we take a look at some code and try to improve it.  Of course, with such a large codebase, and so many areas of the code that have not been touched since they were first written, we&#8217;ve often wondered how to most effectively spend our refactotum time.  This led us to wonder &#8220;what are the areas of the code where a refactoring would have the greatest impact?&#8221;</p>
<p>We started keeping track of our codebase using <a href="http://www.sonarsource.org/">Sonar</a> which was extremely helpful in keeping track of metrics at a class level, but it didn&#8217;t give us quite enough information.  For example, if <code>Class A</code> has a complexity score of 500 and <code>Class B</code> has a complexity score of 200 (higher is worse), you&#8217;d think that spending some time cleaning up <code>Class A</code> would be the most effective thing to do.  But what if <code>Class B</code> is used by 50 times as many other classes as <code>Class A</code>?  Or what if <code>Class B</code>, complicated as it is, has never been modified in the history of the project?  It would be nice to clean this class up, but it might be a better use of time to focus on <code>Class A</code></p>
<p>So our idea was to combine two metrics: the class complexity (based on <a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity">McCabe Cyclomatic Complexity</a>) and the number of times a file has been modified in the codebase.  The idea here was, every time a file has to be modified, it has to be read.  A complex file is harder to read, making the engineer more likely to misunderstand or make a mistake while editing the file.</p>
<p>Luckily, git makes it quite easy to count the number of modifications to files in the codebase:</p>
<span id="more-770"></span>
<pre class="brush: bash;">
git whatchanged | grep '^:.*alm-webapp/src/main/java/.*\.java$' | cut -c65- | sed -e 's/\//./g' -e 's/.java//' | sort | uniq -c | sort -r
</pre>
<p>Obviously, the grep and cut would have to be modified slightly depending on your codebase structure.  The grep is used to ensure only our code is looked at, excluding any third-party code in the system.  The cut and seds are mostly just about munging the filenames into &#8220;probable&#8221; classnames, since that&#8217;s more useful (and what Sonar stores).</p>
<p>This command yields some high-traffic files, but it needs to be combined with high-value targets as well.  For this, we turned to Sonar.</p>
<p>We were unable to use the Sonar web services as thoroughly as we were hoping, so we wound up writing a query directly against the database where the Sonar data is stored. The query for a given metric (in our case, metric 12, class complexity) looks like this:</p>
<pre class="brush: sql;">
    SELECT projects.kee, project_measures.value, project_measures.metric_id
    FROM snapshots, project_measures, projects
    WHERE islast = 1
      AND project_measures.snapshot_id = snapshots.id
      AND project_measures.metric_id = 12
      AND snapshots.qualifier = 'CLA'
      AND snapshots.project_id = projects.id
</pre>
<p>We wrote a Ruby script that pulled the data from these two sources and correlated them together, deriving an eventual &#8220;weighted rank&#8221; from the two.  We went on to include a few more metrics in the final equation.   Output from the script looks like this:</p>
<pre>
Calculating complexity data from sonar...Done!
Calculating revision data from git...Done!
Calculating weighted rank data...Done!
Current formula:
   ( 0.15 * ( complexity / average_complexity ) )
 + ( 0.40 * ( function_complexity / average_function_complexity ) )
 + ( 0.30 * ( efferent_coupling / average_efferent_coupling ) )
 + ( 0.40 * ( revisions / average_revisions ) )

Rank    Score  Revisions  Complexity  F.Complexity  E.Coupling  Class
----  -------  ---------  ----------  ------------  ----------  -----
   1    14.12         60         507             2          67  com.rallydev.ClassG
   2    13.10         93         301             2          71  com.rallydev.ClassQ
   3    12.53         80         318             2          70  com.rallydev.ClassR
   4    11.25         11          45            45          27  com.rallydev.ClassO
   5     9.65          9          43            43           8  com.rallydev.ClassC
   6     9.48         72         194             2          52  com.rallydev.ClassZ
   7     9.24         60         205             2          56  com.rallydev.ClassN
   8     8.79         42         218             2          59  com.rallydev.ClassK
   9     8.75         31         260             3          53  com.rallydev.ClassF
  10     8.63         54         167             2          59  com.rallydev.ClassT
  11     8.38         65         194             2          39  com.rallydev.ClassO
  12     8.29         44         207             3          49  com.rallydev.ClassY
  13     7.81         40         225             2          41  com.rallydev.ClassP
  14     7.48         18          26            26          23  com.rallydev.ClassK
  15     7.44         60         164             2          34  com.rallydev.ClassA
</pre>
<p>We&#8217;ve found it pretty useful to know where our efforts would be most useful.  If you&#8217;re using git and sonar, feel free to modify this script and try it on your own codebase (note, you will need the mysql client binary in your path for it to work).</p>
<pre class="brush: ruby;">
#!/usr/bin/env ruby
# Authors: Rod Hilton and Ryan Scott
# Site: www.rallydev.com

METRICS = {12=&gt;:complexity, 14=&gt;:function_complexity, 74=&gt;:efferent_coupling}
WEIGHTS = {:revisions=&gt;0.4, :complexity=&gt;0.15, :function_complexity=&gt;0.4, :efferent_coupling=&gt;0.3}

def print_around(title, &amp;block)
  print title + &quot;...&quot;
  STDOUT.flush
  yield block
  print &quot;Done!\n&quot;
end

def add_class_data(class_data, class_name, data_key, data_value)
  class_data[class_name] = {} unless class_data.has_key?(class_name)
  class_data[class_name][data_key] = data_value
end

def add_complexity_data(class_data)
  complexity_query = &lt;&lt;-EOF
    SELECT projects.kee, project_measures.value, project_measures.metric_id
    FROM snapshots, project_measures, projects
    WHERE islast = 1
      AND project_measures.snapshot_id = snapshots.id
      AND project_measures.metric_id in (#{METRICS.keys.join(&quot;,&quot;)})
      AND snapshots.qualifier = 'CLA'
      AND snapshots.project_id = projects.id
    EOF

  print_around &quot;Calculating complexity data from sonar&quot; do
    complexity = `echo &quot;#{complexity_query}&quot; | mysql -h alm-build --user=YOUR_SONAR_USERNAME --password=YOUR_SONAR_PASSWORD --database=YOUR_SONAR_DATABASE`

    complexity.each do |complexity_line|
      match = complexity_line.match(/^(\S*)\s+([\d\.]+)\s+(\d+)$/)
      if(match)
        name = match[1]
        metric = match[2].to_f
        metric_id = match[3].to_i
        metric_name = METRICS[metric_id]
        add_class_data(class_data, name.match(/^.*:([^:]*)$/)[1], metric_name, metric)
      end
    end
  end
end

def add_revision_data(class_data)
  print_around &quot;Calculating revision data from git&quot; do
    file_changes = `git whatchanged | grep '^:.*alm-webapp/src/main/java/.*\.java$' | cut -c65- | sed -e 's/\\//./g' -e 's/.java//' | sort | uniq -c | sort -r`
    # file_changes = `cat modified.txt`

    file_changes.each do |file_change_line|
      match = file_change_line.match(/^\s*(\d+)\s+(.*)$/)
      if(match)
        revisions = match[1].to_i
        name = match[2]
        add_class_data(class_data, name, :revisions, revisions)
      end
    end
  end
end

def average_for_data(class_data, key)
  values = class_data.values.collect{|val| val[key]}
  values.inject{ |sum, el| sum + el }.to_f / values.size
end

def add_weighted_rank_data(class_data)

  print_around &quot;Calculating weighted rank data&quot; do
    averages = {}
    WEIGHTS.each do |key, value|
      average = average_for_data(class_data, key)
      averages[key] = average
    end

    class_data.each do |classname, data|
      data[:weighted_rank] = 0
      WEIGHTS.each do |key, weight|
        chunk = weight * (data[key] / averages[key])
        data[:weighted_rank] = data[:weighted_rank] + chunk
      end
    end
  end
end

def remove_classes_without_all_data(class_data)
  num_keys = class_data.values.map{|val| val.size}.max
  class_data.delete_if{|key, val| val.size &lt; num_keys}
end

# --- Main ---

class_data = {}

add_complexity_data(class_data)
add_revision_data(class_data)

class_data = remove_classes_without_all_data(class_data)

add_weighted_rank_data(class_data)

#Sort by rank, descending
class_data_sorted = class_data.sort{|a,b| b[1][:weighted_rank] &lt;=&gt; a[1][:weighted_rank]}

puts &quot;Current formula: &quot;
pieces = []
WEIGHTS.each do |key, weight|
  pieces &lt;&lt; sprintf( &quot;( %3.2f * ( %s / %s ) )&quot;, weight, key.to_s, &quot;average_&quot;+key.to_s)
end
puts &quot;   &quot; + pieces.join(&quot;\n + &quot;)

puts &quot;\n&quot;
puts &quot;Rank    Score  Revisions  Complexity  F.Complexity  E.Coupling  Class&quot;
puts &quot;----  -------  ---------  ----------  ------------  ----------  -----&quot;
class_data_sorted[0..49].each_with_index do |file, index|
  class_name=file[0]
  class_data=file[1]
  printf(&quot;%4u  %7.2f  %9u  %10u  %12u  %10u  %s\n&quot;, (index+1), class_data[:weighted_rank], class_data[:revisions], class_data[:complexity], class_data[:function_complexity], class_data[:efferent_coupling], class_name)
end
</pre>
<p>Feel free to make any improvements or changes to this script that you wish.  It&#8217;s not the most efficient in the world, but it was thrown together pretty quickly to get a decent idea of our highest-impact refactoring targets.</p>
<p>Suggestions for improving the formula?  Made your own changes to the script?  Feel free to post in the comments below, we welcome the discussion!</p>
<img src="http://www.rallydev.com/engblog/?ak_action=api_record_view&id=705&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.rallydev.com/engblog/2010/07/06/finding-high-impact-areas-for-refactoring/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Create 3D Text (The Glasses Kind) With CSS</title>
		<link>http://www.nomachetejuggling.com/2010/05/04/how-to-create-3d-text-with-css/</link>
		<comments>http://www.nomachetejuggling.com/2010/05/04/how-to-create-3d-text-with-css/#comments</comments>
		<pubDate>Wed, 05 May 2010 01:42:52 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[3d]]></category>
		<category><![CDATA[css]]></category>
		<category><![CDATA[effects]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[text]]></category>
		<category><![CDATA[tricks]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/?p=722</guid>
		<description><![CDATA[Recently, I wanted to create some Red/Blue 3D text.  After a great deal of searching on the internet, I discovered that very few people have actually done this, and those that have seemed to rely on creating a duplicate of the content.  Creating a duplicate copy of the text wouldn&#8217;t work for me, [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I wanted to create some Red/Blue 3D text.  After a great deal of searching on the internet, I discovered that very few people have actually done this, and those that have seemed to rely on creating a duplicate of the content.  Creating a duplicate copy of the text wouldn&#8217;t work for me, since my text used a great deal of formatting.</p>
<p>Through hours of trial and error, I found something that seems to work pretty well.  Here are the caveats:</p>
<ol>
<li>It does not work in Internet Explorer</li>
<li>It requires CSS3</li>
<li>It uses alpha colors, which means it&#8217;s a bit more CPU-intensive than text normally is.</li>
</ol>
<p>Otherwise, it seems like a good solution.  This works in Firefox for Linux and Mac and Chrome for Linux and Mac.  It does not work in IE at all, and it doesn&#8217;t work in Safari (last time I checked).</p>
<p>Here it is:</p>
<div style="font-size: 250%; text-align: center; border: 1px solid black; padding: 1em; margin: 1em; text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6), -.5em 0 .2px rgba(100%, 0%, 0%, 0.6); color: rgba(40%, 40%, 40%, 0.0);">
This should be in 3D!
</div>
<p><span id="more-722"></span></p>
<h1>How It Works</h1>
<p>Let&#8217;s start with some basic text in a div:</p>
<pre class="brush: xml;">
&lt;style&gt;
.threed {
  font-size: 250%;
  text-align: center;
  border: 1px solid black;
  margin: 1em;
  border: 1em;
}
&lt;/style&gt;

&lt;div class=&quot;threed&quot;&gt;
Hello world!
&lt;/div&gt;
</pre>
<div style="font-size: 250%; text-align: center; border: 1px solid black; padding: 1em; margin: 1em;">
Hello world!
</div>
<p>First, you can apply a text-shadow using a CSS3 property called <a href="http://www.w3.org/Style/Examples/007/text-shadow">text-shadow</a> like so:</p>
<pre class="brush: css;">
.threed {
  font-size: 250%;
  text-align: center;
  border: 1px solid black;
  margin: 1em;
  border: 1em;
  text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6)
}
</pre>
<div style="font-size: 250%; text-align: center; border: 1px solid black; padding: 1em; margin: 1em;   text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6)">
Hello world!
</div>
<p>Here we put a text-shadow on our text that is offset .5em horizontally and 0em vertically.  It has a &#8216;blur&#8217; of .2px, which means virtually none at all.  The text color is a cyan, at .6 alpha transparency.</p>
<p>The text-shadow element actually allows us to specify multiple text-shadows, so we can just add a second shadow now, this one pink, still .6 alpha transparency, but offset .5em to the LEFT instead of the right (using a negative offset)</p>
<pre class="brush: css;">
.threed {
  font-size: 250%;
  text-align: center;
  border: 1px solid black;
  margin: 1em;
  border: 1em;
  text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6), -.5em 0 .2px rgba(100%, 0%, 0%, 0.6);
}
</pre>
<div style="font-size: 250%; text-align: center; border: 1px solid black; padding: 1em; margin: 1em; text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6), -.5em 0 .2px rgba(100%, 0%, 0%, 0.6);">
Hello world!
</div>
<p>The last thing we&#8217;ve got to figure out how to do is hide the black text itself.  This is actually easy, since you can apply alpha transparency to any color using CSS3.  In this case, we&#8217;re simply going to make the text fully transparent.</p>
<pre class="brush: css;">
/* 3D CSS Effect: www.nomachetejuggling.com */
.threed {
  font-size: 250%;
  text-align: center;
  border: 1px solid black;
  margin: 1em;
  border: 1em;
  text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6), -.5em 0 .2px rgba(100%, 0%, 0%, 0.6);
  color: rgba(40%, 40%, 40%, 0.0);
}
</pre>
<div style="font-size: 250%; text-align: center; border: 1px solid black; padding: 1em; margin: 1em; text-shadow: .5em 0 .2px rgba(0%, 100%, 100%, 0.6), -.5em 0 .2px rgba(100%, 0%, 0%, 0.6); color: rgba(40%, 40%, 40%, 0.0);">
Hello world!
</div>
<p>This effect tends to work best for:</p>
<ul>
<li>Small font sizes</li>
<li>Lots of text</li>
<li>Normal weight (bold text looks bad)</li>
</ul>
<p>You can see this technique used in a lengthy parody of the movie Clash of the Titans <a href="http://www.the-editing-room.com/clash-of-the-titans.html">here</a>.</p>
<h1>Degradation</h1>
<p>This seems to degrade really well in Internet Explorer, which supports neither alpha transparency on text nor text-shadow.  As a result, it shows up as just plain black text.</p>
<p>It degrades very poorly in Safari however, which supports alpha transparency on text but not text-shadows, meaning that the text is rendered invisible without the shadow, so it just shows up as a big blank box.</p>
<h1>Improvements</h1>
<p>I fiddled with a lot of different parameters to try to perfect this, and what you see here is as close as I was able to get.  The trick with 3D text is that you want the overlapping areas between the pink and cyan to be dark enough to show up for both eyes, the result of multiplying the cyan and pink colors together.  With the CSS, it&#8217;s a bit lighter than I&#8217;d like, but it seems to do the job.</p>
<p>I also tried to do it in a way that simply made the main color pink, with a single cyan shadow (and vice versa) but I found that, without that slight blur parameter (.2px), the colors didn&#8217;t seem to blend quite as well, hurting the effect.</p>
<p>If anyone out there figures out a way to improve this, please post a comment here with your tips.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2010/05/04/how-to-create-3d-text-with-css/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Certifications Aren&#8217;t &#8220;Bad&#8221; (They Just Aren&#8217;t &#8220;Good,&#8221; Either)</title>
		<link>http://www.nomachetejuggling.com/2010/04/27/certifications-arent-bad-they-just-arent-good-either/</link>
		<comments>http://www.nomachetejuggling.com/2010/04/27/certifications-arent-bad-they-just-arent-good-either/#comments</comments>
		<pubDate>Wed, 28 Apr 2010 03:14:54 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[certification]]></category>
		<category><![CDATA[education]]></category>
		<category><![CDATA[exam]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[learning]]></category>
		<category><![CDATA[sun]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/?p=708</guid>
		<description><![CDATA[I&#8217;ve been disturbed by a few posts made by James Shore lately.  Though I greatly respect Shore and immensely enjoyed his book, one particular post of his really irked me: &#8220;Your Certification Is Meaningless.&#8221;
In the post, Shore basically argues that certifications, particular those relating to Agile software development, have no value.  In fact, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been disturbed by a few posts made by James Shore lately.  Though I greatly respect Shore and immensely enjoyed <a href="http://www.nomachetejuggling.com/2009/02/19/book-review-the-art-of-agile-development/">his book</a>, one particular post of his really irked me: &#8220;<a href="http://jamesshore.com/Blog/Your-Certification-is-Meaningless.html">Your Certification Is Meaningless</a>.&#8221;</p>
<p>In the post, Shore basically argues that certifications, particular those relating to Agile software development, have no value.  In fact, he goes on to <a href="http://jamesshore.com/Blog/Alternatives-to-Certifications.html">argue</a> that they offer counter-value, that some employers are LESS likely to hire someone with a certification.</p>
<p>The thing is, the main reason this bothers me is that I have a few certifications from Sun (pre-Oracle days), and the process I went through to acquire these certifications is one I found immensely useful.  <strong>It&#8217;s hard for me to see something as meaningless when it holds so much value to me.</strong></p>
<p><span id="more-708"></span></p>
<p>This is not to say I don&#8217;t understand the point.  The certification merely proves that I took a test, and considering how low a score you can get and still &#8220;pass&#8221; the test and receive the certification, it proves little more than that I read a book or took a course.  I agree with this basic assessment of certifications: as a token of proof to offer someone else that I know my stuff, they have very little value.</p>
<p>I like certifications, however, because they help me prove to myself that I learned something.  When I was studying for the <a href="http://in.sun.com/training/certification/java/scjp.xml">SCJP</a> exam, I did so not through a course, but through a book (two books, in fact).  As I studied, I was <strong>constantly</strong> learning things about Java that I didn&#8217;t know &#8211; low-level details of the language, its syntax, the way it handles inheritance, and so forth.  Same thing when I studied for the <a href="http://in.sun.com/training/certification/java/scwcd.xml">SCWCD</a> exam: I was, at the time, at a job that did mostly ColdFusion for web layer, and I had no experience whatsoever with Servlets, JSPs, custom tags, or anything in that area.  The process of reading a book (again, two books) for the SCWCD exam was, primarily, where I learned about web components in Java.  Because of the knowledge I gained during that process, I was able to later get a new job that actually used J2EE technology for the web, and I knew my way around enough to be productive.  If I had not read those books, I probably wouldn&#8217;t have survived the interview, and if I had I wouldn&#8217;t have known what I was doing well enough to do my job.</p>
<p>But really, this is the value of <strong>reading</strong>, not of certification.  Wouldn&#8217;t I have gotten the same benefit from merely reading a book on Java or J2EE?  Not necessarily.  Most books on something like Java are focused on specific applications of it &#8211; they are positioned as &#8220;here&#8217;s how to use Java to do so-and-so&#8221; or &#8220;here&#8217;s how to use J2EE to write the kind of web apps you may write in real life.&#8221;  Books like these don&#8217;t do a deep-dive in the core of the language itself or the standards.  Books that are intended to help you study for a certification exam, however, are forced to leave no stone unturned in the subject area &#8211; forced in a way that a typical book may not be.  An book author writing about JSPs may simply have never written a JSP custom tag in Java (perhaps he or she only worked with tag files) and, as a result, they may only devote a handful of pages to a surface level exploration of that topic.  The SCWCD study guide had to dive all the way into that subject in order to set readers up with the best chance to pass.  Obviously, a really <b>good</b> book would cover all of the material, but the vast majority of books aren&#8217;t going to qualify as &#8220;good&#8221; in my opinion, and finding that perfect book can be challenging.  In the other hand, you can be relatively confident that a certification study guide will cover the entire subject in complete detail.</p>
<p>But again, this shows the value of reading books, just very specific ones.  Why bother with the exam?  For the same reason you bothered taking tests or getting grades in school &#8211; to receive an objective evaluation of how well you understood the material.  If I study for the SCJP exam, then get a 65% (passing, humorously enough), then you can be reasonably certain you understand approximately 65% of the material.  If that&#8217;s not enough for you, the exam actually tells you the specific areas in which you are weak (when I took the SCJP exam, I was helpfully informed my weakest area was with knowledge of the standard library) so you can focus on those areas if you wish.  The value of a test is that someone who knows more than you about a subject can give you a reasonable assessment of how well you&#8217;ve learned that subject.  That&#8217;s all a certification exam is: a test on a specific subject.</p>
<p>I find myself much more aligned with <a href="http://blog.objectmentor.com/articles/2010/04/27/certification-dont-waste-your-time">Bob Martin&#8217;s view</a>.  A certification has value in that it is a mechanism for instruction.  Whether you take a course or read a book, you are learning, and learning has value, always.</p>
<p>Personally, I much prefer a certification that requires an exam, rather than merely a course.  A certification without the examination seems to miss the point, at least for me.  My Certified ScrumMaster certification has less value to me than my Sun Certified Java Programmer certification, because the former was given to me after attending a class for two days, while the latter was something I studied for over the course of a couple months, and ended with an exam proving to me that I understood the material.</p>
<p>Essentially, I view a certification as a thing I do for myself primarily, to help me learn a subject at a deep level.  Why bother even listing it on my resume?  Because what it shows, at least in my opinion, is that I&#8217;m self-motivated and I like to learn and improve on my own.  My certifications prove, at the very least, that I&#8217;m interested enough in programming that I took time out of my normal life to study a topic in depth and take a test.  It&#8217;s not exactly the promise of the typical certification, but that combined with how much I enjoy learning when I am studying for a certification makes them valuable to me.</p>
<p>I certainly hope Shore&#8217;s posts about people passing on candidates with certifications is hyperbole.  I would never suggest that a certification should serve as a substitute for a real interview; I may have the SCJP certification, but if you want to know if I really know my Java you should ask me lots of Java questions in an interview.  It bothers me to think that something I&#8217;ve greatly enjoyed doing &#8211; something that I feel has made me substantially more knowledgeable in certain areas &#8211; would reflect poorly on me as a job candidate.</p>
<p>I&#8217;m going to continue operating as though Shore is exaggerating a bit to illustrate a point.  There are other Sun certifications (Oracle certifications? Weird.) I plan on studying for and earning, and there may be other certifications beyond those.  As far as I&#8217;m concerned, learning always has value, and examinations always help one know how well they are learning.  And hey, if you get a spiffy-looking piece of paper afterwards, that&#8217;s a bonus.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2010/04/27/certifications-arent-bad-they-just-arent-good-either/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Avoiding The Big Design Interview Question</title>
		<link>http://www.nomachetejuggling.com/2010/04/06/avoiding-the-big-design-interview-question/</link>
		<comments>http://www.nomachetejuggling.com/2010/04/06/avoiding-the-big-design-interview-question/#comments</comments>
		<pubDate>Tue, 06 Apr 2010 20:58:49 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[interview]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[tdd]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/?p=686</guid>
		<description><![CDATA[There is one common type of question that I think sets up both the candidate and the interviewer for failure.  I&#8217;ve seen it asked by my interviewers, my co-interviewers, and even by me. The question takes this format:
Sketch out the object model for a x
Generally this question is asked to feel out someone&#8217;s OO [...]]]></description>
			<content:encoded><![CDATA[<p>There is one common type of question that I think sets up both the candidate and the interviewer for failure.  I&#8217;ve seen it asked by my interviewers, my co-interviewers, and even by me. The question takes this format:</p>
<blockquote><p>Sketch out the object model for a <em>x</em></p></blockquote>
<p>Generally this question is asked to feel out someone&#8217;s OO skills.  Do they understand inheritance, polymorphism, abstraction, etc?  Can they describe the relationship between a <em>plant</em>, <em>flower</em>, and <em>petal</em> (a flower is-a plant, and has-a petal)?</p>
<p>I used to ask this question myself when I was first starting out doing interviews.  I would ask the candidate to describe the object model for a <code>Chicken</code>.  I was expecting the candidate to sketch something resembling the following:</p>
<p><img src="http://yuml.me/diagram/scruffy;/class/%5BAnimal%5D%5E%5BChicken%5D,%20%5BChicken%5D+-%5BBeak%5D,%20%5BChicken%5Dproduces-.-%3E%5BEgg%5D.png"/></p>
<p>Now, I wouldn&#8217;t expect it to be perfect UML or anything like that, but I wanted to see the basic idea that the candidate knew that a <code>Chicken</code> was probably a <code>Animal</code> or a <code>Bird</code>, and maybe <code>Bird</code> is an <code>Animal</code>, and maybe <code>Chicken</code>s have <code>Feather</code>s or <code>Beak</code>s, or maybe those belong to <code>Bird</code>, etc.  I thought this was a great question for gauging a candidate&#8217;s comfort with Object Oriented Programming.</p>
<p><strong>I was wrong.</strong></p>
<p><span id="more-686"></span></p>
<p>This is actually a terrible question.  I stopped asking it years ago because I never seemed to get an answer I liked, which told me that it was a bad question.  Only recently, however, have I really come to a full understanding of why it&#8217;s such a bad question.</p>
<h1>Evolutionary Design</h1>
<p>A good software developer does not sit down and sketch out all of the objects in the system and their relationships.  Doing so would be a surefire way to add unnecessary complexity to an application.  One particularly interesting example of this can be found <a href="http://www.objectmentor.com/resources/articles/xpepisode.htm">here</a>, a semi-transcript of Bob Koss and Bob Martin sitting down together to create a small program to keep track of bowling scores.</p>
<p>When the Bobs start, they sketch out a <code>Game</code> class, <code>Frame</code> class, and <code>Throw</code> class.  But when they start to write their tests for the <code>Throw</code> class, they realize they have none because it has no behaviors.  They start to write some tests for the <code>Frame</code> class and discover none there as well.  They finally start by writing tests for the <code>Game</code> class itself, which helps them drive all the way to completing the application.  In the end, they only had two classes: <code>Game</code> and <code>Scorer</code>.</p>
<p>When trying to think of the classes outside of the context in which they would be used, the two Bobs failed.  Once they began writing tests to drive out the behavior, they found that the responsibilities they needed belonged not to three different classes, but to two.  The behavior of the system drove the design.</p>
<p>This is a fundamental principle of Agile software development (and, more specifically, XP): <a href="http://www.artima.com/intv/evolution.html">Evolutionary Design</a>.  Good programmers follow the practice of Evolutionary Design because it prevents the system from being over-engineered and overly complex while incrementally making the system more and more resilient to change.  This is a good practice, and I want to hire people who follow it, but when I asked them design the object model for a <code>Chicken</code>, I am essentially asking them to do Big Design Up Front, something I&#8217;d prefer them not to do if they join the team.  I&#8217;m setting myself up for failure, because anyone who answers this question well may have a tendency to do something I don&#8217;t really like.</p>
<h1>Context is Key</h1>
<p>Imagine asking a similar question to the <code>Chicken</code> question above.  You request the candidate &#8220;design the object model for a Car.&#8221;</p>
<p>Maybe you&#8217;re expecting the candidate to write something like this:</p>
<p><img src="http://yuml.me/diagram/scruffy/class/%5BVehicle%5D%5E%5BCar%5D%2C%20%5BCar%5D+-%5BSteeringWheel%5D%2C%20%5BCar%5D+-%5BTire%5D%2C%20%5BCar%5D+-%5BEngine%5D"/></p>
<p>Seems reasonable.  But imagine that the application for which this <code>Car</code> has been designed in a full-fledged CAD-like application for a car designer. The <code>Car</code> will be used by the designer to help determine how the car looks, how the exterior works, how many doors it has, and so on.  It may look like this:</p>
<p><img src="http://yuml.me/diagram/scruffy;/class/%5BCar%5D+-%5BHood%5D,%20%5BCar%5D+-%5BRadiator%5D,%20%5BCar%5D+-%5BGrille%5D,%20%5BCar%5D+-%5BBumper%5D,%20%5BCar%5D+-%5BHeadLight%5D,%20%5BCar%5D+-%5BDoor%5D,%20%5BDoor%5D+-%5BDoorHandle%5D,%20%5BCar%5D+-%5BACCondenser%5D,%20%5BCar%5D+-%5BTailLight%5D,%20%5BLight%5D%5E%5BHeadLight%5D,%20%5BLight%5D%5E%5BTailLight%5D,%20%5BCar%5D+-%5BTrunk%5D,%20%5BTrunk%5D+-%5BTrunkLatch%5D,%20%5B%3C%3CHinged%3E%3E%5D%5E-.-%5BTrunk%5D,%20%5B%3C%3CHinged%3E%3E%5D%5E-.-%5BHood%5D,%20%5B%3C%3CHinged%3E%3E%5D%5E-.-%5BDoor%5D.png"/></p>
<p>Or imagine instead, that the <code>Car</code> class will be used in a traffic simulator program that&#8217;s really meant to test traffic congestion, stop light placement, and so on.  In that application, a Car is really just something with a direction and a velocity, so it would look more like this:</p>
<p><img src="http://yuml.me/diagram/scruffy/class/%5BCar%5D"/></p>
<p>In the former, the future changes your design should guard against are new types of doors, or new components for a car.  There is no danger of a different kind of Vehicle, such as a Plane, because this is for a Car company.  In the latter, you may need to guard against additional vehicle types such as <code>Bicycle</code> or <code>Scooter</code>.  The design that gets evolved by these two systems will be fundamentally different, so why ask the question without providing information about the system itself?</p>
<p>Ultimately, the problem here is that there is a spectrum of answers to this question, ranging from extremely simple to extremely complex.  But depending on the context, any one of those designs can be the right design.  When an interviewer asks the question, theres a specific place on this spectrum where he or she would like the candidate to answer, and anything below that indicates a poor understanding of OO, while anything above it indicates a tendency to overdesign.  The interviewer has set up the candidate to fail.</p>
<h1>How To Ask This Question</h1>
<p>If you want to know how comfortable a candidate is with OO, ask them the question in a way that resembles real-life OOP a bit more closely.  Start simple, by providing a single simple requirement.  Though the candidate won&#8217;t be able to write and run tests, the requirement serves as a driver for the design.</p>
<p>A good indicator that the question is taking you and the candidate off-track is if the boxes he or she draws on the whiteboard lack method names.  If there are no methods, there are no behaviors, which means the candidate is designing first, regardless of requirements.  Steer the candidate back by asking them to write method names.</p>
<p>For example, ask the candidate to design the object model for a simple bookshelf.  A bookshelf is so simple that there&#8217;s virtually no way to overcomplicate it, so you can say that you simply need to be able to add a book to the bookshelf, nothing else.  Once they have done this, give the candidate another &#8220;test&#8221;, by adding a requirement.  Now say that you want the bookshelf to be a &#8220;smart&#8221; bookshelf, where you can look up a book by title and get a reference to the book.  The candidate will make some changes to their design.  Continue adding requirements to the thing until you&#8217;re satisfied with the evolution of the candidate&#8217;s design.</p>
<ul>
<li>Modify the design to allow me to search the bookshelf by Title, Author, or ISBN</li>
<li>Allow me to use the bookshelf as an ad-hoc library, so I can &#8220;check out&#8221; a book, removing it from the bookshelf.  Make it possible to look up books that have been &#8220;borrowed&#8221;.</li>
<li>Require a user provide their name when checking out a book.  Give them a return date.  Make it so the bookshelf can generate a list of overdue books and who has them.  Where does that method belong?  Should it be on its own object that Bookshelf uses?</li>
<li>Make the bookshelf more concrete, so that there is only a certain number of books that can fit on any given shelf in the overall bookshelf.  Make it possible to ask which shelf a book is on.  Make it possible to add a new shelf.</li>
</ul>
<p>You can obviously pick your own model (Car, Elevator, Fridge, etc) and drive the direction the design should go using requirements.  Have the candidate write method names (but not implementations) where appropriate.  Keep asking if the method is on the right object, or it belongs on another one.</p>
<h1>How To Answer This Question</h1>
<p>Of course, not everyone reads this blog, so if you&#8217;re in an interview you may get the &#8220;design an object model for a <em>x</em>&#8221; question.    If you find yourself in this situation, you essentially want to ask questions of your interviewer to pull requirements out of them.  The reality is, they probably <b>DO</b> have a particular kind of system in mind when they ask the question, so you need to find out what that is.</p>
<p>If you&#8217;re supposed to design the <code>Car</code> class, ask if there are other types of vehicles in the system.  If not, don&#8217;t make a <code>Vehicle</code> parent class, and explain that you see no need unless the system required additional vehicles.  Before you draw a box named <code>Tire</code>, ask if the car needs to be able to support snow tires or some other kind of interchangeable tire.  If not, why would you make a class or interface for them?  Start as simply as you can and only draw a new box when you&#8217;ve extracted enough information from the interviewer to deem it warranted.  If you jump up to the whiteboard and draw two or three boxes before asking any questions, you&#8217;re placing your interview at risk because the interviewer may be picturing a completely different usage of this system than you are.</p>
<p>Of course, it&#8217;s always possible that the interviewer will keep asking for the same information, arguing that you should show your OO skills off without requirements that drive that design out.  If you want the job, your best bet there is to take a random stab at the appropriate level of complexity and hope that you strike somewhere near what the interviewer wants.  In that situation, however, I&#8217;d imagine your interviewer doesn&#8217;t know much about designing good software, and their codebase might be an over-engineered mess, so you may not want that job.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2010/04/06/avoiding-the-big-design-interview-question/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>You Have To Buy It Twice Before It’s Cheap</title>
		<link>http://www.rallydev.com/engblog/2010/01/26/you-have-to-buy-it-twice-before-its-cheap/</link>
		<comments>http://www.rallydev.com/engblog/2010/01/26/you-have-to-buy-it-twice-before-its-cheap/#comments</comments>
		<pubDate>Tue, 26 Jan 2010 20:56:40 +0000</pubDate>
		<dc:creator>The Rally Software Engineering Blog</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[crossposted]]></category>
		<category><![CDATA[Design]]></category>
		<category><![CDATA[Estimating]]></category>
		<category><![CDATA[estimation]]></category>
		<category><![CDATA[Incremental Design]]></category>

		<guid isPermaLink="false">http://www.rallydev.com/engblog/?p=577</guid>
		<description><![CDATA[One of the most common sources of tension between product owners and developers is when product owners are surprised at how high an estimate for a story might be.  Usually this tension is easy to resolve by reiterating that the product owners really have no concept of how much something should cost.  However, [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.rallydev.com%2Fengblog%2F2010%2F01%2F26%2Fyou-have-to-buy-it-twice-before-its-cheap%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.rallydev.com%2Fengblog%2F2010%2F01%2F26%2Fyou-have-to-buy-it-twice-before-its-cheap%2F" height="61" width="51" /></a></div><p>One of the most common sources of tension between product owners and developers is when product owners are surprised at how high an estimate for a story might be.  Usually this tension is easy to resolve by reiterating that the product owners really have no concept of how much something should cost.  However, there is one scenario I see over and over again: when a product owner protests the estimate of a story because it seems, to the PO, like it&#8217;s simply re-using an aspect of the system somewhere else.</p>
<p>&#8220;I already paid for that!&#8221; he or she might say, quite correctly.  A simple example recently for us here was our column picker.  Our grids allow you to select which columns you wish to see on any given grid.  Later on, we created the ability to have grids inside of panels on user dashboards.  Our product owner wanted to put the column picker on the settings pane of a grid panel.  To him, this was simply reusing the column picker that had already been created for an earlier story.  He was quite shocked when our estimate for the effort was just as high as it was the first time.</p>
<p>His frustration is completely understandable.  How is this possible?  Why isn&#8217;t it easy to just drop that component into another place and have it work?  After all, if we were good engineers, wouldn&#8217;t we have written that component to be reusable?</p>
<p>Actually, <strong>no</strong>.  It&#8217;s <strong>because</strong> we were good engineers that it wasn&#8217;t written in that way.  This is one of the hardest things for product owners to understand, and I hope to explain it in this post.</p>
<p><strong>Evolutionary Design</strong></p>
<p>Once upon a time, development teams worked in specific phases.  First they would design all of the code they were going to write; boxes would be drawn on whiteboards, sequences captured in documents, and so on.  Once the design was finished, the developers would go off and write the code for it.  Luckily, our industry has realized that this is a problematic way to write software.</p>
<p>It&#8217;s simply not likely that the team will discover all of the quirks of the design during the design phase.  It&#8217;s even more likely that requirements and features will change during the long span of time this process takes, forcing the developers to throw away work and go &#8220;back to the drawing board&#8221; on the design.  Splitting the design phase from the coding phase is a recipe for disaster.</p>
<p>Instead, it&#8217;s generally preferable to practice <a href="http://en.wikipedia.org/wiki/Continuous_design">evolutionary design</a>; allow the design to grow organically as the code is written.  This, combined with testing and refactoring, seems to be the best known way to ensure that the quality of the code remains high as a product grows.</p>
<p>Doing this makes it easier to deal with changes that effect design, and it prevents the team from wasting time going &#8220;back to the drawing board&#8221; in the event a problem is discovered.</p>
<p><strong>YAGNI</strong></p>
<p>One principle to follow as you code is the <a href="http://en.wikipedia.org/wiki/YAGNI">YAGNI</a> principle.  YAGNI means &#8220;You Ain&#8217;t Gonna Need It&#8221; and essentially it means that developers should discourage themselves from adding additional code to support something that is not, at the time, required.  Developers have a strong desire to add code here or there while editing code, and YAGNI helps us remember to resist the urge to add superfluous code or functionality.</p>
<p>Following this principle helps eliminate waste, and helps keep developers focused on adding value that product owners want.  But why?</p>
<p>If I&#8217;m editing <strong><em>Module A</em></strong> to add <strong><em>Functionality X</em></strong>, why not just add <strong><em>Functionality Y</em></strong> while I&#8217;m there?  It may delay the delivering of <strong><em>Functionality X</em></strong> in the short-term, but later when it&#8217;s decided that <strong><em>Functionality Y</em></strong> must be supported as well, it will be dirt cheap, right?</p>
<p>The trick to understanding why YAGNI helps is realizing that there are thousands upon thousands of potential <strong><em>Module A</em></strong>s in a system.  The truth is, <strong><em>Functionality Y</em></strong> may simply never be required.  And even if it is, <strong><em>Functionality Z</em></strong> may not be.  Adding that functionality would be a waste of time and resources if it&#8217;s never used.</p>
<p><strong>YAGNI Applied to Design</strong></p>
<p>The same principle behind YAGNI can be extended to aspects of high-level design.  When we originally designed the Column Picker component, it was not designed to be dropped into any part of the system.  This was intentional: if we had spent the time to make the Column Picker completely generic and reusable, but then had never needed to drop it into another part of the system, the additional effort required to make it super-generic would have been a wasted effort.  This is true for any aspect of the system being designed: we can spend the extra time and effort to make something extremely generic, but if that generality is never needed, that time is waste.  Many times developers will refer to something that&#8217;s overly generic as &#8220;over-engineered.&#8221;</p>
<p>This means that the description of the component can often be misleading.  We never built &#8220;a column picker&#8221; &#8211; we built &#8220;a column picker for a grid page&#8221;.  The column picker was written in a way that assumed it was part of a grid page.  Again, it could have been written more generically, but doing so would have potentially created waste (<em>this does not mean that it&#8217;s alright to design code that violates <a href="http://en.wikipedia.org/wiki/Solid_(Object_Oriented_Design)">principles of good design</a>.   Code can be well-designed but still not fully generic</em>).</p>
<p>So when it came time to put the component in a completely different context than the one for which it was designed, it was still a lot of work: almost as much as was originally required to make the first pass.  Though some time was saved simply because it was a known and well-understood problem for which we would leverage newly-developed knowledge, it still effectively required writing a whole new component: one that was much more generic and utilized what it could of the previous increment.</p>
<p>Essentially, to avoid having developers waste time, components should be &#8220;generic on demand&#8221;.  Once a component needs to be reused, then it should be refactored into something extremely generic, but not before.  The end result is that a product owner will have to pay for a component twice before it&#8217;s cheap.</p>
<p>This may seem counterintuitive to product owners, but it&#8217;s important to understand.  Because the team approaches coding in a way that causes the second time to be nearly as expensive as the first, the team is able to deliver <strong>everything else</strong> quickly.</p>
<p>The first time, it is costly because the developers have to solve unknowns and create something new from scratch.</p>
<p>The second time, it is costly because it has to be molded into something generic and reusable.</p>
<p>The third time, however, is cheap.</p>
<img src="http://www.rallydev.com/engblog/?ak_action=api_record_view&id=577&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.rallydev.com/engblog/2010/01/26/you-have-to-buy-it-twice-before-its-cheap/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Quantitatively Evaluating Test-Driven Development</title>
		<link>http://www.nomachetejuggling.com/2009/12/13/quantitatively-evaluating-test-driven-development/</link>
		<comments>http://www.nomachetejuggling.com/2009/12/13/quantitatively-evaluating-test-driven-development/#comments</comments>
		<pubDate>Mon, 14 Dec 2009 05:50:46 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[school]]></category>
		<category><![CDATA[Test-Driven Design]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/?p=646</guid>
		<description><![CDATA[The thesis for my Master&#8217;s degree in Software Engineering is finished.
It&#8217;s the result of many months of research, I hope others may find it interesting and informative.
Abstract
Test-Driven Development is a Software Engineering practice gaining increasing popularity within the software industry. Many studies have been done to determine the effectiveness of Test-Driven Development, but most of [...]]]></description>
			<content:encoded><![CDATA[<p>The thesis for my Master&#8217;s degree in Software Engineering is finished.</p>
<p>It&#8217;s the result of many months of research, I hope others may find it interesting and informative.</p>
<p><strong>Abstract</strong></p>
<p>Test-Driven Development is a Software Engineering practice gaining increasing popularity within the software industry. Many studies have been done to determine the effectiveness of Test-Driven Development, but most of them evaluate effectiveness according to a reduction in defects. This kind of evaluation ignores one of the primary claimed benefits of Test-Driven Development: that it improves the design of code. To evaluate this claim of Test-Driven Development advocates, it is important to evaluate the effect of Test-Driven Development upon object-oriented metrics that measure the quality of the code itself. Some studies have measured code in this manner, but they generally have not worked with real-world code written in a natural, industrial setting. Thus, this work utilizes Open Source Software as a sample for evaluation, separating Open Source projects that were written using Test-Driven Development from those that were not. These projects are then evaluated according to various object-oriented metrics to determine the overall effectiveness of Test-Driven Development as a practice for improving the quality of code. This study finds that Test-Driven Development provides a substantial improvement in code quality in the categories of cohesion, coupling, and code complexity.</p>
<p><strong>Download</strong></p>
<p>If you&#8217;d like to read it, you can download it here:</p>
<p><a href='http://www.nomachetejuggling.com/files/tdd_thesis.pdf'>Quantitatively Evaluating Test-Driven Development by Applying Object-Oriented Quality Metrics to Open Source Projects</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2009/12/13/quantitatively-evaluating-test-driven-development/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Units are Not Classes: Improving Unit Testing By Removing Artificial Boundaries</title>
		<link>http://www.rallydev.com/engblog/2009/11/17/units-are-not-classes/</link>
		<comments>http://www.rallydev.com/engblog/2009/11/17/units-are-not-classes/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 20:53:42 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Automated Testing]]></category>
		<category><![CDATA[bdd]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[crossposted]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[junit]]></category>
		<category><![CDATA[mocking]]></category>
		<category><![CDATA[mockito]]></category>
		<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[testing]]></category>

		<guid isPermaLink="false">http://www.rallydev.com/engblog/?p=424</guid>
		<description><![CDATA[Many developers think of unit tests as tests that test a single class.  In fact, I myself once thought this way.  If I wanted to write unit tests for a two-class system in which a class used another class, I&#8217;d write two unit tests.  After all, if I created instances of both [...]]]></description>
			<content:encoded><![CDATA[<div class="tweetmeme_button" style="float: right; margin-left: 10px;"><a href="http://api.tweetmeme.com/share?url=http%3A%2F%2Fwww.rallydev.com%2Fengblog%2F2009%2F11%2F17%2Funits-are-not-classes%2F"><img src="http://api.tweetmeme.com/imagebutton.gif?url=http%3A%2F%2Fwww.rallydev.com%2Fengblog%2F2009%2F11%2F17%2Funits-are-not-classes%2F" height="61" width="51" /></a></div><p>Many developers think of unit tests as tests that test a single class.  In fact, I myself once thought this way.  If I wanted to write unit tests for a two-class system in which a class used another class, I&#8217;d write two unit tests.  After all, if I created instances of both classes in my test, that wouldn&#8217;t <strong>really</strong> be a unit test, would it?</p>
<p>In recent years, I have revised my stance on this matter.  This distinction between what is and is not a unit test is one I no longer draw in the same way.</p>
<p>Unit Tests need to be:</p>
<ul>
<li><strong>Fast</strong> &#8211; Unit Tests should never run so slowly that they discourage developers from running them all the time.</li>
<li><strong>Focused</strong> &#8211; Unit Tests should focus on a single area so that they can isolate problems to that area when they fail.</li>
</ul>
<p>Once upon a time, I thought &#8216;focused&#8217; meant that it should be focused on a single class.  Instead, it should focus on an area, but that area can include multiple classes.</p>
<p><span id="more-424"></span></p>
<p><strong>An Example</strong></p>
<p>Let&#8217;s say we have a simple Calculator class with some tests (normally we&#8217;d write the tests first, but since we&#8217;re talking about the tests in this post we&#8217;re going to write them afterwards).  As with any example fabricated for demonstration purposes, the classes in this post have little need for the level of testing I will be applying to them, but they serve an illustrative purpose.</p>
<pre class="brush: java;">
package com.rallydev.engblog.unittesting;

public class Calculator {

  public int calculate(char operation, int operand1, int operand2) {
    switch (operation) {
    case '+':
      return operand1 + operand2;
    case '-':
      return operand1 - operand2;
    default:
      throw new UnsupportedOperationException(String.format(
          &quot;'%s' is not a known operation&quot;, operation));
    }
  }

}
</pre>
<p>Here is the test for this class:</p>
<pre class="brush: java;">
package com.rallydev.engblog.unittesting;

import static org.junit.Assert.assertEquals;

import org.junit.Before;
import org.junit.Test;

public class CalculatorTest {

  private Calculator calculator;

  @Before
  public void setUp() {
    this.calculator = new Calculator();
  }

  @Test
  public void shouldAdd() {
    assertEquals(5, calculator.calculate('+', 2, 3));
  }

  @Test
  public void shouldSubtract() {
    assertEquals(1, calculator.calculate('-', 5, 4));
  }

  @Test(expected = UnsupportedOperationException.class)
  public void shouldThrowExceptionForUnknownOperation() {
    calculator.calculate('Q', 1, 2);
  }
}
</pre>
<p>But after thinking about it, we realize that the responsibility for parsing what the caller wants to do and the responsibility for actually performing that operation should be separated.</p>
<p>So we&#8217;re going to create a new class, CalculationProcessor, which actually handles the calculations themselves.</p>
<pre class="brush: java;">
package com.rallydev.engblog.unittesting;

public class CalculationProcessor {
  public int add(int operand1, int operand2) {
    return operand1 + operand2;
  }

  public int subtract(int operand1, int operand2) {
    return operand1 - operand2;
  }
}
</pre>
<p>The tests for this class should be obvious, so we won&#8217;t go into them.</p>
<p>We will also modify our Calculator class to be injected with CalculationProcessor at construction time, which it will use to perform the operations.  That looks like this:</p>
<pre class="brush: java;">
package com.rallydev.engblog.unittesting;

public class NewCalculator {
  private CalculationProcessor calculationProcessor;

  public NewCalculator(CalculationProcessor calculationProcessor) {
    this.calculationProcessor = calculationProcessor;
  }

  public int calculate(char operation, int operand1, int operand2) {
    switch (operation) {
    case '+':
      return calculationProcessor.add(operand1, operand2);
    case '-':
      return calculationProcessor.subtract(operand1, operand2);
    default:
      throw new UnsupportedOperationException(String.format(
          &quot;%s is not a known operation&quot;, operation));
    }
  }
}
</pre>
<p>So the question is, what should the test for <code>NewCalculator</code> look like?</p>
<p>If we follow the strict &#8220;One Unit Test, One Class&#8221; paradigm, we have to create a mock for the <code>CalculatorProcessor</code> and pass it into the <code>Calculator</code>.  </p>
<p>One possible way it could work is by mocking out the <code>add</code> and <code>subtract</code> methods so that they have mock implementations which actually perform the operations.  That solution really only works here because this example is so simple (the implementation of add is trivial).  Were this problem more real-world, mocking out the responses based on the inputs may not be feasible, so let&#8217;s imagine that we cannot do this for the purposes of this post (when mocking out the responses is possible, most of this post is rendered moot, as that is usually the best way to go).</p>
<p>The other way to write these tests would be to create a mock and verify that our <code>NewCalculator</code> delegates to <code>CalculationProcessor</code> appropriately.  It would like this:</p>
<pre class="brush: java;">package com.rallydev.engblog.unittesting;

import org.junit.Before;
import org.junit.Test;

import static org.mockito.Mockito.*;

public class NewCalculatorBadTest {
	private NewCalculator calculator;
	private CalculationProcessor mockCalculationProcessor;

	@Before
	public void setUp() {
		this.mockCalculationProcessor = mock(CalculationProcessor.class);
		this.calculator = new NewCalculator(mockCalculationProcessor);
	}

	@Test
	public void shouldAdd() {
		calculator.calculate('+', 2, 3);
		verify(mockCalculationProcessor).add(2,3);
	}

	@Test
	public void shouldSubtract() {
		calculator.calculate('-', 2, 3);
		verify(mockCalculationProcessor).subtract(2,3);
	}

	@Test(expected=UnsupportedOperationException.class)
	public void shouldThrowExceptionForUnknownOperation() {
		calculator.calculate('Q', 1, 2);
	}
}
</pre>
<p>I hate this test.  This test does little but double-check the implementation of <code>NewCalculator</code>.</p>
<p>This test is extremely brittle.  If the calculator had more responsibilities (say, multiplication, exponents, etc.) and the tests were more thorough (boundary checking, looking for division by zero, and so on) then changing the implementation of <code>NewCalculator</code> would require changing dozens of broken tests.</p>
<p><em>The tests are there to make us feel safe about refactoring the code, but virtually any refactoring breaks them, which requires us to manually fix the tests.</em>  When this happens, a refactoring effort loses its test harness: the code and the tests must <em>both</em> change together, rather than one at a time with the one verifying the correctness of the other.</p>
<p>Instead, I would prefer to leave the test as it was, only modifying the <code>setUp</code> method to correctly construct the <code>NewCalculator</code> with real instantiations of its dependency.</p>
<pre class="brush: java;">
package com.rallydev.engblog.unittesting;

import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;

public class NewCalculatorBetterTest {
  private NewCalculator calculator;

  @Before
  public void setUp() {
    CalculationProcessor calculationProcessor = new CalculationProcessor();
    this.calculator = new NewCalculator(calculationProcessor);
  }

  @Test
  public void shouldAdd() {
    assertEquals(5, calculator.calculate('+', 2, 3));
  }

  @Test
  public void shouldSubtract() {
    assertEquals(1, calculator.calculate('-', 5, 4));
  }

  @Test(expected = UnsupportedOperationException.class)
  public void shouldThrowExceptionForUnknownOperation() {
    calculator.calculate('Q', 1, 2);
  }
}
</pre>
<p>There are a few things to notice about this test.  First and foremost, the bodies of the three test methods are now identical to how they were before the refactoring.  This means that the refactoring could have taken place while using the test to ensure it was correct, though the <code>setUp</code> method would have had to change.</p>
<p>Secondly, even though a real <code>CalculationProcessor</code> was instantiated for the test, it was not assigned to a field.  It is scoped exclusively to the <code>setUp</code> method.  This is because the test really has no reason to know about the class beyond the fact that it needs it to construct the <code>NewCalculator</code>.</p>
<p><strong>Blurring the Line</strong></p>
<p>Is this a unit test, or is it something else?  Unit-testing pedants would argue that it&#8217;s not a unit test, but an integration test.  <a href="http://www.michaelfeathers.com/">Michael Feathers</a> may disagree:</p>
<blockquote><p>
&#8220;In the industry, people often go back and forth about whether particular tests are unit tests. Is a test really a unit test if it uses another production class? I go back to the two qualities: Does the test run fast? Can it help us localize errors quickly?&#8221; (Source: <a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052">Working Effectively with Legacy Code</a>)
</p></blockquote>
<p>The test above is extremely fast, but how effectively does it help us localize errors?  If it were the only failing test for a system full of classes and tests, it would help us narrow down the error pretty quickly: there is either a problem parsing the operator, or a problem performing the operation.</p>
<p>If we had a separate test for the CalculationProcessor itself, but it was passing, then we would know the error is in the parsing.  It didn&#8217;t help us localize the problem quite as quickly as the mocking test would have, but it is also a far stronger test, less likely to break under the strain of a refactoring.</p>
<p>It&#8217;s a trade-off, of course, but I now tend to lean toward creating instances of the dependency classes in the setup of the test in these situations.  I have simple guidelines to help me determine when I should create a mock versus a concrete instance of a class.</p>
<p><strong>Verify() is a Crutch</strong></p>
<p>When you&#8217;re writing a test, you go through three phases, which <a href="http://en.wikipedia.org/wiki/Behavior_driven_development">BDD</a> proponents refer to as the Given, When, and Then.  First you write the Givens, which attempt to fabricate a pre-existing situation for the purposes of your test.  Then you write the Whens, which are the operations being tested.  Last you assert some Thens, which are the expected results of performing the operation.</p>
<p>In the case of our simple unit test above, the Given is that a <code>NewCalculator</code> exists.  The When is that <code>calculate</code> is called with some parameters.  And then Then, of course, is that we get the desired result.  But how do we write our Thens?</p>
<p>My feeling is that, if we reach into our toolbox and pull out a <code>verify</code> to write our Thens, we are cheating our tests out of the chance to be truly valuable.  When we reach for <code>verify</code>, we are creating brittle tests that resist refactoring rather than enable it.  We are using <code>verify</code> as a crutch, but we should only reach for it as a last resort.</p>
<p>Instead, reach for concrete instantiations of classes where possible.  Create a mock that will be used to verify method invocation for one of two reasons:</p>
<ol>
<li><strong>Speed</strong> &#8211; If creating an instance of the class will significantly slow down the test, it should be mocked out instead.  This is likely to be the case for classes that clearly turn tests into integration tests, such as classes that facilitate a connection to a database or over a network.  This may also be the case for classes that perform a great deal of processing.</li>
<li><strong>Complexity</strong> &#8211; Create a mock if creating an instance of a class requires creating a number of additional classes that it depends on, which in turn depend on more classes, and so on.  You do not want your setUp methods to contain thousands of lines of object instantiation to support your tests.  I recommend creating real objects as deeply down the dependency tree as possible, then mocking out the rest.  How far down the tree should you go?  That&#8217;s really a matter of taste, but I recommend trying two layers deep and no more.  When you do this, you are likely to find that you have no need to verify the calls on the mock objects (other tests already cover those scenarios), but instead can set up mock objects to respond in specific ways to method invocations, simulating their behavior for the purpose of the test so that your tests can verify actual results.</li>
</ol>
<p><strong>Going Forward</strong></p>
<p>Writing tests without the hard Unit/Class restriction allows us to write tests that enable the safe refactoring of classes, but come at the potential price of slowing down our tests and complicating the <code>setUp</code> methods for those tests.  There is a delicate balance there, but in general I recommend trying to err on the side of concrete class instantiation in tests, at least over method invocation verification (mocking out responses is always still preferred).</p>
<p>This view is, of course, subject to change (as it was when I felt that the restriction was valuable), but since blurring this line my tests have remained fast and, more importantly, allowed me to code faster by letting me refactor when necessary.</p>
<p>Agree?  Disagree?  Leave a comment.</p>
<img src="http://www.rallydev.com/engblog/?ak_action=api_record_view&id=424&type=feed" alt="" />]]></content:encoded>
			<wfw:commentRss>http://www.rallydev.com/engblog/2009/11/17/units-are-not-classes/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Verizon Droid vs T-Mobile G1</title>
		<link>http://www.nomachetejuggling.com/2009/11/06/verizon-droid-vs-t-mobile-g1/</link>
		<comments>http://www.nomachetejuggling.com/2009/11/06/verizon-droid-vs-t-mobile-g1/#comments</comments>
		<pubDate>Sat, 07 Nov 2009 00:12:35 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[hardware]]></category>
		<category><![CDATA[mobile]]></category>
		<category><![CDATA[operating systems]]></category>
		<category><![CDATA[phone]]></category>
		<category><![CDATA[t-mobile]]></category>
		<category><![CDATA[verizon]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/?p=596</guid>
		<description><![CDATA[Now that the Verizon Droid has been released, lots of blogs and technology sites are comparing it to the iPhone.  When I was researching the droid, I found most of these comparisons worthless, as I&#8217;ll never use an iPhone as long as Apple&#8217;s policies regarding the phone and its app store remain as they [...]]]></description>
			<content:encoded><![CDATA[<p>Now that the Verizon Droid has been released, lots of blogs and technology sites are comparing it to the iPhone.  When I was researching the droid, I found most of these comparisons worthless, as I&#8217;ll never use an iPhone as long as Apple&#8217;s policies regarding the phone and its app store remain as they are today.</p>
<p>But for the last year I&#8217;ve been a very happy T-Mobile G1 user.  I love the Android operating system, I love the Google integration, I love the (relative) openness of the device and the near perfect openness of the application market.  I cannot imagine using a phone that doesn&#8217;t run Andoid any time soon.  </p>
<p>Despite loving the software on the G1, I&#8217;ve never been completely crazy about the hardware itself.  The screen sliding feels a little cheap to me, the phone generally feels a bit sluggish, and the trackball becomes nearly worthless after significant use.  Overall, these are minor annoyances, but annoyances nonetheless.  The G1 always felt like something of a knockoff iPhone; it was the thing you got when you couldn&#8217;t afford a slick, sleek iPhone from Apple.  It has features like an iPhone, but generally inferior hardware.</p>
<p>So when I started seeing the Verizon Droid, I got excited.  I was eager to switch back to Verizon (I had switched from Verizon to T-Mobile to get the G1 when it first came out) due to Verizon&#8217;s superior network coverage and the fact that my wife is a Verizon user.  Moreover, the phone looked simply stunning to me.  Solid, industrial, sleek, thin (or at least thinner than the G1).  Overall, a bad-ass looking phone.</p>
<p>Unsurprisingly, I purchased a Droid the day it was released.  In fact, I suffered the early termination fee with T-Mobile in order to get it.</p>
<p>I&#8217;ve had the phone for a day now and I wanted to offer some comparisons between it and the G1.</p>
<p><span id="more-596"></span></p>
<p><strong>The Good</strong></p>
<p>The hardware of the Droid is solid.  It feels heavy and sturdy, sliding the screen to reveal the keyboard differs from the cheap spring of the G1 a great deal (it&#8217;s almost, but not quite, difficult to slide).  The phone is extremely fast and responsive.  Applications start quickly, process quickly, and generally seem speedier.  The screen of the Droid is significantly larger than with the G1, and the clarity and resolution of the Droid&#8217;s screen are simply stunning.  My wife&#8217;s contact picture actually looks like her.</p>
<p>The phone is only slightly thinner than the G1, but it makes a huge difference &#8211; it feels FAR less bulky in my pocket.  The obnoxious upward curve of the bottom of the G1 is gone, replaced by a solid boxy square on the Droid.  The front of the phone is devoted almost entirely to the screen.  The trackball of the G1 (which becomes less and less responsive over time) has been replaced by a directional pad, and that pad can be accessed only by sliding the keyboard out, devoting even more of the phone to the screen itself.  </p>
<p>The power button is in a more convenient place on the Droid as well.  Whereas the power/lock button on the G1 was somewhat awkward to use(I always worried about dropping the phone when pressing it to darken the screen before putting it back in my pocket), the Droid&#8217;s power/lock button is easy to push and encourages holding the phone in a more solid hand configuration.  The volume keys have been moved to the opposing side of the phone, but that doesn&#8217;t seem to make a difference either way.</p>
<p>Additionally, the vibration seems a bit stronger on the Droid.  I always leave my phone in vibrate mode, but the G1 vibration was pretty weak.  Often I&#8217;d get a text or a phone call and not even feel it in my pocket.  So far, that hasn&#8217;t been a problem with the Droid, whose vibration is powerful without being loud.  Battery life is far better with the Droid as well &#8211; a full day of use with the G1 left the battery dead if I didn&#8217;t charge it during the day at least a bit.  A full day of use with the Droid doesn&#8217;t even get the battery into the yellow, and that&#8217;s with the screen significantly brighter.</p>
<p>One feature I particularly like is that the Droid comes with a devoted headphone jack.  Listening to podcasts on the G1 was a pain, as it required using an awkwardly long adapter cable plugged into the USB port.  This also prevented me from charging the device while listening to something, something I often wanted to do in the car.  The Droid has a separate charging port and headphone jack, which is far easier to work with.</p>
<p>Most importantly, the phone connects to Verizon, so I have significantly better 3G coverage than I did with T-Mobile, especially in conference rooms at work (where I need the comfort of Google Reader the most).</p>
<p><strong>The Bad</strong></p>
<p>The Droid isn&#8217;t without it&#8217;s faults, unfortunately.  The Droid keyboard is vastly inferior to the G1&#8217;s keyboard.  Firstly, there are only 4 rows of keys on the Droid, as opposed to the G1&#8217;s five.  This means pressing numbers requires using an &#8216;ALT&#8217; key.  Not hugely irritating, but mildly so.  Far worse, however, is the fact that the keyboard keys have no gaps between them as they do on the G1, and the buttons themselves are flat rather than being slightly rounded.  Typos are far, far more common with the Droid phone, it&#8217;s nearly impossible for me to get through a simple text message without fat-fingering something.  To make matters worse, because the backspace key is DIRECTLY above the enter key, I find myself accidentally hitting enter when I&#8217;m trying to backspace, which means I&#8217;m sending a LOT of text messages that end in a typo, only to be followed by another text-message correcting the mistake.</p>
<div id="attachment_597" class="wp-caption alignright" style="width: 310px"><a href="http://www.nomachetejuggling.com/files/2009-11-06-16.56.31.jpg"><img src="http://www.nomachetejuggling.com/files/2009-11-06-16.56.31-300x224.jpg" alt="Fuck you, Motorola." title="Droid charger" width="300" height="224" class="size-medium wp-image-597" /></a><p class="wp-caption-text">Fuck you, Motorola.</p></div>
<p>Another irritation is that the Droid does not use a standard USB port.  It sure looks a hell of a lot like one, but it isn&#8217;t.  I could plug the G1 into anything that had a Mini-USB connector on the end.  Wall chargers, car chargers, even the cables my wife uses for HER phone (very convenient if I happened to need a quick charge in her car).  The Droid uses some proprietary connector, so you have to buy adapters for the thing if you want to charge it.  This is completely obnoxious and unnecessary &#8211; it&#8217;s clearly Motorola trying to suck a little bit more money out of me.  The real kick in the balls, however, is what the phone comes with in terms of chargers.  It comes with a basic USB connector to connect it to your computer, and a wall adapter FOR THE USB CABLE.  If you want to plug it into the wall, you must sacrifice the USB cable.  This is particularly obnoxious for me because I had my G1&#8217;s usb cable (a standard USB with mini adapter on the end) in my office downstairs, a wall charger in the bedroom so it could charge at night, a wall charger at work so I could charge at work, and a car charger in my car if I needed to make a call but had let my battery die.  The Droid&#8217;s supplied chargers give me ONE of these at any given moment, and I must separately purchase what I need for the other three.</p>
<p>UPDATE: A commenter has explained that the plug the Droid uses IS, in fact, an open standard, called Micro-B.  A quick search on Newegg revealed many cheap Micro-B cables that I could use with the phone.  So that&#8217;s much less annoying.  Still would have bee nice to have a separate wall charger that didn&#8217;t use up the one USB cable that comes with the phone, though.</p>
<p>The camera for the Droid is 5 Megapixels.  Seems impressive, except that so far I&#8217;ve had some pretty crappy luck with it.  In fact, the picture of the charger took me five tries to get right, and still came out blurry, even when I switched the focus mode for closeup shots.  The flash is basically worthless as well, it never seems to flash at the correct time, and it is effectively a &#8220;make this photo blurry&#8221; toggle.</p>
<p>Call quality on the Droid seems significantly worse as well.  I have not yet determined if the speaker is the problem, but so far it&#8217;s much more difficult to hear people during a call on the Droid.</p>
<p>Another annoyance is how close the row of four hardware buttons are to the bottom of the screen on the Droid.  I was using Twidroid and reading some private messages on my twitter account, then I hit menu.  The only menu item on this screen is for &#8220;Delete all messages&#8221;.  I decided I didn&#8217;t want to do that, and hit &#8220;back&#8221; to exit out of that menu.  Unfortunately, the &#8220;back&#8221; button is flush with the bottom of the screen, so my attempt to go &#8220;back&#8221; registered on the touchscreen as a click on the menu item, so Twitdroid proceeded to permanently delete all of my private messages.  I had to actually rip the battery out of the phone in a panic to interrupt it quickly enough, and I still lost my most recent thirty or so messages.  Annoying.</p>
<p><strong>Overall</strong></p>
<p>Many of the nicest features of the Droid are actually features of the Android 2.0 operating system, the next version of the OS running on the G1.  It remains unknown at this point if the G1 will get this version of the OS, but it&#8217;s what contains most of Droid&#8217;s coolest features, such as the turn-by-turn directions and other various improvements to Google Maps.  The 2.0 upgrade also comes with a cost: a few of my favorite apps such as &#8220;reddit is fun&#8221;, &#8220;K-9 Mail&#8221;, and &#8220;Pure Calendar&#8221; don&#8217;t actually work correctly, but that will likely be fixed in due time.</p>
<p>I also do not yet have the Multimedia Station charger/dock for the Droid, which I think would be awesome on my bedroom nightstand, nor do I have the car mount, both of which I want and I think will make me appreciate the Droid more.</p>
<p>As it stands though, I&#8217;m not sure the Droid is compelling enough on its own to warrant the switch from T-Mobile to Verizon.  I love the increased coverage, the devoted headphone jack, the screen improvements, and the overall feel of the phone, but I really dislike being nickel-and-dimed on chargers and I kind of really hate the keyboard (I&#8217;m hoping I get used to it).</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2009/11/06/verizon-droid-vs-t-mobile-g1/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Google Reader&#8217;s Creepy New Feature</title>
		<link>http://www.nomachetejuggling.com/2009/10/25/google-readers-creepy-new-feature/</link>
		<comments>http://www.nomachetejuggling.com/2009/10/25/google-readers-creepy-new-feature/#comments</comments>
		<pubDate>Sun, 25 Oct 2009 19:26:02 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[google]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[privacy]]></category>
		<category><![CDATA[rss]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[weird]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/?p=584</guid>
		<description><![CDATA[I&#8217;m a big user of Google Reader, so it annoyed me a bit when I started seeing things like &#8220;50 people liked this&#8221; and similar features peppering my Reader interface a while back.  I wasn&#8217;t alone, there&#8217;s a Google Groups thread where a number of people lament the inability to deactivate this &#8220;feature.&#8221;
But a [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m a big user of Google Reader, so it annoyed me a bit when I started seeing things like &#8220;50 people liked this&#8221; and similar features peppering my Reader interface a while back.  I wasn&#8217;t alone, there&#8217;s a <a href="http://groups.google.com/group/google-reader-howdoi/browse_thread/thread/b5f96533a772faaa/73fe8efae51c7c2c?lnk=gst&#038;q=">Google Groups thread</a> where a number of people lament the inability to deactivate this &#8220;feature.&#8221;</p>
<p>But a few days ago, I saw the payoff: <a href="http://googleblog.blogspot.com/2009/10/reading-gets-personal-with-popular.html">Google Reader Recommendations</a>.  Recommendation engines are one of my favorite things about the new social web &#8211; Amazon&#8217;s book recommendations and Netflix&#8217;s movie recommendations have led me to find things I never would have discovered on my own.  So when I saw that Google Reader had recommendations of other blogs or RSS feeds for me, I was excited.</p>
<p><span id="more-584"></span></p>
<p>I figured, like most other recommendation engines, Google Reader now looked at what feeds I subscribe to and found other feeds that were subscribed to by people who subscribed to the feeds I like.  This is generally how recommendation engines work: if I love &#8220;Back to the Future&#8221; and 90% of Netflix users who rate that movie highly also highly rate &#8220;Ghostbusters&#8221; highly and I&#8217;ve never seen it, Netflix will recommend Ghostbusters to me.</p>
<p>But when I looked at my recommendations, a strange thing caught my attention.</p>
<p><a href="http://www.nomachetejuggling.com/files/creepy_reader.png"><img src="http://www.nomachetejuggling.com/files/creepy_reader-300x95.png" alt="Creepy Suggestions" title="Creepy Suggestions" width="300" height="95" class="aligncenter size-medium wp-image-585" /></a></p>
<p>There is a recommendation for a blog related to TeX in there.  If I scroll down, there are actually five or six other TeX resources.</p>
<p>This stood out because I don&#8217;t subscribe to <strong>ANY</strong> RSS feeds that related to TeX in any way, not even tangentially.  So why did Google so strongly suggest them?</p>
<p>Well, I don&#8217;t subscribe to TeX feeds, but I am working on my Master&#8217;s thesis, and I&#8217;ve had to do a lot of Googling for help on LaTeX.  A very large portion of searches I do in Google are LaTeX related, simply because I often need to troubleshoot a problem or look up how to format something.</p>
<p>So Google Reader&#8217;s recommendations are not merely based on feeds.  They are based in my search results as well, even though that&#8217;s &#8220;separate&#8221; from Reader.  It wouldn&#8217;t surprise me if people were getting recommendations based on the content of their Gmail accounts either.</p>
<p>Creepy.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2009/10/25/google-readers-creepy-new-feature/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Wedding Photos Online</title>
		<link>http://www.nomachetejuggling.com/2009/09/18/wedding-photos/</link>
		<comments>http://www.nomachetejuggling.com/2009/09/18/wedding-photos/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 22:32:44 +0000</pubDate>
		<dc:creator>Rod Hilton</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[photos]]></category>
		<category><![CDATA[wedding]]></category>

		<guid isPermaLink="false">http://www.nomachetejuggling.com/2009/09/18/jb0959/</guid>
		<description><![CDATA[



JB0959

Originally uploaded by rodhilton


The photos from my wedding are up on Flickr.  Check &#8216;em out here.  Our photographer was excellent.  I highly recommend her.
The wedding was great.  Virtually nothing went wrong &#8211; we even just barely avoided some rain but avoided it nonetheless.  I was kind of dreading having to [...]]]></description>
			<content:encoded><![CDATA[<div style="float: right; margin-left: 10px; margin-bottom: 10px;">
<a href="http://www.flickr.com/photos/rodhilton/3932201814/" title="photo sharing"><img src="http://farm3.static.flickr.com/2439/3932201814_e67c8cb9b0_m.jpg" alt="" style="border: solid 2px #000000;" /></a><br />
<br />
<span style="font-size: 0.9em; margin-top: 0px;"><br />
<a href="http://www.flickr.com/photos/rodhilton/3932201814/">JB0959</a><br />
<br />
Originally uploaded by <a href="http://www.flickr.com/people/rodhilton/">rodhilton</a><br />
</span>
</div>
<p>The photos from my wedding are up on Flickr.  Check &#8216;em out <a href="http://www.flickr.com/photos/rodhilton/collections/72157621960411651/">here</a>.  Our <a href="http://www.annettedragonphotography.com/content.php">photographer</a> was excellent.  I highly recommend her.</p>
<p>The wedding was great.  Virtually nothing went wrong &#8211; we even just barely avoided some rain but avoided it nonetheless.  I was kind of dreading having to be social for a whole evening, but even the reception turned out to be a good time (though I had to go hide in order to eat my slice of cake).</p>
<p>Overall, being married doesn&#8217;t feel too much different from not being married.  I&#8217;ve known I&#8217;d marry Julia since second week we dated, and I knew she&#8217;d make a beautiful bride (she did).</p>
<p>It was great seeing family and merging my 7-person family with her 100-something-person family.  I also really loved how many of our friends from college were able to make it, including one of my professors.  It was great seeing everyone again.</p>
<p>My friend Dennis was a fantastic Best Man, and Julia&#8217;s sister Olivia did an wonderful job as Maid of Honor.  It was a truly unforgettable time.<br />
<br clear="all" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.nomachetejuggling.com/2009/09/18/wedding-photos/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>
