Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: b5afb4166c
Fetching contributors…

Cannot retrieve contributors at this time

1010 lines (691 sloc) 65.027 kb
<!DOCTYPE html>
<!--[if IEMobile 7 ]><html class="no-js iem7"><![endif]-->
<!--[if lt IE 9]><html class="no-js lte-ie8"><![endif]-->
<!--[if (gt IE 8)|(gt IEMobile 7)|!(IEMobile)|!(IE)]><!--><html class="no-js" lang="en"><!--<![endif]-->
<head>
<meta charset="utf-8">
<title>ywen.in.coding</title>
<meta name="author" content="Yi Wen">
<meta name="description" content="Introduction I am surprised when I read this post because I am one of Martin Fowler fans and still is. But I have to disagree large part of Martin&# &hellip;">
<!-- http://t.co/dKP3o1e -->
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="320">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="canonical" href="http://ywen.github.com">
<link href="/favicon.png" rel="icon">
<link href="/stylesheets/screen.css" media="screen, projection" rel="stylesheet" type="text/css">
<script src="/javascripts/modernizr-2.0.js"></script>
<script src="/javascripts/ender.js"></script>
<script src="/javascripts/octopress.js" type="text/javascript"></script>
<link href="/atom.xml" rel="alternate" title="ywen.in.coding" type="application/atom+xml">
<!--Fonts from Google"s Web font directory at http://google.com/webfonts -->
<link href="http://fonts.googleapis.com/css?family=PT+Serif:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<link href="http://fonts.googleapis.com/css?family=PT+Sans:regular,italic,bold,bolditalic" rel="stylesheet" type="text/css">
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-30555202-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body >
<header role="banner"><hgroup>
<h1><a href="/">ywen.in.coding</a></h1>
<h2>Everythng I do</h2>
</hgroup>
</header>
<nav role="navigation"><ul class="subscription" data-subscription="rss">
<li><a href="/atom.xml" rel="subscribe-rss" title="subscribe via RSS">RSS</a></li>
</ul>
<form action="http://google.com/search" method="get">
<fieldset role="search">
<input type="hidden" name="q" value="site:ywen.github.com" />
<input class="search" type="text" name="q" results="0" placeholder="Search"/>
</fieldset>
</form>
<ul class="main-navigation">
<li><a href="/">Blog</a></li>
<li><a href="/blog/archives">Archives</a></li>
</ul>
</nav>
<div id="main">
<div id="content">
<div class="blog-index">
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/04/18/100-percent-test-coverage-is-the-starting-point/">100% Test Coverage Is the Starting Point</a></h1>
<p class="meta">
<time datetime="2012-04-18T21:18:00-05:00" pubdate data-updated="true">Apr 18<span>th</span>, 2012</time>
| <a href="/blog/2012/04/18/100-percent-test-coverage-is-the-starting-point/#disqus_thread">Comments</a>
</p>
</header>
<div class="entry-content"><h2>Introduction</h2>
<p>I am surprised when I read this <a href="http://martinfowler.com/bliki/TestCoverage.html">post</a> because I am one of Martin Fowler fans and still is. But I have to disagree large part of Martin&#8217;s view on this issue.</p>
<p>First, the part that I agree with him is that test coverage should not be a goal, and a high number doesn&#8217;t mean much. But from this fact, I have my own conclusions.</p>
<h2>What is ideal test coverage number</h2>
<p>In short, 100% test coverage number is not a goal, it is a requirement, a starting point for doing good tests. Below 100% is unacceptable.</p>
<p>Why? I will use some ruby code as my example</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">return</span> <span class="kp">true</span> <span class="k">if</span> <span class="n">condition?</span>
</span></code></pre></td></tr></table></div></figure>
<p>with one test in rspec:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">context</span> <span class="s2">&quot;when the condition is true&quot;</span> <span class="k">do</span>
</span><span class='line'> <span class="n">it</span> <span class="s2">&quot;returns true&quot;</span> <span class="k">do</span>
</span><span class='line'> <span class="n">subject</span><span class="o">.</span><span class="n">stub</span><span class="p">(</span><span class="ss">:condition?</span><span class="p">)</span><span class="o">.</span><span class="n">and_return</span> <span class="kp">true</span>
</span><span class='line'> <span class="n">subject</span><span class="o">.</span><span class="n">method</span><span class="o">.</span><span class="n">should</span> <span class="n">be_true</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>When you run the test with coverage, the line has a 100% coverage number. But do you really test the method well? the answer is no because you also need to test when condition is <code>false</code>. So the &#8220;real&#8221; coverage here is actually like 50% roughly.</p>
<p>Now think about it, when the test coverage tool tells you that you are 100% covered, it is probably lying, you don&#8217;t. What about Martin&#8217;s claims of &#8220;high coverage&#8221; like 90%? how poor that coverage is if 100% cverage is not that convicing?</p>
<h2>Test every method?</h2>
<p>Do I absoutely test every each single method? The answer is no. Here is an example:</p>
<p>I love constructor injection pattern, so a lot of my code looks like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Class</span> <span class="n">A</span>
</span><span class='line'> <span class="kp">attr_reader</span> <span class="ss">:dep1</span><span class="p">,</span> <span class="ss">:dep2</span>
</span><span class='line'> <span class="kp">private</span> <span class="ss">:dep1</span><span class="p">,</span> <span class="ss">:dep2</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">dep1</span><span class="p">,</span> <span class="n">dep2</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@dep1</span><span class="p">,</span> <span class="vi">@dep2</span> <span class="o">=</span> <span class="n">dep1</span><span class="p">,</span> <span class="n">dep2</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>How would I test this code in seperation? Basically I can&#8217;t, and I don&#8217;t. So if I write this code and commit, my test coverage will go below 100%. Is that OK? No, absolutely not OK. Then what do I do wrong?</p>
<p>I have to step back and ask myself, why do I write this code? Do I really need it? The answer most likely is: yes I do. However, it is not useful on its own, I will need my dependencies in some of instance methds in that class. But I don&#8217;t need the dependencies until I actually work on the instance methods.</p>
<p>So what I do wrong is the sequence of my actions. I should have had written one test that will present an intent, or a uasge of an instance of this class, and I start to impelment the method that does it. When I implement the method, I may find out that I have to add such a constructor (or not, for what it worth). At that time, I add this constructor and it is covered by an execution of the test against the instance method. My coverage number is still 100%.</p>
<p>This example essentially is the principle of &#8220;Do not test private methods&#8221;.</p>
<h2>validates_present_of</h2>
<p>I would like to be off topic a little bit to discuss a view that some people hold: do not test your validations in Rails since you are tesing the framework.</p>
<p>Well, the truth is, you are not testing framework. When you add one line into your class like</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">validates_present_of</span> <span class="ss">:name</span>
</span></code></pre></td></tr></table></div></figure>
<p>You add a business rule in it. The framework does not have this rule, it doesn&#8217;t know the <code>:name</code> is required in this model class. So you should be testing this line to make sure name is being required.</p>
<p>Think of an exetreme situation: Given that you don&#8217;t test this line, some developer accidently deletes the line. No tests would fail and the fault code goes to production. Then next thing you know, you eitehr raises a bunch of 500 error when user doesn&#8217;t fill in the name, or worse, some users register successfully without a name. You then may not be able to charge his card because no name associates with it. Would you still think this line is framework concern at that point?</p>
<p>If you write you test like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">it</span> <span class="s2">&quot;is required&quot;</span> <span class="k">do</span>
</span><span class='line'> <span class="n">subject</span><span class="o">.</span><span class="n">name</span> <span class="o">=</span> <span class="kp">nil</span>
</span><span class='line'> <span class="n">subject</span><span class="o">.</span><span class="n">valid?</span>
</span><span class='line'> <span class="n">subject</span><span class="o">.</span><span class="n">errors</span><span class="o">[</span><span class="ss">:name</span><span class="o">].</span><span class="n">should</span> <span class="kp">include</span><span class="p">(</span><span class="s2">&quot;is required&quot;</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>Then you are testing the framework because the error message is generated by the framework, not by your code. So something like:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">subject</span><span class="o">.</span><span class="n">should</span> <span class="n">have</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">error_on</span><span class="p">(</span><span class="ss">:name</span><span class="p">)</span>
</span></code></pre></td></tr></table></div></figure>
<p>is good.</p>
<p>Some would argue it is so painful to write like 5 lines of code for each attribute being validated. Very true, but how about this in your test:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">it_requires_attributes</span> <span class="ss">:name</span><span class="p">,</span> <span class="ss">:email</span>
</span></code></pre></td></tr></table></div></figure>
<p>This looks easy, right? All you have to do is to add a macro behind the scene to exapand into some good tests. I am not advocating this macro itself, I am just saying there are a lot of ways to make your tests DRY.</p>
<h2>In team environments</h2>
<p>It is very difficult to configure a CI environment with less than 100% test coverage. The problem is this: Say your manager demands a 86% test coverage. Then one could just wait for another teammate commits and increase the test coverage to 86.1%, then he commits without test, drop the test coverage back to 86%. Mission accomplished.</p>
<p>So the only way that makes sense is to ensure to increase or maintain the test coverage with every commits (or every merge back to the main line if you use git). To do so, a lot of job must be done on the CI servers side to be able to:</p>
<ul>
<li>Know the current thershold</li>
<li>Increase the thershold automatically when the test coverage goes up</li>
<li>Break the build when the test coverage is below the thershold</li>
</ul>
<p>With a 100% code coverage, this is so much simpler, each commit either has 100% coverage, or it doesn&#8217;t. The CI servers just need to fail those who don&#8217;t.</p>
<h2>Summary</h2>
<p>I understand Martin&#8217;s position completely. He is addressing the problem where the test coverage number becomes only a goal, a symbol, not the real effort. But it doesn&#8217;t mean a CI server should not measure the test coverage. In my own practice, when we have this number and when we realize how bad it is, we tend to do a better job, pay more attention to the code we write. It is a very useful tool for a team in learning.</p>
<p>When a team becomes better, the build will not break because of the test coverage, then it doesn&#8217;t really matter if the CI server keeps measureing it. It will give people confidence, validate what they have been doing. Thus a good ending.</p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/04/05/coding-standard-part-3/">My Coding Standard for Rails Projects (Part 3)</a></h1>
<p class="meta">
<time datetime="2012-04-05T22:41:00-05:00" pubdate data-updated="true">Apr 5<span>th</span>, 2012</time>
| <a href="/blog/2012/04/05/coding-standard-part-3/#disqus_thread">Comments</a>
</p>
</header>
<div class="entry-content"><h2>Unit Testing</h2>
<p>Unit Testing is the central piece of a project for two reasons:</p>
<ul>
<li>Tests direct how the production code is written.</li>
<li>Tests assure any given execution paths within a unit (method) output when a developer thinks they output</li>
</ul>
<p>I am going to trying to describe how the tests direct how the code under test is written.</p>
<p>I have class which takes a hash called <code>settings</code> and use the <code>settings</code> to do something.</p>
<p>Like below:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">SomeClass</span>
</span><span class='line'> <span class="kp">attr_reader</span> <span class="ss">:settings</span>
</span><span class='line'> <span class="kp">private</span> <span class="ss">:settings</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@settings</span> <span class="o">=</span> <span class="n">settings</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nf">deliver!</span><span class="p">(</span><span class="n">mail</span><span class="p">)</span>
</span><span class='line'> <span class="n">list</span> <span class="o">=</span> <span class="no">Redis</span><span class="o">::</span><span class="no">List</span><span class="o">.</span><span class="n">new</span> <span class="n">settings</span><span class="o">[</span><span class="ss">:redis_key_name</span><span class="o">]</span><span class="p">,</span> <span class="ss">:marshal</span> <span class="o">=&gt;</span> <span class="kp">true</span>
</span><span class='line'> <span class="n">settings</span><span class="o">[</span><span class="ss">:marshallable_converters</span><span class="o">].</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">setting</span><span class="o">|</span>
</span><span class='line'> <span class="n">mail</span> <span class="o">=</span> <span class="no">MarshallableConverterSetting</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">setting</span><span class="p">)</span><span class="o">.</span><span class="n">marshallable_class</span><span class="o">.</span><span class="n">marshallable</span><span class="p">(</span><span class="n">mail</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="n">list</span> <span class="o">&lt;&lt;</span> <span class="n">mail</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>Now the problem is that sometimes <code>settings</code> will miss some keys. It may not have <code>:redis_key_name</code>, for example. In this case, I can assume that a default for the missing keys.</p>
<p>The first attempt is to do something like this in the <code>initialize</code>:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@settings</span> <span class="o">=</span> <span class="n">default_settings</span><span class="o">.</span><span class="n">merge</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="kp">private</span>
</span><span class='line'><span class="k">def</span> <span class="nf">default_settings</span>
</span><span class='line'> <span class="p">{</span><span class="ss">:redis_key_name</span> <span class="o">=&gt;</span> <span class="s2">&quot;some-name&quot;</span><span class="p">,</span> <span class="ss">:marshallable_converters</span> <span class="o">=&gt;</span> <span class="ss">:some_default</span><span class="p">}</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>First, let me say although this is relatively small, it breaks something important about OO design: the logic for inserting the defaults doesn&#8217;t belong to this class logically, it should not be this class&#8217;s responsibility to consider this.</p>
<p>In the real world, I may not realize this at all, it is such a small and innocent adds. But what happned was, I wrote my tests first and tried to go with this path, then I found out how am I going to test this? I could not check the <code>settings</code> hash since it is private (and it should be). I could call <code>deliver!</code>, adding contexts to check when a setting is misisng, the default takes over, but that will make the tests so messy and irrelevant. Then I figured I couldn&#8217;t do this. I should seek other implementations. So the end result is like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">SomeClass</span>
</span><span class='line'> <span class="kp">attr_reader</span> <span class="ss">:settings</span>
</span><span class='line'> <span class="kp">private</span> <span class="ss">:settings</span>
</span><span class='line'>
</span><span class='line'> <span class="c1"># @api private</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@settings</span> <span class="o">=</span> <span class="no">Settings</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">settings</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="c1"># @api private</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">deliver!</span><span class="p">(</span><span class="n">mail</span><span class="p">)</span>
</span><span class='line'> <span class="n">list</span> <span class="o">=</span> <span class="no">Redis</span><span class="o">::</span><span class="no">List</span><span class="o">.</span><span class="n">new</span> <span class="n">settings</span><span class="o">.</span><span class="n">redis_key_name</span><span class="p">,</span> <span class="ss">:marshal</span> <span class="o">=&gt;</span> <span class="kp">true</span>
</span><span class='line'> <span class="n">settings</span><span class="o">.</span><span class="n">marshallable_converters</span><span class="o">.</span><span class="n">each</span> <span class="k">do</span> <span class="o">|</span><span class="n">setting</span><span class="o">|</span>
</span><span class='line'> <span class="n">mail</span> <span class="o">=</span> <span class="no">MarshallableConverterSetting</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">setting</span><span class="p">)</span><span class="o">.</span><span class="n">marshallable_class</span><span class="o">.</span><span class="n">marshallable</span><span class="p">(</span><span class="n">mail</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="n">list</span> <span class="o">&lt;&lt;</span> <span class="n">mail</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p></p>
<p>A new class <code>Settings</code> is being added for handling default values. Both the code and tests become much simpler. As a bonus, <code>Settings</code> class is later being reused by other classes as well.</p>
<h2>Integration Tests</h2>
<p>A few words about the tools.</p>
<p>I don&#8217;t like cucumber since day one. It is messy with global steps; it claims writing cucumber tests is doing BDD, well, it is not. It is doing integration testing, pure and simple.</p>
<p>Reardless, cucumber is widely used and something better than cuucmber coming out from cucumber, such as sinnach and turnip.</p>
<p>The great thing about cucumber is Gherkin, a great way communicating between Business Analyst (BA) / Product Manager (PM) / QA and developers.</p>
<p>Integration tests are essential to a project: unit testing should cover all the logic within a method, but there is no guarantee that calls between methods will work correctly. We cannot prove the correctness of a program in a reasonable time, but we can increase the chance of its being correctly written by using the integration tests.</p>
<p>When a developer starting on a new feature, he writes a feature with several scenarios (could be written by a BA), which of course won&#8217;t pass. And actively communicate with business people on if this is what they want. Getting some resonable insights on what the feature is about, his task then become clearly defined: implement something to make the feature goes green.</p>
<p>Same for bug fixes, first write a feature that will fail because of the bug in question. Then fix the bug and verify the feature passes. This approach will give developer a clear defined goal. And in the end, the developer can say with confidence: I fixed the bug because now this feature is green. This is also a great way to let the managements have faith in the development team as well.</p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/04/02/coding-standard-part-2/">My Coding Standard for Rails Projects (Part 2)</a></h1>
<p class="meta">
<time datetime="2012-04-02T00:00:00-05:00" pubdate data-updated="true">Apr 2<span>nd</span>, 2012</time>
| <a href="/blog/2012/04/02/coding-standard-part-2/#disqus_thread">Comments</a>
</p>
</header>
<div class="entry-content"><h2>Builders</h2>
<p>In the part 1, the code snippet about the controller has a line</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">user</span> <span class="o">=</span> <span class="no">Builders</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">build</span>
</span></code></pre></td></tr></table></div></figure>
<p>This implies that a <a href="http://en.wikipedia.org/wiki/Builder_pattern">Builder Pattern</a> is used for creating a model, more precisely, creating an <a href="http://domaindrivendesign.org/node/88">&#8220;Aggregate&#8221;</a> in the Domain Driven Design terminology. The return value of a builder should always be the root object of the aggregate. Below is an example of a <code>build</code> method.</p>
<figure class='code'><figcaption><span>User Builder (builder.rb)</span> <a href='/downloads/code/builder.rb'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Builders</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">Builder</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">build</span>
</span><span class='line'> <span class="no">BusinessModel</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">build</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">business_object</span><span class="o">|</span>
</span><span class='line'> <span class="n">business_object</span><span class="o">.</span><span class="n">email_addresses</span> <span class="o">=</span> <span class="o">[</span><span class="no">EmailAddress</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">build</span><span class="o">]</span>
</span><span class='line'> <span class="n">business_object</span><span class="o">.</span><span class="n">phones</span> <span class="o">=</span> <span class="o">[</span><span class="no">Phone</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">build</span><span class="o">]</span>
</span><span class='line'> <span class="n">business_object</span><span class="o">.</span><span class="n">address</span> <span class="o">=</span> <span class="no">Address</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">build</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>A DRY version of a typical builder in the form of an internal DSL could be:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Builders</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span>
</span><span class='line'> <span class="n">build_for</span> <span class="ss">:user</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:has_many_associations</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="ss">:email_addresses</span><span class="p">,</span> <span class="ss">:phones</span><span class="o">]</span><span class="p">,</span>
</span><span class='line'> <span class="ss">:has_one_associations</span> <span class="o">=&gt;</span> <span class="o">[</span><span class="ss">:address</span><span class="o">]</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>A lof of Rails projects I have seen have building <code>email_addresses</code> and <code>phones</code> logic in the <code>UsersController</code>, which then becomes hard to unit test and impossible to reuse.</p>
<p>Another replacement to the builders is using hooks, such as <code>after_create</code>. This makes your code highly depends on a specific ORM implementation, making the one line <code>user.create!</code> becomes hard to understand, and slow the unit tests.</p>
<p>The User BusinessModel should be responsible building a <code>user</code> and only it. Below is a possible implementation:</p>
<figure class='code'><figcaption><span>BusinessModel Builder (business_model_builder.rb)</span> <a href='/downloads/code/business_model_builder.rb'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">BusinessModel</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span>
</span><span class='line'> <span class="k">class</span> <span class="o">&lt;&lt;</span> <span class="nb">self</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">build</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'> <span class="nb">self</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">valid_params</span><span class="p">(</span><span class="n">params</span><span class="p">))</span><span class="o">.</span><span class="n">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">object</span><span class="o">|</span>
</span><span class='line'> <span class="k">raise</span> <span class="no">ObjectInvalidError</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">object</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span> <span class="k">unless</span> <span class="n">object</span><span class="o">.</span><span class="n">valid?</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="kp">private</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">valid_params</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'> <span class="o">[</span><span class="ss">:id</span><span class="p">,</span> <span class="ss">:first_name</span><span class="p">,</span> <span class="ss">:last_name</span><span class="o">].</span><span class="n">inject</span><span class="p">({})</span> <span class="k">do</span> <span class="o">|</span><span class="n">attributes</span><span class="p">,</span> <span class="n">key</span><span class="o">|</span>
</span><span class='line'> <span class="n">attributes</span><span class="o">.</span><span class="n">merge!</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="n">key</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>This, as usual, can be abstracted into a DSL:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">BusinessModel</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span>
</span><span class='line'> <span class="k">class</span> <span class="o">&lt;&lt;</span> <span class="nb">self</span>
</span><span class='line'> <span class="kp">private</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">valid_params</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="n">have_builder_method</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h2>Business Models</h2>
<p>A business model, in Domain Driven Design term, is a <a href="http://domaindrivendesign.org/node/109">Entity</a>. A business model should be persisted, but the model itself knows nothing about how itself being persisted, it delegates such a task to its persistence class.</p>
<p>A business model, contains attributes and business-related calculations based on these atrributes.</p>
<p>A business model also contains the validations that can be called by <code>user.valid?</code></p>
<h2>Persistence Classes</h2>
<p>In the controller code in the part 1:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="no">Persistence</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span><span class="o">.</span><span class="n">persist</span>
</span></code></pre></td></tr></table></div></figure>
<p>A Persistence class takes the business model object as its only parameter in its constructor and the persists the object. The Persistence object knows to how to map a model object&#8217;s attributes into database columns, for example. An example of such a method could be like this:</p>
<figure class='code'><figcaption><span>Uer Persistence Class (persistence_create.rb)</span> <a href='/downloads/code/persistence_create.rb'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Persistence</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">persist</span>
</span><span class='line'> <span class="no">ActiveRecordStore</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">business_object</span><span class="p">)</span><span class="o">.</span><span class="n">save</span>
</span><span class='line'> <span class="c1">#save part of attributes to redis</span>
</span><span class='line'> <span class="no">RedisStore</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">business_object</span><span class="p">)</span><span class="o">.</span><span class="n">save</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>Buidling a business model from the persistence layer might look like this:</p>
<figure class='code'><figcaption><span>Uer Persistence Class (persistence_load.rb)</span> <a href='/downloads/code/persistence_load.rb'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Persistence</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">load</span>
</span><span class='line'> <span class="n">user</span> <span class="o">=</span> <span class="no">ActiveRecordStore</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">business_object</span><span class="p">)</span><span class="o">.</span><span class="n">load</span>
</span><span class='line'> <span class="no">RedisStore</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span><span class="o">.</span><span class="n">load</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>The <code>ActiveRecordStore::User</code> in the code could be smart enough to load a user based on what attributes in the <code>business_object</code>. For example:</p>
<figure class='code'><figcaption><span>ActiveRecordStore example (active_record_store_load.rb)</span> <a href='/downloads/code/active_record_store_load.rb'>download</a></figcaption>
<div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">ActiveRecordStore</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">Store</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">load</span>
</span><span class='line'> <span class="n">non_empty_attributes</span> <span class="o">=</span> <span class="no">HashHelper</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">physical_attributes</span><span class="p">)</span><span class="o">.</span><span class="n">non_blanks</span>
</span><span class='line'> <span class="no">Physical</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">all</span><span class="p">(</span><span class="n">non_empty_attributes</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>The code bears some explainations: <code>physical_attributes</code> is a method to transform the business model object attributes into the table columns. This method is used by both <code>save</code> and <code>load</code>. The <code>Physical::User</code> is a child of <code>ActiveRecord::Base</code> that talks to the database directly.</p>
<p>Some custom methods might be needed, such as <code>find_by_email_address</code>. These kind of finders, though, can be easily standardized.</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">generate_has_many_association_finders</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">:association_name</span> <span class="o">=&gt;</span> <span class="ss">:email_addresses</span>
</span></code></pre></td></tr></table></div></figure>
<h2>DSLs</h2>
<p>All the above examples can often be DRYed up by some internal DSLs. But I feel that I must say that these DSLs should not be overused.</p>
<p>A sympton of overuse of DSL (and thus over abstract the logic) is that the DSL allows too much options. When you find out you have to handle more than 2 slightly different situations in one DSL implementation method, it is time to seperate the situations into 2 or more slightly different DSL macros. And of course these DSL macros implementations can share a large portation of logic by abstract the common code out.</p>
</div>
</article>
<article>
<header>
<h1 class="entry-title"><a href="/blog/2012/04/01/coding-standard-part-1/">My Coding Standard for Rails Projects (Part 1)</a></h1>
<p class="meta">
<time datetime="2012-04-01T00:00:00-05:00" pubdate data-updated="true">Apr 1<span>st</span>, 2012</time>
| <a href="/blog/2012/04/01/coding-standard-part-1/#disqus_thread">Comments</a>
</p>
</header>
<div class="entry-content"><p>The purpose of this post is to discuss what is I think good when coding a Rails project. Some of thoughts incorporate the internal communications with my collogues <a href="https://github.com/azimux">Miles Georgi</a> and <a href="https://github.com/jeshuaborges">Jeshua Borges</a>. To publicize my thoughts as a public blog port, I hope I could get more feedbacks and improve upon the comments</p>
<h2>Layers</h2>
<p>The Rails framework is a layered architecture, and when an application becomes significantly more complicated, the default layers of Rails are not enough. I would like to discuss the layers I want to see to go into a Rails application. Next I will discuss these layers one by one</p>
<h2>Thin controllers</h2>
<p>Everybody talks about thin controllers, yet with all the trams I have worked with, the controllers never be thin. Why not? I think the answer is that people never really know where these extra yet necessary code should be put into if not in a controller. I will try to explain how I want to avoid any extra code put into the controller. In my view, the only tasks belong to a controller are:</p>
<ul>
<li>Authentications</li>
<li>Authorizations</li>
<li>Delegate the tasks to other layers</li>
<li>Setup objects for page rendering</li>
</ul>
<p>Putting anything more than the above tasks is considered to be too much by my standard.</p>
<p>A typical controller <code>create</code>, <code>show</code> ad <code>index</code> actions may look like this:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">UsersController</span>
</span><span class='line'> <span class="k">def</span> <span class="nf">create</span>
</span><span class='line'> <span class="n">user</span> <span class="o">=</span> <span class="no">Builders</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">params</span><span class="p">)</span><span class="o">.</span><span class="n">build</span>
</span><span class='line'> <span class="no">Persistence</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span><span class="o">.</span><span class="n">persist</span>
</span><span class='line'> <span class="n">respond_with</span> <span class="no">Presenters</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nf">show</span>
</span><span class='line'> <span class="n">user</span> <span class="o">=</span> <span class="no">Finders</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">find</span><span class="p">(</span><span class="n">params</span><span class="o">[</span><span class="ss">:id</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="n">respond_with</span> <span class="no">Presenters</span><span class="o">::</span><span class="no">User</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">user</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nf">index</span>
</span><span class='line'> <span class="n">users</span> <span class="o">=</span> <span class="no">Finders</span><span class="o">::</span><span class="no">Users</span><span class="o">.</span><span class="n">all</span><span class="p">(</span><span class="n">params</span><span class="p">)</span>
</span><span class='line'> <span class="n">respond_with</span> <span class="no">Presenters</span><span class="o">::</span><span class="no">MinimalUserList</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">users</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>You may see, if several models use the same pattern as described above, we can DRY it up using some nice little DSL:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">UsersController</span>
</span><span class='line'> <span class="n">create_action</span> <span class="ss">:user</span>
</span><span class='line'> <span class="n">show_action</span> <span class="ss">:user</span>
</span><span class='line'> <span class="n">index_action</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">:with_presenter</span> <span class="o">=&gt;</span> <span class="no">Presenters</span><span class="o">::</span><span class="no">MinimalUserList</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>Even better, the specs can be as simple as:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'> <span class="n">desceribe</span> <span class="no">UsersController</span> <span class="k">do</span>
</span><span class='line'> <span class="n">include_examples</span> <span class="s2">&quot;standard create action&quot;</span><span class="p">,</span> <span class="ss">:model_name</span> <span class="o">=&gt;</span> <span class="ss">:user</span>
</span><span class='line'> <span class="n">include_examples</span> <span class="s2">&quot;standard show action&quot;</span><span class="p">,</span> <span class="ss">:model_name</span> <span class="o">=&gt;</span> <span class="ss">:user</span>
</span><span class='line'> <span class="n">include_examples</span> <span class="s2">&quot;standard index action&quot;</span><span class="p">,</span> <span class="ss">:model_name</span> <span class="o">=&gt;</span> <span class="ss">:user</span><span class="p">,</span> <span class="ss">:with_presenter</span> <span class="o">=&gt;</span> <span class="no">Presenters</span><span class="o">::</span><span class="no">MinimalUserList</span>
</span><span class='line'> <span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>You could always choose not to use these default actions generators, however, it will be more coding and probably less readable code as the result.</p>
<h2>Views and Presenters</h2>
<p>Let&#8217;s face it: the views will always have logic for any given complicated enough sites. There will always be ifs and elses in the view templates. We cannot avoid them.</p>
<p>But by using the Presenter pattern, we can greatly make view much less complicated. Let&#8217;s see an example (I use HAML):</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='haml'><span class='line'><span class="p">-</span> <span class="n">image_name</span> <span class="o">=</span> <span class="vi">@user</span><span class="o">.</span><span class="n">confirmed?</span> <span class="s2">&quot;confirmed.png&quot;</span> <span class="p">:</span> <span class="s2">&quot;unconfirmed.png&quot;</span>
</span><span class='line'><span class="nt">%img</span><span class="p">{</span><span class="ss">:source</span> <span class="o">=&gt;</span> <span class="n">image_name</span><span class="p">,</span> <span class="ss">:alt</span> <span class="o">=&gt;</span> <span class="s2">&quot;confirmed status&quot;</span><span class="p">}</span>
</span><span class='line'>...
</span></code></pre></td></tr></table></div></figure>
<p>The above example already has a condition statement. With a presenter, the view can be changed to:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
</pre></td><td class='code'><pre><code class='haml'><span class='line'><span class="nt">%img</span><span class="p">{</span><span class="ss">:source</span> <span class="o">=&gt;</span> <span class="vi">@user</span><span class="o">.</span><span class="n">confirmed_status_image_name</span><span class="p">,</span> <span class="ss">:alt</span> <span class="o">=&gt;</span> <span class="s2">&quot;confirmed status&quot;</span><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure>
<p>The <code>confirmed_status_image_name</code> method returns the image path will be used. Natually, such a method should not be in a business model class since it concerns the view and only the view. A presenter is the best place to put such logic. The same logic, when in a view, is hard to unit test, but when it is in its own method, it is super simple to write the tests.</p>
<p>A view template should have one and only one instance variable that passed from its associated controller action: a some sort of presenter instance. It should not have anything else. When a view requires some logic, this logic belongs to an instance method of that presenter class.</p>
<p>What about if the controller is rendering a JSON? A presenter can and should help with that. Again, JSON is just another representation of your resource, thus JSON should not be part of your business logic, it should be in a presenter. Some code snippet shows you how simple it could be:</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">module</span> <span class="nn">Presenters</span>
</span><span class='line'> <span class="k">class</span> <span class="nc">User</span> <span class="o">&lt;</span> <span class="no">ObjectForDisplay</span>
</span><span class='line'> <span class="n">to_json_properties</span> <span class="ss">:name_with_first_last_in_front</span><span class="p">,</span> <span class="ss">:email_addresses</span><span class="p">,</span> <span class="ss">:phone</span><span class="p">,</span> <span class="ss">:status</span>
</span><span class='line'> <span class="n">forward_methods</span> <span class="ss">:email_addresses</span><span class="p">,</span> <span class="ss">:status</span><span class="p">,</span> <span class="ss">:phone</span>
</span><span class='line'>
</span><span class='line'> <span class="k">def</span> <span class="nf">name_with_first_last_in_front</span>
</span><span class='line'> <span class="s2">&quot;</span><span class="si">#{</span><span class="n">object</span><span class="o">.</span><span class="n">first_name</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">object</span><span class="o">.</span><span class="n">last_name</span><span class="si">}</span><span class="s2">&quot;</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>The <code>to_json_properties</code> defines a baseline of what attributes will be included in the <code>to_json</code> returns. Each attribute is either forwarded from the business model object, or defined in the presenter class when it apprantely doesn&#8217;t belong to a business model.</p>
</div>
</article>
<div class="pagination">
<a href="/blog/archives">Blog Archives</a>
</div>
</div>
<aside class="sidebar">
<section>
<h1>Recent Posts</h1>
<ul id="recent_posts">
<li class="post">
<a href="/blog/2012/04/18/100-percent-test-coverage-is-the-starting-point/">100% test coverage is the starting point</a>
</li>
<li class="post">
<a href="/blog/2012/04/05/coding-standard-part-3/">My coding standard for Rails projects (part 3)</a>
</li>
<li class="post">
<a href="/blog/2012/04/02/coding-standard-part-2/">My coding standard for Rails projects (part 2)</a>
</li>
<li class="post">
<a href="/blog/2012/04/01/coding-standard-part-1/">My coding standard for Rails projects (part 1)</a>
</li>
</ul>
</section>
<section>
<h1>GitHub Repos</h1>
<ul id="gh_repos">
<li class="loading">Status updating&#8230;</li>
</ul>
<a href="https://github.com/ywen">@ywen</a> on GitHub
<script type="text/javascript">
$.domReady(function(){
if (!window.jXHR){
var jxhr = document.createElement('script');
jxhr.type = 'text/javascript';
jxhr.src = '/javascripts/libs/jXHR.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(jxhr, s);
}
github.showRepos({
user: 'ywen',
count: 0,
skip_forks: true,
target: '#gh_repos'
});
});
</script>
<script src="/javascripts/github.js" type="text/javascript"> </script>
</section>
<section>
<h1>Latest Tweets</h1>
<ul id="tweets">
<li class="loading">Status updating&#8230;</li>
</ul>
<script type="text/javascript">
$.domReady(function(){
getTwitterFeed("hayafirst", 4, false);
});
</script>
<script src="/javascripts/twitter.js" type="text/javascript"> </script>
<a href="http://twitter.com/hayafirst" class="twitter-follow-button" data-show-count="false">Follow @hayafirst</a>
</section>
<section class="googleplus">
<h1>
<a href="https://plus.google.com/ywen.github?rel=author">
<img src="http://www.google.com/images/icons/ui/gprofile_button-32.png" width="32" height="32">
Google+
</a>
</h1>
</section>
</aside>
</div>
</div>
<footer role="contentinfo"><p>
Copyright &copy; 2012 - Yi Wen -
<span class="credit">Powered by <a href="http://octopress.org">Octopress</a></span>
</p>
</footer>
<script type="text/javascript">
var disqus_shortname = 'ywen';
var disqus_script = 'count.js';
(function () {
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
}());
</script>
<script type="text/javascript">
(function(){
var twitterWidgets = document.createElement('script');
twitterWidgets.type = 'text/javascript';
twitterWidgets.async = true;
twitterWidgets.src = 'http://platform.twitter.com/widgets.js';
document.getElementsByTagName('head')[0].appendChild(twitterWidgets);
})();
</script>
</body>
</html>
Jump to Line
Something went wrong with that request. Please try again.