<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Late to the Party: Keep it Simple, Stupid</title>
    <link>http://cwilliams.textdriven.com/articles/2005/07/05/keep-it-simple-stupid</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Ruby. Rails. Stuff.</description>
    <item>
      <title>Keep it Simple, Stupid</title>
      <description>&lt;p&gt;At my job, I program in Java nearly 100% of the time. It was only recently that I began my own project where I use Ruby on Rails &amp;ndash; the original project that I was hired to work on, and that I still help develop, is written fully in Java.&lt;/p&gt;
&lt;p&gt;The Ruby on Rails project loads the underlying data into the database by performing a number of transforms on data in another corporate DB that I have no control over. I normalize the data and make it compatible with ActiveRecord.&lt;/p&gt;
&lt;p&gt;I created small programs in Java to do the transformations initially, purely because to me &lt;a href="http://encyclopedia.laborlawtalk.com/Golden_hammer"&gt;everything still looks like a nail&lt;/a&gt;. After some time I also did the transforms in Ruby. Here&amp;rsquo;s a simple example of&amp;nbsp;my continuing education in The Ruby Way, or essentially how dumb I can be when I write Ruby code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.martinfowler.com/ap2/range.html"&gt;Ranges&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the transform program I typically will load data from the previous day, but may want to load data over any given range of dates.&amp;nbsp;So I created a simple DateRange class to handle this.&lt;/p&gt;&lt;pre&gt;public class DateRange {
  private Date start;
  private Date end;

  public DateRange(Date start, Date end) {
    this.start = start;
    this.end = end;
    // omitting the comparsions to make sure start is really the earlier date
  }
  
  public boolean contains(Date check) {
    return (check.after(start) || check.equals(start)) 
      &amp;amp;&amp;amp; (check.before(end) || check.equals(end));
  }
}
&lt;/pre&gt;
&lt;p&gt;This code works all right, but it can get ugly to try and specify Dates quickly. So I added more methods to the class, such as:&lt;/p&gt;&lt;pre&gt;public static Date date(int month, int day, int year)) {
  Calendar cal = Calendar.getInstance();
  cal.set(Calendar.YEAR, year - 1900);  // since Java Calendar years start at 1900
  cal.set(Calendar.DAY_OF_MONTH, day);
  cal.set(Calendar.MONTH, month - 1); // Since Java months are zero-based
  cal.set(Calendar.HOUR, 0);
  cal.set(Calendar.MINUTE, 0);
  cal.set(Calendar.SECOND, 0);
  cal.set(Calendar.MILLISECOND, 0);
  return cal.getTime();
}
&lt;/pre&gt;
&lt;p&gt;I&amp;rsquo;ll spare you the numerous static methods I created to help myself out. Beyond being so verbose, the Java version irks me because I&amp;rsquo;m adding static methods to a DateRange class to create Date objects easier. The&amp;nbsp;Date class should be doing that&amp;hellip;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ruby&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In Ruby, I was &amp;lsquo;tainted&amp;rsquo; by the Java implementation. I started work on my Ruby DateRange&amp;hellip;&lt;/p&gt;
&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;DateRange&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="attribute"&gt;@start&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="attribute"&gt;@end&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;
     &lt;span class="comment"&gt;# omitting the comparisons to make sure start is really the earlier date&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;contains?&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;date&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;date&lt;/span&gt; &lt;span class="punct"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="attribute"&gt;@start&lt;/span&gt; &lt;span class="keyword"&gt;or&lt;/span&gt; &lt;span class="ident"&gt;date&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="attribute"&gt;@end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The seasoned Ruby programmers can all snicker now. Here&amp;rsquo;s how I used it:&lt;/p&gt;
&lt;pre&gt;
&lt;span class="ident"&gt;range&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;DateRange&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;local&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2005&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;local&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;2005&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;I quickly realized I couldn&amp;rsquo;t easily iterate over the range. I needed to mixin &lt;strong&gt;Enumerable&lt;/strong&gt; and implement an &lt;strong&gt;each&lt;/strong&gt; method!&lt;/p&gt; 

&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;DateRange&lt;/span&gt;
  &lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;Enumerable&lt;/span&gt;
  &lt;span class="comment"&gt;# ...&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;each&lt;/span&gt;
    &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@start&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="attribute"&gt;@end&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;date&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="keyword"&gt;yield&lt;/span&gt; &lt;span class="ident"&gt;date&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="comment"&gt;# ...&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;If full-out laughter has not erupted yet, you must not program in Ruby.&amp;nbsp;I was very proud of this code for a while, and the transform programs were finished quickly.&lt;/p&gt;
&lt;p&gt;About a month later I returned to edit the transforms and create some new ones. I looked at the code and thought something just wasn&amp;rsquo;t right. Duh! &lt;em&gt;Ranges are embedded in Ruby! I never needed to create my own class.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I quickly refactored all of my code to look like:&lt;/p&gt;
&lt;pre&gt;&lt;span class="ident"&gt;range&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;local&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;2005&lt;/span&gt;&lt;span class="punct"&gt;)..&lt;/span&gt;&lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;local&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;2005&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Problem solved, right? &lt;strong&gt;Wrong&lt;/strong&gt;. I broke the &lt;strong&gt;each&lt;/strong&gt; method. Time returns the next millisecond for &lt;strong&gt;succ&lt;/strong&gt;, so when &lt;strong&gt;each&lt;/strong&gt; tries to iterate over the range, it will bring up the next millisecond &amp;ndash; I want the next day.&lt;/p&gt;
&lt;p&gt;My next brilliant solution:&lt;/p&gt;
&lt;pre&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Time&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;succ&lt;/span&gt;
    &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;at&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;24&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt; &lt;span class="number"&gt;60&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt; &lt;span class="number"&gt;60&lt;/span&gt;&lt;span class="punct"&gt;))&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;I redefined the succ method to return 24 hours later. So why is this wrong? Because in Ruby there are the classes &lt;strong&gt;Time&lt;/strong&gt;, &lt;strong&gt;Date&lt;/strong&gt; and &lt;strong&gt;DateTime&lt;/strong&gt; - each for different reasons. What I wanted all along was a range of &lt;strong&gt;Date&lt;/strong&gt; objects, not &lt;strong&gt;Time&lt;/strong&gt; objects &amp;ndash; thats why I named the first class DateRange to begin with.&lt;/p&gt;
&lt;p&gt;So our next try:&lt;/p&gt;
&lt;pre&gt;&lt;span class="ident"&gt;range&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Date&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;civil&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2005&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)..&lt;/span&gt;&lt;span class="constant"&gt;Date&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;civil&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;2005&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;And we&amp;rsquo;re working again. Date defines &lt;strong&gt;succ&lt;/strong&gt; to return the next day, we never had to create any extra code to handle our date ranges, and we&amp;rsquo;ve learned a number of very wring ways to solve the problem.&lt;/p&gt;</description>
      <pubDate>Tue, 05 Jul 2005 22:16:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:24c11d3260e8df8d8bea306452e77c23</guid>
      <author>cwilliams</author>
      <link>http://cwilliams.textdriven.com/articles/2005/07/05/keep-it-simple-stupid</link>
      <category>Ruby</category>
      <category>Personal</category>
      <category>Programming</category>
    </item>
  </channel>
</rss>
