<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Continuous Thinking</title>
 <link href="http://www.continuousthinking.com/atom.xml" rel="self"/>
 <link href="http://www.continuousthinking.com/"/>
 <updated>2012-02-04T14:45:40-05:00</updated>
 <id>http://www.continuousthinking.com/</id>
 <author>
   <name>Zach Dennis</name>
   <email>zach.dennis@gmail.com</email>
 </author>

 
 <entry>
   <title>The Fallacy Of Fast, Putting Test Execution Speed In Its Place</title>
   <link href="http://www.continuousthinking.com/2012/02/04/the-fallacy-of-testing-putting-test-execution-speed-in-its-place.html"/>
   <updated>2012-02-04T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2012/02/04/the-fallacy-of-testing-putting-test-execution-speed-in-its-place</id>
   <content type="html">&lt;p&gt;A colleague recently sent over a link to Corey Haines video on &lt;a href='http://confreaks.com/videos/641-gogaruco2011-fast-rails-tests'&gt;Fast Rails Tests&lt;/a&gt; from GoGaRuCo 2011. From watching this it got me thinking about fast tests and a common misconception that people have. For the record, Corey is not one of those people, but his talk got me thinking about this topic.&lt;/p&gt;

&lt;h2 id='the_problem'&gt;The Problem&lt;/h2&gt;

&lt;p&gt;People are becoming obsessed with execution speed, almost entirely. They&amp;#8217;ve got umpteen thousand tests that execute in 2 seconds. On the surface this is awesome! Unfortunately, this can be a false achievement (but not always) that their tests test a whole lot of nothing and end up being quite brittle. Mocking is used, but inappropriately and way too much. The tests end up being incredibly fast but not very valuable.&lt;/p&gt;

&lt;h3 id='speed_kills'&gt;Speed Kills&lt;/h3&gt;

&lt;p&gt;I&amp;#8217;ve gone through my own &lt;a href='http://www.youtube.com/watch?v=hb5QaCfm7bg'&gt;Michael Angelo Batio&lt;/a&gt; phase in the past I&amp;#8217;m not simply speculating. I&amp;#8217;ve been in those trenches, I&amp;#8217;ve experienced it, I&amp;#8217;ve done it, and I&amp;#8217;ve seen others succumb as well. Faster tests are better; they will be executed more frequently; they will provide faster feedback loops; they will be the cause of less idle time for the developers who sit and wait for the test suite to finish running. But fast is not the primary goal. It is merely one of the forces at play that we as developers must figure out how to resolve.&lt;/p&gt;

&lt;h2 id='goals_of_testing'&gt;Goals of Testing&lt;/h2&gt;

&lt;p&gt;The primary goal for tests is to help continually drive the development of software over time. The broadness of this statement is intentional because there are many things at play which impact our ability to reach this goal. Things like: behavior validation, reliability, readability, frequency of execution, design/testability, etc.&lt;/p&gt;

&lt;h3 id='behavior_validation'&gt;Behavior Validation&lt;/h3&gt;

&lt;p&gt;Of these the most important thing is behavior validation. Without it the others don&amp;#8217;t matter: they are pointless. If you have 100,000 examples that run in 5 seconds, but they&amp;#8217;re not testing actual behavior of the components than you are providing nothing but empty statistics. Behavior validation is not about speed, it&amp;#8217;s about behavior.&lt;/p&gt;

&lt;p&gt;Greenhorns have slow, ugly, poorly designed tests. Those who have more experience and are better at testing will see a million ways to improve these tests. It&amp;#8217;s tempting to simply throw at them all of the other things they &lt;em&gt;should&lt;/em&gt; be doing, but all in good time. First and foremost, we need to make sure we all have this basic principle of testing under our belt. Otherwise, we&amp;#8217;ll be putting the cart before the horse so-to-speak.&lt;/p&gt;

&lt;h3 id='reliability'&gt;Reliability&lt;/h3&gt;

&lt;p&gt;Reliability is the next important. It may seem like a given but in many cases it is not and it often has to be learned through hard-ship and experience from people new to testing. Tests need to execute reliably all of the time. For unit level tests and examples this is the easiest because there are the fewest things at work in the test. For higher level (functional, integration, etc) this gets trickier because there are more things at play and which need to be considered.&lt;/p&gt;

&lt;h4 id='test_order_independence'&gt;Test Order Independence&lt;/h4&gt;

&lt;p&gt;There are multiple ways to look at reliability. One way is to run your test suite in backwards or random order (RSpec supports this). This will find tests which have dependencies on the order in which other the tests are run. Tests should reliably and consistently pass regardless of the order you run them in.&lt;/p&gt;

&lt;h4 id='component_independence_isolating_system_under_test'&gt;Component Independence (Isolating System Under Test)&lt;/h4&gt;

&lt;p&gt;Another way to consider reliability is thinking about it in terms of unexpected dependencies. For example, if we are testing something simple, like, the requirement that a User has a name, then when we change the Account, our test for that User validation should not fail. There are a number of cases where unexpected changes in other parts of the system impact our test. In some cases, this shows we have bugs, in other cases, it shows that our tests are not reliable because they are being impacted by things that have nothing to do with the behavior the test focuses on.&lt;/p&gt;

&lt;p&gt;Reliability is so basic, yet it is often misunderstood. The less reliable the tests are the harder it is to trust them and have confidence in your system and continue to evolve the system swiftly. Unreliable tests put the tests themselves in question.&lt;/p&gt;

&lt;h3 id='readability'&gt;Readability&lt;/h3&gt;

&lt;p&gt;Readability is next down the list. As much as it pains me to make this third, I think it is the proper place for it. Being able to understand and have others understand your tests is hugely important. I have seen countless tests which test many things (some indirectly) and it is hard to determine what exactly they&amp;#8217;re testing. Readability goes a long way to ensuring that the code can evolve, change, and maintain with much greater ease; irregardless of if its you or someone else doing the changes.&lt;/p&gt;

&lt;p&gt;However, you can extract out readable tests from those that lack readability but still test actual behavior of the system and its components. It may be tedious and take longer, but it can be done. A good place to start here is to focus your tests around a single behavior of a component in the system and to strive to &lt;a href='http://techblog.daveastels.com/2006/08/27/one-expectation-per-example-a-remake-of-one-assertion-per-test/'&gt;achieve one assertion per test&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id='frequency_of_execution'&gt;Frequency of Execution&lt;/h3&gt;

&lt;p&gt;Here are we now: frequency of execution. This is where having fast tests become important. The faster they are the more they get executed. The more they get executed the quicker the feedback loop is which directly impacts all of the above things. But without the above things (except maybe for design) speed doesn&amp;#8217;t matter: you just feel good about seeing more dots on the screen.&lt;/p&gt;

&lt;p&gt;Having 100,000 tests pass in 5 seconds doesn&amp;#8217;t mean you have 100,00 meaningful tests (although you may). People who get bit by the speed bug early on fall into the trap of over-mocking. They end up testing the mock library in various ways but don&amp;#8217;t actually test their software. It&amp;#8217;s a rather interesting phenomenon: we are providing countless creative ways to ensure mocking libraries in many application domains. This results in a meth-like high, feeling great about the number of examples, and speed of execution. At some point, the high ends.&lt;/p&gt;

&lt;p&gt;But there are simple things you can do to increase execution speed without sacrificing value while you are learning how to best utilize things like mocking libraries. And Corey offers a great tip in his video: spec_no_rails/. Have a folder which doesn&amp;#8217;t boot up the entire framework, but has tests for things that don&amp;#8217;t actually depend on the framework being loaded.&lt;/p&gt;

&lt;p&gt;Designing for testability, which is up next, is also a great way for increasing the speed of tests because you&amp;#8217;ll be able to separate out the behavior into their rightful places and test them largely independent from one another.&lt;/p&gt;

&lt;p&gt;Some other things that impact test execution speed is the language or framework itself. For example, Ruby 1.9.3 is much faster at loading and executing code than any earlier versions. And Rails 3.2 has a number of performance enhancements.&lt;/p&gt;

&lt;h3 id='design_testability'&gt;Design, Testability&lt;/h3&gt;

&lt;p&gt;Lastly (for this list at least), as we grow and become better at the above four we will begin to find ourselves exploring new ways of using tests to help drive and shape the design of our code. This often means we get better at applying better design practices in our code like Single Responsibility, Loose Coupling, etc.&lt;/p&gt;

&lt;p&gt;Whether we test drive or test after we begin to use our experiences and newfound abilities to shape the design of your software so the behavior can be tested, reliably, and in a readable manner. This means that tests become a heavy influence on your design. Your code becomes testable. And before you know it you&amp;#8217;ll be telling people you design for &lt;a href='http://loosecouplings.blogspot.com/2011/01/relationship-between-testability-and.html'&gt;testability&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='the_balance'&gt;The Balance&lt;/h2&gt;

&lt;p&gt;In terms of balancing, we should err on the side of having good reliable tests first. It is more valuable to have a good reliable but slow test opposed to a fast, meaningless test. We can always come back to the slow test and find ways of improving its execution speed, but that should come after we are sure it&amp;#8217;s doing its job (testing behavior) and doing it consistently (reliably).&lt;/p&gt;

&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Speed of execution is important but its importance is relative to the other properties at play. And all of the properties impact one another, but they are not all equally important. As we grow in all of these areas we are able to explore more advanced ways of achieving all of these. But speed must come after the ones before it are working to the advantage of our ability to ensure that our software is working. Otherwise, we may end up we good conference conversation and not much else.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;There are other important things related to testing that were left out of this post. And the above areas could all have been taken to much greater depths. This post was a quick attempt to raise to the surface an issue I see with inexperienced testers latching onto things like fast tests without first understanding writing a good reliable test.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Language impacts our ability to create</title>
   <link href="http://www.continuousthinking.com/2012/01/29/language-impacts-our-ability-to-create.html"/>
   <updated>2012-01-29T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2012/01/29/language-impacts-our-ability-to-create</id>
   <content type="html">&lt;p&gt;Christopher Alexander, from his infamous book The Timeless Way of Building:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If your language is empty, your buildings cannot be full. If your language is poor, you cannot make good buildings until you enrich your language. If your language is rigid, your buildings must be rigid. If your language is florid, your buildings will be florid. Your language generates the buildings you make, and the buildings live or not, according to the life your language has.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Replace &lt;em&gt;buildings&lt;/em&gt; with &lt;em&gt;software&lt;/em&gt; and what Alexander says still holds true. The breadth and depth of our language directly impacts our ability to craft, at every level, software.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>rspec-requestable-examples</title>
   <link href="http://www.continuousthinking.com/2012/01/28/rspec-requestable-examples.html"/>
   <updated>2012-01-28T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2012/01/28/rspec-requestable-examples</id>
   <content type="html">&lt;p&gt;Recently, while refactoring legacy code in a system, we found core domain rules that were not being clearly expressed in the application, neither in the code nor the end user. As a result, the burden of knowing all of the rules was pushed onto the user, and when the system did enforce a rule, it would likely just break for the user, not help the user move forward. Unfortunately, this &amp;#8220;legacy&amp;#8221; code was legacy because there was no test coverage for these rules; their logic was cryptically spread throughout the code of the application in a few really large classes which mixed far too many responsibilities and abstractions.&lt;/p&gt;

&lt;p&gt;We decided to catalog all of the rules first through exploratory testing and inquiry with our client, users, and other developers. We found several simple rules like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;splits words on new lines&lt;/li&gt;

&lt;li&gt;strips leading and trailing white-space&lt;/li&gt;

&lt;li&gt;strips leading and trailing periods&lt;/li&gt;

&lt;li&gt;strips double quotes&lt;/li&gt;

&lt;li&gt;strips single quotes&lt;/li&gt;

&lt;li&gt;strips empty lines&lt;/li&gt;

&lt;li&gt;strips line filled only with white-space&lt;/li&gt;

&lt;li&gt;replaces any white-space character in the middle of a term w/a single space&lt;/li&gt;

&lt;li&gt;removes duplicate words&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There were many more rules just like these (30 to be exact). None of them by themselves were very complex, but many of them were used in combination to make certain types of word lists. These rules were what we wanted to capture in good unit-level tests around the different types of word lists.&lt;/p&gt;

&lt;p&gt;While writing these tests (specs) we found an interesting property of our rules. They wanted to break out of stock functionality provided by &lt;a href='http://github.com/rspec/rspec'&gt;RSpec&lt;/a&gt;. This led us to create a new RSpec extension which proved valuable to us and may prove valuable to you. Here&amp;#8217;s a quick walk through of our experience and what led us to creating a new extension. It starts with writing specs around these rules, and the word lists that would use them.&lt;/p&gt;

&lt;h2 id='the_first_word_list'&gt;The First Word List&lt;/h2&gt;

&lt;p&gt;The first word list was pretty straightforward. We wrote an initial spec (using RSpec) to cover the rules:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;FirstWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;#list_of_words=&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;

    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sx'&gt;%w(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;)&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sx'&gt;%w(foo bar)&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    
    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips single quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sx'&gt;%w(&amp;#39;foo&amp;#39; &amp;#39;bar&amp;#39;)&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sx'&gt;%w(foo bar)&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    
    &lt;span class='c1'&gt;# ... etc more rules ...&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Using RSpec as-is worked well until we hit the second word list.&lt;/p&gt;

&lt;h2 id='the_second_word_list'&gt;The Second Word List&lt;/h2&gt;

&lt;p&gt;The second word list was similar to the first, and while some rules overlapped, there were others that did not. For example, single quotes were stripped in the first word list, but they were left as-is in the second list. Initially, our first goal was to clearly express the rules in our spec so we could drive code changes. We duplicated the overlapping examples:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;SecondWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;#list_of_words=&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    
    &lt;span class='c1'&gt;# this was copy and pasted from FirstWordList spec&lt;/span&gt;
    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sx'&gt;%w(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;)&lt;/span&gt;
      &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sx'&gt;%w(foo bar)&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    
    &lt;span class='c1'&gt;# this is a new rule&lt;/span&gt;
    &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;allows &amp;#39;!, ?, @, #, $, %, &amp;amp;, *, -, +, _ :, .&amp;#39; characters&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
      &lt;span class='c1'&gt;# ...&lt;/span&gt;
    &lt;span class='k'&gt;end&lt;/span&gt;
    
    &lt;span class='c1'&gt;# ... more word list rules examples&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='how_can_we_reuse_these_examples'&gt;How Can We Re-Use These Examples?&lt;/h2&gt;

&lt;p&gt;Once we had all of the rules for both of these word lists expressed, we took a step back and asked ourselves: how can we re-use these examples? After all, we still had a third type of word list to add which would also share in overlap with many of the rules.&lt;/p&gt;

&lt;h2 id='rspecs_builtin_it_should_behave_like'&gt;RSpec&amp;#8217;s Builtin: it_should_behave_like&lt;/h2&gt;

&lt;p&gt;RSpec has a built-in utility to re-use groups of examples. It works by first defining a shared set of examples:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;shared_examples_for&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips single quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='c1'&gt;# ...&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  
  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='c1'&gt;# ...&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  
  &lt;span class='n'&gt;it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;allows &amp;#39;!, ?, @, #, $, %, &amp;amp;, *, -, +, _ :, .&amp;#39; characters&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='c1'&gt;# ...&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This lets you include the shared &amp;#8220;a word list&amp;#8221; examples into your concrete-specs, like so:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;FirstWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it_should_behave_like&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;SecondWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it_should_behave_like&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The problem with this is that it assumes you have a collection of examples which always go together. While we often find this feature of RSpec incredibly useful, in our case it falls short of the word list rules. We don&amp;#8217;t want a collection of examples re-usable together as a set; rather, we want a collection of examples in which we can pick and choose which to run.&lt;/p&gt;

&lt;h2 id='a_new_approach_sharing_rspec_examples'&gt;A New Approach Sharing RSpec Examples&lt;/h2&gt;

&lt;p&gt;To solve this problem, we created rspec-requestable-examples, which is an RSpec extension that gives you the ability to defined shared example groups where you can explicitly include which examples to run. We ended up with a new kind of shared example group:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;requestable_examples_for&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;requestable_it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sx'&gt;%w(&amp;quot;foo&amp;quot; &amp;quot;bar&amp;quot;)&lt;/span&gt;
    &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sx'&gt;%w(foo bar)&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
    
  &lt;span class='n'&gt;requestable_it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;strips single quotes&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='sx'&gt;%w(&amp;#39;foo&amp;#39; &amp;#39;bar&amp;#39;)&lt;/span&gt;
    &lt;span class='n'&gt;subject&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;list_of_words&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;should&lt;/span&gt; &lt;span class='n'&gt;eq&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='sx'&gt;%w(foo bar)&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

  &lt;span class='n'&gt;requestable_it&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;allows &amp;#39;!, ?, @, #, $, %, &amp;amp;, *, -, +, _ :, .&amp;#39; characters&amp;quot;&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
    &lt;span class='c1'&gt;# ...&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
  
  &lt;span class='c1'&gt;# ... more rule examples ...&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;In the above code, we created a &lt;em&gt;requestable_example_for&lt;/em&gt; set of example groups. Inside of it we moved all of our individual rule examples from the other specs into here and changed it to &lt;em&gt;requestable_it&lt;/em&gt;. Using &lt;em&gt;requestable_it&lt;/em&gt; is similar to saying it except it makes the example &amp;#8220;requestable&amp;#8221;. You can still use it if you&amp;#8217;d like, but it won&amp;#8217;t be requestable, it will just be a normal example.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s how we explicitly request these new examples from our FirstWordList and SecondWordList specs:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;FirstWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it_should_behave_like&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:examples&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips single quotes&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='c1'&gt;# ...more rules&lt;/span&gt;
  &lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;SecondWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it_should_behave_like&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:examples&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;allows &amp;#39;!, ?, @, #, $, %, &amp;amp;, *, -, +, _ :, .&amp;#39; characters&amp;quot;&lt;/span&gt;
    &lt;span class='c1'&gt;# ...more rules&lt;/span&gt;
  &lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;By pulling out all of the rule examples, we kept them together in a requestable example group. This left the concrete specs to simply specify which rules to run. It could be argued that we could have pulled out only the duplicate rules and created many shared example groups (using shared_examples_for or similar).&lt;/p&gt;

&lt;p&gt;One reason we did not do this was for clarity. We felt that it was more important to keep the rules together in a cohesive unit. After all, they are all types of rules to apply to our word lists. This also afforded us the ability to avoid having some rules defined in shared files and others rules defined in the concrete specs. With rspec-requestable-examples, we have one file with the rules, and each concrete spec simply says which ones to use. We felt this kept the specs very robust, readable, and easy to maintain.&lt;/p&gt;

&lt;h2 id='the_third_and_fourth_word_lists'&gt;The Third and Fourth Word Lists&lt;/h2&gt;

&lt;p&gt;Using the new concept of requestable examples gave us extreme flexibility in introducing a third type of word list:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;ThirdWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it_should_behave_like&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:examples&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips single quotes&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips stop words&amp;quot;&lt;/span&gt;
    &lt;span class='c1'&gt;# ...more rules&lt;/span&gt;
  &lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;While creating the ThirdWordList we found found that there was actually a FourthWordList as well; it was as easy to introduce another combination of rules and express it for a FourthWordList:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='n'&gt;describe&lt;/span&gt; &lt;span class='no'&gt;FourthWordList&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt;
  &lt;span class='n'&gt;it_should_behave_like&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;a word list&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:examples&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips double quotes&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;strips stop words&amp;quot;&lt;/span&gt;
    &lt;span class='s2'&gt;&amp;quot;requires at least one word&amp;quot;&lt;/span&gt;
    &lt;span class='c1'&gt;# ...more rules&lt;/span&gt;
  &lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='experimenting_validating_learning'&gt;Experimenting, Validating, Learning&lt;/h2&gt;

&lt;p&gt;We could have written our specs and moved on, but we thought there was a better way to get more mileage out of our specs. Our initial attempt was really an experiment. Was there another way to share examples that are closely related, but which didn&amp;#8217;t always apply? Would it benefit us to try group the examples that go together &amp;#8211; together?&lt;/p&gt;

&lt;p&gt;We tried to work with RSpec&amp;#8217;s built-in tools, but we wanted to take it one step further, so we explored rspec-requestable-examples. In its initial form, it wasn&amp;#8217;t nearly as clean as it is now, but we wanted to see if the idea was worth the time. It proved valuable for the word list rules and within a few weeks following we found it worked well when we had to refactor the user roles/permission system.&lt;/p&gt;

&lt;p&gt;Since then we&amp;#8217;ve put rspec-requestable-examples up on Github, cleaned up its implementation, added its own Cucumber features, tied into &lt;a href='http://travis-ci.org/mhs/rspec-requestable-examples'&gt;Travis CI&lt;/a&gt;, and released it as a stable and stellar RubyGem: &lt;a href='http://rubygems.org/gems/rspec-requestable-examples'&gt;rspec-requestable-examples&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And while this doesn&amp;#8217;t replace any functionality currently offered in RSpec, it augments what is there to provide another tool to those using it.&lt;/p&gt;

&lt;h2 id='more_info_on_rspecrequestableexamples'&gt;More info on rspec-requestable-examples&lt;/h2&gt;

&lt;p&gt;For general information check out its Github page: &lt;a href='https://github.com/mhs/rspec-requestable-examples'&gt;https://github.com/mhs/rspec-requestable-examples&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For feature requests or issues please report them to its Github issues: &lt;a href='https://github.com/mhs/rspec-requestable-examples/issues'&gt;https://github.com/mhs/rspec-requestable-examples/issues&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This &lt;a href='http://mutuallyhuman.com/blog/2012/01/27/rspec-requestable-examples'&gt;post&lt;/a&gt; was featured on Mutually Human&amp;#8217;s &lt;a href='http://mutuallyhuman.com/blog'&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord-import 0.2.9 for Rails 3.2</title>
   <link href="http://www.continuousthinking.com/2012/01/20/activerecord-import-0-2-9-for-rails-3-2.html"/>
   <updated>2012-01-20T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2012/01/20/activerecord-import-0-2-9-for-rails-3-2</id>
   <content type="html">&lt;p&gt;Following the &lt;a href='https://github.com/zdennis/activerecord-import'&gt;release&lt;/a&gt; of Rails 3.2 today, &lt;a href='https://github.com/zdennis/activerecord-import'&gt;activerecord-import&lt;/a&gt; has published its 0.2.9 gem. It&amp;#8217;s dependencies are now ActiveRecord 3.2 friendly as well as 3.1 and 3.0.&lt;/p&gt;

&lt;p&gt;Included in the 0.2.9 release are the following updates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;make 3.2 dependency friendly (&lt;a href='https://github.com/duckpond'&gt;Samantha Jones&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;internally use ActiveSupport #sum instead of custom #sum_sizes implementation (&lt;a href='https://github.com/Empact'&gt;Ben Woosley&lt;/a&gt;)&lt;/li&gt;

&lt;li&gt;use connection pool instead of actual connect on load which fixes an issue with using activerecord-import on Heroku (&lt;a href='https://github.com/nbudin'&gt;Nat Budin&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have any questions don&amp;#8217;t hesitate to hit me up on twitter, &lt;a href='http://twitter.com/zachdennis'&gt;@zachdennis&lt;/a&gt;, or file a &lt;a href='https://github.com/zdennis/activerecord-import/issues'&gt;github issue&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Integrated Teams: Remote People</title>
   <link href="http://www.continuousthinking.com/2011/12/31/remote-people-are-an-opportunity-for-innovation-and-workplace-evolution.html"/>
   <updated>2011-12-31T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/12/31/remote-people-are-an-opportunity-for-innovation-and-workplace-evolution</id>
   <content type="html">&lt;p&gt;Five years ago, when we started &lt;a href='http://www.mutuallyhuman.com'&gt;Mutually Human&lt;/a&gt;, we shared the belief that colocation was essential to build the type of community and organization that we wanted to work in, be a part of, and invite others to join. My thinking was primarily around the social and relationship aspects of being physically present with one another. If I am going to spend the majority of my life working then I want it to be with people in situations that have the potential to develop deep, lasting, and meaningful relationships. There are people who are capable of cleanly separating their work and personal lives. I&amp;#8217;m just not one of them. For me, it&amp;#8217;s all intertwined.&lt;/p&gt;

&lt;p&gt;The idea of hiring remote has always made me feel somewhat uncomfortable. Given the amount of emphasis placed on relationships it always felt like hiring remote would never work for us, at least not in the long-term. However, this past year has really challenged many of my own assumptions.&lt;/p&gt;

&lt;p&gt;For one, it&amp;#8217;s been hard to see people who I&amp;#8217;d love to work with end up somewhere else. I&amp;#8217;ve also found myself too often asking &amp;#8216;what if?&amp;#8217; instead of &amp;#8216;why not?&amp;#8217;. As it turns out being human has a way of reinforcing the safety and comfort of colocation: thousands of years of social and genetic evolution. It hasn&amp;#8217;t been until the recent advent of technology that being remote, in the ways possible today, has even been possible.&lt;/p&gt;

&lt;p&gt;As social animals we&amp;#8217;re so used to the obvious benefits of colocation: non-verbal gestures, social gatherings, information and cultural osmosis, and hallway chatter among many others. Have you ever had the feeling when you&amp;#8217;re at the white-board with someone and you know its time to stop? Without saying a word, a mutual understanding that you&amp;#8217;ve &amp;#8216;got it&amp;#8217; washes over both of you. That seems rather hard to re-create when you&amp;#8217;re not physically present with one another. There will be no more facial cues or non-verbal gestures; no more going back and forth with the marker expanding on what the other just scribbled or drew.&lt;/p&gt;

&lt;p&gt;Our brains are quite incredible, interpreting and processing complex and intricate social interactions. This extends to environmental and cultural factors as well. Near the end of the day when I sense someone over by the couches I know its time for standup. Or when everyone in the office congregates around two desks when there are six available a sense of community washes over us. It&amp;#8217;s a good feeling when the people prefer the company of each other despite our individual quirks and idiosyncrasies. This all reinforces the type of place we&amp;#8217;ve always wanted Mutually Human to be. I think it&amp;#8217;s also why considering remote workers has never been as easy as looking for non-remote people. We&amp;#8217;re more than simply serving our clients and users, and providing a service. We&amp;#8217;re people who like to be around each other.&lt;/p&gt;

&lt;p&gt;But, this remote worker phenomena isn&amp;#8217;t going to go away. It&amp;#8217;s becoming an integrated component in the workplace. In many organizations and in many ways this is already true. 37Signals is one of many companies that is almost entirely remote (&lt;a href='http://37signals.com/svn/posts/3064-stop-whining-and-start-hiring-remote-workers'&gt;Stop Whining and Start Hiring Remote Workers&lt;/a&gt;); services like Amazon&amp;#8217;s Mechanical Turk make it extremely easy to find remote individuals (different than how this article refers to remote workers) for specific tasks; and my ears are still ringing from a conversation about virtual personal assistants.&lt;/p&gt;

&lt;p&gt;For a while now the trend has been the growing availability of remote workers and the shrinking pool of those willing to relocate. At some point, a balance will be found, but I don&amp;#8217;t think the industry is anywhere near that yet. Of course, it would be ideal if small teams were fully co-located as we&amp;#8217;d be able to take advantage of what social and genetic evolution has outfitted us with. But this isn&amp;#8217;t likely to happen as there are too many variables in play culturally, socially, professionally, etc which will continue to give life to the possibilities and realities of being a remote worker. &lt;em&gt;This is especially true in the world of software services and products.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As always, technology continuously has and will evolve how humans interact and organize to get things done. The discomfort felt around embracing these changes are likely a symptom of something bigger; that our social structure as it pertains to the professional world is evolving. This evolution will cause people to experiment and innovate, finding new and adapted means that can be used to achieved desired ends. This will be true whether these ends are technical/professional (e.g. quality products being built) or social/relational (e.g. strong relationships, healthy company culture).&lt;/p&gt;

&lt;p&gt;Between the completely co-located and the completely remote lies a middle ground; one where two very different working styles co-exist in an often uncomfortable (but natural) tension; one which when looked on in the right light provides the fuel and discomfort necessary to ignite non-traditional thinking related to how we work to evolve just that &amp;#8211; how we work.&lt;/p&gt;

&lt;p&gt;Over the past five years, opinions have changed, both mine and those at Mutually Human. Essentially that bringing remote people into the team is more about finding effective means of working together when we can&amp;#8217;t use the traditional channels of communicating and interacting. It&amp;#8217;s something I look forward to exploring as we continue to grow.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Of Circumstance And Choice</title>
   <link href="http://www.continuousthinking.com/2011/12/31/circumstance-and-choice.html"/>
   <updated>2011-12-31T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/12/31/circumstance-and-choice</id>
   <content type="html">&lt;p&gt;Our circumstances and choices progress in tandem pushing against each other; forever interleaving throughout time is the consciousness of our minds and the environment of our circumstance; perpetually leading to a new circumstance and a new choice. This is to say, that, circumstance can influence our choices as much as our choices can influence our circumstance as they evolve together never in isolation, directing our future, being influenced by our past, but always existing in the present.&lt;/p&gt;

&lt;p&gt;Although, a stronger mind and a steadier heart, tips the scale in the best of ways; in favor of conscious, intentional decisions in which we are fully present; not allowing circumstance to strip us from ourselves in the temporal situations of the day.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>A Day Like Today, A Day At The Office</title>
   <link href="http://www.continuousthinking.com/2011/12/08/a-day-like-today-a-day-at-the-office.html"/>
   <updated>2011-12-08T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/12/08/a-day-like-today-a-day-at-the-office</id>
   <content type="html">&lt;p&gt;Today, I sat down my standing desk, glanced down momentarily at the orange &lt;a href='http://mutuallyhuman.com/movember-giveaway.jpg'&gt;HTML5 sticker&lt;/a&gt; on the closed lid of my Mac Book pro, closed my eyes, and took a deep breath. A moment later I lifted the lid and watched as it awoke from its sleep. So many desktop icons, so many open applications — even the dock is flush from the top to the bottom of the screen. This clutter will have to wait. There’s much to get done.&lt;/p&gt;

&lt;p&gt;First things first, open Chrome, check my personal email which there are a handful; a few being spam; a few more being marketing emails; and a couple having originated from real people. I read and respond to those quickly. My work inbox has about three times more emails. Most are automated notifications from service-based apps I use or am working. Most of these simply informational and can be ignored. I prioritize the rest, respond letting people know I’ll get back to them, and minimize this Chrome window to avoid distraction.&lt;/p&gt;

&lt;p&gt;With emails out of the way I’m ready to fire up Terminal, see what the latest git commits are for the project I’m working on. A quick &amp;#8220;git fetch&amp;#8221; and a &amp;#8221;&lt;a href='https://github.com/mhs/tidbits/blob/master/gitconfig'&gt;git review&lt;/a&gt;&amp;#8221; shows me no new commits to merge in. I can continue on the feature from yesterday from right where I left off; which I find in about two seconds — courtesy of &amp;#8220;git status&amp;#8221; and a convention of putting a giant YOU STOPPED HERE reminder where I left off. A lot of rich client-side JavaScript, HTML, and CSS awaited me. I launch TextMate and embraced it.&lt;/p&gt;

&lt;p&gt;Ten minutes in I notice it’s too quiet. My mind is all over the place, focus eludes me. Six seconds later Pandora and Airfoil are filling the room with rhythm. It hooks into my brain and my brain conforms. All of my thoughts begin to move in concert with one another, a pace is set, my focus narrows in on the problem at hand.&lt;/p&gt;

&lt;p&gt;Two hours later, I’m getting hungry. I stop typing and take a step back to review the code I just wrote. I review it for consistency with itself and with other parts of the application. I notice the usage of &amp;#8220;word-lists&amp;#8221;, and &amp;#8220;sentiment_lists&amp;#8221;. Dasherized or snake-cased? Let’s go dasherized. Next I notice &amp;#8220;includes-exclude-list&amp;#8221; in a similar view. In the previous examples the suffix &amp;#8220;-lists&amp;#8221; was pluralized. In this case the pluralization seems misplaced. I update it to &amp;#8220;include-exclude-lists&amp;#8221; and then do a project-wide search in TextMate and update all of the references from HTML class names to CSS selectors and their usage throughout JavaScript.&lt;/p&gt;

&lt;p&gt;After lunch, it’s back to the code. The conventions we’re using for organizing JavaScript on this project is working nicely. If it wasn’t I would have likely switched to &lt;a href='http://documentcloud.github.com/backbone/'&gt;Backbone.js&lt;/a&gt; or even as far as &lt;a href='http://jashkenas.github.com/coffee-script/'&gt;CoffeeScript&lt;/a&gt;. I would love to move this to CoffeeScript, but we’ve got a good, clean, consistent, and convention-oriented approach to the JavaScript. It’s proving to be flexible, predictable, and easy to change. Someday maybe CoffeeScript will make sense, but today, it won’t solve any problems. It would just have been fun.&lt;/p&gt;

&lt;p&gt;As it nears standup time, which at &lt;a href='http://mutuallyhuman.com'&gt;Mutually Human&lt;/a&gt; is at the end of the day, the feature is finished. After another detailed review of the afternoon’s changes, I discipline myself to make sure I’m being consistent and following conventions. I look over the tests and the scenarios that have been added and decide a few are missing. A few minutes later those are added, so I do a &lt;a href='http://mutuallyhuman.com/blog/2011/01/10/clean-commits'&gt;clean commit&lt;/a&gt; and push.&lt;/p&gt;

&lt;p&gt;After reviewing the next card in which to start tomorrow, I go pick up the guitar and wait for our standup to commence.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Defining a Company</title>
   <link href="http://www.continuousthinking.com/2011/11/19/defining-a-company.html"/>
   <updated>2011-11-19T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/11/19/defining-a-company</id>
   <content type="html">&lt;p&gt;Recently, I found this definition in the book Built To Last by Jim Collins and Jerry Porras:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A group of people get together and exist as an institution that we call a company so that they are able to accomplish something collectively that they could not accomplish separately.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a cornerstone of why Mutually Human exists and should be a foundational tenet of any company worth starting, building, or joining.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>The Beginner's Mind</title>
   <link href="http://www.continuousthinking.com/2011/11/10/the-beginner-s-mind.html"/>
   <updated>2011-11-10T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/11/10/the-beginner-s-mind</id>
   <content type="html">&lt;p&gt;The days before we had formulated opinions, conventions, and tastes; when we gleefully stumbled through unknown obstacles and challenges to garner a little understanding; when we did it whatever way we could because we had no idea what the right way might have been; when &amp;#8220;best practice&amp;#8221; meant whatever we were doing right then because that was the only practice we had; when every victory no matter how small felt monumental.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Personal Reflection: What I Want Out Of Life</title>
   <link href="http://www.continuousthinking.com/2011/11/06/personal-reflection-what-i-want-out-of-life.html"/>
   <updated>2011-11-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/11/06/personal-reflection-what-i-want-out-of-life</id>
   <content type="html">&lt;p&gt;Everyone wants something of life. I want something out of mine. I&amp;#8217;ve always been able to articulate parts of what I want out of life, but there have always been these elusive chunks. I&amp;#8217;d always push them aside and tell myself I&amp;#8217;d get to them later. There were always enough things to keep me busy.&lt;/p&gt;

&lt;p&gt;Busy-ness, as good as it can feel sometimes, is deceptive and distracting. Identifying what you want out of life and why is hard, at least it has been for me. Today, I sat down to write down a list to act as a personal reminder for where I&amp;#8217;m at right now. As I grow as a person these things may change, but until then&amp;#8230;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to spend time with my family, specifically with my nieces and nephews. They bring a joy to my life that I never want to miss out on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to be healthy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to be able to enjoy life and the people I spend it with.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to create the kind of company that is a vessel for promoting a shared vision where a community of people can come together to make the world a better place. Currently, I want to pursue this by bringing better software into the world.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to have strong, honest, worthwhile relationships with my family, friends, co-workers and clients.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to wake up every day and feel that where I am exactly where I&amp;#8217;m supposed to be at this time in my life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to create a company where people feels that it is exactly where they are supposed to be at this time in their life.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to have the type of relationships with that the thought about going anywhere else never crosses their mind.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to create a company that is more of a community than a company.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to help my colleagues grow personally and professionally. I want them to push me to grow personally and professionally.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to become an accomplished teacher through code, writing, speaking, and instructional settings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I never want to stop learning. I never want to lose a passion for knowledge. I want to be a student day in, day out, every day of my life. There is something to be learned from everyone and I want to learn what that might be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to continue to grow in the areas that I have a great interest and passion in, such as software/product development, business, relationships/community, and writing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to spend more time with people I find inspiring, motivating, and uplifting and less with folks who do the opposite.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
&lt;p&gt;I want to be inspiring, motivating, and uplifting to others.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are some things missing from this list which others may find obvious. It&amp;#8217;s not to say I don&amp;#8217;t value other things, but those are not what I want out of life. If I am able to accomplish the above I know those other things will either follow, or they simply won&amp;#8217;t matter.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Git: Tagging commits after the fact</title>
   <link href="http://www.continuousthinking.com/2011/09/27/git--tagging-commits-after-the-fact.html"/>
   <updated>2011-09-27T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/09/27/git--tagging-commits-after-the-fact</id>
   <content type="html">&lt;p&gt;If you ever forget to tag a series of commits with the story id or issue # you can use &lt;em&gt;git filter-branch&lt;/em&gt; to do it for you.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;git filter-branch --msg-filter &lt;span class='se'&gt;\&lt;/span&gt;
  &lt;span class='s1'&gt;&amp;#39;cat &amp;amp;&amp;amp; echo [contributes \#123456]&amp;#39;&lt;/span&gt; &lt;span class='se'&gt;\&lt;/span&gt;
  master..HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The above command tags the commits in my current topic branch (that aren&amp;#8217;t in master) with the story id. This will change the history of the branch so if it&amp;#8217;s been shared or merged think twice before doing this. Note that the escaped hash is intentional as the bash shell will treat everything following an unescaped hash as a comment otherwise.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Mysql2 3.0.x: Waiting for a result...</title>
   <link href="http://www.continuousthinking.com/2011/09/26/mysql2-3-0-x--waiting-for-a-result---.html"/>
   <updated>2011-09-26T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/09/26/mysql2-3-0-x--waiting-for-a-result---</id>
   <content type="html">&lt;p&gt;Upgrading a Rails 3.0.x app to Rails 3.1 uncovered an issue with the mysql2 gem when it comes to running features that rely on an external process like Selenium or Webkit. You can install the &lt;em&gt;activerecord-mysql2-retry-ext&lt;/em&gt; gem to work around it until it gets resolved in mysql2 itself.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem install -r activerecord-mysql2-retry-ext
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The error we got intermittently got with mysql2 and Rails 3.1 was this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;Mysql2::Error: This connection is still waiting &lt;span class='k'&gt;for &lt;/span&gt;a result, try again once you have the result
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Sadly, this &lt;a href='https://github.com/brianmario/mysql2/issues/99'&gt;issue&lt;/a&gt; with the &lt;a href='https://github.com/brianmario/mysql2/'&gt;mysql2&lt;/a&gt; gem has been known about since December 2010. It appears it may have been fixed as the issue was closed on June 17, 2011, but it needs to be re-opened as it is happening again. This issue has also been &lt;a href='https://github.com/thoughtbot/capybara-webkit/issues/154'&gt;reported&lt;/a&gt; against &lt;a href='https://github.com/thoughtbot/capybara-webkit'&gt;capybara-webkit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This issue is with mysql2 version 3.0.7 (if failed with other 3.0.x gems I could get my hands on as well). I tried downgrading to the previous mysql2 gem we had installed, but it is not compatible with ActiveRecord 3.1.0.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;activerecord-mysql2-retry-ext&lt;/em&gt; gem is a quick work around until the actual issue can be fixed in the mysql2 gem. Update your Gemfile:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem &lt;span class='s2'&gt;&amp;quot;activerecord-mysql2-retry-ext&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The work around in the gem retries executed queries up to 5 times if they raise an exception before giving up and re-raising the exception to your code. &lt;em&gt;You do not need to change any of your code, just install the gem.&lt;/em&gt; It has worked great on our project, but YMMV.&lt;/p&gt;

&lt;p&gt;This gem should not be used run in &lt;em&gt;production&lt;/em&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails 3.1 Engine namespaces can creep into URLs in application layout</title>
   <link href="http://www.continuousthinking.com/2011/09/22/rails-3-1-engine-namespaces-can-creep-into-urls-in-application-layout.html"/>
   <updated>2011-09-22T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/09/22/rails-3-1-engine-namespaces-can-creep-into-urls-in-application-layout</id>
   <content type="html">&lt;p&gt;With Rails 3.1 Engines it is possible for the namespace to creep into the URL generation for your application layouts. This can occur if you are not using named routes, but instead are specifying &lt;em&gt;:controller&lt;/em&gt; in a options Hash:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# the following route generated in an application layout&lt;/span&gt;
&lt;span class='n'&gt;link_to&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Foo&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;bar&amp;quot;&lt;/span&gt; 

&lt;span class='c1'&gt;# when rendered from the action of an engine would&lt;/span&gt;
&lt;span class='c1'&gt;# try to generate the route&lt;/span&gt;
&lt;span class='n'&gt;link_to&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Foo&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:controller&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;myengine/foo&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:action&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This issue will manifest itself onto other areas being rendered from the layout that relied on things like Rails &lt;em&gt;current_page?&lt;/em&gt; and &lt;em&gt;url_for&lt;/em&gt; helpers since under the hood they all rely on the same route generation logic.&lt;/p&gt;

&lt;p&gt;To fix this you can replace any non-named routes with named routes:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# routes.rb&lt;/span&gt;
&lt;span class='n'&gt;match&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;/foo&amp;#39;&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;controller#action&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:as&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;foo&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now you can use &lt;em&gt;foo_path&lt;/em&gt; instead of relying on passing around &lt;em&gt;:controller&lt;/em&gt; into any helper that generates a route which is cleaner and preferrable IMO.&lt;/p&gt;

&lt;h3 id='why_does_this_happen'&gt;Why Does This Happen?&lt;/h3&gt;

&lt;p&gt;ActionDispatch::Routing::RouteSet tries to determine if a route is relative and if it is it will try to properly namespace the route based on current controller context. From Rails &lt;em&gt;actionpack/lib/action_dispatch/routing/route_set.rb&lt;/em&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# if the current controller is &amp;quot;foo/bar/baz&amp;quot; and :controller =&amp;gt; &amp;quot;baz/bat&amp;quot;&lt;/span&gt;
&lt;span class='c1'&gt;# is specified, the controller becomes &amp;quot;foo/baz/bat&amp;quot;&lt;/span&gt;
&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;use_relative_controller!&lt;/span&gt;
  &lt;span class='k'&gt;if&lt;/span&gt; &lt;span class='o'&gt;!&lt;/span&gt;&lt;span class='n'&gt;named_route&lt;/span&gt; &lt;span class='o'&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class='n'&gt;different_controller?&lt;/span&gt;
    &lt;span class='n'&gt;old_parts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;current_controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;split&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
    &lt;span class='n'&gt;size&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;controller&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;count&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;
    &lt;span class='n'&gt;parts&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;old_parts&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;.&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;-size&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;controller&lt;/span&gt;
    &lt;span class='vi'&gt;@controller&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='vi'&gt;@options&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:controller&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;parts&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;join&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It explicitly checks to see if we&amp;#8217;re dealing with a &lt;em&gt;named_route&lt;/em&gt;. If so, it won&amp;#8217;t try to massage the route. This is why using an explicit &lt;em&gt;controller&lt;/em&gt; in route generation is susceptible to this issue.&lt;/p&gt;

&lt;p&gt;Next, it looks to see if we&amp;#8217;re in a different controller, which for engines will always be the case since they are namespaced in their own module.&lt;/p&gt;

&lt;p&gt;After that, the massaging occurs and thats when the problem occurs.&lt;/p&gt;

&lt;p&gt;Easy fix though, use named routes.&lt;/p&gt;

&lt;h3 id='is_this_a_bug'&gt;Is this a bug?&lt;/h3&gt;

&lt;p&gt;It might be, but I don&amp;#8217;t think it is. I think it is just how the Rails Engines have been designed to work in 3.1.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This &lt;a href='http://mutuallyhuman.com/blog/2011/09/22/rails-3-1-engine-namespaces-can-creep-into-urls-in-application-layout'&gt;post&lt;/a&gt; was featured on Mutually Human&amp;#8217;s &lt;a href='http://mutuallyhuman.com/blog'&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Highcharts, SVG, VML, and Auto-Sizing for Legends</title>
   <link href="http://www.continuousthinking.com/2011/09/16/highcharts-svg-vml-and-auto-sizing-for-legends.html"/>
   <updated>2011-09-16T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/09/16/highcharts-svg-vml-and-auto-sizing-for-legends</id>
   <content type="html">&lt;p&gt;Recently we hit a limitation with &lt;a href='http://www.highcharts.com/'&gt;Highcharts&lt;/a&gt;: it has no way of dynamically resizing itself or its parent container to ensure that you see the legend and the full chart at the same time. Here&amp;#8217;s the issue at hand: &lt;a href='http://jsfiddle.net/KYfHM/2/'&gt;http://jsfiddle.net/KYfHM/2/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This isn&amp;#8217;t a problem if you know in advance how many data series you&amp;#8217;ll be showing, because you can specify the proper width and height when you create the chart. We&amp;#8217;re populating the charts on a lot of dynamic factors, so we don&amp;#8217;t know how many series will always be displayed upfront and we don&amp;#8217;t know how long the labels will be. For us, this meant that our legend could easily grow beyond the bounds the chart.&lt;/p&gt;

&lt;p&gt;No one wants to see a cut-off legend.&lt;/p&gt;

&lt;p&gt;Determined to resolve the problem we created a &lt;em&gt;chart-resizing.js&lt;/em&gt; file which would unobtrusively define the ability for charts to automatically resize. Modern browsers support SVG, but IE7 and IE8 do not, and IE9 even has its own quirks.&lt;/p&gt;

&lt;p&gt;We decided to start with an &lt;em&gt;SVGChartResizing&lt;/em&gt; object which would be used to define the strategy for how the charts should be resized. This worked great in Chrome, Safari, and Firefox.&lt;/p&gt;

&lt;h2 id='ie9'&gt;IE9&lt;/h2&gt;

&lt;p&gt;Initially our SVGChartResizing object relied on the following code to determine &lt;em&gt;y&lt;/em&gt; position of our legend:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;legend&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;position&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;top&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Unfortunately, IE9 returns the offset from the document rather than relative to its parent. To fix that we changed the code to work along with IE9:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;legend&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;position&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;top&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;chart&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;position&lt;/span&gt;&lt;span class='p'&gt;().&lt;/span&gt;&lt;span class='nx'&gt;top&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;For SVG supporting browsers we were set. Now onto non-SVG supporting browsers.&lt;/p&gt;

&lt;h2 id='ie7_ie8'&gt;IE/7 IE8&lt;/h2&gt;

&lt;p&gt;IE7 and IE8 don&amp;#8217;t support SVG, they supports VML, which they are both equally finicky about.&lt;/p&gt;

&lt;h3 id='breaking_jquery'&gt;Breaking jQuery&lt;/h3&gt;

&lt;p&gt;When VML is present on the page IE breaks jQuery when using pure pseudo-selectors:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;:text&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='c1'&gt;// fails with SCRIPT16389 error&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The feedback you get from IE not very helpful. Fortunately, a similar &lt;a href='http://www.sitecrafting.com/blog/jquery-cufon-dont-mix/'&gt;issue&lt;/a&gt; was discovered way back in April 2010 when integrating Cufon, jQuery, and IE. There were only a few places where a pure pseudo selector was used so we updated them to be slightly more specific:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;input:text&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Adding the &lt;em&gt;input&lt;/em&gt; makes it more specific so jQuery won&amp;#8217;t try to select certain VML elements.&lt;/p&gt;

&lt;h3 id='getting_computed_heights_on_vml_objects'&gt;Getting computed heights on VML objects&lt;/h3&gt;

&lt;p&gt;A Highcharts legend is a container which groups all of the individual legend items themselves. With the SVG-capable browsers you could ask the legend for its height and it would return its computed height. This was reliable enough to get the actual height needed to display the legend.&lt;/p&gt;

&lt;p&gt;It seems that IEs DOM interface to VML objects doesn&amp;#8217;t quite work the same way. It seems practically impossible to determine the computed height of a VML container. So rather than asking for the legend&amp;#8217;s &lt;em&gt;height&lt;/em&gt; we had to find alternative paths.&lt;/p&gt;

&lt;p&gt;In IE8 we were able to use &lt;em&gt;scrollHeight&lt;/em&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;legend_h&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;legend&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;scrollHeight&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;IE7&amp;#8217;s scrollHeight didn&amp;#8217;t work the same way so we had to resort finding the largest child node and then rely on that to determine the legend&amp;#8217;s height:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='javascript'&gt;&lt;span class='nx'&gt;values&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;$&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;map&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;legend&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;children&lt;/span&gt;&lt;span class='p'&gt;(),&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;){&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;e&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;offsetHeight&lt;/span&gt;&lt;span class='p'&gt;;&lt;/span&gt; &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='nx'&gt;legend_h&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nb'&gt;Math&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;max&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;apply&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nb'&gt;Math&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;values&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='the_end'&gt;The End&lt;/h2&gt;

&lt;p&gt;For all of the complexities that Highcharts supports it was surprising that it didn&amp;#8217;t surprise gracefully resizing the chart and re-positioning the legend. From many Google searches it appears we aren&amp;#8217;t alone in this feature request, although most users seem to have found their own type of work around. Until it gets resolved there will be an open &lt;a href='https://github.com/highslide-software/highcharts.com/issues/435'&gt;issue&lt;/a&gt; for this.&lt;/p&gt;

&lt;p&gt;At the end end of the day the code is cleaner than we thought would have thought given the oddities we initially hit and the time it took to sort through the problems related to IE7 and IE8.&lt;/p&gt;

&lt;p&gt;I remember walking away from work thinking I can&amp;#8217;t wait until I get &lt;a href='http://jashkenas.github.com/coffee-script/'&gt;coffee-script&lt;/a&gt; on this project.&lt;/p&gt;

&lt;p&gt;You can find the full code of what it took in this &lt;a href='https://gist.github.com/1185140'&gt;source code&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This &lt;a href='http://mutuallyhuman.com/blog/2011/09/12/highcharts-svg-vml-and-auto-sizing-for-legends'&gt;post&lt;/a&gt; was featured on Mutually Human&amp;#8217;s &lt;a href='http://mutuallyhuman.com/blog/'&gt;blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Notable Git 1.7.6 Updates</title>
   <link href="http://www.continuousthinking.com/2011/09/15/notable-git-1-7-6-updates.html"/>
   <updated>2011-09-15T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/09/15/notable-git-1-7-6-updates</id>
   <content type="html">&lt;p&gt;&lt;em&gt;git merge&lt;/em&gt; now supports the ndash alias:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='c'&gt;# create topic branch to work in&lt;/span&gt;
git checkout -b foo

&lt;span class='c'&gt;# do work... make commits... get back on master&lt;/span&gt;
git checkout master

&lt;span class='c'&gt;# merge foo into master&lt;/span&gt;
git merge --no-merge -
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Also, &lt;em&gt;git checkout&lt;/em&gt; also supports the ndash alias which refers to the previous branch.&lt;/p&gt;

&lt;p&gt;The above example also works without &amp;#8211;&amp;#8211;no&amp;#8211;merge. Speaking of &amp;#8211;&amp;#8211;no&amp;#8211;merge, you can now configure it in your git config and stop passing it in with every command line merge.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;git config --add merge.ff no

&lt;span class='c'&gt;# no longer need to specify --no-ff&lt;/span&gt;
git merge foo
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;From the &lt;a href='http://gitlog.wordpress.com/2011/06/27/git-1-7-6/'&gt;gitlog&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“git merge” uses “merge.ff” configuration variable to decide to always create a merge commit (i.e. &amp;#8211;&amp;#8211;no&amp;#8211;ff, aka merge.ff=no), refuse to create a merge commit (i.e. &amp;#8211;&amp;#8211;ff&amp;#8211;only, aka merge.ff=only). Setting merge.ff=yes (or not setting it at all) restores the default behaviour of allowing fast&amp;#8211;forward to happen when possible.&lt;/p&gt;
&lt;/blockquote&gt;</content>
 </entry>
 
 <entry>
   <title>SSH Presentation Slides</title>
   <link href="http://www.continuousthinking.com/2011/09/02/ssh-presentation-slides.html"/>
   <updated>2011-09-02T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/09/02/ssh-presentation-slides</id>
   <content type="html">&lt;p&gt;I did a learning lunch a while ago on SSH. As developers we use SSH on a daily basis but often aren&amp;#8217;t aware of some of the things we can do with it. These slides covers the basics of those things.&lt;/p&gt;
&lt;div class='slideshare'&gt;
&lt;iframe src='http://icant.co.uk/slidesharehtml/embed.php?url=http://www.slideshare.net/zdennis/ssh-9115832&amp;amp;width=425' style='border:none;width:475px;height:395px;'&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;p&gt;You can access the full slide deck on slideshare &lt;a href='http://www.slideshare.net/zdennis/ssh-9115832'&gt;here&lt;/a&gt;.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Estimates and Commitments?</title>
   <link href="http://www.continuousthinking.com/2011/07/28/estimates-v-commitments.html"/>
   <updated>2011-07-28T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/07/28/estimates-v-commitments</id>
   <content type="html">&lt;p&gt;I was scanning the Internet tonight and came across Mike Cohn&amp;#8217;s article &lt;a href='http://blog.mountaingoatsoftware.com/separate-estimating-from-committing'&gt;Separate Estimating from Committing&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I respect Mike Cohn a lot, but the idea that we need to separate estimates from commitments doesn&amp;#8217;t add up. On one hand, I can&amp;#8217;t commit so here&amp;#8217;s my estimate. Okay that makes sense, but then on the other hand, if I increase what I can&amp;#8217;t commit to - my estimate - I can increase it by a factor of X and then all of a sudden we can commit. That doesn&amp;#8217;t seem likely.&lt;/p&gt;

&lt;p&gt;The future is too unpredictable. The farther out we&amp;#8217;re estimating the more error prone our estimates are going to be. Simply extending our estimates so we can give a guaranteed commitment will sound nice to product owners and the like, but it&amp;#8217;s not going to make it true.&lt;/p&gt;

&lt;p&gt;Most product owners would rather have the commitment any ways. In my experience they don&amp;#8217;t care about a estimate of 6 - 8 months if you also are going to give them a commitment of 9 months. Just tell them 9 months. They&amp;#8217;ll be happier in the long run (especially when it&amp;#8217;s not done at 6 months). But if we end up giving a commitment, what&amp;#8217;s the point of utilizing the estimates beyond coming up with that commitment? And if the commitment ends up being the important piece of information doesn&amp;#8217;t that put us back to square one anyways?&lt;/p&gt;

&lt;p&gt;Keeping track of both estimates and commitments seems counter-intuitive, you either can anticipate the future and the complexities surrounding the software you&amp;#8217;re building or you can&amp;#8217;t. It doesn&amp;#8217;t make sense to have it both ways. Saying so otherwise seems like pretending.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord-import 0.2.6 and ar-extensions 0.9.4</title>
   <link href="http://www.continuousthinking.com/2011/04/06/activerecord-import-0-2-6-and-ar-extensions-0-9-4.html"/>
   <updated>2011-04-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/04/06/activerecord-import-0-2-6-and-ar-extensions-0-9-4</id>
   <content type="html">&lt;p&gt;&lt;a href='http://stackoverflow.com/posts/5568092/'&gt;It was asked&lt;/a&gt; on stackoverflow this morning how to use the :synchronize option with import to synchronize based a field(s) besides the primary key field.&lt;/p&gt;

&lt;p&gt;activerecord-import 0.2.6 (for Rails 3) and ar-extensions 0.9.4 (for Rails 2) have been released which provide the additional option &lt;em&gt;synchronize-keys&lt;/em&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# By default, synchronize tries to use the primary key field of your model, in this case Topic.primary_key which is :id&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find_by_author&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Zach&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;import&lt;/span&gt; &lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:synchronize&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;topics&lt;/span&gt;

&lt;span class='c1'&gt;# Let&amp;#39;s specify a different unique column in which to synchronize on&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find_by_author&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Zach&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;import&lt;/span&gt; &lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:synchronize&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:synchronize_keys&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:topic_uuid&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This can be useful if you want to reload a bunch a of new records you&amp;#8217;re importing:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='c1'&gt;# +author+ is a unique field in this case&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:author&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Zach&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt; &lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='ss'&gt;:author&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;Bob&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new_record?&lt;/span&gt; &lt;span class='c1'&gt;# =&amp;gt; true&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt; &lt;span class='c1'&gt;# =&amp;gt; nil&lt;/span&gt;

&lt;span class='no'&gt;Topic&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;import&lt;/span&gt; &lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:synchronize&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:synchronize_keys&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:author&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new_record?&lt;/span&gt; &lt;span class='c1'&gt;# =&amp;gt; false&lt;/span&gt;
&lt;span class='n'&gt;topics&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;id&lt;/span&gt; &lt;span class='c1'&gt;# =&amp;gt; 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The keys you use to synchronize should be unique.&lt;/p&gt;

&lt;h3 id='install'&gt;Install&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem install activerecord-import &lt;span class='c'&gt;# for Rails 3&lt;/span&gt;
gem install ar-extensions &lt;span class='c'&gt;# for Rails 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Clarity, Important 100+ years ago, Important Today</title>
   <link href="http://www.continuousthinking.com/2011/03/16/clarity-important-100-years-ago-important-today.html"/>
   <updated>2011-03-16T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2011/03/16/clarity-important-100-years-ago-important-today</id>
   <content type="html">&lt;p&gt;Ludwig Wittgenstein&amp;#8217;s claims in philosophy hold true in today&amp;#8217;s in the pursuit of design and software development. He claimed, &amp;#8220;Everything that can be thought at all can be thought clearly. Everything that can be said, can be said clearly.&amp;#8221;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Retrospectives</title>
   <link href="http://www.continuousthinking.com/2011/02/18/retrospectives.html"/>
   <updated>2011-02-18T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/02/18/retrospectives</id>
   <content type="html">&lt;p&gt;This past weekend I was spending time with my brother and his family. One of the things I love about visiting with them (besides their adorable kids) is how interested they are in what I do. They seem to ask all of the right questions that make me fall back in love with what I do, how I do it, and why I do it.&lt;/p&gt;

&lt;p&gt;Don&amp;#8217;t get me wrong, I love what I do even on the days I&amp;#8217;m not hanging out with the family, but I often fall into the trap of normalcy. At one point, everything I was doing was new and fresh and it was an uphill battle just to get to do a fraction of it. Now, at MHS, all of those things have become what we practice every day &amp;#8211; it&amp;#8217;s become my new normal&amp;#8230;&lt;/p&gt;
&lt;a href='http://mutuallyhuman.com/blog/2011/02/17/retrospectives'&gt;Read the full article on at Mutually Human's blog&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Why Ruby?</title>
   <link href="http://www.continuousthinking.com/2011/01/25/why-ruby.html"/>
   <updated>2011-01-25T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2011/01/25/why-ruby</id>
   <content type="html">&lt;p&gt;After reading &lt;a href='http://darcyclarke.me/thoughts/why-not-ruby/'&gt;Why not !ruby?&lt;/a&gt; I felt like conversing, but since it&amp;#8217;s my wife and I alone at the house she doesn&amp;#8217;t speak developer-speak, I figured the interwebs might be a better place to share my thoughts.&lt;/p&gt;

&lt;p&gt;I think Ruby as a language and as a community connects with a lot of people in more ways than just a surface level &amp;#8220;can i accomplish X with ruby?&amp;#8221;.&lt;/p&gt;

&lt;p&gt;I can&amp;#8217;t speak for other people and I&amp;#8217;ll avoid using the &amp;#8216;people I know&amp;#8217; as a reason to run to or run away from Ruby. I have really enjoyed Ruby over the years, so much that I don&amp;#8217;t ever desire to go back to PHP, Perl, or Java. Ruby has been so expressive that it as challenged my assumptions about what a language should allow you as the coder to do.&lt;/p&gt;

&lt;p&gt;This expression of creatively solving a problem has been very rewarding. The box I am constrained in is defined, but it&amp;#8217;s less rigid then in many other languages. I like this feeling. I like working inside a slightly bigger box that provides me with more ways to solve problems, and with building blocks to let me create my own ways of solving problems.&lt;/p&gt;

&lt;p&gt;I also love that the community is largely supportive and encouraging. This isn&amp;#8217;t to say others aren&amp;#8217;t, but I&amp;#8217;ve had better experiences with feedback in the Ruby community. And I&amp;#8217;m not sure I get what&amp;#8217;s up with the non-Ruby world assuming Rubyists are all elitist mac fanboys. I think we know what we like and why we like it. I like my Mac. I used a PC for years and Linux for years following. And now I have a Mac. It works for me. I&amp;#8217;m happy with it. Likewise, I&amp;#8217;ve used PHP, Perl, and Java for years, but I like Ruby more. It works me. I solve problems and I am happy to solve them in Ruby. Again, it works me.&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t just love Ruby though. I love JavaScript to. A long time ago I loved PHP. Shortly after that was 4D/Active4D. There were a few scandalous programming language love affairs after that, but who&amp;#8217;s counting, right? Most recently I tried to love Scala. I mean I really really tried. It ended up as a short-lived romance with me in the hospital and Scala in AA. It just wasn&amp;#8217;t meant to work.&lt;/p&gt;

&lt;p&gt;Back on point though, I don&amp;#8217;t know why you do or don&amp;#8217;t ruby, but I know why I ruby. And that&amp;#8217;s all I really care about.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Heroku Autoscaling Bug</title>
   <link href="http://www.continuousthinking.com/2010/11/03/heroku-autoscaling-bug.html"/>
   <updated>2010-11-03T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/11/03/heroku-autoscaling-bug</id>
   <content type="html">&lt;p&gt;Recently while working on autoscaling &lt;a href='http://www.heroku.com'&gt;Heroku&lt;/a&gt; apps with Mark Van Holstyn and Chris Rittersdorf at &lt;a href='http://www.mutuallyhuman.com'&gt;Mutually Human&lt;/a&gt; we uncovered a bug with Heroku itself.&lt;/p&gt;

&lt;p&gt;When you tell Heroku to scale down its number of dynos it will still serve requests to dynos that are being shut down and it will kill dynos that are still actively serving requests. If you manually throttle dynos infrequently then you will probably not notice this, but the problem is still there. Since we were autoscaling based on live site usage and incoming requests, it expedited the visibility of this bug since our application would scale dynos up and down much more frequently to support application usage.&lt;/p&gt;

&lt;p&gt;This bug has been confirmed by the Heroku support team and has not yet been fixed. When it is fixed I&amp;#8217;ll post an update. In the mean time, scaling up is no problem, but if you scale down know that someone may get a Heroku HTTP 502 App Failed To Respond error because Heroku just killed a dyno serving a request.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>First grandrapids.rb Fall 2010 Meetup</title>
   <link href="http://www.continuousthinking.com/2010/10/06/frist-grandrapids-rb-fall-2010-meetup.html"/>
   <updated>2010-10-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/10/06/frist-grandrapids-rb-fall-2010-meetup</id>
   <content type="html">&lt;p&gt;Tonight I attended the &lt;a href='http://www.meetup.com/mi-ruby/'&gt;Grand Rapids ruby user group&lt;/a&gt; meeting. The first one since the summer hiatus! There was a great turnout of about 15 people.&lt;/p&gt;

&lt;p&gt;Derek Kastner gave a great presentation on &lt;a href='http://gembundler.com/'&gt;Bundler&lt;/a&gt; ). At high level Bundler is a library/tool that manages an application&amp;#8217;s dependencies through its entire life across many machines systematically and repeatably. Derek&amp;#8217;s slides/presentation can be found here: &lt;a href='http://github.com/dkastner/bundler-pres'&gt;http://github.com/dkastner/bundler-pres&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The presentation segway&amp;#8217;d into discussing Maven and Bundler, Bundler and Rails, Bundler and Isolate (Bundler alternative), and then onto IDEs such as Eclipse, Netbeans, VIM, Emacs, TextMate, and now &lt;a href='http://redcareditor.com/'&gt;Redcar&lt;/a&gt; &amp;#8211; which I&amp;#8217;m rooting for Redcar. It looks awesome and has the best commit policy known to open source.&lt;/p&gt;

&lt;p&gt;It ended with Carl Furrow showing us the world of &lt;a href='http://www.minecraft.net/'&gt;Minecraft&lt;/a&gt;. All I have to say to that is Carl was like a zenmaster navigating the landscape of his 3D world, traveling to the center of the earth, dodging box-headed skeletons shooting arrow-like objects. I feel all in attendance were enlightened.&lt;/p&gt;

&lt;p&gt;Next month should be awesome, Zach Church is giving a talk on Rails 3!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord-import 0.2.2 released!</title>
   <link href="http://www.continuousthinking.com/2010/10/06/activerecord-import-0-2-2-released.html"/>
   <updated>2010-10-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/10/06/activerecord-import-0-2-2-released</id>
   <content type="html">&lt;p&gt;activerecord-import 0.2.2 has been released. This contains no functionality changes, just gem dependency updates.&lt;/p&gt;

&lt;h3 id='updates'&gt;Updates&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;activerecord-import, now only depends on activerecord, the rails dependency has been removed entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='installing'&gt;Installing&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem install activerecord-import -v 0.2.2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Happy rubying!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord-import 0.2.1 released!</title>
   <link href="http://www.continuousthinking.com/2010/10/05/activerecord-import-0-2-1-released.html"/>
   <updated>2010-10-05T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/10/05/activerecord-import-0-2-1-released</id>
   <content type="html">&lt;p&gt;activerecord-import 0.2.1 has been released. This contains no functionality changes, just gem dependency updates.&lt;/p&gt;

&lt;h3 id='resolved_issues'&gt;Resolved Issues&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update gemspec to require rails &amp;#8220;~&amp;gt; 3.0.0rc&amp;#8221; rather than &amp;#8220;&amp;gt;= 3.0.0rc&amp;#8221;, which closes &amp;#8220;issue #2&amp;#8221;:http://github.com/zdennis/activerecord-import/issues/closed#issue/2&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='installing'&gt;Installing&lt;/h3&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem install activerecord-import -v 0.2.1
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Happy rubying!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>On Criticism and Encouragement</title>
   <link href="http://www.continuousthinking.com/2010/09/26/criticism-encouragement-a-personal-look-back.html"/>
   <updated>2010-09-26T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/09/26/criticism-encouragement-a-personal-look-back</id>
   <content type="html">&lt;p&gt;I will do great things in this life, but never at the expense of another person. I have and will continue to make many mistakes in this life. My past mistakes have allowed me to experience the differences between criticism and encouragement at many different levels and for many different reasons. Criticism and blame have never led me to achieve anything worthwhile. On the other hand what&amp;#8217;s been afforded to me through love, encouragement, appreciation, forgiveness, and empathy have been the starting point of every worthwhile achievement I can remember.&lt;/p&gt;

&lt;p&gt;The biggest differences I can recall between criticism and encouragement has to do with what is planted within. Criticism generally has made me frustrated, angry, discouraged, and ultimately depressed. On a few occasions it temporarily instilled in me the will to &amp;#8216;show&amp;#8217; the other person. This feeling quickly dissipated and was again replaced by a feeling of distress. Encouragement on the other hand has had a different life-changing quality about it &amp;#8211; it inspired, motivated, and uplifted me. It took my mistakes and gave me energy and helped strengthen my resolve and determination to learn from those mistakes. It provided a framework for growth and in the process created respect and loyalty.&lt;/p&gt;

&lt;p&gt;Dale Carnegie sums these experiences up nicely, &amp;#8221;I&amp;#8217;ve yet to see a person who didn&amp;#8217;t do better work under a spirit of encouragement than one of criticism.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Every interaction in our lives happens only once. Each interaction gives us the chance to imprint something on our own lives as well as those we interact with. With every opportunity that arises I hope to provide the encouragement that so many others have given me in hopes that this will help them achieve great things in their life. If I do this, then I&amp;#8217;ll have achieved one in mine.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord-import 0.2.0 released!</title>
   <link href="http://www.continuousthinking.com/2010/09/26/activerecord-import-0-2-0-released.html"/>
   <updated>2010-09-26T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/09/26/activerecord-import-0-2-0-released</id>
   <content type="html">&lt;p&gt;activerecord-import 0.2.0 has been released this evening! There are no changes to existing functionality, only some nice updates:&lt;/p&gt;

&lt;h1 id='the_mysql2_adapter_is_now_supported_in_addition_to_sqlite3_postgresql_and_mysql'&gt;the Mysql2 adapter is now supported (in addition to SQLite3, PostgreSQL, and MySQL)&lt;/h1&gt;

&lt;h1 id='activerecordimport_got_stupid_simple_to_require_and_use'&gt;activerecord-import got stupid simple to require and use&lt;/h1&gt;

&lt;h1 id='the_010_release_um_surprise'&gt;the 0.1.0 release, um, surprise!&lt;/h1&gt;

&lt;h2 id='mysql2_support'&gt;Mysql2 Support&lt;/h2&gt;

&lt;p&gt;Okay, the first line item &amp;#8211; mysql2 support. This is a little late coming I know, but it&amp;#8217;s there now. The mysql2 support is identical to the mysql support so if you&amp;#8217;re upgrading a pre-Rails 3 app (that used ar-extensions or activerecord-import) you won&amp;#8217;t have to change any code using #import. More on that later.&lt;/p&gt;

&lt;h2 id='stupid_simple_requires'&gt;Stupid Simple Requires&lt;/h2&gt;

&lt;p&gt;activerecord-import and its predecessor (activerecord-extensions) was always a little kludgy to require and use. It was never painstaking to load up, but nonetheless it could have been better. Well, that better comes today.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the breakdown of the better: activerecord-import is now loads when your ActiveRecord connection is established. This means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;no need to separately require activerecord-import or adapter-specific code&lt;/li&gt;

&lt;li&gt;supports &lt;em&gt;you&lt;/em&gt; using multiple database adapters simultaneously&lt;/li&gt;

&lt;li&gt;activerecord-import will only load once for an adapter, so no worries re-establishing connections&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn&amp;#8217;t earth shattering awesome, but this is a small step forward for the library and it makes it easier to use!&lt;/p&gt;

&lt;p&gt;For more information on requiring activerecord-import in Rails and non-Rails projects see &amp;#8220;Requiring&amp;#8221;:http://github.com/zdennis/activerecord-import/wiki/Requiring on the wiki.&lt;/p&gt;

&lt;h2 id='010_release_um_surprise'&gt;0.1.0 Release, um, Surprise!&lt;/h2&gt;

&lt;p&gt;The 0.1.0 activerecord-import gem has been out for a few months, and I know a few of you have been using it as I&amp;#8217;ve been receiving emails and instant messages. However, if you didn&amp;#8217;t know it was out, surprise! I apologize for not communicating when the gem became available, but hindsight is 20/20, and moving forward things I will be more communicative.&lt;/p&gt;

&lt;p&gt;If you didn&amp;#8217;t know activerecord-import 0.1.0 took all of the import functionality out of the activerecord-extensions gem and bundled it in its own gem. It is Rails 3 friendly whereas activerecord-extensions is not and will never be (at least by me). The 0.1.0 release launched support for the following adapters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;mysql&lt;/li&gt;

&lt;li&gt;postgresql&lt;/li&gt;

&lt;li&gt;sqlite3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And as of this announcement mysql2 support was added.&lt;/p&gt;

&lt;p&gt;Well, there you have it, the world just got a little bit better today. When I pushed the gem I am pretty sure a tiny angel got its wings.&lt;/p&gt;

&lt;h2 id='install_the_gem'&gt;Install the gem&lt;/h2&gt;
&lt;pre&gt;
gem install activerecord-import -v 0.2.0
&lt;/pre&gt;
&lt;h2 id='install_in_your_gemfile'&gt;Install in your Gemfile&lt;/h2&gt;
&lt;pre&gt;
gem &quot;activerecord-import&quot;, &quot;&gt;= 0.2.0&quot;
&lt;/pre&gt;
&lt;h2 id='docs'&gt;Docs&lt;/h2&gt;

&lt;p&gt;For docs see the &amp;#8220;wiki&amp;#8221;:http://github.com/zdennis/activerecord-import/wiki/&lt;/p&gt;

&lt;p&gt;Happy rubying!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>The Customer Fallacy</title>
   <link href="http://www.continuousthinking.com/2010/09/24/the-customer-fallacy.html"/>
   <updated>2010-09-24T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/09/24/the-customer-fallacy</id>
   <content type="html">&lt;pre&gt;
nothing so kills the spirit
as a man that jumps to conclusions
to assign blame before he knows
that what he sees are illusions

failing to see the fallacy
of the reasons he thinks it has to be
after this, then because of this
thinking he's figured it logically

but if berries are red and berry bushes are plants
surely all berries are not red
but he thinks that they must be
and so he believes
never thinking what he's thinking's absurd
&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>A journey of possibilities with community at the core</title>
   <link href="http://www.continuousthinking.com/2010/08/01/a-journey-of-possibilities-with-community-at-the-core.html"/>
   <updated>2010-08-01T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/08/01/a-journey-of-possibilities-with-community-at-the-core</id>
   <content type="html">&lt;p&gt;One of my goals for Mutually Human Software is to create an authentic community. To create a place where everyone feels that this is where they belong at this time in their life. When people feel a sense of belonging they aren&amp;#8217;t wishing they were somewhere else, they feel like they belong right where they are. This is one of the possibilities I aspire to realize with MHS.&lt;/p&gt;

&lt;p&gt;The question I&amp;#8217;ve been struggling with is how do we create that kind of community? There&amp;#8217;s a lot of conventional business wisdom about how to build, run, and lead a business. Unfortunately, a lot of it what&amp;#8217;s there is at odds with what I view as essential for building an authentic community. My sights are much higher then simply having a profitable company or a good company. I want an exceptional one. I believe an authentic community is critical to realize this possibility.&lt;/p&gt;

&lt;p&gt;A few years ago I focused on the culture of a company being key to whether or not they were a great company and whether or not I wanted to emulate them. Recently it hit me that culture is merely an indicator of a deeper and more meaningful metric &amp;#8211; the health and shared values of the community. Culture is a by-product of the community, not a means to achieve it.&lt;/p&gt;

&lt;p&gt;Another way I think about culture is that it is a reflection of the community. This has been intriguing to think about because it exposes that you can&amp;#8217;t copy culture. You can attempt to emulate it, but likely that emulation will fail to create the culture you want because culture is an outcome of community, not a thing in and of itself.&lt;/p&gt;

&lt;p&gt;This is a lesson I&amp;#8217;ve learned over the past few years. I wanted to emulate companies I thought were great and while some things worked for a short period of time, nothing created the kind of relationships, cohesion, or sense of belonging that we had the possibility to achieve.&lt;/p&gt;

&lt;p&gt;Before I looked at the results of a great company&amp;#8217;s community, but now I am paying close attention to the shared- values, goals, and disciplines of those companies and their communities. My focus is not to take what I see and put policies in place at MHS. That would not be authentic. Rather my focus is bringing what I see and allowing others to bring what they see and to allow the community to grow and evolve &amp;#8211; allowing people to have a hand in creating the very thing that defines us and ultimately results in a culture we all are proud of.&lt;/p&gt;

&lt;p&gt;Today is another step towards the realization of being an exceptional company and an exceptional community. I find the possibilities and the journey so inspiring!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Accountability Can't Be Dictated</title>
   <link href="http://www.continuousthinking.com/2010/07/31/accountability-can-t-be-dictated.html"/>
   <updated>2010-07-31T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/07/31/accountability-can-t-be-dictated</id>
   <content type="html">&lt;p&gt;Everyone talks about accountability. It&amp;#8217;s one of those things we all want and expect, but it&amp;#8217;s something that is often struggled with. No one wakes up and plans to fail holding themselves accountable. Yet, even with good intentions we often fail to follow-through. Why is it so difficult?&lt;/p&gt;

&lt;p&gt;Whether in conversation or reading it strikes me as odd how often accountability is being dictated as opposed to owned. If I tell you to be more accountable what do you think the chances are that you will become more accountable? I bet slim to none.&lt;/p&gt;

&lt;p&gt;We can always up the ante and impose consequences. Perhaps the more severe the consequence the more accountable you&amp;#8217;ll become. There is some truth in this method, but it comes at a cost. An example of that cost is creating a fear-based culture which can become focused on retribution. If you&amp;#8217;ve ever worked for an employer who ruled by fear and consequence you know what I&amp;#8217;m referring to.&lt;/p&gt;

&lt;p&gt;Accountability in my opinion doesn&amp;#8217;t fail because individuals have malicious intent. I think it fails because we often try to impose it on others rather than owning it ourselves. Accountability starts with the individual. I choose to be accountable or not. I choose to be responsible with the commitments and decisions I&amp;#8217;ve made. No one else. No matter how much you encourage me at the end of the day it&amp;#8217;s still up to me.&lt;/p&gt;

&lt;p&gt;In Peter Block&amp;#8217;s book Community he points out in reference to accountability is &amp;#8221;&amp;#8230; that people will be accountable and committed to what they have a hand in creating.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I believe he&amp;#8217;s referring to authentic creation as well. Dictating to someone how to solve a problem every step of the way isn&amp;#8217;t allowing them to be a part of creating that solution. They have no stake in, no connection to the solution or the process of getting there. This may be perceived as creation by the individual in control, but it&amp;#8217;s an illusion.&lt;/p&gt;

&lt;p&gt;Instead of dictating step one, step two, etc, why not present the problem and allow the individual to own achieving the solution? You can still make yourself available, provide guidance, and set parameters. This doesn&amp;#8217;t have to remove you from the equation, but it removes you from controlling the entire process. You&amp;#8217;re trading your control for their freedom. It&amp;#8217;s in their freedom they are able to be a part of the process for solving the problem. They become a creator in that instance. I believe this creates accountability that is owned by an individual opposed to that which is demanded of us by others.&lt;/p&gt;

&lt;p&gt;While there are support measures for peers and our communities to help us be accountable, ultimately it&amp;#8217;s up to us as individuals. Accountability can&amp;#8217;t be dictated. It must be owned.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Daniel Parker accident</title>
   <link href="http://www.continuousthinking.com/2010/05/17/daniel-parker-accident.html"/>
   <updated>2010-05-17T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/05/17/daniel-parker-accident</id>
   <content type="html">&lt;p&gt;You may know his name if you&amp;#8217;re a developer, because so was Daniel. You may know him from his work with Quickbooks and Ruby or maybe his GMail rubygem or one of his many other projects that he authored or contributed to.&lt;/p&gt;

&lt;p&gt;You may know him as a Christian, because so was Daniel. While he wrote code because it was fun and he was quite good at it, he first and fore-most lived for the Lord.&lt;/p&gt;

&lt;p&gt;You may know Daniel as a fervent competitor with a kind heart and a powerfully analytical mind. You may know Daniel for a number of other reasons, and if you didn&amp;#8217;t know Daniel then I assure you, if you did, he would have left nothing but an impact of an honest, energetic, intelligent, warm hearted, analytical, yet loving person.&lt;/p&gt;

&lt;p&gt;I knew Daniel because of his work in the Ruby community and in the Ruby community in the midwest and specifically Michigan. Last fall I attended GRGivecamp with Daniel. Four months ago, Daniel came and began working with me at Mutually Human Software. Daniel and I worked closely together for about 30 hours a week every week. Every day we&amp;#8217;d pair program (or party as Daniel would call it). Almost every day we&amp;#8217;d eat lunch together and talk - sometimes about work and sometimes about everything else in life. I never imagined that four months of my life with someone could have such an impact. That&amp;#8217;s also the kind of person Daniel was - impactful in all the best ways.&lt;/p&gt;

&lt;p&gt;Before I had ever met Daniel personally, my colleague John Hwang had told me that he was the kind of person we wanted to work with, not just the type of developer, but the kind of person. At first I was skeptical, but after I met and began workingw ith Daniel I knew John was right. Daniel was more then just a developer &amp;#8211; he was human. He was the kind of spirit and person who anyone would want to build a team around. He was an amazing developer, but even more-so he was an exceptional person. It&amp;#8217;s hard to believe that Daniel was only 23 years old.&lt;/p&gt;

&lt;p&gt;I will miss you Daniel, as a friend, as a colleague, as a human. May your life go on to impact countless lives. I know you have impacted mine.&lt;/p&gt;

&lt;p&gt;P.S. - when you get to heaven be sure to teach everyone Rook, they&amp;#8217;ll love it just as much as you did when I introduced it to you. That will forever be a cherished night in my life.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>UNIX tee in real life</title>
   <link href="http://www.continuousthinking.com/2010/04/29/unix-tee-in-real-life.html"/>
   <updated>2010-04-29T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/04/29/unix-tee-in-real-life</id>
   <content type="html">&lt;p&gt;I wrote a nice little article on using the UNIX tee command in real life. If you&amp;#8217;re wanting to see the purpose of tee or learn something new about bash, check it out:&lt;/p&gt;

&lt;p&gt;&amp;#8220;http://mutuallyhuman.com/2010/4/29/unix-tee-in-real-life&amp;#8221;:http://mutuallyhuman.com/2010/4/29/unix-tee-in-real-life&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>activerecord-import gets basic SQLite3 and PostgreSQL support</title>
   <link href="http://www.continuousthinking.com/2010/04/09/activerecord-import-gets-basic-sqlite3-and-postgresql-support.html"/>
   <updated>2010-04-09T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2010/04/09/activerecord-import-gets-basic-sqlite3-and-postgresql-support</id>
   <content type="html">&lt;p&gt;A few weeks back I started working on extracting the import functionality from ar-extensions into its own library. The initial extraction involved pulling out all of the MySQL functionality first, test by test, piece by piece. Well, tonight I pulled in the basic support for SQLite3 and PostgreSQL.&lt;/p&gt;

&lt;p&gt;While it&amp;#8217;s working great for MySQL, SQLite3, and PostgreSQL it has not been released as its own rubygem yet. I expect that to happen in the near-term future. In the meantime you can always check out the project on github:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://github.com/zdennis/activerecord-import/&amp;#8221;:http://github.com/zdennis/activerecord-import/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the past folks have emailed about sparse documentation. When the gem is released documentation will be provided by the github wiki ( &amp;#8220;http://wiki.github.com/zdennis/activerecord-import/&amp;#8221;:http://wiki.github.com/zdennis/activerecord-import/ ) and the most up-to-date will be provided in the RDOC itself.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve ran some benchmarks recently against MySQL 5.1 and you can find the results here: &amp;#8220;http://wiki.github.com/zdennis/activerecord-import/benchmarks&amp;#8221;:http://wiki.github.com/zdennis/activerecord-import/benchmarks&lt;/p&gt;

&lt;p&gt;More to come!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Import Updates</title>
   <link href="http://www.continuousthinking.com/2010/03/12/activerecord-import-updates.html"/>
   <updated>2010-03-12T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2010/03/12/activerecord-import-updates</id>
   <content type="html">&lt;p&gt;Nearly four years ago I embarked on figuring out ActiveRecord internals enough so I could have a library which allowed me to perform bulk inserts of data in an optimized way based on the database adapter being used. Over those four years, I&amp;#8217;ve maintained and updated the functionality with contributions from the community. A big thanks to Blythe Dunham, James Herdman, Gabe da Silveira, Thibaud Guillaume-Gentil, Marcus Crafter, and Mark Van Holstyn.&lt;/p&gt;

&lt;p&gt;Now that Rails is nearing a 3.0 release, it&amp;#8217;s time for to revisit this import functionality, make it compatible with the heavily refactored and cleaned up ActiveRecord internals (thx Rails core team) and add some more polished features and implementation.&lt;/p&gt;

&lt;p&gt;The import functionality which was in ActiveRecord::Extensions is being extracted into its own library, &lt;em&gt;activerecord-import&lt;/em&gt;. This library will be smaller and its only purpose will be to provide mass import functionality.&lt;/p&gt;

&lt;p&gt;The work has already begun over on github: &amp;#8220;http://github.com/zdennis/activerecord-import&amp;#8221;:http://github.com/zdennis/activerecord-import&lt;/p&gt;

&lt;p&gt;I look forwarding to officially releasing this in the upcoming weeks!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Binary Chop Shop in Scala</title>
   <link href="http://www.continuousthinking.com/2009/11/03/binary-chop-shop-in-scala.html"/>
   <updated>2009-11-03T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2009/11/03/binary-chop-shop-in-scala</id>
   <content type="html">&lt;p&gt;In an effort to start learning Scala again (i started in the summer then got busy) I decided to tackle a simple yet fun code kata from Dave Thomas called &amp;#8220;karate chop&amp;#8221;:http://codekata.pragprog.com/2007/01/kata_two_karate.html&lt;/p&gt;

&lt;p&gt;I ended up using &amp;#8220;Specs&amp;#8221;:http://code.google.com/p/specs/ to make sure I passed Dave Thomas&amp;#8217;s test criteria. I&amp;#8217;m sure my below two solutions (recursive and while loop) are quite clunky compared to someone who&amp;#8217;s familiar with Scala, but the goal of this was to get something running and passing. In a week or two I&amp;#8217;ll revisit again after learning some more things about Scala and hopefully be able to tidy things up a bit.&lt;/p&gt;

&lt;p&gt;Anyways, here&amp;#8217;s my code:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='scala'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;BinaryChopShop&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='n'&gt;chopRecursive&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt; &lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt; &lt;span class='kt'&gt;List&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='o'&gt;],&lt;/span&gt; &lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt; &lt;span class='kt'&gt;Int*&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt; &lt;span class='kt'&gt;Int&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;isEmpty&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

    &lt;span class='k'&gt;val&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;isEmpty&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='n'&gt;args&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

    &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;){&lt;/span&gt;
      &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;target&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt; 
    &lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
      &lt;span class='k'&gt;val&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
      &lt;span class='k'&gt;val&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;

      &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;chopRecursive&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;slice&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;),&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
      &lt;span class='k'&gt;else&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;chopRecursive&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;slice&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt;&lt;span class='o'&gt;),&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
    &lt;span class='o'&gt;}&lt;/span&gt;
  &lt;span class='o'&gt;}&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='n'&gt;chopWhile&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt; &lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt; &lt;span class='kt'&gt;List&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt;&lt;span class='o'&gt;])&lt;/span&gt;&lt;span class='k'&gt;:&lt;/span&gt;&lt;span class='kt'&gt;Int&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='n'&gt;nlist&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;list&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;var&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

    &lt;span class='k'&gt;while&lt;/span&gt;&lt;span class='o'&gt;(!&lt;/span&gt;&lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;isEmpty&lt;/span&gt;&lt;span class='o'&gt;){&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;){&lt;/span&gt;
        &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;first&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;target&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
      &lt;span class='o'&gt;}&lt;/span&gt;
  
      &lt;span class='k'&gt;val&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt; &lt;span class='o'&gt;/&lt;/span&gt; &lt;span class='mi'&gt;2&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
      &lt;span class='k'&gt;val&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
  
      &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt; &lt;span class='o'&gt;==&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt;&lt;span class='o'&gt;)&lt;/span&gt; &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='n'&gt;offset&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
      &lt;span class='k'&gt;if&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;target&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='n'&gt;value&lt;/span&gt;&lt;span class='o'&gt;){&lt;/span&gt;
        &lt;span class='n'&gt;nlist&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;slice&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='mi'&gt;0&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
      &lt;span class='o'&gt;}&lt;/span&gt; &lt;span class='k'&gt;else&lt;/span&gt; &lt;span class='o'&gt;{&lt;/span&gt;
        &lt;span class='n'&gt;offset&lt;/span&gt; &lt;span class='o'&gt;+=&lt;/span&gt; &lt;span class='n'&gt;index&lt;/span&gt;
        &lt;span class='n'&gt;nlist&lt;/span&gt; &lt;span class='k'&gt;=&lt;/span&gt; &lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;slice&lt;/span&gt;&lt;span class='o'&gt;(&lt;/span&gt;&lt;span class='n'&gt;index&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='n'&gt;nlist&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;size&lt;/span&gt;&lt;span class='o'&gt;);&lt;/span&gt;
      &lt;span class='o'&gt;}&lt;/span&gt;
    &lt;span class='o'&gt;}&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='o'&gt;-&lt;/span&gt;&lt;span class='mi'&gt;1&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
  &lt;span class='o'&gt;}&lt;/span&gt;  
&lt;span class='o'&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Summary of thoughts on data and migrations</title>
   <link href="http://www.continuousthinking.com/2009/10/17/summary-of-thoughts-on-data-and-migrations.html"/>
   <updated>2009-10-17T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/10/17/summary-of-thoughts-on-data-and-migrations</id>
   <content type="html">&lt;p&gt;I shared a summary of my thoughts today with my project team (we&amp;#8217;re distributed, multi-national team)&amp;#8230; and I thought what the heck why not share with the rest of the world to. Here goes&amp;#8230;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m not sure what everyone&amp;#8217;s conventions or views are on handling the removal of data in the app that is no longer used, so here are some of the guidelines I follow to help promote sharing and consistency.&lt;/p&gt;

&lt;h2 id='seed_data'&gt;Seed data&lt;/h2&gt;

&lt;p&gt;To load data that has to exist for the application to run, I like to use seed data and I am a big fan of Michael Bleigh&amp;#8217;s seed-fu plugin. Seed data should be setup so that it can be loaded at any point during the lifetime of an application. It should not destroy data that leaves orphaned data and it should not duplicate data.&lt;/p&gt;

&lt;h2 id='updating_data'&gt;Updating data&lt;/h2&gt;

&lt;p&gt;I like to use migrations to update existing data. If the migration and data update is complex and irreversible I will add a unit test around the migration because due to the high risk of causing irreversible damage (unless a full DB backup is loaded).&lt;/p&gt;

&lt;h2 id='updating_applicationrequired_data'&gt;Updating application-required data&lt;/h2&gt;

&lt;p&gt;When the data that the application depends on changes (ie; the seed data) I tend to update both the seed files as well as add a migration to properly handle any existing data, whether this means removing the data, marking it as delete or inactive, etc.&lt;/p&gt;

&lt;h2 id='updating_data'&gt;Updating data&lt;/h2&gt;

&lt;p&gt;In development modifying data directly through MySQL or ruby scripts is much more forgivable and often very fast and efficient. We have no risk of causing users of the application harm or loss of data. Once something is figured out I like to either add a seed-file and/or a migration if it&amp;#8217;s a change that needs to get made on staging and production.&lt;/p&gt;

&lt;p&gt;In staging modifying data directly is less appealing because staging is supposed to represent what happens when we go to production. If we have to modify data directly in staging then we&amp;#8217;ll probably have to modify it in production, so a migration and/or seed-file is a better place to track the change. I find it tempting sometimes to script/console and modify data directly.&lt;/p&gt;

&lt;p&gt;A problem with this is that we risk screwing up staging for folks who are using it to preview features, check out bug fixes, etc. I find it better to dump the database and pull it over to my local development machine. Once I have it I can load it up locally, recreate the issue, and do whatever I need to do to find the source of the issue. This removes the risk that you fill further break staging for any users using it. Once I find the issue if I need to I will add/update a migration and/or seed file.&lt;/p&gt;

&lt;p&gt;In production modifying data directly is super dangerous. It&amp;#8217;s a change that occurs outside of version control and potentially without being run in development and/or staging which could catch bugs in the updates. The risk of causing irrevocable damage is so high I think doing this should be avoided.&lt;/p&gt;

&lt;p&gt;I find it&amp;#8217;s always been better to take an extra few minutes to make sure the fix is right and then to deploy, then it is to make a quick fix directly in production and find the change caused new issues. Production should never turn into a debugging sandbox. Pulling over a backup if necessary is safer and allows us developers more freedom to freely change the data to find the appropriate fix.&lt;/p&gt;

&lt;h2 id='if_you_have_to_use_scriptconsole_not_mysql'&gt;If you have to use script/console not MySQL&lt;/h2&gt;

&lt;p&gt;If you find you need to update data directly it&amp;#8217;s better to use script/console, then by touching the database directly using MySQL. For example, Scott once asked me to change his user name. Changing his user name was a very low risk change, so I loaded up script/console and made it.&lt;/p&gt;

&lt;p&gt;The benefit of script/console is that you let all of the rules and validations inside the application be run when you make the change. If I had made Scott&amp;#8217;s username too short, too long, include inadmissable characters I would not find out if I did it directly through MySQL, unless I had duplicated all of the logic in MySQL stored procedures and triggers (which I cringe at the thought of).&lt;/p&gt;

&lt;h2 id='conclusion'&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Well, that&amp;#8217;s pretty much a summary of my personal guidelines when it comes to dealing with data updates, migrations, seed-files, etc. If you have any other guidelines you follow that you find helpful please share. I think being on the same page here will help us as we push forward.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>git review</title>
   <link href="http://www.continuousthinking.com/2009/10/01/git-review.html"/>
   <updated>2009-10-01T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/10/01/git-review</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve gotten into the habit of review code that comes down from every other developer, rather than blindly merging in. For a while I was typing &amp;#8220;git log master..origin/master&amp;#8221; but it became to tedious to type out. I&amp;#8217;ve updated my .gitconfig to provide the following alias:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='nb'&gt;alias&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='nv'&gt;review&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; !&lt;span class='s2'&gt;&amp;quot;git log  master..origin/master&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now I can simply say:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;git review
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;If you want to view actual code changes rather than simply the changelog just add the -p flag:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;git review -p
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;A little nicer.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>BDD not so much, really? Part II</title>
   <link href="http://www.continuousthinking.com/2009/05/28/bdd-not-so-much-really-part-ii.html"/>
   <updated>2009-05-28T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/05/28/bdd-not-so-much-really-part-ii</id>
   <content type="html">&lt;p&gt;Focusing on behaviour may yield different tools throughout the process. Cucumber and RSpec are just two examples. You could very well use Cucumber plus test/unit, or perhaps just RSpec, or maybe nothing at all. These are just tools to support a development style. They are NOT the development style themselves. You can use Cucumber in a way that doesn&amp;#8217;t support BDD. Same goes for RSpec and any other tool.&lt;/p&gt;

&lt;p&gt;I realize there are people who don&amp;#8217;t buy into the RSpec philosophy. To them it&amp;#8217;s just another take on unit testing. I do buy into RSpec. From day one RSpec&amp;#8217;s goal has been to be a BDD tool that tries to get the words right. Can you use xUnit libraries in a way to achieve the same affect? Yes you can, but most of those usages have been heavily influenced by RSpec which was built on the ideas and motivation for BDD and &amp;#8220;getting the words right&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Without this focus many of the high level test/unit style add-ons (especially in the ruby world like context, shoulda, test/spec, etc.) wouldn&amp;#8217;t exist. So to me, this makes the subtle differences very important as it changed how everyone wrote their tests.&lt;/p&gt;

&lt;p&gt;For me personally, testing is an activity after you write code. I find it refreshing to talk about writing code examples to drive design and tests to talk about actual testing. Perhaps it could be phrased as, you start with examples and when you&amp;#8217;re done you end up with tests. Similar to starting with user stories and ending up with features. Right now that works in my head, but it&amp;#8217;s late and I may need to revisit that thought after a few hours of sleep.&lt;/p&gt;

&lt;p&gt;Example is just a better word then test to. When you talk to someone and you don&amp;#8217;t understand what they&amp;#8217;re talking about you don&amp;#8217;t say, &amp;#8220;give me a test&amp;#8221;, you say, &amp;#8220;give me an example&amp;#8221;. Well, that language is more natural. You are providing an example of how something should work. This example ends up providing regression (test) value once its implemented, but you didn&amp;#8217;t start with a test, you started with an example of the code you wanted.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>BDD not so much, really?</title>
   <link href="http://www.continuousthinking.com/2009/05/28/bdd-not-so-much-really.html"/>
   <updated>2009-05-28T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/05/28/bdd-not-so-much-really</id>
   <content type="html">&lt;p&gt;&lt;em&gt;Updated May 29, 2009&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This rant is in response to &lt;a href='http://robertlally.com/post/bdd-not-so-much'&gt;http://robertlally.com/post/bdd-not-so-much&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;BDD didn&amp;#8217;t start off as a replacement for TDD. It started off a way to better understand and explain the process of TDD. The name change as I understand it was to communicate the intent of TDD in a clearer and more direct way. You&amp;#8217;re not writing tests for the sake of writing tests, you&amp;#8217;re driving behaviour. Focus on the behaviour you want to achieve first and foremost. Use that behaviour as the driving force for your examples (or tests).&lt;/p&gt;

&lt;p&gt;Corey Haines nailed it on his comment to the same post, &amp;#8220;BDD is no longer a replacement for TDD, but, rather it is a workflow for creating a system that more closely resembles what the client is looking for.&amp;#8221; I think two of best tools which exist to support the BDD workflow of outside-in are Cucumber and RSpec. Cucumber for higher level system behaviour and RSpec for driving lower level design.&lt;/p&gt;

&lt;p&gt;In the article, the author criticizes the &amp;#8220;should&amp;#8221; language. Rather than simply scoffing at the idea of replacing &amp;#8220;assert&amp;#8221; with &amp;#8220;should&amp;#8221;, I tend to think about it in terms of natural communication. The reason I like &amp;#8220;should&amp;#8221; language over &amp;#8220;assert&amp;#8221; language is that when I&amp;#8217;m communicating with another developer I don&amp;#8217;t say, &amp;#8220;assert equal one day to do things good&amp;#8221;. That doesn&amp;#8217;t make any sense. I say, &amp;#8220;one day to do things to should be good&amp;#8221;. It&amp;#8217;s much more natural for me to write closer to the language I think and communicate than it is to translate it to assertion-speak. I want to communicate in my code more closely to how I communicate to other people.&lt;/p&gt;

&lt;p&gt;While the term BDD is a few years old it takes a while for dialogue to happen, and understanding to occur. I&amp;#8217;m sure a lot of people hear about BDD, read about it from Dan North&amp;#8217;s &lt;a href='http://dannorth.net/introducing-bdd'&gt;Introducing BDD&lt;/a&gt;. BDD started as a way to explain and better understand BDD, but what I think was realized was that it was much more than simply TDD.&lt;/p&gt;

&lt;p&gt;Many tools are emerging which claim to support BDD-style development. It&amp;#8217;s important to note that BDD isn&amp;#8217;t the tool. You can have many tools support BDD style development in different ways and to different degrees. Although a good tools makes any process easier, what makes BDD is the mindset you have and how you go about writing software. Certain tools emerged with this in mind and are thus labeled BDD tools. Cucumber, RSpec, and JBehave are some examples.&lt;/p&gt;

&lt;p&gt;The article mistakingly sheds Cucumber in the light of solely driving the design of code and suggests its a bad tool to do that. Of course it is! It is not a tool intended to drive the design of your code from a low level. It is to communicate in plain text how the application should behave. The plain text is something that is business readable, something that adds value not at the code design level, but at a higher level: communication and understanding requirements!&lt;/p&gt;

&lt;p&gt;Cucumber is equivalent to a high level integration test for those of you who come from a testing background. It runs the entire application (or whatever can be reached through automation, different types of systems have different limitations). It works in combination with a tool used to drive out the design of your application using lower level code examples. For example, RSpec.&lt;/p&gt;

&lt;p&gt;The #1 output of BDD is a working application that is behaving as expected. In addition to that you have an application-level regression suite in which you can run against the code base at any time. You also end up with smaller, more focused code examples which provide regression against isolated behaviour of the system.&lt;/p&gt;

&lt;p&gt;Combined, you end up with documentation at two critical aspects. The first is business readable scenarios that the system supports. The second is developer documentation made up of the lower level code examples. Since these are often written more clearly than assert-style syntax it&amp;#8217;s easy to produce human readable behaviour specifications for focused pieces of behaviour. And in the end you have a repeatable process which allows you to confidently produce the working software.&lt;/p&gt;

&lt;p&gt;I also don&amp;#8217;t see where UML to BDD comparisons make any sense. UML is a modeling language. BDD is more of an approach or methodology. A more accurate comparison would be plain text scenarios vs. UML. Although that makes little sense as a comparison because UML is not something you can give a non technical person to write, read, and edit.&lt;/p&gt;

&lt;p&gt;BDD by itself doesn&amp;#8217;t fix any problems. It provides an approach which focuses on behaviour first. To me, there&amp;#8217;s no point in building a low level library if you&amp;#8217;re not aware what higher level problem you&amp;#8217;re solving or objective you&amp;#8217;re adding value to. This boils down to a person still has to &amp;#8220;do the work&amp;#8221; to make it successful.&lt;/p&gt;

&lt;p&gt;At the end of the day though I cannot speak for anyone else except myself. Shifting my focus on behaviour rather than &amp;#8220;tests&amp;#8221; led me to write better code examples. Often times I would write less of these because I was writing better examples. It&amp;#8217;s also helped improve communication between myself and my team, customers, and other developers. BDD may evolve into something else, or perhaps a new perspective will come around that will take the world by storm. I am all about continuous learning and improvement. And I invite any ideas Mr. Lally or anyone else brings to the table.&lt;/p&gt;

&lt;p&gt;Also, BDD never claimed to be THE answer. Any process that claims to be THE answer will surely not be THE answer for everyone in all situations. BDD has been an answer for many people though and as of now it will continue to be an answer for me in how I work.&lt;/p&gt;

&lt;p&gt;A good resource worth checking out for BDD, it&amp;#8217;s philosophy, and how to apply it in practice is &lt;a href='http://www.pragprog.com/titles/achbd/the-rspec-book'&gt;The RSpec Book&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>rspec/cucumber ML email etiquette</title>
   <link href="http://www.continuousthinking.com/2009/05/09/rspec-cucumber-ml-email-etiquette.html"/>
   <updated>2009-05-09T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/05/09/rspec-cucumber-ml-email-etiquette</id>
   <content type="html">&lt;p&gt;&lt;a href='http://blog.aslakhellesoy.com/'&gt;Aslak Hellesoy&lt;/a&gt; recently &lt;a href='http://www.ruby-forum.com/topic/186233'&gt;requested&lt;/a&gt; on the rspec/cucumber mailing list the other day that folks stop top posting. His words:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I find it really hard to follow conversations that use top posting (http://en.wikipedia.org/wiki/Posting_style). If you have a [Cucumber] topic, please respond with inline comments. And use plain text email - not html.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I agree with Aslak&amp;#8217;s request for the most part. There are times when top posting is perfectly acceptable, but those are too often blurred by the countless times where people are just plain lazy. While most of the replies have been rather humorous in response a couple recent replies have the look of actual requests to the community: snip out things not pertaining to your reply and the removal signatures.&lt;/p&gt;

&lt;p&gt;The only part I don&amp;#8217;t agree with is the text email. I&amp;#8217;m sorry, but if you use an email client which can&amp;#8217;t show html, or can&amp;#8217;t not show the html part of an email then you need to find a new email client. I have the feeling Aslak was referring to folks that only send HTML email, void of a plain text part. If that&amp;#8217;s the case I am in full agreement with his request.&lt;/p&gt;

&lt;p&gt;Aslak&amp;#8217;s request was well intended and thoughtfully brought about. I hope the replies stop before there is a giant list of dos and donts, followed by a flamewar that will most likely have a negative impact on such a wonderful community.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>RSpactor, love Cucumber</title>
   <link href="http://www.continuousthinking.com/2009/04/28/rspactor-love-cucumber.html"/>
   <updated>2009-04-28T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/04/28/rspactor-love-cucumber</id>
   <content type="html">&lt;p&gt;If &lt;a href='http://rubyphunk.com/tags/rspactor'&gt;RSpactor&lt;/a&gt; loved Cucumber it&amp;#8217;d be even more amazing. From the &lt;a href='http://github.com/rubyphunk/rspactor/issues/#issuea/1'&gt;ticket&lt;/a&gt; request:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It would be amazing if RSpactor integrated with Cucumber although it would need to be a different than how it currently works with RSpec. Now that Cucumber has tag support I think this good be done in a reasonable way that improved the developer workflow for projects that utilized Cucumber.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example. When I am working on changing how money is managed in my app I know that I want to run the features tagged @accounting. At the start of my work it&amp;#8217;d be great if I could add the @accounting tag to RSpactor so it would run those features after it successfully ran specs.&lt;/p&gt;

&lt;p&gt;Perhaps there would also be a preference setting which auto ran the Cucumber scenarios after specs ran, or one that forced you to manually hit play. Although if you had typed in tags, it the play button would run cucumber with those tags.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Got a better idea for Cucumber integration? Join the discussion! &lt;a href='http://github.com/rubyphunk/rspactor/issues/#issuea/1'&gt;http://github.com/rubyphunk/rspactor/issues/#issue/1&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Managing Client Expectations</title>
   <link href="http://www.continuousthinking.com/2009/04/08/managing-client-expectations.html"/>
   <updated>2009-04-08T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/04/08/managing-client-expectations</id>
   <content type="html">&lt;p&gt;Managing client expectations is simple, but like most things simple&amp;#8211;it&amp;#8217;s very hard to do, do right, and do consistently. I think this is a common problem in today&amp;#8217;s web development companies. The industry has a lot of young, creative, and smart people building companies with little to no experience in customer relations. For every person who is naturally gifted or good at managing client expectations there are probably several more people who just don&amp;#8217;t get it. And the worst part, is that they probably aren&amp;#8217;t aware of the fact that they don&amp;#8217;t get it.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m one of those young, creative, and somewhat smart people in the industry trying to build a &lt;a href='http://www.mutuallyhuman.com'&gt;company&lt;/a&gt; in the web industry, but this is an issue that has been nagging me for months, and it&amp;#8217;s to the point where I feel like it needs to be shouted from the mountain tops (although this blog is probably more like a anthill). It may not be the best business decision on my part since it encourages competing companies to become better. If they do it will make us humans work that much harder.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m sorry to say it, but few web development companies seem to do a good job of development and a good job of managing client expectations. Maybe your company is good at development, but stinks at managing client expectations. Or maybe it&amp;#8217;s the other way around and you are great with the customer, but your team is a bunch of junior developers who crank out crap. Oddly enough, if your company falls into the latter you have a much better chance of being successful and surviving than the former.&lt;/p&gt;

&lt;p&gt;Before look at some of the effects of managing (and failing to manage) client expectations let&amp;#8217;s start with a simple definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Managing client expectations is the ability communicate proactively with the client in a reasonable and realistic manner that allows them to take ownership of decisions that may affect their project or business.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Managing client expectations is about communicating honestly, openly, and often with the client. It requires informing them of things that have the potential to impact their business or their project. I use the term &lt;em&gt;proactive&lt;/em&gt; in the definition because you&amp;#8217;re not doing it right if you do something and than communicate after the fact. Heck, doing that is like this the plumber who came to your house and failed to manage your expectations:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A plumber comes to your house to fix your toilet. At first glance it looks like it&amp;#8217;ll take an hour to do so you set aside $100 on the counter to cover the cost and leave so the plumber can work in peace. While working the plumber discovers a much bigger plumbing problem. He&amp;#8217;s really in the zone though, so rather than calling you he just does what&amp;#8217;s necessary to fix the issue. You get home later in the day, and on the counter you see your $100. Next to it is an invoice for $2,200 and a note that reads: &lt;em&gt;I ran into a bigger problem, but I was really in the zone so I replaced the plumbing in the basement because it would have had to have been done.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Do you feel the plumber did a good job of managing your expectations? Would you hire that plumber back? Would you pay the bill? I would answer three hell nos. Yet, many web developers and young web entrepreneurs find this perfectly acceptable and they wouldn&amp;#8217;t think twice about doing it. To them it&amp;#8217;s just how you move a project along its merry little way.&lt;/p&gt;

&lt;p&gt;For folks who aren&amp;#8217;t aware this is a problem&amp;#8211;_it is a problem and you should stop doing it_. For folks who do it and know they do it, &lt;em&gt;wake up&lt;/em&gt;, its unhealthy for your client, you, and your business.&lt;/p&gt;

&lt;p&gt;I think it&amp;#8217;s universal knowledge that finding a new client is more costly then keeping a client. Every time you interact with a client you have a chance to increase or decrease your likelihood of keeping them as a client. When you manage their expectations well you will most likely keep them. Here are three general reasons why:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;build a healthy relationship&lt;/li&gt;

&lt;li&gt;build trust&lt;/li&gt;

&lt;li&gt;empower the client, giving them ownership&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='positive_effects_of_managing_client_expectations'&gt;Positive effects of managing client expectations&lt;/h2&gt;

&lt;h3 id='build_a_healthy_relationship'&gt;Build a healthy relationship&lt;/h3&gt;

&lt;p&gt;Every time you interact with a client you have the ability to build a slightly better relationship. Setting clear expectations with the client with good solid communication strengthens the bond between you and your customer. Customers who have a healthy relationship w/their suppliers are not likely to jump ship.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A new developer joins your team. Every time you work with him you notice he takes the time do things right rather than just quick. He also seem to ask questions and raise questions at all the right times. You find yourself comfortable working with him and before you know if you even think that you do better when working with him. When the developer&amp;#8217;s 90 day review comes up you&amp;#8217;re first to speak up and ask the team to keep him.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id='build_trust'&gt;Build trust&lt;/h3&gt;

&lt;p&gt;Part of building a healthy relationship is trust. To me, trust is like trying to level a character in EverQuest. As you build up stats and level you gain a new skill or perhaps a new magic. The higher you level the more your character is capable of. The same is true for the relationship with a client. As you achieve new levels of trust with your client you achieve new capabilities for doing things. Perhaps your client sends you more work. Perhaps your client refers you to his peers and to other companies. Perhaps your client invites you to more business-oriented meetings because he wants you involved in streamlining technical aspects of their business. Perhaps you become the goto shop for your client&amp;#8217;s organization. Without trust this is not possible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A new developer joins your team. After the first few months of working with her you find she is a good, honest, hard working, and capable developer. You build up trust in her as a developer. A potential client comes in and you need to send over a couple developers to help kick off the first Planning Game and do some story estimation. You send her. You know she&amp;#8217;ll do a good job, ask questions, and be honest.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id='empower_the_client_giving_them_ownership'&gt;Empower the client, giving them ownership&lt;/h3&gt;

&lt;p&gt;Empowering the client is something that we really need to do a better job of in our industry. Managing a clients expectations lets the client own the decisions that need to be made that impact their project or business. These decisions are not ours to make, they are our clients. When the client owns the decisions, they own the project, they own the direction of the project. This isn&amp;#8217;t to say we don&amp;#8217;t guide or assist our clients in finding that direction. This is one of the many reasons we are often hired, however, when a client gives you permission to make decisions for them, &lt;em&gt;they made that decision&lt;/em&gt;. When that&amp;#8217;s not the case and we make decisions for the clients we are simply being lazy and bad vendors.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As a developer who practices Behaviour Driven Development I want my customers to own the scenarios that are written to drive the development of an application. The customer may physically write any of the scenarios. I may type them while sitting with the client, or during a phone call, but I am merely being a scribe. They own the scenarios. I never want the customer to feel that scenarios are written simply to translate business speak to technical speak, I want the customer to own the scenarios so its clear to them what they are paying me to build. Doing this empowers the client, it gives them ownership. They are usually much more engaged in the project when this happens.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='negative_effects_of_failing_to_manage_client_expectations'&gt;Negative effects of failing to manage client expectations&lt;/h2&gt;

&lt;p&gt;Now, when you don&amp;#8217;t manage client expectations you can have the opposite effect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hurt the relationship&lt;/li&gt;

&lt;li&gt;lose trust&lt;/li&gt;

&lt;li&gt;empower yourself, taking ownership away from the client&lt;/li&gt;

&lt;li&gt;increase the risk you negatively impact the clients business&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='hurt_the_relationship'&gt;Hurt the relationship&lt;/h3&gt;

&lt;p&gt;Not managing client expectations hurts the relationship. You may get away with it once, twice, or even three times, but sooner or later you will guess wrong and your customer will be ticked off. This is usually when they start looking for a new vendor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Your customer has a feature they want added. You estimate 50 hours. It ends up taking you 110 hours. You don&amp;#8217;t tell the client, you simply send them a bill. The customer is ticked, he asks that you stop working until the bill can be addressed. He wants to do a phone call with you to dispute the bill. Your customer is not happy.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id='lose_trust'&gt;Lose trust&lt;/h3&gt;

&lt;p&gt;Losing trust is a part of hurting a relationship, but trust is so important on its own. Most companies want to be a partner with the client. They want the client to leverage their expertise in solving a problem. If we don&amp;#8217;t have that kind of relationship we lack the trust required for the customer to to utilize us in that way. Every time we fail to manage a client&amp;#8217;s expectations we lose a level of trust. At some point its gone, and we&amp;#8217;re out of the picture.&lt;/p&gt;

&lt;h3 id='empower_yourself_taking_ownership_away_from_the_client'&gt;Empower yourself, taking ownership away from the client&lt;/h3&gt;

&lt;p&gt;Making decisions that affect the client&amp;#8217;s project or business are a big no no. It takes ownership away from the client and only empowers yourself, but that empowerment only lasts a short while. You may have won the battle, but you will surely lose the war. First of all, decisions that impact the client&amp;#8217;s project or business are theirs to make&amp;#8211;not yours. Sometimes an emergency arises, the app is down! Chaos ensues! What to do? One of the very first things you do is call your client and give them the ability to say &amp;#8220;no, don&amp;#8217;t fix it&amp;#8221;. Even though that answer may be highly unlikely, its not your decision to make, unless you have an arrangement with your client to make those decisions. Perhaps you have an agreement which covers what to do in those circumstances. If you do, more power to you. If you don&amp;#8217;t, you may want to consider getting one.&lt;/p&gt;

&lt;p&gt;Maybe you&amp;#8217;re wondering what happens if you can&amp;#8217;t reach the client? Do you wait to fix it until they call you back? I would say that depends on the nature of the issue. At minimum you should leave a voicemail and send a quick email, both which have your contact information. Doing this allows you to do everything reasonably possible to contact the client of the issue. And it may add 30 seconds to 2 minutes of overhead. This is usually reasonable. However, this is one of those times where it depends based on the relationship you have with your client. Fixing the issue first and responding later may be acceptable based on your arrangement. My belief is that if that&amp;#8217;s not your arrangement than you should be contacting your client. Well, you should be contacting them anyways&amp;#8211;that&amp;#8217;s just being a good vendor.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The client&amp;#8217;s site goes down. You get a call from one of their programmers (not a decision maker or gold owner) about it. You log in, evaluate, and decide to tackle it. Some time later you get it fixed! Woot! Invigorating, wasn&amp;#8217;t it? Then you send a bill to the client. The person who pays the bill and has decision making power for paying the bill is very upset. Why a $1,200 bill? And why wasn&amp;#8217;t he made aware of it? He heard from his one of his programmers their was an issue, but that it got resolved, why is the vendor sending a bill?!!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id='increasing_risk_negatively_impacts_the_clients_business'&gt;Increasing risk negatively impacts the clients business&lt;/h3&gt;

&lt;p&gt;Every time you make a reckless decision on behalf of your client without having some kind of prior arrangement or relationship in place you increase the risk that you will negatively impact their project or business. These are risks that are not yours to own, they are your clients. They always deserve the ability to say &amp;#8220;no&amp;#8221; even if it seems highly unlikely. The only time they shouldn&amp;#8217;t have that option is if someone&amp;#8217;s physical health is in immediate danger, but I haven&amp;#8217;t seen any webapps running medical equipment, handling stop lights, or coordinating the release of water at Hoover Dam.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>BDD w/Rails Class</title>
   <link href="http://www.continuousthinking.com/2009/04/03/bdd-w-rails-class.html"/>
   <updated>2009-04-03T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/04/03/bdd-w-rails-class</id>
   <content type="html">&lt;p&gt;Shortly after RailsConf and while &lt;a href='http://www.pragprog.com/titles/achbd/the-rspec-book'&gt;The RSpec Book&lt;/a&gt; is hitting the printers I&amp;#8217;m going to be teaching a BDD w/Rails class with the amazing guys at &lt;a href='http://www.collectiveidea.com'&gt;Collective Idea&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://mutuallyhuman.com/2009/4/3/bdd-with-rails-class'&gt;Official announcement&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://ideafoundry.info/behavior-driven-development'&gt;Offical Course&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope to see you there!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Scenario Observation</title>
   <link href="http://www.continuousthinking.com/2009/03/20/scenario-observation.html"/>
   <updated>2009-03-20T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/03/20/scenario-observation</id>
   <content type="html">&lt;p&gt;One of the hardest things about being the developer and the scenario writer is that we&amp;#8217;re in the thick of it. Once we get something written down we want to get it to work and then move on. This may involve copy and pasting part of an existing scenario to just get the job done. We get antsy.&lt;/p&gt;

&lt;p&gt;One of the benefits of having the customer (or someone else) write the scenario is that we get to be the critic and not the author. We can focus on the scenario and ask questions like: does it read well? Is it doing too much? Is doing little? Can I understand its intent? etc. etc.&lt;/p&gt;

&lt;p&gt;When working with a pair our pair should really challenge us to write good, communicating, intention revealing scenarios (just like they should be doing with code). This can be hard when we are working solo because we may just be staring at the screen for too long, and we can&amp;#8217;t see the forest for the trees. If that&amp;#8217;s the case grab someone else for a quick review, even if it&amp;#8217;s after you finish implementing the scenario. Refactoring applies to scenarios to.&lt;/p&gt;

&lt;p&gt;Scenarios are like code, if we don&amp;#8217;t tend them well, they will grow messy and hard to maintain. We are best served to spend a little time upfront to keep them tidy rather than wait until we have hundreds of steps that don&amp;#8217;t do a good job of communicating and require people to have to read through all of the step definitions to figure it out.&lt;/p&gt;

&lt;p&gt;Go forth and code! ;)&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions 0.8.2 released</title>
   <link href="http://www.continuousthinking.com/2009/03/17/ar-extensions-0-8-2-released.html"/>
   <updated>2009-03-17T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2009/03/17/ar-extensions-0-8-2-released</id>
   <content type="html">&lt;p&gt;ar-extensions 0.8.2 is released. This release fixes compatibility issues with Rails 2.3.1 and Rails 2.3.2. It should show up soon at a rubygems mirror near you.&lt;/p&gt;

&lt;p&gt;Thanks to Stephen Heuer, Glenn Rempe, and Michael Murray.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem install ar-extensions -v 0.8.2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>CachingPresenter has moved</title>
   <link href="http://www.continuousthinking.com/2009/02/14/cachingpresenter-has-moved.html"/>
   <updated>2009-02-14T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2009/02/14/cachingpresenter-has-moved</id>
   <content type="html">&lt;h2 id='what_is_cachingpresenter'&gt;What is CachingPresenter?&lt;/h2&gt;

&lt;p&gt;CachingPresenter is a very small presenter pattern implementation in Ruby. In short, the presenter pattern is a technique used to separate presentation logic (aka display logic or view logic) from domain logic and from the view templates themselves. There are a number of reasons this pattern is beneficial when used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it stops presentation logic from creeping into domain objects and muddying up their implementation and their business logic&lt;/li&gt;

&lt;li&gt;it stops unnecessary logic from creeping into the views themselves which should be as simple, flexible, and changeable as possible&lt;/li&gt;

&lt;li&gt;it allows you to organize presentation logic in better ways than simply maintaining helper modules that are included everywhere&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CachingPresenter seems to be benefit most web-based projects where there is benefit from a separation between the view templates and corresponding presentation logic. It works superbly with Rails, but it is not dependent on Rails. You can use it for any ruby project, web-based or not.&lt;/p&gt;

&lt;h2 id='recent_changes'&gt;Recent Changes&lt;/h2&gt;

&lt;h3 id='requiring_is_removed_in_favor_of_accepts'&gt;:requiring is removed in favor of :accepts&lt;/h3&gt;

&lt;p&gt;The :requiring option has been removed in favor of :accepts. This allows all additional arguments to be optional. For example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;NinjaPresenter&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;CachingPresenter&lt;/span&gt;
  &lt;span class='n'&gt;presents&lt;/span&gt; &lt;span class='ss'&gt;:ninja&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:accepts&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:sword&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:agility&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='c1'&gt;# supplying all options&lt;/span&gt;
&lt;span class='n'&gt;ninja&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;NinjaPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='ss'&gt;:ninja&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Ninja&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:sword&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Sword&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:agility&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;100&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;percent&lt;/span&gt;

&lt;span class='c1'&gt;# supplying only some options, previously this would yell at you for not supplying :agility&lt;/span&gt;
&lt;span class='n'&gt;ninja&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;NinjaPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='ss'&gt;:ninja&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Ninja&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:sword&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='no'&gt;Sword&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='caches_hashreader_methods'&gt;Caches hash-reader methods&lt;/h3&gt;

&lt;p&gt;If a presenter defines the #[] method or if what is being presented on responds to the&lt;/p&gt;

&lt;h1 id='_methods_all_calls_to_the_presenter_using_hashlike_accessors_will_successfully_be'&gt;[] methods all calls to the presenter using hash-like accessors will successfully be&lt;/h1&gt;

&lt;p&gt;cached. Previously this would die.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;SamuraiPresenter&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;CachingPresenter&lt;/span&gt;
  &lt;span class='n'&gt;presents&lt;/span&gt; &lt;span class='ss'&gt;:samurai&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:accepts&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:stats&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;

  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='p'&gt;\&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='p'&gt;\&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;key&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
     &lt;span class='vi'&gt;@stats&lt;/span&gt;&lt;span class='p'&gt;\&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='n'&gt;key&lt;/span&gt;&lt;span class='p'&gt;\&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='n'&gt;samurai&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;SamuraiPresenter&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;new&lt;/span&gt; &lt;span class='ss'&gt;:samurai&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:stats&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='ss'&gt;:dexterity&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='mi'&gt;80&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;percent&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
&lt;span class='n'&gt;samurai&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:dexterity&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='c1'&gt;# =&amp;gt; 80.percent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 id='does_not_try_to_cache_writer_methods'&gt;Does not try to cache writer methods&lt;/h3&gt;

&lt;p&gt;Usually you don&amp;#8217;t use writer methods on presenters, but every now and then there is a good reason. Previously, CachingPresenter would completely fail if you writer to define an writer method, now it doesn&amp;#8217;t. And it will successfully not be cached.&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='k'&gt;class&lt;/span&gt; &lt;span class='nc'&gt;SamuraiPresenter&lt;/span&gt; &lt;span class='o'&gt;&amp;lt;&lt;/span&gt; &lt;span class='no'&gt;CachingPresenter&lt;/span&gt;
  &lt;span class='n'&gt;presents&lt;/span&gt; &lt;span class='ss'&gt;:samurai&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='ss'&gt;:accepts&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:stats&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;

   &lt;span class='c1'&gt;# previously this line would have failed miserably&lt;/span&gt;
  &lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;sword&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;sword&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;

&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='questions__docs__contact__etc'&gt;Questions / Docs / Contact / Etc&lt;/h2&gt;

&lt;p&gt;Any questions, checkout the &lt;a href='http://github.com/mhs/caching_presenter'&gt;github page&lt;/a&gt; and its corresponding &lt;a href='http://wiki.github.com/mhs/caching_presenter/'&gt;wiki&lt;/a&gt; . If all else fails let me know, zach dot dennis at gmail dot com&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions 0.8.1 released</title>
   <link href="http://www.continuousthinking.com/2009/02/10/ar-extensions-0-8-1-released.html"/>
   <updated>2009-02-10T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2009/02/10/ar-extensions-0-8-1-released</id>
   <content type="html">&lt;p&gt;ar-extensions 0.8.1 is released. This is primarily a bug fix release to ensure it works successfully with Rails 2.2.2. Here are the changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fixed issue in http://zdennis.lighthouseapp.com/projects/14379/tickets/14-join-table-conditions-broken&lt;/li&gt;

&lt;li&gt;Updated usage of Inflector to point to ActiveSupport::Inflector&lt;/li&gt;

&lt;li&gt;Fixed bug where finder conditions which use arext-suffixed keys and normal field keys would fail when using a conditions hash. (Gabe da Silveira)&lt;/li&gt;

&lt;li&gt;added timestamps options to not automatically add timestamps even if record timestamps is disabled in ActiveRecord::Base (Thibaud Guillaume-Gentil)&lt;/li&gt;

&lt;li&gt;Updated to use alias_method_chain so that multiple aliased finders remain intact (Marcus Crafter)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may take a little while for the gem to show up in the rubygem mirrors. Thanks to everyone who contributed!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Long time, no see</title>
   <link href="http://www.continuousthinking.com/2009/01/06/long-time-no-see.html"/>
   <updated>2009-01-06T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2009/01/06/long-time-no-see</id>
   <content type="html">&lt;p&gt;It&amp;#8217;s been a long while since I&amp;#8217;ve written. It&amp;#8217;s been more due to time constraints than anything. Last spring I joined &lt;a href='http://www.mutuallyhuman.com'&gt;Mutually Human Software&lt;/a&gt; full-time, then in the early summer spoke at RailsConf, and then in the late summer started working on &lt;a href='http://www.pragprog.com/titles/achbd/the-rspec-book'&gt;The RSpec Book&lt;/a&gt;. 2008 was a very busy year all the while spearheading a project for the state of Nebraska.&lt;/p&gt;

&lt;p&gt;I have a lot of rough draft articles I&amp;#8217;d like to clean up and push out, as well as finish Annex &amp;#8211; the soon-to-be 1.0 release of ar-extensions. In the meantime I am going to be pushing some things out to the Mutually Human &lt;a href='http://www.mutuallyhuman.com/blog'&gt;blog&lt;/a&gt; like the recent post on &amp;#8220;Using custom &lt;a href='http://mutuallyhuman.com/2009/1/6/using-custom-activerecord-events-callbacks'&gt;ActiveRecord events/callbacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ve also just wrapped up the year with finishing a project for one our clients. If you need assistance with an existing project, or are looking to get a new project off the ground, or are interested in training/consulting we do that over at Mutually Human. Our specialty is web applications. Be sure to drop us a line at zdennis at mutuallyhuman dot com.&lt;/p&gt;

&lt;p&gt;Stay tuned, this is going to be an eventful Spring both at continuousthinking and MHS,&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions 0.8.0, forgot to mention</title>
   <link href="http://www.continuousthinking.com/2008/08/16/ar-extensions-0-8-0-forgot-to-mention.html"/>
   <updated>2008-08-16T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/08/16/ar-extensions-0-8-0-forgot-to-mention</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Update: ar-extensions is no longer maintained for Rails 3.x and above. Please see &lt;a href='http://github.com/zdennis/activerecord-import/tree/master'&gt;activerecord-import&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I forgot to mention that ar-extensions no longer loads adapter specific functionality by itself. You need to tell it what you want. For example if you want to load import functionality for MySQL you&amp;#8217;d have to require the right files, like so:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='ruby'&gt;&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ar-extensions/adapters/mysql&amp;#39;&lt;/span&gt;
&lt;span class='nb'&gt;require&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ar-extensions/import/mysql&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Sorry about that.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions 0.8.0 released!</title>
   <link href="http://www.continuousthinking.com/2008/08/06/ar-extensions-0-8-0-released.html"/>
   <updated>2008-08-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/08/06/ar-extensions-0-8-0-released</id>
   <content type="html">&lt;p&gt;ar-extensions 0.8.0 is finally released! All known bugs and compatibility issues with Rails 2.1.0 have been resolved.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;li&gt;
&lt;li&gt;0 does not work with the latest Rails edge due to some additional features on edge that weren&amp;#8217;t in 2.1.0&lt;/li&gt;
&lt;/li&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;li&gt;
&lt;li&gt;0 should not be used with Rails 2.0.2 or below&lt;/li&gt;
&lt;/li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any feature requests or bugs please report them on &lt;a href='http://zdennis.lighthouseapp.com/projects/14379-ar-extensions'&gt;lighthouse&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='installing'&gt;Installing&lt;/h2&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;gem install ar-extensions
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h2 id='oracle_and_postgresql_users'&gt;Oracle and PostgreSQL users&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;re using ar-extensions 0.7.0 with Oracle or PostgreSQL I am very interested to find out if 0.8.0 works fine. I don&amp;#8217;t have Oracle, and I&amp;#8217;m not a PostgreSQL user. If you&amp;#8217;re interested in running the test suite against one of those databases please let me know.&lt;/p&gt;

&lt;p&gt;Thanks for your patience and enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>cheat --execute</title>
   <link href="http://www.continuousthinking.com/2008/08/01/cheat-execute.html"/>
   <updated>2008-08-01T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/08/01/cheat-execute</id>
   <content type="html">&lt;p&gt;I hate having to continuously lookup the steps to install things every few weeks. The cheat gem works for most things to find installation instructions relatively quickly, but sometimes I just want to install something, not necessarily have to search through lines of example usage to find the installation instructions. Enter two new options for the cheat gem: dash x and dash dash execute. It&amp;#8217;s simple. For example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;&lt;span class='nb'&gt;cd&lt;/span&gt; /some/dummy/rails/project
cheat install_rspec_rails -x

  &lt;span class='c'&gt;# This is to install the latest rspec/rspec-rails into &lt;/span&gt;
  &lt;span class='c'&gt;# a rails project. &lt;/span&gt;
  script/plugin install git://github.com/dchelimsky/rspec.git
  script/plugin install git://github.com/dchelimsky/rspec-rails.git
  script/generate rspec

Would you like to execute the above sheet? &lt;span class='o'&gt;(&lt;/span&gt;Y/N&lt;span class='o'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I&amp;#8217;ve sent defunkt a pull request on github, I hope it includes the change. Until then, the change is only on my &lt;a href='http://github.com/zdennis/cheat/tree/master'&gt;fork&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install do the following:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='bash'&gt;git clone git://github.com/zdennis/cheat.git
&lt;span class='nb'&gt;cd &lt;/span&gt;cheat
rake package
sudo gem install pkg/cheat-1.2.2.gem
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Enjoy,&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions, Rails 2.x followup</title>
   <link href="http://www.continuousthinking.com/2008/07/18/ar-extensions-rails-2-x-followup.html"/>
   <updated>2008-07-18T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/07/18/ar-extensions-rails-2-x-followup</id>
   <content type="html">&lt;p&gt;&lt;strong&gt;Update: ar-extensions is no longer maintained for Rails 3.x and above. Please see &lt;a href='http://github.com/zdennis/activerecord-import/tree/master'&gt;activerecord-import&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First things first, ar-extensions moved to Lighthouse and Github. So please no more tickets or patches on rubyforge. I&amp;#8217;ll close out or move over the ones on rubyforge that currently reside there.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ar-extensions at &lt;a href='http://zdennis.lighthouseapp.com/projects/14379-ar-extensions/overview'&gt;Lighthouse&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;ar-extensions at &lt;a href='http://github.com/zdennis/ar-extensions/tree/master'&gt;GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, the fun stuff.&lt;/p&gt;

&lt;h3 id='arextensions_and_rails_2x_compability'&gt;ar-extensions and Rails 2.x compability&lt;/h3&gt;

&lt;p&gt;For the most part ar-extensions 0.7.0 (and below) is not compatible with Rails 2.0.x and 2.1. The import functionality works, but ar-extensions will bork on some edge cases of using ActiveRecord::Base.find methods. It won&amp;#8217;t return the wrong value, it will simply raise an exception. So if you&amp;#8217;re using ar-extensions in your Rails 2.x app, the app itself will probably bork (and I realize that you probably already know this). If you&amp;#8217;re using the import functionality in isolation then you should be fine.&lt;/p&gt;

&lt;p&gt;Some of the loading issues with ar-extensions that people had are due to ar-extensions being loaded during the time that Rails goes through the loading process (if you put require &amp;#8216;ar-extensions&amp;#8217; in config/environments/development.rb, test.rb or production.rb). You can get around this by moving if after the Rails::Initializer.run block in your config/environment.rb file.&lt;/p&gt;

&lt;p&gt;Tonight I made several commits to get ar-extensions closer to Rails 2.1.0 compatibility. HEAD right now is Rails 2.0.1 compatible, but not 2.0.2 or 2.1.0 compatible. As soon as ar-extensions is compatible I will release 0.8.0. I am hoping for it to be released within the next few days. And by compatible I mean that ar-extensions not only passes its own tests, but it also doesn&amp;#8217;t break any of ActiveRecord&amp;#8217;s tests.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Using Seed Data with RSpec Stories</title>
   <link href="http://www.continuousthinking.com/2008/07/17/using-seed-data-with-rspec-stories.html"/>
   <updated>2008-07-17T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/07/17/using-seed-data-with-rspec-stories</id>
   <content type="html">&lt;p&gt;Yesterday I needed to introduce seed data into our application. In order for our story suite to continue to run I needed to populate seed data into the testing environment when the stories ran. I didn&amp;#8217;t want to use the production seed data in my test environment, but I wanted to keep things simple. I am already using using &amp;#8220;seed_fu&amp;#8221;:http://github.com/mbleigh/seed-fu/tree from Michael Bleigh to handle the seed data for production. Why not leverage it for stories as well?&lt;/p&gt;

&lt;p&gt;I made a minor modification to the task to support passing in an argument to rake or setting an environment variable so you can load &amp;#8220;fixtures&amp;#8221; from a different directory. In my &amp;#8220;stories/helper.rb&amp;#8221; file I have added near the top:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;system &amp;quot;rake db:seed FIXTURE_PATH=stories/fixtures&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This loads the seed data from &amp;#8220;RAILS_ROOT/stories/fixtures&amp;#8221;. Here&amp;#8217;s the modified seed_fu rake task:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;namespace :db do
  desc &amp;quot;Loads seed data from db/fixtures for the current environment.&amp;quot;
  task :seed =&amp;gt; :environment do
    fixture_path = ENV[&amp;quot;FIXTURE_PATH&amp;quot;] ? ENV[&amp;quot;FIXTURE_PATH&amp;quot;] : &amp;quot;db/fixtures&amp;quot;
    Dir[File.join(RAILS_ROOT, fixture_path, &amp;#39;\*.rb&amp;#39;)].sort.each { |fixture| 
      puts &amp;quot;\n== Seeding from #{File.split(fixture).last} &amp;quot; + \
         (&amp;quot;=&amp;quot; * (60 - (17 + File.split(fixture).last.length)))
      load fixture 
      puts &amp;quot;=&amp;quot; * 60 + &amp;quot;\n&amp;quot;
    }
    Dir[File.join(RAILS_ROOT, fixture_path, RAILS_ENV, &amp;#39;\*.rb&amp;#39;)].sort.each { |fixture| 
      puts &amp;quot;\n== [#{RAILS_ENV}] Seeding from #{File.split(fixture).last} &amp;quot; + \
          (&amp;quot;=&amp;quot; * (60 - (20 + File.split(fixture).last.length + RAILS_ENV.length)))
      load fixture 
      puts &amp;quot;=&amp;quot; * 60 + &amp;quot;\n&amp;quot;
    }
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After this my seed data was resembling the typical format:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ExpenseCategory.transaction do
  ExpenseCategory.seed(:object_code) do |s|
     s.object_code = &amp;quot;1234&amp;quot;
     s.name = &amp;quot;Foo&amp;quot;
  end

  ExpenseCategory.seed(:object_code) do |s|
     s.object_code = &amp;quot;1235&amp;quot;
     s.name = &amp;quot;Bar&amp;quot;
  end

  ExpenseCategory.seed(:object_code) do |s|
     s.object_code = &amp;quot;1236&amp;quot;
     s.name = &amp;quot;Baz&amp;quot;
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And while I like this it&amp;#8217;s a little verbose. So I modified seed_fu to introduce the &lt;em&gt;seed_many&lt;/em&gt; method to consolidate that:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ExpenseCategory.transaction do
  ExpenseCategory.seed_many(:object_code, [
     { :object_code =&amp;gt; &amp;quot;1234&amp;quot;, :name =&amp;gt; &amp;quot;Foo&amp;quot;},
     { :object_code =&amp;gt; &amp;quot;1235&amp;quot;, :name =&amp;gt; &amp;quot;Bar&amp;quot;},
     { :object_code =&amp;gt; &amp;quot;1236&amp;quot;, :name =&amp;gt; &amp;quot;Baz&amp;quot;}
  ])
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It maintains a simple API and highly readable seed data. I&amp;#8217;ve committed this to my fork of seed_fu, and am hoping that Michael accepts the patch and adds it to seed_fu.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The patch for the rake FIXTURE_PATH: &amp;#8220;http://github.com/zdennis/seed-fu/commit/4d391aa214c369f161e37c194b07d49e55312b35&amp;#8221;:http://github.com/zdennis/seed-fu/commit/4d391aa214c369f161e37c194b07d49e55312b35&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;The patch to add the seed_many method: &amp;#8220;http://github.com/zdennis/seed-fu/commit/9f7e8b27b7cb175911474a898ea282771ab2a5c3&amp;#8221;:http://github.com/zdennis/seed-fu/commit/9f7e8b27b7cb175911474a898ea282771ab2a5c3&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions, Rails 2.x</title>
   <link href="http://www.continuousthinking.com/2008/07/17/ar-extensions-rails-2-x.html"/>
   <updated>2008-07-17T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/07/17/ar-extensions-rails-2-x</id>
   <content type="html">&lt;p&gt;There are some issues with ar-extensions and Rails 2.x. At first glance it mainly has to do with load order and what to load. I&amp;#8217;m going to try to post an update or at least instructions tomorrow so people can use ar-extensions with Rails 2.x and up.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m going to be moving the codebase to github and will start work on ar-extensions to get closer to a 1.0 release later this fall. I plan to kick out 0.8 which includes some bug fixes and any Rails 2.x issues as soon as possible.&lt;/p&gt;

&lt;p&gt;I am also looking into using Lighthouse for tickets. Rubyforge&amp;#8217;s bug tracking isn&amp;#8217;t the greatest and apparently there have been tickets there for a while that I had no idea about (sorry about that).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;9 will be the first release where I look to improve and cleanup the codebase. Thanks for your patience.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Any questions, comments or suggestions feel free to let me know. Thanks,&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Refactoring Your Rails Application - Tutorial Content</title>
   <link href="http://www.continuousthinking.com/2008/06/03/refactoring-your-rails-application-tutorial-content.html"/>
   <updated>2008-06-03T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/06/03/refactoring-your-rails-application-tutorial-content</id>
   <content type="html">&lt;p&gt;I posted the tutorial slides and example app as well as the refactoring catalog to OReilly&amp;#8217;s RailsConf 2008 web site, but I couldn&amp;#8217;t tell you where to access it, because I couldn&amp;#8217;t find the public download links. So here are the links to the material on this server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;Rails Refactoring Catalog from the tutorial &amp;#8220;:http://www.continuousthinking.com/railsconf2008/refactoring_your_rails_application_catalog.pdf&lt;/li&gt;

&lt;li&gt;&amp;#8220;Refactoring Your Rails App tutorial slides&amp;#8221;:http://www.continuousthinking.com/railsconf2008/refactoring_your_rails_app_slides.pdf&lt;/li&gt;

&lt;li&gt;&amp;#8220;Refactoring Your Rails App example app from the tutorial&amp;#8221;:http://www.continuousthinking.com/railsconf2008/example_app.zip&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The example app is also available from github if you&amp;#8217;d like to download the revisions and the different branches used for the tutorial&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://github.com/zdennis/strac/&amp;#8221;:http://github.com/zdennis/strac/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Just refer to the refactoring branch and any other branch with &amp;#8220;refactoring&amp;#8221; in the name.&lt;/p&gt;

&lt;p&gt;The official project which the example app is based on is called Strac. The official github repository can be found at &amp;#8220;http://github.com/mvanholstyn/strac/&amp;#8221;:http://github.com/mvanholstyn/strac/&lt;/p&gt;

&lt;p&gt;If you have any questions, comments or feedback on any of the material or the example app feel free to email me at zach dot dennis at gmail dot com.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>RailsConf: RYRA, how'd it go?</title>
   <link href="http://www.continuousthinking.com/2008/05/29/railsconf-ryra-how-d-it-go.html"/>
   <updated>2008-05-29T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/05/29/railsconf-ryra-how-d-it-go</id>
   <content type="html">&lt;p&gt;In regards to the tutorial on Refactoring Your Rails Application, how you felt the talk went?&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll post more later with slides and links for the downloadable code.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>H.R. 5353 - I called, have you?</title>
   <link href="http://www.continuousthinking.com/2008/05/05/h-r-5353-i-called-have-you.html"/>
   <updated>2008-05-05T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/05/05/h-r-5353-i-called-have-you</id>
   <content type="html">&lt;p&gt;I just got off the phone with my state representative Peter Hoekstra&amp;#8217;s office to urge him to support the Internet Freedom Preservation Act os 2008 &amp;#8211; &amp;#8220;H.R. 5353&amp;#8221;:http://www.opencongress.org/bill/110-h5353/show&lt;/p&gt;

&lt;p&gt;For more information on the issue or to determine who to call and what to say, please see &amp;#8220;www.savetheinternet.com&amp;#8221;:http://www.savetheinternet.com&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Net Neutrality - Save The Internet</title>
   <link href="http://www.continuousthinking.com/2008/05/03/net-neutrality-save-the-internet.html"/>
   <updated>2008-05-03T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/05/03/net-neutrality-save-the-internet</id>
   <content type="html">&lt;p&gt;If you haven&amp;#8217;t heard of &amp;#8220;Net Neutrality&amp;#8221;:http://en.wikipedia.org/wiki/Network_neutrality before, wikipedia describes it as:&lt;/p&gt;

&lt;p&gt;&amp;#8221;&amp;#8230; a principle that is applied to residential broadband networks, and potentially to all networks. A neutral broadband network is one that is free of restrictions on the kinds of equipment that may be attached, on the modes of communication allowed, which does not restrict content, sites or platforms, and where communication is not unreasonably degraded by other communication streams.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Unfortunately there are corporations out there which want to control access, speeds and content available to those connecting to the Internet through their services. Below is an informative 10 minute video (I found it at &amp;#8220;http://www.matthewgood.org/2008/05/net-neutrality/&amp;#8221;:http://www.matthewgood.org/2008/05/net-neutrality/). If you have the time please hit play.&lt;/p&gt;
&lt;div align='center'&gt;
&lt;object height='355' width='425'&gt;
&lt;param name='movie' value='http://www.youtube.com/v/JP_3WnJ42kw&amp;amp;hl=en' /&gt;
&lt;param name='wmode' value='transparent' /&gt;
&lt;embed height='355' src='http://www.youtube.com/v/JP_3WnJ42kw&amp;amp;amphl=en' type='application/x-shockwave-flash' width='425' wmode='transparent' /&gt;
&lt;/object&gt;
&lt;/div&gt;
&lt;p&gt;If this issue concerns checkout &amp;#8220;www.savetheinternet.com&amp;#8221;:http://www.savetheinternet.com . I urge you to spread awareness of the issue and contact your congressman.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Book Review - Ruby on Rails: Enterprise Application Development</title>
   <link href="http://www.continuousthinking.com/2008/05/03/book-review-ruby-on-rails-enterprise-application-development.html"/>
   <updated>2008-05-03T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/05/03/book-review-ruby-on-rails-enterprise-application-development</id>
   <content type="html">&lt;p&gt;I know Slashdot is a busy place, but come on, four months and a book review is still pending, and they don&amp;#8217;t respond to any emails? Anyways here is my review of &amp;#8220;Ruby on Rails: Enterprise Application Development&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Ruby on Rails &amp;#8211; Enterprise Application Development by Elliot Smith and Rob Nichols targets a new niche in the Rails world of published books. Its goal is to connect all of the dots that make up typical Rails development for developers who have been through the tutorials, but wonder &amp;#8216;what do I do next?&amp;#8217;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;p&amp;gt;The focus of this book is breadth and not depth. The authors do a good job of balancing the explanation of essential Rails concepts while letting the reader know when they are approaching a more advanced topic that won&amp;amp;#8217;t be covered in depth.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;Throughout the book the authors follow a fictional, yet realistic scenario in which Rory the IT guy implements a simple web-based contacts management application. Each chapter builds on the previous walking the reader through the whole process of development to production deployment.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;There is no Rails development until Chapter 4, pg 91. The emphasis of the first 90 pages is understanding what Rails is and why you would use it, as well as introducing the problem scenario that will be used throughout the book. This would be a bigger turn off then it was, but the authors made up for this a little walking the reader through installing everything required for Rails development on multiple operating systems.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;Rather then focus on a single platform for development or production the authors use a mixed environment of Ubuntu Linux, &amp;lt;span class=&amp;quot;caps&amp;quot;&amp;gt;OSX&amp;lt;/span&amp;gt; and Windows and a cross platform Eclipse &amp;lt;span class=&amp;quot;caps&amp;quot;&amp;gt;IDE&amp;lt;/span&amp;gt;. They also take the time to walk the reader through installation and setup of each platform as it pertains to Rails development.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;The majority of the development in this book sticks to the functionality included in Rails itself. When it comes to core components of Rails the authors do a great job of covering them: migrations, models, validations, associations, controllers, filters, views and view helpers.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;Plugins are not covered except for acts_as_attachment, which is now deprecated in favor of attachment_fu.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;The only issue I had with the book was with the sections on testing. The authors cover unit and functional testing with the built-in Rails testing framework. Unfortunately, the example tests are horrible and should not appear in production quality code. The sections on testing should only be used to understand how the built-in testing framework works in Rails and not as an example for writing tests. It is too bad that the authors didn&amp;amp;#8217;t cover integration testing either.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;A good thing that did come out of the testing sections in this book is the encouragement for developers to write tests which expose bugs before fixing them. It&amp;amp;#8217;s the only way to ensure you really fixed it.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;Rails 1.2.3 is used throughout the book so any changes, improvements or deprecations in Rails 2.0 aren&amp;amp;#8217;t covered. If the reader follows the book with Rails 1.2.3 they should have no issues walking through and developing the code themselves. If the reader follows the book with Rails 2.0 they should be aware of some of the changes, those can be found at &amp;lt;a href=&amp;quot;http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done&amp;quot;&amp;gt;http://weblog.rubyonrails.org/2007/12/7/rails-2-0-it-s-done&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;The things that stuck out to me were:&amp;lt;/p&amp;gt;


&amp;lt;ul&amp;gt;
&amp;lt;li&amp;gt;view template file naming conventions&amp;lt;/li&amp;gt;
	&amp;lt;li&amp;gt;the verbosity of not having named routes&amp;lt;/li&amp;gt;
	&amp;lt;li&amp;gt;the lack of the db:rollback rake task&amp;lt;/li&amp;gt;
&amp;lt;/ul&amp;gt;


&amp;lt;p&amp;gt;The authors take the time to walk the reader through setting up and using Subversion as an integral part of Rails software development. It also includes setting up and using Apache and Mongrel to serve Rails. As the book moves from development to production deployment the user is shown how to deploy automatically from Subversion to their production server using Capistrano.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;There were a few minor typos and one redundant sentence on page 52. This is considerably lower then other technical books that I&amp;amp;#8217;ve read.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;The only giant red sections marked in my copy are the ones on testing. Take those examples with a grain of salt.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;Overall, the majority of the book is filled with good advice for novice Rails developers like, &amp;amp;#8220;do not wait until your application is built before you create and test the production environment&amp;amp;#8221; and &amp;amp;#8220;involve the end users throughout the process&amp;amp;#8221;.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;If you are a novice Rails developer who understand bits and pieces of Rails this book does a good job of connecting the other dots because the authors take the time to go through the full process of development to production. On the other hand if you have a good grasp on the whole Rails development process you can skip this book.&amp;lt;/p&amp;gt;


&amp;lt;p&amp;gt;A good chapter outline of this book can be found at PACKT&amp;#39;s &amp;lt;a href=&amp;quot;http://www.packtpub.com/Ruby-on-Rails-Enterprise-Application-Open-Source/book&amp;quot;&amp;gt;web site&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;.&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>form_test_helper, select_form update</title>
   <link href="http://www.continuousthinking.com/2008/04/02/form_test_helper-select_form-update.html"/>
   <updated>2008-04-02T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/04/02/form_test_helper-select_form-update</id>
   <content type="html">&lt;p&gt;Revision 71 of form_test_helper includes a bug fix for the select_form method. Previously calling select_form with a block would submit the form. The fix forces you to call submit on the form. So&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# THIS which used to submit the form
form = select_form &amp;#39;trip&amp;#39; do |form|
  form.trip.destination = &amp;quot;bahamas&amp;quot;
end

# WILL NOW LOOK LIKE THIS
form = select_form &amp;#39;trip&amp;#39; do |form|
  form.trip.destination = &amp;quot;bahamas&amp;quot;
end
form.submit&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This doesn&amp;#8217;t affect the usage of submit_form which still acts as expected.&lt;/p&gt;

&lt;p&gt;This will be included in the next release of form_test_helper. Currently trunk for form_test_helper works with Rails 2.0.0 and higher (including today&amp;#8217;s most recent trunk commit).&lt;/p&gt;

&lt;p&gt;The form_test_helper edge docs have been updated as well and can be found &amp;#8220;here&amp;#8221;:http://continuous.rubyforge.org/form_test_helper/rdoc/&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails Ticket #11491</title>
   <link href="http://www.continuousthinking.com/2008/04/01/rails-ticket-11491.html"/>
   <updated>2008-04-01T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/04/01/rails-ticket-11491</id>
   <content type="html">&lt;p&gt;If you have a few minutes, please review and comment on Rails ticket #11491.&lt;/p&gt;

&lt;p&gt;&amp;#8220;http://dev.rubyonrails.org/ticket/11491&amp;#8221;:http://dev.rubyonrails.org/ticket/11491&lt;/p&gt;

&lt;p&gt;In short, it adds the ability for &amp;#8220;render :partial =&amp;gt; some_collection&amp;#8221; to render the correct partial based on each element in some_collection. Currently Rails uses the first element to determine what to render for every element in the collection.&lt;/p&gt;

&lt;p&gt;Thanks in advance,&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>More People != More Progress</title>
   <link href="http://www.continuousthinking.com/2008/03/25/more-people-more-progress.html"/>
   <updated>2008-03-25T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/03/25/more-people-more-progress</id>
   <content type="html">&lt;p&gt;There is a common misconception that the best way to add capacity to a project and reduce its completion date is simple &amp;#8211; just throw more people at it. Although there is some truth in this, it is usually applied at the wrong times and it ends up having a very negative impact on the project.&lt;/p&gt;

&lt;p&gt;This mindset that project development is a series of tasks and that somehow you can just throw people at them and everything will work out is foreign to me, because it won&amp;#8217;t work out &amp;#8211; at least not when it&amp;#8217;s applied in haste.&lt;/p&gt;

&lt;p&gt;Adding value to a project is more than completing tasks. Tasks are not isolated during project development. They are features which build on top of one another. Making good responsible decisions and understanding the code base both technically and conceptually goes a long way to help exploit easier and better ways of implementing features. This also helps keep the code base well factored, which in turn helps teams progress consistently and avoid creating a giant roadblock of technical debt which may have lurked just ahead.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>What is a factory and why FactoryLoader?</title>
   <link href="http://www.continuousthinking.com/2008/03/22/why_factory_loader.html"/>
   <updated>2008-03-22T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/03/22/why_factory_loader</id>
   <content type="html">&lt;p&gt;This statement and question were posted to the &amp;#8220;http://www.gr-ruby.org&amp;#8221;:http://www.gr-ruby.org mailing list as it pertained to the release of FactoryLoader. This post should answer the question &amp;#8220;what is a factory?&amp;#8221; and also provide more insight into what FactoryLoader&amp;#8217;s role is.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; I&amp;#39;ve read over your website, but I still have a lagging question which
&amp;gt; completely blinds my ability to see the usefulness of it: What is a factory?&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A factory is &amp;#8220;a mechanism for encapsulating complex creation logic&amp;#8221; [0].&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example. Let&amp;#8217;s say that you start writing an application that is a project management tool for a business. To start with they need the ability to create Projects. This is no big deal, you have a ProjectsController#create action and it makes your Project by doing something similar to the below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def create
  project = Project.new params[:project]
  if project.save
    flash[:notice] = &amp;quot;successfully created the project&amp;quot;
    render :action =&amp;gt; &amp;quot;create&amp;quot;
  else
    flash[:error] = &amp;quot;failed to create the project&amp;quot;
    render :action =&amp;gt; &amp;quot;new&amp;quot;
  end
end  &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now a few weeks later the customer says that in order to create a project it needs to be assigned a project manager off the bat (the currently logged in user). This is not a very big deal since you have a &amp;#8220;current_user&amp;#8221; already, you just update your controller to look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def create
  project = Project.new params[:project]
  project.manager = current_user
  if project.save
    flash[:notice] = &amp;quot;successfully created the project&amp;quot;
    render :action =&amp;gt; &amp;quot;create&amp;quot;
  else
    flash[:error] = &amp;quot;failed to create the project&amp;quot;
    render :action =&amp;gt; &amp;quot;new&amp;quot;
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A few more weeks go by and your customer says that projects are tied to company budgets and when they are created they need to be automatically assigned to the correct budget based on the type of project. So we update to ProjectsController#create looks like the below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def create
  project = Project.new params[:project]
  project.manager = current_user
  project.budget = Budget.find_by_project_type(project.type)
  if project.save
    flash[:notice] = &amp;quot;successfully created the project&amp;quot;
  else
    flash[:error] = &amp;quot;failed to create the project&amp;quot;
    render :action =&amp;gt; &amp;quot;new&amp;quot;
  end
end  &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Uh oh. There are important business rules being applied in the controller. The controller&amp;#8217;s responsibility is to map an incoming request with an outgoing response and to know high level what the application needs to be doing. It should not know the intimate details of Project creation. Since we&amp;#8217;re implementing the business rules on the controller we can&amp;#8217;t re-use them for anything, unless we make a POST request to ProjectsController#create. This is quite limiting.&lt;/p&gt;

&lt;p&gt;Another option to make them more reusable would be to tuck this away in the Project model itself. Perhaps we add a before_save callback which finds the appropriate budget. Even then we&amp;#8217;ve only moved the budget logic out of the controller and there is still requirement for a Project to have a manager. If we go this route we&amp;#8217;ll be separating two important pieces of how a Project gets constructed from each other. We would have the ProjectsController#create action setting the manager and then a before_save callback on the Project model finding a budget, both of which are required for a Project to be constructed.&lt;/p&gt;

&lt;p&gt;One thought to remedy this would be put everything in the Project model, maybe in a before_save callback or overriding the constructor. But we quickly hit a roadblock because our Project model doesn&amp;#8217;t know about the current user, that is application state and only the model knows about that. We could do something stupid and make the current_user global to the application, but that is a bad decision with pretty bad repercussions.&lt;/p&gt;

&lt;p&gt;It&amp;#8217;d be nice if we had a single object responsible for constructing a Project with these business rules. This is where a ProjectFactory comes into play. The ProjectFactory looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ProjectFactory
  def create(project_attrs, manager)
    project = Project.new project_attrs
    project.budget = Budget.find_by_project_type(project.type)
    project.save!
    project
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And the ProjectsController#create action looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def create
  project = ProjectFactory.create params[:project], current_user
  flash[:notice] = &amp;quot;successfully created the project&amp;quot;
rescue 
  flash[:error] = &amp;quot;failed to create the project&amp;quot;
  render :action =&amp;gt; &amp;quot;new&amp;quot;    
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is pretty straightforward. I just moved some of the lines from the action into the factory. More importantly then just moving line of code is that the act of constructing a valid project (given the customer&amp;#8217;s requirements) isn&amp;#8217;t the responsibility of the Project. The act of constructing a valid project is a process by itself which is important to the customer, so we isolate it in a ProjectFactory.&lt;/p&gt;

&lt;p&gt;This is valuable because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the business logic used to construct a project is in one spot. Should the customer change, add or remove requirements you only have to go to one spot to implement them. Granted if the method signature to this changes you have to go update the spots calling the create method, but you the actual logic for constructing the project isn&amp;#8217;t spread throughout multiple files or classes.&lt;/li&gt;

&lt;li&gt;it promotes reusability (the whole DRY thing), since my ProjectFactory is much more reusable then my ProjectsController.&lt;/li&gt;

&lt;li&gt;it promotes single responsibility&lt;/li&gt;

&lt;li&gt;it provides clearer meaning to the code base because we aren&amp;#8217;t muddying up the controller or the Project model with creation logic&lt;/li&gt;

&lt;li&gt;it makes for easier testing and easier to understand tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The technical implementation of this pattern is mentioned in the GoF book [1]. The value of the pattern as it applies to Domain Driven Design is mentioned in the DDD book by Eric Evans.&lt;/p&gt;

&lt;p&gt;Hopefully that helps clarify what a factory is, by seeing how it is used and some of the value it provides. This relates to the FactoryLoader because sometimes the progression of creation logic is over time.&lt;/p&gt;

&lt;p&gt;For the first few weeks or months of a project you are hardcoding things like &amp;#8220;Project.create&amp;#8221; in multiple spots. When the customer starts introducing requirements for constructing (or updating) a Project you have to go update all of those spots with the same code (violating DRY) or go find all of those spots and refactor them to use a ProjectFactory, and then make a ProjectFactory. It doesn&amp;#8217;t happen all the time, but when it does happen it can be time consuming, frustrating and painful to do.&lt;/p&gt;

&lt;p&gt;What FactoryLoader would do in our example is it give us a ProjectFactory upfront w/o having to write any code. If we used FactoryLoader in the above example our ProjectsController#create action would look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;def create
  project = ProjectFactory.create params[:project]
  if project.save
    flash[:notice] = &amp;quot;successfully created the project&amp;quot;
    render :action =&amp;gt; &amp;quot;create&amp;quot;
  else
    flash[:error] = &amp;quot;failed to create the project&amp;quot;
    render :action =&amp;gt; &amp;quot;new&amp;quot;
  end
end  &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Where the ProjectFactory is created for you by FactoryLoader (you didn&amp;#8217;t create the class, FactoryLoader did dynamically). There&amp;#8217;s only one line that differs between the example that uses the FactoryLoader and the one that doesn&amp;#8217;t.&lt;/p&gt;

&lt;p&gt;Now when the customer starts adding business rules for creating a Project you can create your own ProjectFactory class and implement the customer&amp;#8217;s business rules. FactoryLoader will see that you have provided your own ProjectFactory so it won&amp;#8217;t dynamically create one. Since all of the spots where you create a Project are already using a ProjectFactory they get the changes for free. Overall you get to touch less code for the changes and you get to spend less time refactoring if any refactoring is needed.&lt;/p&gt;

&lt;p&gt;The goal of FactoryLoader is to allow developers the ability to scale to these customer requirements with less pain. The above examples have been quite trivial, hopefully they are clear enough and meaningful enough to express why I wrote FactoryLoader,&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;Zach Dennis http://www.continuousthinking.com&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0 - Domain Driven Design by Eric Evans&lt;/li&gt;

&lt;li&gt;1 - Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson and Vlissides&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Factory Loader</title>
   <link href="http://www.continuousthinking.com/2008/03/18/factory-loader.html"/>
   <updated>2008-03-18T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2008/03/18/factory-loader</id>
   <content type="html">&lt;p&gt;FactoryLoader is intended to help scale object creation with less pain and less refactoring by creating factory classes for basic object construction.&lt;/p&gt;

&lt;p&gt;In the early stages of a project object creation is simple and dependencies are kept to a minimum. As the project grows so does the complexity of object creation and its dependencies. It doesn&amp;#8217;t make sense to create custom factory classes upfront to deal with complex object construction that may not exist yet. But when those custom factories are needed it is usually painful and time consuming to update the code base to use them. It&amp;#8217;s also easy for developers to give-in due to time constraints and start making bad decisions.&lt;/p&gt;

&lt;p&gt;This is where FactoryLoader comes into play. It automatically creates a Factory class for your objects and provides a &lt;em&gt;create&lt;/em&gt; method which passes any arguments along to your object&amp;#8217;s constructor.&lt;/p&gt;

&lt;p&gt;When you need to have custom factory behavior you can implement the factory without having to update other code references (assuming you&amp;#8217;ve used the factory in the rest of your application rather then direct class references).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  project/
    init.rb
    lib/
     |--things/
            |-- foo.rb
            |-- bar.rb
     |--factories/
            |-- bar_factory.rb&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given the above project directory structure you could have the following code in init.rb:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; factory_loader = FactoryLoader.new(&amp;quot;lib/factories&amp;quot;)
 factory_loader.load(&amp;quot;lib/things&amp;quot;)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first call constructs a factory loader telling it which directory is used to store developer-written custom factories.&lt;/p&gt;

&lt;p&gt;The second call will create an in-memory factory class for each *.rb file in the lib/things/ directory. A FooFactory class will be created to correspond with the foo.rb file. The generated factory will provide a &lt;em&gt;create&lt;/em&gt; method which will pass along all arguments to the constructor of the object it wraps. So&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; FooFactory.new.create :a =&amp;gt; :b&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;is the same as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; Foo.new :a =&amp;gt; :b&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Even though a bar.rb file exists a BarFactory will NOT be created. This is because we told the FactoryLoader that custom factories are storied in lib/factories/ and a bar_factory.rb file exists there, so FactoryLoader assumes you want to use a custom factory. It also assumes that the class inside of bar_factory.rb is BarFactory.&lt;/p&gt;

&lt;p&gt;FactoryLoader dynamically creates the factory classes â€” they are not written to disk. FactoryLoader also uses file naming conventions to determine what to do. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; foo.rb =&amp;gt; FooFactory
 crazy_dolphins.rb =&amp;gt; CrazyDolphinsFactory&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='factorynew'&gt;Factory.new&lt;/h3&gt;

&lt;p&gt;The dynamically created factories are classes and &lt;em&gt;create&lt;/em&gt; is an instance method on them. You have to construct a factory in order to use it. This is so the factories themselves can be easily used in dependency injection frameworks.&lt;/p&gt;

&lt;h3 id='making_a_custom_factory'&gt;Making a custom factory&lt;/h3&gt;

&lt;p&gt;So you&amp;#8217;re using FactoryLoader to do the work of creating factories for you. Let&amp;#8217;s say our Foo object now has some creation logic that we do not want in Foo&amp;#8217;s constructor. To put it in the FooFactory just create the file in lib/factories/foo_factory.rb. The contents of foo_factory.rb might look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class FooFactory  
  def create options={}
    if business_logic_passes?
      Foo.new options
    else
      raise &amp;quot;business logic failed&amp;quot;
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='install_it'&gt;Install it!&lt;/h3&gt;

&lt;p&gt;gem install -r factory_loader&lt;/p&gt;

&lt;h3 id='more_info'&gt;More Info&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;RDOC: &amp;#8220;http://mhs.rubyforge.org/factory_loader/rdoc/&amp;#8221;:http://mhs.rubyforge.org/factory_loader/rdoc/&lt;/li&gt;

&lt;li&gt;Public git repository: &amp;#8220;git://github.com/zdennis/factory_loader.git&amp;#8221;:git://github.com/zdennis/factory_loader.git&lt;/li&gt;

&lt;li&gt;Homepage: &amp;#8220;www.continuousthinking.com/factory_loader&amp;#8221;:www.continuousthinking.com/factory_loader&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='author'&gt;Author&lt;/h3&gt;

&lt;p&gt;Me, Zach Dennis&lt;/p&gt;

&lt;h3 id='special_thanks'&gt;Special Thanks&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Dave Crosby at Atomic Object&lt;/li&gt;

&lt;li&gt;Ryan Fogle at Atomic Object&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Trying RSpec's Rubyesque Stories</title>
   <link href="http://www.continuousthinking.com/2008/03/05/trying-rspec-s-rubyesque-stories.html"/>
   <updated>2008-03-05T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2008/03/05/trying-rspec-s-rubyesque-stories</id>
   <content type="html">&lt;p&gt;Today my pair and I wrote some stories using the rubyesque RSpec story style along with a corresponding step file. It went better then expected. We ended up a story like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# in stories/expenses/a_user_creating_a_misc_expense_story.rb
Story &amp;quot;User creating misc. expense&amp;quot;, %|
  As a user 
  I want be able to submit an expense reimbursement request for a misc. expense
  so that I can be reimbursed for business expenditures|,
  :steps_for =&amp;gt; :expense,
  :type =&amp;gt; RailsStory do

  Scenario &amp;quot;creating a misc. expense unsuccessfully&amp;quot; do
    Given &amp;quot;a user at a new expense reimbursement page&amp;quot;
    # ....
  end

  Scenario &amp;quot;creating a misc. expense successfully&amp;quot; do
    Given &amp;quot;a user at a new expense reimbursement page&amp;quot;
    # ...
  end
end


# in stories/steps/expense.rb
steps_for :expense do
  Given &amp;quot;a user at a new expense reimbursement page&amp;quot; do
    go_to_root
    click_new_expense_reimbursement_link
  end

  # ...
end&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;div class='article_sidebar'&gt;
One nice thing that came out of this was a small patch to RSpec which David committed tonight involving the options you pass along to Story. Now when declaring a story you can consistently use the *steps_for* option rather then using *steps_for* and/or *steps*. &lt;br /&gt;&lt;br /&gt;

Previously you could use the *steps* option to pass in a custom StepGroup but that is no longer supported in trunk. Now you use *steps_for* when supplying a custom StepGroup, a symbol or an array of StepGroups and symbols. This helps avoid confusion of passing in *steps* or *steps_for* and not getting what you expect.
&lt;/div&gt;

Overall there are four story styles (that I'm aware of) in RSpec: plain text stories, rubyesque stories with separate step files, rubyesque stories with inlined steps and rubyesque stories with inlined blocks.

We did try using plain text stories at first, but one drawback of plain text stories is being able to run them individually from within your editor or easily from the command line. We didn't have the need for plain text stories so we opted to not use it.

We started using the rubyesque stories with inlined steps secondly until we got a feel for the stories and then we moved those steps into their own file so we could achieve higher reuse and better step organization.

We knew coming in that we were not going to use the inlined block style since we have used that on another project and it gets clunky really fast. 

If you're considering using RSpec stories try the rubyesque stories with step matchers (inlined or in separate files). If you're going to take the plunge into trying plain text stories look to RSpec itself for examples. The actual stories in the stories/ directory helped us get up and running earlier today.

&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Mocha's error messages suck</title>
   <link href="http://www.continuousthinking.com/2008/02/26/mocha-s-error-messages-suck.html"/>
   <updated>2008-02-26T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2008/02/26/mocha-s-error-messages-suck</id>
   <content type="html">&lt;p&gt;Mocha&amp;#8217;s parameter matching error messages suck.&lt;/p&gt;

&lt;p&gt;When writing a failing test similar to the below snippet I am given the error message &amp;#8220;undefined method `keys&amp;#8217; for :no_args:Symbol&amp;#8221;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@user.should_not_receive(:update_attributes).with(has_key(&amp;#39;name&amp;#39;))&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I love Mocha&amp;#8217;s parameter matching, but what kind of error message is that?&lt;/p&gt;

&lt;p&gt;This is not the first time I&amp;#8217;ve gawked at Mocha&amp;#8217;s error messages, but this time just did it for me. My pair didn&amp;#8217;t know if we should ping or if we had broken our app.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Pair Programming in 1 sentence</title>
   <link href="http://www.continuousthinking.com/2008/01/29/pair-programming-in-1-sentence.html"/>
   <updated>2008-01-29T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2008/01/29/pair-programming-in-1-sentence</id>
   <content type="html">&lt;p&gt;Pair programming is a catalyst to writing better software.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Trying out Vlad the Deployer</title>
   <link href="http://www.continuousthinking.com/2008/01/26/using-vlad.html"/>
   <updated>2008-01-26T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2008/01/26/using-vlad</id>
   <content type="html">&lt;p&gt;This blog wasn&amp;#8217;t using any form of automated deployment until late last night. For the longest time rsync and ssh seemed to be adequate enough even though I&amp;#8217;m familiar with &amp;#8220;Capistrano&amp;#8221;:http://www.capify.org and had been well aware of &amp;#8220;Vlad the Deployer&amp;#8217;s&amp;#8221;:http://rubyhitsquad.com/Vlad_the_Deployer.html release. Since I know about Capistrano I decided to invest some time getting to know Vlad.&lt;/p&gt;

&lt;p&gt;This site is currently running on a 0.7.3 &amp;#8220;Mephisto&amp;#8221;:http://mephistoblog.com/ installation with a custom theme by yours truly and it&amp;#8217;s hosted on &amp;#8220;Dreamhost&amp;#8221;:http://www.dreamhost.com/ servers. Out of the box Vlad works with mongrel+apache+svn. Unfortunately Dreamhost uses apache+fastcgi, but thankfully tweaking Vlad was a piece of cake.&lt;/p&gt;

&lt;p&gt;I followed the instructions on the &amp;#8220;examples&amp;#8221;:http://rubyhitsquad.com/Examples.html page for Vlad, but ultimately found I needed to do a little tweaking for my environment. Based on those basic examples I ended up making the following changes to my Rakefile and deploy.rb recipe file.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s what I appended to my Rakefile:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# appended to my Rakefile
require &amp;#39;vlad&amp;#39;
Vlad.load(:app =&amp;gt; :apache)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here&amp;#8217;s my config/deploy.rb file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;set :domain,      &amp;quot;continuousthinking.com&amp;quot;
set :deploy_to,   &amp;quot;/my/path/to/continuousthinking.com/&amp;quot;
set :repository,  &amp;quot;http://myserver/svn/continuousthinking.com/trunk&amp;quot;
set :web_command, &amp;quot;echo skipping web &amp;quot;

namespace :vlad do
  remote_task :start_app do
    run &amp;quot;pkill -f dispatch.fcgi&amp;quot;
    fork do
      puts &amp;quot;sending a request to the domain so dispatchers restart&amp;quot;
      `wget http://#{domain} -O /dev/null`
    end
  end

  remote_task :update do
    Rake::Task[&amp;#39;vlad:after_update&amp;#39;].invoke
  end

  remote_task :after_update do
    run &amp;quot;ln -s #{deploy_to}/shared/system/database.yml #{deploy_to}/current/config/database.yml&amp;quot;
    run &amp;quot;rm -f /home/zdennis/continuousthinking.com &amp;amp;&amp;amp;
         ln -s #{deploy_to}/current /home/zdennis/continuousthinking.com&amp;quot;      
  end

  remote_task :deploy =&amp;gt; [:update, :start_app]
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I overrode the :web_command setting so Vlad didn&amp;#8217;t try to restart apache. The other tasks were added to customize specific needs for the deployment of the blog:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;:start_app - kill all of dispatchers on Dreamhost and then send a request to have Dreamhost launch new ones&lt;/li&gt;

&lt;li&gt;:update - adds this task to the :update task call chain. This simulates an after_update.&lt;/li&gt;

&lt;li&gt;:after_update - create symlinks, etc to be performed after code has been updated.&lt;/li&gt;

&lt;li&gt;:deploy - update code and restart the app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Overall, it was a pleasant process. I give Vlad a +1.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ar-extensions get a little praise</title>
   <link href="http://www.continuousthinking.com/2008/01/20/ar-extensions-get-a-little-praise.html"/>
   <updated>2008-01-20T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2008/01/20/ar-extensions-get-a-little-praise</id>
   <content type="html">&lt;p&gt;Alan Miles found the import functionality of my ar-extensions gem/plugin helpful and he posted about it &amp;#8220;here&amp;#8221;:http://www.jobwd.com/article/show/31&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m so glad to hear that ar-extensions is helping Alan and it&amp;#8217;s nice to see that he&amp;#8217;s sharing this usefulness with others via his &amp;#8220;blog&amp;#8221;:http://www.jobwd.com/&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Ã¢ÅË-k Hotkey in bash, on linux</title>
   <link href="http://www.continuousthinking.com/2007/12/29/hotkeys-in-bash.html"/>
   <updated>2007-12-29T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/12/29/hotkeys-in-bash</id>
   <content type="html">&lt;p&gt;I never thought I would say &amp;#8220;I wish my console acted more like the OSX&amp;#8217;s Terminal.app&amp;#8221;, but the truth is that I said that two days ago. That day my MacBook Pro (MBP) went out of commission due to an accidental overdose of Raspberry Iced Tea. Ever since then I&amp;#8217;ve been plugging away on my Kubuntu box using Yakuake and Emacs23 to develop.&lt;/p&gt;

&lt;p&gt;I have this obsessive need to clear the terminal all the time during development, primarily when I&amp;#8217;m going to run tests. On my MBP I would just hit &amp;#8984;-k to clear the terminal, but I don&amp;#8217;t have that luxury in Yakuake or any other terminal that I know of. So why not roll my own?&lt;/p&gt;

&lt;p&gt;After googling around for a while I found this &amp;#8220;article&amp;#8221;:http://linuxgazette.net/issue55/henderson.html by Bryan Henderson from the &amp;#8220;Linux Gazette&amp;#8221;:http://linuxgazette.net . Even though the article is seven years old it still applies. In addition to this article I also read the man page for readline which has a lot of cool information in it. Since bash relies on readline to do the input processing new doors have opened for what I want to tinker with on my system.&lt;/p&gt;

&lt;h2 id='writing_your_k_hotkey'&gt;Writing Your &amp;#8984;-k Hotkey&lt;/h2&gt;

&lt;p&gt;Create a ~/.inputrc file. In that file put the following contents. Now log out and log back in (or fire up a new terminal session):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;\ek&amp;quot;:&amp;quot;\C-a\C-kclear\n\C-y&amp;quot;
&amp;quot;\C-x\C-r&amp;quot;: re-read-init-file&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first line expresses that I want Meta-k to map to the following set of keystrokes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;C-a which brings me to the beginning of the line&lt;/li&gt;

&lt;li&gt;C-k which cuts the line&lt;/li&gt;

&lt;li&gt;clear which is used to clear the terminal&lt;/li&gt;

&lt;li&gt;a newline which executes the clear command just as if I typed it and hit enter&lt;/li&gt;

&lt;li&gt;C-y which pastes what I cut with C-k back onto the terminal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And now you have a Terminal.app &amp;#8984;-k hotkey on any system that uses bash. The only difference is that its mapped to Meta-k.&lt;/p&gt;

&lt;p&gt;The second line is a simple nicety so you can reload your ~/.inputrc file without having to log out and log back in. Just type C-x C-r to reload any changes.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>On Writing Good Software</title>
   <link href="http://www.continuousthinking.com/2007/12/22/make-yourself-write-good-software.html"/>
   <updated>2007-12-22T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/12/22/make-yourself-write-good-software</id>
   <content type="html">&lt;p&gt;The craft of writing is so similar to that of software development. I recently found this out by reading On Writing Well by William Zinsser. Below are some quotes from the book with commentary on how they apply to the software developer.&lt;/p&gt;

&lt;h3 id='you_will_write_only_as_well_as_you_make_yourself_write'&gt;You will write only as well as you make yourself write.&lt;/h3&gt;

&lt;p&gt;Substitute &lt;em&gt;write&lt;/em&gt; with &lt;em&gt;write software&lt;/em&gt; and it remains a truism.&lt;/p&gt;

&lt;p&gt;Writing software is easy. Writing good software is hard. It takes discipline to become a good software developer. The only way to get there is to write better software today then you wrote yesterday. And the only way to do that is to learn from what you and others have written.&lt;/p&gt;

&lt;h3 id='clutter_is_the_disease_of_american_writing'&gt;Clutter is the disease of American writing.&lt;/h3&gt;

&lt;p&gt;The same can be said for writing good software. It&amp;#8217;s very painful to create or find a bloated method or class doing something it shouldn&amp;#8217;t be doing. It&amp;#8217;s even more painful to maintain. Small and simple works wonders within the design of a program.&lt;/p&gt;

&lt;h3 id='strip_every_sentence_to_its_cleanest_components'&gt;Strip every sentence to its cleanest components.&lt;/h3&gt;

&lt;p&gt;Strip every method and class to include only the functionality it needs to do its job. Methods which might be used at some point &amp;#8211; get rid of them. Comments which try to explain away complexity or ambiguity &amp;#8211; simplify the code so it&amp;#8217;s readable and remove the them. Classes which try to do everything &amp;#8211; refactor and pull out things it doesn&amp;#8217;t need to do into their own class or module. Clever code &amp;#8211; turn it into simple code. Simplify, simplify, simplify.&lt;/p&gt;

&lt;h3 id='you_must_know_what_the_essential_tools_are_and_what_job_they_were_designed_to_do'&gt;You must know what the essential tools are and what job they were designed to do.&lt;/h3&gt;

&lt;p&gt;A carpenter must know how-to hammer nails and saw wood before he can build a house. Likewise, a developer must know how-to write good code, perform object decomposition and refactor before he can build an application. Other basic tools and skills that a developer should know are: writing testable code, testing and test automation.&lt;/p&gt;

&lt;h3 id='take_your_stand_with_conviction'&gt;Take your stand with conviction.&lt;/h3&gt;

&lt;p&gt;Care about the software you develop. Stand up for customer involvement. Stand up for short iterations. Stand up for testing. Stand up for quality, even when the deadline is fast approaching, it&amp;#8217;s the best chance you&amp;#8217;ve got for hitting it with working software.&lt;/p&gt;

&lt;h3 id='never_hesitate_to_imitate_another_writer'&gt;Never hesitate to imitate another writer.&lt;/h3&gt;

&lt;p&gt;Never hesitate to imitate another developer, especially one that writes better software than you. It will make you better in the process. Find open source projects that exceptional developers have worked on and read that code. How are they attacking a problem? How did they solve it?&lt;/p&gt;

&lt;p&gt;A while back a coworker asked me if I had read through Mephisto&amp;#8217;s source and I said I had scanned it, but that I didn&amp;#8217;t think it was anything special besides the routing. A few weeks later I started reading the source. Rick Olson, the author of Mephisto, has some great techniques and code tucked away in Mephisto, things that I would be missing out on if my coworker would have never challenged me to read the source. Thanks Drew.&lt;/p&gt;

&lt;h3 id='its_hard_not_to_be_intimidated_by_the_expertise_of_the_expert'&gt;&amp;#8230;it&amp;#8217;s hard not to be intimidated by the expertise of the expert.&lt;/h3&gt;

&lt;p&gt;Ask questions. If you don&amp;#8217;t understand something, ask. If you think it&amp;#8217;s a dumb question, ask. Let the resident expert enlighten you. When they explain something and you still don&amp;#8217;t get it, ask clarifying questions. They didn&amp;#8217;t wake up one day an expert. And neither will you.&lt;/p&gt;

&lt;h3 id='writing_is_related_to_character_if_your_values_are_sound_your_writing_will_be_sound'&gt;Writing is related to character. If your values are sound your writing will be sound.&lt;/h3&gt;

&lt;p&gt;Developers who have character are exceptional people to work with. They not only write better software, they inspire those around them to write better software.&lt;/p&gt;

&lt;h3 id='decide_what_you_want_to_do_then_decide_to_do_it_then_do_it'&gt;Decide what you want to do. Then decide to do it. Then do it.&lt;/h3&gt;

&lt;p&gt;For all of those &amp;#8220;I want to learn language X&amp;#8221;, &amp;#8220;I want to start learning TDD&amp;#8221;, etc. statements &amp;#8211; start learning language X, start doing TDD.&lt;/p&gt;

&lt;h3 id='think_small'&gt;Think small.&lt;/h3&gt;

&lt;p&gt;Two immediate thoughts come to mind. First, good object decomposition. Work with simple objects that work with a single responsibility and let the overall system evolve of those simple objects. Second, short iterations over long ones and short stories over full blown specification documents. Thinking small in these regards will help you produce cleaner and simpler code as well as produce the right working features &amp;#8211; sooner.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>rak, ack and findit</title>
   <link href="http://www.continuousthinking.com/2007/12/13/rak-ack-and-findit.html"/>
   <updated>2007-12-13T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/12/13/rak-ack-and-findit</id>
   <content type="html">&lt;p&gt;In &amp;#8220;Helpful Command Line Tools&amp;#8221;:http://www.continuousthinking.com/2007/11/23/helpful-command-line-tools from last month I posted on my custom findit script.&lt;/p&gt;

&lt;p&gt;Jason Porrit commented on that post and mentioned &amp;#8220;ack&amp;#8221;:http://search.cpan.org/~petdance/ack-1.75_01/ack , a perl alternative to grep and find which offers terminal color highlighting to your results. I also found this morning a ruby alternative called &amp;#8220;rak&amp;#8221;:http://rak.rubyforge.org&lt;/p&gt;

&lt;p&gt;All of these utilities do the same thing, they search a directory structure for files whose contents match a given pattern.&lt;/p&gt;

&lt;h2 id='heres_ack'&gt;Here&amp;#8217;s Ack&lt;/h2&gt;
&lt;img src='/assets/2007/12/13/ack.png' /&gt;
&lt;h2 id='heres_rak'&gt;Here&amp;#8217;s Rak&lt;/h2&gt;
&lt;img src='/assets/2007/12/13/rak.png' /&gt;
&lt;h2 id='heres_findit'&gt;Here&amp;#8217;s findit&lt;/h2&gt;
&lt;img src='/assets/2007/12/13/findit.png' /&gt;
&lt;p&gt;Overall ack and rak beat out findit, but findit has a much better name. I think I&amp;#8217;ll just alias findit to rak. (yes I&amp;#8221;m biased to ruby code over perl code).&lt;/p&gt;

&lt;p&gt;The only thing ack and rak are missing is a filename only option. If I can find every file matching a pattern from a given start directory that would rid me of findfile as well!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>be gone from my view foul demon</title>
   <link href="http://www.continuousthinking.com/2007/12/08/be-gone-from-my-view-foul-demon.html"/>
   <updated>2007-12-08T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/12/08/be-gone-from-my-view-foul-demon</id>
   <content type="html">&lt;div style='float: left; margin-right: 7px;'&gt;&lt;img src='http://www.continuousthinking.com/assets/2007/12/8/be_gone_foul_demon-20071208-002443.jpg' /&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;#8217;s be disciplined and keep model constants out of our views.&lt;/p&gt;

&lt;p&gt;If you have anything like the below in your views, remove it! You may think that it&amp;#8217;s a harmless way to re-use a default set in your model, but that is a lie and you need to stop believing it. The above morsel of model loitering easily leads to a full fledged model invasion, which happens slowly and over time.&lt;/p&gt;

&lt;p&gt;The view is meant to be stupid, so give it knowledge of nothing in your domain. If you need to pass in defaults then pass them in through instance variables, locals or as default settings on new ActiveRecord models. Let an object with the responsibility of knowing what should be used make that decision and let your view simply display it.&lt;/p&gt;

&lt;p&gt;I was recently tempted to use a Avatar::NO_IMAGE_PATH default in a view &amp;#8211; the thought lasted a few short seconds and then I banished it from my mind. The NO_IMAGE_PATH default was better handled as a default on an Avatar that didn&amp;#8217;t have an image.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# using this in a view
Avatar::DEFAULT_IMAGE

# became

@avatar.image_path&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you keep a list of things that are good candidates for refactoring run the below script from app/views/ in a terminal. It will find all of the model constants laying dormant.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd app/views/
grep -HnE &amp;quot;[A-Z].+::[A-Z]&amp;quot; *&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You will see output like the below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;projects/show.html.erb:22:Avatar::DEFAULT_IMAGE
users/index.html.erb:4:User::SOME_SETTING
events/_list.html.erb:6:Event::DEFAULT_TIMEZONE&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A small victory for clean and well factored code.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>RMagick, Rubygems and Windows</title>
   <link href="http://www.continuousthinking.com/2007/12/05/rmagick-rubygems-and-windows.html"/>
   <updated>2007-12-05T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/12/05/rmagick-rubygems-and-windows</id>
   <content type="html">&lt;p&gt;Rubygems 0.9.5 doesn&amp;#8217;t like RMagick on Windows. Here is a useful post from a Google thread which describes how to fix this. Basically re-install 0.9.4.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;I woud like to thank Robin Mayfield for indirectly resolving my 
similar issue with RMagick. 

RMagick is now installed and working. 

Here&amp;#39;s what I did: 

1. Downloaded 0.9.4 RubyGems zip file. 

2. Ran the setup.rb 

3. From within the unzipped RMagic-win32 directory I ran: gem install 
rmagick-1.14.1-win32.gem --local 

I didn&amp;#39;t need to insert require &amp;#39;RMagick&amp;#39; in the environment.rb file. 

Yeeha!!

Apparently, RMagick doesn&amp;#39;t work with RubyGems 0.9.5. 

Thanks again. 

Regards 

Walter &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thanks to Walter Lockhart for reposting this.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>magic models, meh</title>
   <link href="http://www.continuousthinking.com/2007/12/01/magic-models.html"/>
   <updated>2007-12-01T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/12/01/magic-models</id>
   <content type="html">&lt;p&gt;While catching up on RSS feeds this morning I followed a few interesting links and again came across a link to &amp;#8220;Dr. Nic&amp;#8217;s Magic Models&amp;#8221;:http://magicmodels.rubyforge.org/dr_nic_magic_models . In the past I felt uneasy about this gem, but now I just don&amp;#8217;t think it should be used for real projects, although I&amp;#8217;m sure it was a fun exercise for the author to write.&lt;/p&gt;

&lt;p&gt;The idea seems to be based on removing declarative statements about your model in your model. You would normally write:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person &amp;lt; ActiveRecord::Base
  has_many :memberships
  has_many :groups, :through =&amp;gt; :memberships
  belongs_to :family
  validates_presence_of :firstname, :lastname, :email
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The author finds an issue with this, to him it seems unncessary. So he ponders the question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why do I have write my own has_many, belongs_to, and validates_presence_of commands if all the data is in the database schema?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I think this is the wrong question to ask, but I can see where the author came up with the question. As I read through the entire page on magic models I see my code beginning to vanish. Something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person &amp;lt; ActiveRecord::Base
  has_many :memberships
  has_many :groups, :through =&amp;gt; :memberships
  belongs_to :family
  validates_presence_of :firstname, :lastname, :email
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person &amp;lt; ActiveRecord::Base
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# no more code , the person.rb model file has been deleted&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This progression bothers me because in the end you end up without any self-documenting code, and you&amp;#8217;ve moved application logic from your application into your database. It seems that I&amp;#8217;d rather have a database constraint (like not allowing null fields) reinforce self-documenting declarations in the model such as:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;validates_presence_of :firstname, :lastname, :email&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And why would you want to kill declarative relationships in your application?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  has_many :memberships
  has_many :groups, :through =&amp;gt; :memberships
  belongs_to :family&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to &amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# ... nothing here ...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Self-documenting code is useful especially when you&amp;#8217;re describing how one object relates to another object in your application.&lt;/p&gt;

&lt;p&gt;It seems much more appealing to see that in a model rather then having to go fish in the database schema. Leave application logic in the application. There are times you need to use database constraints (among other things) to reinforce your application logic, but you shouldn&amp;#8217;t remove self-documenting clean code just because you can.&lt;/p&gt;

&lt;p&gt;This is just my developer preference, but I think it&amp;#8217;s a good preference to have. I don&amp;#8217;t want to unnecessarily spread application logic outside of my application code for the sake of being clever.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>form_test_helper edge gets support for multiple submit buttons</title>
   <link href="http://www.continuousthinking.com/2007/11/27/form_test_helper-edge-gets-support-for-multiple-submit-buttons.html"/>
   <updated>2007-11-27T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/27/form_test_helper-edge-gets-support-for-multiple-submit-buttons</id>
   <content type="html">&lt;p&gt;form_test_helper edge has been updated to support multiple submit buttons on a form. It also includes a fix to avoid namespace collisions if models are named Select, Option, etc.&lt;/p&gt;

&lt;p&gt;If you have a view which looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;form id=&amp;quot;test&amp;quot;&amp;gt;
  &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;yes&amp;quot; /&amp;gt;
  &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;no&amp;quot; /&amp;gt;
&amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can have choose which value to submit when the form is submitted:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# selecting the form and submitting it in separate steps
form = select_form &amp;quot;test&amp;quot;, :submit_value =&amp;gt; &amp;quot;yes&amp;quot;
form.submit

# submitting a form with a submit value in one step
submit_form &amp;quot;test&amp;quot;, :submit_value =&amp;gt; &amp;quot;yes&amp;quot;

# submitting a form with a submit value in one step using a block
submit_form &amp;quot;test&amp;quot;, :submit_value =&amp;gt; &amp;quot;yes&amp;quot; do |form|
   # .. 
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You don&amp;#8217;t have to supply a :submit_value. If you don&amp;#8217;t the first submit value found on the form will be used. If you try to supply a non-existent value then an exception will raised.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# trying to submit on a non-existent input value
form = select_form &amp;quot;test&amp;quot;, :submit_value =&amp;gt; &amp;quot;fooey&amp;quot;
form.submit  # =&amp;gt; raises a FormTestHelper::Form::MissingSubmitError&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='installing'&gt;Installing&lt;/h3&gt;

&lt;p&gt;As an external:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./script/plugin install -x http://form-test-helper.googlecode.com/svn/form_test_helper&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Not as an external:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./script/plugin install http://form-test-helper.googlecode.com/svn/form_test_helper&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With piston:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd vendor/plugins/
piston import http://form-test-helper.googlecode.com/svn/form_test_helper&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='rdoc'&gt;Rdoc&lt;/h3&gt;

&lt;p&gt;Rdoc pages for form_test_helper edge are hosted on rubyforge. You can find them at &amp;#8220;http://continuous.rubyforge.org/form_test_helper/rdoc/&amp;#8221;:http://continuous.rubyforge.org/form_test_helper/rdoc/&lt;/p&gt;

&lt;p&gt;If you have any questions feel free to ask. If you find issues, bugs or odd behavior please create an issue over at &amp;#8220;http://code.google.com/p/form-test-helper/&amp;#8221;:http://code.google.com/p/form-test-helper/&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>form_test_helper 1.0.1 and 1.1.1</title>
   <link href="http://www.continuousthinking.com/2007/11/27/form_test_helper-1-0-1-and-1-1-1.html"/>
   <updated>2007-11-27T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/27/form_test_helper-1-0-1-and-1-1-1</id>
   <content type="html">&lt;p&gt;form_test_helper 1.0.1 and 1.1.1 have been released.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;li&gt;
&lt;li&gt;1 is for people who are on 1.2.x (specifically 1.2.5 and 1.2.6)&lt;/li&gt;
&lt;/li&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;li&gt;
&lt;li&gt;1 is for people who are on a Rails Edge revision between 6764 and 7420&lt;/li&gt;
&lt;/li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are on Rails Edge newer then 7420 then you&amp;#8217;ll want to use form_test_helper edge. A separate announcement will be made for that release.&lt;/p&gt;

&lt;p&gt;The 1.0.1 and 1.1.1 releases fix a namespace collision issue if you happen to have a model named Option or Select. Thanks to Tomasz Wegrzanowski for pointing this out and supplying a patch.&lt;/p&gt;

&lt;p&gt;For information on how-to install, or for usage examples please check out the rdoc for these releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;1.0.x series rdoc&amp;#8221;:http://continuous.rubyforge.org/form_test_helper-1.0.x/rdoc/&lt;/li&gt;

&lt;li&gt;&amp;#8220;1.1.x series rdoc&amp;#8221;:http://continuous.rubyforge.org/form_test_helper-1.1.x/rdoc/&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will probably be the last release for the 1.1.x branch of development since it targets such as a small set of revisions on Rails Edge and it will be out of date shortly if it isn&amp;#8217;t already.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Helpful Command Line Tools</title>
   <link href="http://www.continuousthinking.com/2007/11/23/helpful-command-line-tools.html"/>
   <updated>2007-11-23T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/23/helpful-command-line-tools</id>
   <content type="html">&lt;p&gt;Here&amp;#8217;s a post about some of the command line tools (both standard on *nix systems and homegrown) which make software development just a little more efficient.&lt;/p&gt;

&lt;p&gt;The homegrown tools may only work on OSX. This is because unix utilities on OSX often have different options to do the same thing (such as sed&amp;#8217;s -E on OSX and -r in Ubuntu).&lt;/p&gt;

&lt;h2 id='find'&gt;find&lt;/h2&gt;

&lt;p&gt;find is a unix utility for searching files in a directory hierarchy. find is a powerful tool that comes with a lot of options. Some are more common then others.&lt;/p&gt;

&lt;p&gt;Here are the options I use frequently:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;-name pattern - this will match filenames against the supplied pattern&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;-exec command argument \; - runs the specified command against each file matched&lt;/p&gt;

&lt;p&gt;# Using -name to find all files or directories which match the pattern &amp;#8220;*.rhtml&amp;#8221; find ./ -name &amp;#8220;*.rhtml&amp;#8221;&lt;/p&gt;

&lt;p&gt;# Using -exec to find all rhtml files whose file contents match &amp;#8220;Continuous Thinking&amp;#8221; find ./ -name &amp;#8220;*.rhtml&amp;#8221; -exec grep -Hn &amp;#8220;Continuous Thinking&amp;#8221; {} \;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For development the -name option doesn&amp;#8217;t help me much as TextMate&amp;#8217;s Apple-Tab is far superior and faster to use, but editors like TextMate lack the efficiency of doing a -name and -exec combination from the command line. Sure TextMate has Apple-Shift-F to search file contents project wide, but what about all of those files you want to exclude (like log files), plugins (vendor/plugins) or the whole rails directory (vendor/rails).&lt;/p&gt;

&lt;p&gt;TextMate doees give you the ability to exclude certain files (or directories) from your TextMate project, but it removes all references to them from within your TextMate project. This feature will speed up Apple-Shift-F searches, but sometimes you want to include those other files or directories.&lt;/p&gt;

&lt;p&gt;The find command given the -name and -exec options can be a pain to type out. So I&amp;#8217;ve written a helper script called findit.&lt;/p&gt;

&lt;h2 id='findit'&gt;findit&lt;/h2&gt;

&lt;p&gt;findit is a wrapper around find. It&amp;#8217;s simple and fast. It&amp;#8217;s usage is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;findit where pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maybe you&amp;#8217;re looking for that view template which contains the text &amp;#8216;Fuzzy Bear&amp;#8217;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zdennis@elijah:&amp;gt; findit app/views/ Fuzzy Bear
app/views//bears/new.rhtml:26:      &amp;lt;label for=&amp;quot;fuzzy_bear&amp;quot;&amp;gt;Fuzzy Bear&amp;lt;/label&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notice how you don&amp;#8217;t have to use quotations around the arguments Fuzzy Bear. Everything after the first argument is treated as a part of the pattern.&lt;/p&gt;

&lt;p&gt;Another example may be that you&amp;#8217;re looking for where alias_method_chain is defined in rails. Well let&amp;#8217;s look:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zdennis@elijah:&amp;gt; findit vendor/rails/ def alias_method_chain
vendor/rails//activesupport/lib/active_support/core_ext/module/aliasing.rb:23:  def alias_method_chain(target, feature)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So the power of findit comes from the fact that it&amp;#8217;s easy to use and it handles most common occurrences of what a developer like me looks for such as the filenames that matched, the line numbers it matched on and a printout of those matching lines.&lt;/p&gt;

&lt;p&gt;findit also ignores all .svn, CVS, .log, .project, .dylib and .o files. Of course you can change this though by editing the findit.&lt;/p&gt;

&lt;h4 id='download'&gt;Download&lt;/h4&gt;

&lt;p&gt;Give it a try click &amp;#8220;here&amp;#8221;:http://www.continuousthinking.com/assets/2007/11/23/findit.rb&lt;/p&gt;

&lt;h2 id='findfile'&gt;findfile&lt;/h2&gt;

&lt;p&gt;findfile is similar to findit except that it only matches on filename patterns. The usage is still the same:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;findfile where pattern&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recently I had some issues with installing PostgreSQL from &amp;#8220;ports&amp;#8221;:http://www.macports.org and there was a patch to the Portfile for the PostgreSQL port to get it to install correctly. I had no idea where the Portfile was so I let findfile to the work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;findfile /opt/local/var/macports Portfile | grep -i postgres&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id='download'&gt;Download&lt;/h4&gt;

&lt;p&gt;Give it a try click &amp;#8220;here&amp;#8221;:http://www.continuousthinking.com/assets/2007/11/23/findfile.rb&lt;/p&gt;

&lt;h2 id='locate__slocate'&gt;locate | slocate&lt;/h2&gt;

&lt;p&gt;locate (and by extension slocate) may be one of the most under utilized unix tools in the mac world.&lt;/p&gt;

&lt;p&gt;locate is used to find files by searching a database. Since it uses a database of file paths it is almost instantaneous whereas tools like find can take a while depending on how much files you have in a directory structure.&lt;/p&gt;

&lt;p&gt;slocate can be thought of as &amp;#8220;secure locate&amp;#8221;. For more information consult this &amp;#8220;doc&amp;#8221;:http://linux.about.com/library/cmd/blcmdl1_slocate.htm&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the same example from findfile but this time using locate:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;locate Portfile | grep postgres
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql7/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql80/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql80-doc/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql80-server/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql81/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql81-doc/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql81-server/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql82/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql82-doc/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql82-server/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql83/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql83-doc/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql83-server/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/databases/postgresql_autodoc/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/java/postgresql-jdbc/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/python/py-postgresql-exception/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/python/py-postgresql-greentrunk/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/python/py-postgresql-layout/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/python/py-postgresql-pqueue/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/python/py-postgresql-proboscis/Portfile
/opt/local/var/macports/sources/rsync.macports.org/release/ports/ruby/rb-postgres/Portfile&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;locate loses its usefulness when it&amp;#8217;s database is out of date. Fortunately it&amp;#8217;s easy to add it to cron. Here&amp;#8217;s what I have in my /etc/crontab file to have slocate update it&amp;#8217;s database every night at midnight:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;0 0 * * * root /opt/local/bin/slocate -u&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;locate comes with Leopard, and slocate comes with ports. I have my locate aliased to actually run slocate. They use different databases so pick one and use it or alias one command over the other like I have. There&amp;#8217;s not much of a point to have both slocate and locate.&lt;/p&gt;

&lt;p&gt;If you decide to give slocate a try you can install easily by running:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo port install slocate&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='whatsmyip'&gt;whatsmyip&lt;/h2&gt;

&lt;p&gt;whatsmyip is a script I use in my &amp;#8220;screen configuration&amp;#8221;:http://www.continuousthinking.com/2007/1/7/screenrc-configuration so I can always tell what my local ip address is. ifconfig output is pain enough to look at and I try to avoid it at all costs:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zdennis@elijah:&amp;gt; whatsmyip 
en1: 10.0.4.100 en2: 10.37.129.2 en3: 10.211.55.2&lt;/code&gt;&lt;/pre&gt;

&lt;h4 id='download'&gt;Download&lt;/h4&gt;

&lt;p&gt;Give it a shot, click &amp;#8220;here&amp;#8221;:http://www.continuousthinking.com/assets/2007/11/23/whatsmyip.rb&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>OSX Leopard mysql gem for ruby</title>
   <link href="http://www.continuousthinking.com/2007/11/21/osx-leopard-mysql-gem-for-ruby.html"/>
   <updated>2007-11-21T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/21/osx-leopard-mysql-gem-for-ruby</id>
   <content type="html">&lt;p&gt;If you install mysql from ports then you can install the mysql ruby bindings in the following manner:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sudo su

ARCHFLAGS=&amp;#39;-arch i386&amp;#39; gem install -r mysql -- \
   --with-mysql-include=/opt/local/include/mysql5/mysql/ \
   --with-mysql-lib=/opt/local/lib/mysql5/mysql/&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you don&amp;#8217;t use ports then check out &amp;#8220;http://nullcreations.net/entry/installing-ruby-mysql-gem-in-osx-10-5-leopard&amp;#8221;:http://nullcreations.net/entry/installing-ruby-mysql-gem-in-osx-10-5-leopard&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>OSX Leopard sqlite-ruby and sqlite2</title>
   <link href="http://www.continuousthinking.com/2007/11/18/osx-leopard-sqlite-ruby-and-sqlite2.html"/>
   <updated>2007-11-18T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/18/osx-leopard-sqlite-ruby-and-sqlite2</id>
   <content type="html">&lt;p&gt;OSX Leopard comes with sqlite3 and sqlite3-ruby pre-installed. If you need to install the sqlite-ruby gem for sqlite2 you&amp;#8217;ll find that it fails to install by itself.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s what you&amp;#8217;ll probably get:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zdennis@elijah:&amp;gt;sudo gem install sqlite-ruby
Select which gem to install for your platform (universal-darwin9.0)
 1. sqlite-ruby 2.2.3 (ruby)
 2. sqlite-ruby 2.2.3 (mswin32)
 3. sqlite-ruby 2.2.2 (ruby)
 4. sqlite-ruby 2.2.2 (mswin32)
 5. Skip this gem
 6. Cancel installation
&amp;gt; 1
Building native extensions.  This could take a while...
ERROR:  While executing gem ... (Gem::Installer::ExtensionBuildError)
    ERROR: Failed to build gem native extension.

ruby extconf.rb install sqlite-ruby
checking for main() in -lsqlite... no
checking for sqlite.h... no
*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of
necessary libraries and/or headers.  Check the mkmf.log file for more
details.  You may need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby
        --with-sqlite-dir
        --without-sqlite-dir
        --with-sqlite-include
        --without-sqlite-include=${sqlite-dir}/include
        --with-sqlite-lib
        --without-sqlite-lib=${sqlite-dir}/lib
        --with-sqlitelib
        --without-sqlitelib


Gem files will remain installed in /Library/Ruby/Gems/1.8/gems/sqlite-ruby-2.2.3 for inspection.
Results logged to /Library/Ruby/Gems/1.8/gems/sqlite-ruby-2.2.3/ext/gem_make.out&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you become root and attempt to do the install it will also fail.&lt;/p&gt;

&lt;h2 id='installing_with_sqlite2_from_ports'&gt;Installing with sqlite2 from ports&lt;/h2&gt;

&lt;p&gt;I have &amp;#8220;MacPorts&amp;#8221;:http://www.macports.org/ installed and you&amp;#8217;ll want to make sure sqlite2 is installed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zdennis@elijah: sudo port install sqlite2&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now to install sqlite-ruby:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# run the command as root
zdennis@elijah: sudo su

sh-3.2# ARCHFLAGS=&amp;quot;-arch i386&amp;quot;  gem install sqlite-ruby -- --with-sqlite-include=/opt/local/include/ --with-sqlite-lib=/opt/local/lib/

Select which gem to install for your platform (universal-darwin9.0)
 1. sqlite-ruby 2.2.3 (ruby)
 2. sqlite-ruby 2.2.3 (mswin32)
 3. sqlite-ruby 2.2.2 (ruby)
 4. sqlite-ruby 2.2.2 (mswin32)
 5. Skip this gem
 6. Cancel installation
&amp;gt; 1
Building native extensions.  This could take a while...
Successfully installed sqlite-ruby-2.2.3
Installing ri documentation for sqlite-ruby-2.2.3...
Installing RDoc documentation for sqlite-ruby-2.2.3...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;#8217;s it. Now it works:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;zdennis@elijah: irb
irb(main):001:0&amp;gt; require &amp;#39;rubygems&amp;#39;
=&amp;gt; false
irb(main):002:0&amp;gt; require &amp;#39;sqlite&amp;#39;
=&amp;gt; true
irb(main):003:0&amp;gt; &lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Food Service and Craftsmanship</title>
   <link href="http://www.continuousthinking.com/2007/11/15/food-service-and-craftsmanship.html"/>
   <updated>2007-11-15T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/15/food-service-and-craftsmanship</id>
   <content type="html">&lt;p&gt;I wonder if restaurants and fast food places could learn from the craftsmanship model. Today at lunch I went to KFC and they screwed up my order. I&amp;#8217;m somewhat of a regular at the local KFC by the office and the person who took my order I believe is new.&lt;/p&gt;

&lt;p&gt;It hit me that this happens all of the time, regardless of it being a fast food place or a normal sit down restaurant. I&amp;#8217;m a rather picky eater and have been dubbed &amp;#8220;Sally&amp;#8221; from &amp;#8220;How Harry Met Sally&amp;#8221;:http://www.imdb.com/title/tt0098635. Sally and I both share the &amp;#8220;picky&amp;#8221; part of our eating habits.&lt;/p&gt;

&lt;p&gt;My thought is that people who are new on the job in the restaurant world often screw up orders. And after seeing &amp;#8220;Waiting&amp;#8221;:http://www.imdb.com/title/tt0348333 I&amp;#8217;m even inclined to think that my orders get jacked up on purpose.&lt;/p&gt;

&lt;p&gt;But keeping my hopes and dreams in mind (no sprinkled parsley on my mashed potatoes please) as it pertains to servers wanting to do a good job and take price in their work I think they should put more emphasis on the craftsmanship model. No junior servers or order takers w/o a senior standing by.&lt;/p&gt;

&lt;p&gt;At least perhaps then I&amp;#8217;ll get what I ordered.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>test/unit story runner</title>
   <link href="http://www.continuousthinking.com/2007/11/14/test-unit-story-runner.html"/>
   <updated>2007-11-14T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/14/test-unit-story-runner</id>
   <content type="html">&lt;p&gt;As you may know rspec has integrated RBehave into itself. In the rspec world it&amp;#8217;s more recently been called Story Runner.&lt;/p&gt;

&lt;p&gt;Some background links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;Introducing RBehave&amp;#8221;:http://dannorth.net/2007/06/introducing-rbehave&lt;/li&gt;

&lt;li&gt;&amp;#8220;User stories with RSpec&amp;#8217;s Story Runner&amp;#8221;:http://evang.eli.st/blog/2007/9/1/user-stories-with-rspec-s-story-runner&lt;/li&gt;

&lt;li&gt;&amp;#8220;Story Runner in Plain English&amp;#8221;:http://blog.davidchelimsky.net/articles/2007/10/21/story-runner-in-plain-english&lt;/li&gt;

&lt;li&gt;&amp;#8220;Plain Text Stories: Part III&amp;#8221;:http://blog.davidchelimsky.net/articles/2007/10/25/plain-text-stories-part-iii&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Story Runner itself hasn&amp;#8217;t officially been released and while it has been becoming more polished myself and a colleague (Drew Colthorp) wanted higher level acceptance tests in my ruby projects (including rails).&lt;/p&gt;

&lt;p&gt;Story Runner also has two implementations (or at least APIs). The latest is the plain text Story Runner. This requires that for every story you have at least two files. One that is plain text for the customer to write and one that is a &amp;#8220;matcher&amp;#8221; file developers write. Information on this can be found &amp;#8220;here&amp;#8221;:http://blog.davidchelimsky.net/articles/2007/10/25/plain-text-stories-part-iii&lt;/p&gt;

&lt;p&gt;The older version of Story Runner uses the original RBehave style syntax. Lots of blocks and lots of argument passing. There is also a bug in this implementation regarding sharing blocks given to story parts. But enough about rspec, this post is on a lighter weight and simpler Story Runner.&lt;/p&gt;

&lt;p&gt;So here&amp;#8217;s to a working and testing implementation of a Story Runner in test/unit.&lt;/p&gt;

&lt;h2 id='testunit_story_runner'&gt;test/unit Story Runner&lt;/h2&gt;

&lt;p&gt;To start, an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class EventCreationTest &amp;lt; ActionController::IntegrationTest
  fixtures :all

  Story &amp;quot;As a user I should be able to create an event so that others can RSVP and attend.&amp;quot;

  Scenario &amp;quot;Creating an event unsuccessfully with insufficient input&amp;quot; do
    Given :a_user_at_the_create_an_event_page
    When :they_submit_the_create_an_event_form_with_insufficient_input
    Then :they_will_see_an_error_explanation
    And :they_will_see_the_create_an_event_page
  end 

   #
   # HELPERS
   #
   def a_user_at_the_create_an_event_page
       # ....
   end

   def submit_the_create_an_event_form_with_insufficient_input
       # ...
   end

   def see_an_error_explanation
       # ...
   end

   def see_the_create_an_event_page
      # ...
   end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Some important things to note on the structure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Story takes a description of the story. It does NOT take a block.&lt;/li&gt;

&lt;li&gt;multiple Story&amp;#8217;s can be defined in a file although I prefer organizing them in separate files&lt;/li&gt;

&lt;li&gt;all Scenario&amp;#8217;s which follow a Story will belong to that Story.&lt;/li&gt;

&lt;li&gt;the Scenario takes a description of the particular scenario or acceptance test for a story. It does take a block.&lt;/li&gt;

&lt;li&gt;inside of a Scenario you describe the story parts. These are Given, When, Then, and And.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some important things to note on the story part descriptions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each story part can take a string or symbol description&lt;/li&gt;

&lt;li&gt;helper method calls are generated off from the story part description&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Helper method calls are generated by taking the full story part description and then removing the leading word until a helper method is found. If there are no helper methods found then an exception is raised.&lt;/p&gt;

&lt;p&gt;Some important things to note on the goals of this implementation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;in theory customers write acceptance tests&lt;/li&gt;

&lt;li&gt;in practice developers translate customer desires into acceptance tests&lt;/li&gt;

&lt;li&gt;ideally the acceptance tests should be high level enough that a customer can read/write them&lt;/li&gt;

&lt;li&gt;since developers will most likely write these acceptance tests this implementation should allow for developer shortcuts&lt;/li&gt;

&lt;li&gt;this should just work on a test/unit project, projects updating to this shouldn&amp;#8217;t have to &lt;em&gt;convert&lt;/em&gt; or make changes up front to existing code&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='scriptplugin_install'&gt;script/plugin install&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;script/plugin install \
  http://continuous.rubyforge.org/svn/tags/test_unit_story_runner-0.1.0&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='final_thoughts'&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;Before I forget you can do argument passing as well on story parts:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Scenario &amp;quot;a user successfully making a guess in the game&amp;quot; do
  Given :a_user_at_the_game
  When :they_make_a_guess_of, 20_000
  Then :they_will_win_a_car
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This feature is there, but I would advocate only using it when it helps the readability of your tests.&lt;/p&gt;

&lt;p&gt;This is a stable (tested) experiment. It&amp;#8217;s a thin wrapper around the test/unit framework and it works with any Test::Unit::TestCase. The price to pay for higher level acceptance tests is now next to nothing so give it a shot.&lt;/p&gt;

&lt;p&gt;This is the creation of a trip to Madison, WI where Drew and I had a chance to discuss and vent about the state of acceptance tests in Rails projects specifically. A few days later we had this implementation, and about a month later you&amp;#8217;ve got this post&amp;#8230;&lt;/p&gt;

&lt;p&gt;Suggestions and feedbacks are warmly welcomed.&lt;/p&gt;

&lt;p&gt;Happy rubying!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>rspec_on_rails render_and_receive_matcher</title>
   <link href="http://www.continuousthinking.com/2007/11/14/rspec_on_rails-render_and_receive_matcher.html"/>
   <updated>2007-11-14T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/11/14/rspec_on_rails-render_and_receive_matcher</id>
   <content type="html">&lt;p&gt;Earlier today my pair and I saw a repetitious pattern in our view specs when we were using helpers. It looked similar to the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;quot;displays foo&amp;quot; do
   template.should_receive(:bar).with(@foo).and_return(%|&amp;lt;p id=&amp;#39;bar&amp;#39;&amp;gt;&amp;lt;/p&amp;gt;|)
   render_it
   response.should have_tag(&amp;quot;p#bar&amp;quot;)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The repetition was in the three lines:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup a simple should receive and return&lt;/li&gt;

&lt;li&gt;make the call to render&lt;/li&gt;

&lt;li&gt;verify the response had the returned element&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tonight I spent some time spiking a way to cure this repetition. I&amp;#8217;m a bigger fan of verbosity in specs over DRYness, but I think my exploration gives us something good. The above example now looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;it &amp;quot;displays foo&amp;quot; do
   during_render do
     template.should receive_and_render(:bar).with(@foo)
   end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The receive_and_render method sets up a &lt;em&gt;should&lt;/em&gt;receive_ expectation on the template. For completeness there is also a stub_and_render method. As you might guess this method sets up a &lt;em&gt;stub!&lt;/em&gt; on the template.&lt;/p&gt;

&lt;p&gt;This doesn&amp;#8217;t just work on the template object. It works on any object, but you should probably only use it on objects that show up in the view.&lt;/p&gt;

&lt;h2 id='scriptplugin_install'&gt;script/plugin install&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;script/plugin install \
    http://continuous.rubyforge.org/svn/trunk/rspec/matchers/rspec_on_rails_render_and_receive&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='final_thoughts'&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;This in an experiment. As I am learning more about the spirit of rspec and it&amp;#8217;s organization there are a few things I want to change with this. Right now this is implemented as a matcher which doesn&amp;#8217;t feel quite right, but time will tell. So in the meantime&amp;#8230; Happy rubying!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>superclass_delegating ...</title>
   <link href="http://www.continuousthinking.com/2007/11/02/some-new-rails-gems.html"/>
   <updated>2007-11-02T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/11/02/some-new-rails-gems</id>
   <content type="html">&lt;h2 id='superclass_delegates'&gt;superclass delegates&lt;/h2&gt;

&lt;p&gt;Rails edge revision 8056 introduces some great new reader/writer/accessor methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;superclass_delegating_reader&lt;/li&gt;

&lt;li&gt;superclass_delegating_writer&lt;/li&gt;

&lt;li&gt;superclass_delegating_accessor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is best explained with an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Foo
  superclass_delegating_accessor :name
end
class Bar &amp;lt; Foo ; end
class Baz &amp;lt; Foo ; end

Foo.name = &amp;quot;Mr. T&amp;quot;          # =&amp;gt; &amp;quot;Mr. T&amp;quot;
Foo.name                    # =&amp;gt; &amp;quot;Mr. T&amp;quot;
Bar.name                    # =&amp;gt; &amp;quot;Mr. T&amp;quot;
Baz.name                    # =&amp;gt; &amp;quot;Mr. T&amp;quot;

Bar.name = &amp;quot;Junkyard Dawg&amp;quot;  # =&amp;gt; &amp;quot;Junkyard Dawg&amp;quot;
Foo.name                    # =&amp;gt; &amp;quot;Mr. T&amp;quot;
Bar.name                    # =&amp;gt; &amp;quot;Junkyard Dawg&amp;quot;
Baz.name                    # =&amp;gt; &amp;quot;Mr. T&amp;quot;

Foo.name = &amp;quot;Million $$ Man&amp;quot; # =&amp;gt; &amp;quot;Million $$ Man&amp;quot;
Foo.name                    # =&amp;gt; &amp;quot;Million $$ Man&amp;quot;
Bar.name                    # =&amp;gt; &amp;quot;Junkyard Dawg&amp;quot;
Baz.name                    # =&amp;gt; &amp;quot;Million $$ Man&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There are two reasons why this rocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;you can independently override something on a subclass without screwing up the the value for the inheritance hierarchy (which is the problem with cattr_accessor/reader/writer methods).&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;you can update the superclass&amp;#8217;s value and the subclasses which don&amp;#8217;t set their specify their own value will receive the update (which is the problem with class_inheritable_accessor/reader/writer methods).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Ruby's String#split gets explained</title>
   <link href="http://www.continuousthinking.com/2007/11/01/ruby-s-string-split-gets-explained.html"/>
   <updated>2007-11-01T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/11/01/ruby-s-string-split-gets-explained</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve posted an article on how Ruby&amp;#8217;s String#split method works over at Atomic Spin.&lt;/p&gt;

&lt;p&gt;&amp;#8220;http://spin.atomicobject.com/2007/11/01/ruby-stringsplit/&amp;#8221;:http://spin.atomicobject.com/2007/11/01/ruby-stringsplit/&lt;/p&gt;

&lt;p&gt;Not that String#split is all that exciting, but I enjoyed exploring how it&amp;#8217;s implementation truly works, and I&amp;#8217;m glad I can share with with everyone who comes across this blog.&lt;/p&gt;

&lt;p&gt;Happy rubying!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Plain Text Story Running</title>
   <link href="http://www.continuousthinking.com/2007/10/23/plain-text-story-running.html"/>
   <updated>2007-10-23T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/10/23/plain-text-story-running</id>
   <content type="html">&lt;p&gt;David Chelimsky announced yesterday the first implementation of Plain Text Stories.&lt;/p&gt;

&lt;p&gt;&amp;#8220;http://blog.davidchelimsky.net/articles/2007/10/22/plain-text-stories-on-rails&amp;#8221;:http://blog.davidchelimsky.net/articles/2007/10/22/plain-text-stories-on-rails&lt;/p&gt;

&lt;p&gt;More on this to come&amp;#8230;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Story Runner - constructive ideas</title>
   <link href="http://www.continuousthinking.com/2007/10/16/story-runner-constructive-ideas.html"/>
   <updated>2007-10-16T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/10/16/story-runner-constructive-ideas</id>
   <content type="html">&lt;p&gt;Yesterday I ranted on some criticisms that I have of RSpec&amp;#8217;s Story Runner. This post will try to follow up the criticisms which an implementation I like.&lt;/p&gt;

&lt;p&gt;The code we started with yesterday is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Story &amp;quot;View Home Page&amp;quot;, %{
  As a user I want to view my home page
  So that I can get a birds eye view of the system
}, :type =&amp;gt; RailsStory do

  Scenario &amp;quot;Latest published article&amp;quot; do
    Given &amp;quot;an author named&amp;quot;, &amp;quot;Zach&amp;quot; do |name|
       @user = User.create! :name =&amp;gt; name
    end

    When &amp;quot;he visits the home page&amp;quot;, &amp;quot;/&amp;quot; do |path|
       get path
    end

    Then &amp;quot;he should see the latest article published front and center&amp;quot; do
       # ... do something to see the article shows as expeted
    end
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here is a version of this that I like, and is implemented in test/unit story runner (which has yet to make its public debut):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Story &amp;quot;As a user I want to view my home page so that I can get a birds eye view of the system&amp;quot;

Scenario &amp;quot;Latest published article&amp;quot; do
  Given &amp;quot;an author&amp;quot;
  When &amp;quot;he visits the home page&amp;quot;
  Then &amp;quot;he will see the latest article published front and center&amp;quot;
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='story_description'&gt;Story Description&lt;/h2&gt;

&lt;p&gt;It gets rid of the unnecessary description and :type parameters. It leaves only the story itself.&lt;/p&gt;

&lt;h2 id='story_doend_blocks'&gt;Story Do/End Blocks&lt;/h2&gt;

&lt;p&gt;It removes them. They are not needed. They provide unnecessary grouping which hurts readability for the customer.&lt;/p&gt;

&lt;h2 id='scenario_doend_blocks'&gt;Scenario Do/End Blocks&lt;/h2&gt;

&lt;p&gt;These are kept. These are the one area where I feel making a visual grouping is important for the customer and the developer. All Scenario&amp;#8217;s will be attached to the Story declaration which precedes it.&lt;/p&gt;

&lt;h2 id='argument_passing'&gt;Argument Passing&lt;/h2&gt;

&lt;p&gt;I removed the arguments from the original example. They weren&amp;#8217;t providing value to my tests. I do believe argument passing is valuable but it must be in a way that adds value to the test. For example in a game I am ok with the 500_000 below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  Scenario &amp;quot;Becoming the top scorer&amp;quot; do
    Given &amp;quot;a player&amp;quot;
    When &amp;quot;he makes a guess of&amp;quot;, 500_000
    Then &amp;quot;he will see himself as the number one scorer&amp;quot;
  end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It seems that a lot of cases where arbitrary arguments are passed can be updated to make their descriptions more meaningful. It can do this by describing what is under test based on what may influence the test. Typically a user&amp;#8217;s name doesn&amp;#8217;t do this. So rather then:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Given &amp;quot;a user named Zach&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&amp;#8217;d rather see why &amp;#8220;Zach&amp;#8221; is special. Maybe he&amp;#8217;s an admin:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Given &amp;quot;an administrator&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='the_process'&gt;The Process&lt;/h2&gt;

&lt;p&gt;I haven&amp;#8217;t explained yet how test/unit story runner is implemented so bare with me. When you add a new Story or Scenario it looks like the example posted above.&lt;/p&gt;

&lt;p&gt;When you change or update an existing Story or Scenario it still looks like the example posted above. There is no embedded code, or horrendous blocks following every declaration (just the Scenario one!).&lt;/p&gt;

&lt;h2 id='reusable_code'&gt;Reusable Code&lt;/h2&gt;

&lt;p&gt;Here&amp;#8217;s where a high level overview of test/unit story runner comes to fruition. It takes a story part&amp;#8217;s (Given/When/Then/And) description and turns that into a helper method using a simple mapping process.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;take the description and downcase it&lt;/li&gt;

&lt;li&gt;strip out all punctuation&lt;/li&gt;

&lt;li&gt;then replace spaces with underscores&lt;/li&gt;

&lt;li&gt;look for the method name&lt;/li&gt;

&lt;li&gt;if it exists, execute it, otherwise strip the first word and repeat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So every story description maps to a method. And these methods can be included at the bottom of your story file or in a shared helper file (or both!).&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a few example mappings:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Given &amp;quot;an administrator&amp;quot; # =&amp;gt; an_administrator
When &amp;quot;he clicks the big button&amp;quot; # =&amp;gt; clicks_the_big_button
Then &amp;quot;he will see a picture&amp;quot;  # =&amp;gt; see_a_picture
And &amp;quot;he will see another button!&amp;quot; # =&amp;gt; see_another_button

def an_administrator
  # ...
end

def clicks_the_big_button
  # ...
end

def see_a_picture
  # ...
end

def see_another_button
  # ...
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;What I like about this is that it is easy for developers to map a description to a method, and it separates the implementation of a Story from it&amp;#8217;s definition. This allows the customers to work consistently to add and updates Story&amp;#8217;s, as well as the same for developers.&lt;/p&gt;

&lt;h2 id='final_thoughts'&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;One thing that lacks right now in the test/unit story runner is a way to mark Story&amp;#8217;s as pending. I think this can be accomplished though by capitalizing the Story, Scenario or any of the story parts.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Story &amp;quot;Logging in&amp;quot;

SCENARIO &amp;quot;User with good credentials&amp;quot; do
  # this whole scenario is pending regardless of whats in it
  Given &amp;quot;...&amp;quot;
  When &amp;quot;...&amp;quot;
end

Scenario &amp;quot;User with bad credentials&amp;quot; do
  # this whole scenario is executed
end


STORY &amp;quot;Logging out&amp;quot; # marks the whole story as pending 

Scenario &amp;quot;logged in user&amp;quot; do
  # this will be marked as pending because of the story it belongs to
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;There has been recent discussion on the RSpec mailing list about this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://rubyforge.org/pipermail/rspec-users/2007-October/003690.html&amp;#8221;:http://rubyforge.org/pipermail/rspec-users/2007-October/003690.html&lt;/li&gt;

&lt;li&gt;&amp;#8220;http://rubyforge.org/pipermail/rspec-users/2007-October/003704.html&amp;#8221;:http://rubyforge.org/pipermail/rspec-users/2007-October/003704.html&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It seems that everyone is in agreement that the holy grail is a pure plain text file. There are drawbacks with this though that are currently being evaluated.&lt;/p&gt;

&lt;p&gt;Pat Maddox has came up with a nice alternative to my above suggestion called SpecMatcher&amp;#8217;s. It looks promising to the users of rspec though that Story Runner will turn into something truly beneficial to developers and customers alike.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Story Runner - constructive criticism</title>
   <link href="http://www.continuousthinking.com/2007/10/15/story-runner-constructive-criticism.html"/>
   <updated>2007-10-15T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/10/15/story-runner-constructive-criticism</id>
   <content type="html">&lt;p&gt;If you keep up with RSpec development you&amp;#8217;ll know that RBehave has been integrated into RSpec and is known as the &amp;#8220;Story&amp;#8221; Runner. This is a unfolding of current thoughts and criticism, I apologize for any lack of explanation, but I need to do a quick braindump.&lt;/p&gt;

&lt;p&gt;I love the concept of Story Runner, but I do not like it&amp;#8217;s current syntax. Below are the criticism&amp;#8217;s for why. First though the code example I&amp;#8217;ll use to discuss the Story syntax.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Story &amp;quot;View Home Page&amp;quot;, %{
  As a user I want to view my home page
  So that I can get a birds eye view of the system
}, :type =&amp;gt; RailsStory do

  Scenario &amp;quot;Latest published article&amp;quot; do
    Given &amp;quot;an author named&amp;quot;, &amp;quot;Zach&amp;quot; do |name|
       @user = User.create! :name =&amp;gt; name
    end

    When &amp;quot;he visits the home page&amp;quot;, &amp;quot;/&amp;quot; do |path|
       get path
    end

    Then &amp;quot;he should see the latest article published front and center&amp;quot; do
       # ... do something to see the article shows as expeted
    end
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='story_description'&gt;Story Description&lt;/h3&gt;

&lt;p&gt;The story description is hideous. It requires a description, and then the story description, and then a type flag (at least for Rails projects). The Story itself should contain it&amp;#8217;s actual story description. The pseudo description set in the first parameter and the :type flag should be able to be dropped. Right now these two things do not add value, but decrease customer readability.&lt;/p&gt;

&lt;h3 id='story_doend_blocks'&gt;Story Do/End Blocks&lt;/h3&gt;

&lt;p&gt;Everything is organized with do/end blocks. While I love the closure capabilities of ruby I am not a big fan of overusing blocks in Story files themselves. I would much rather drop the do/end blocks unless they provide needed clarity.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;d like to remove the do/end block on Story because it the definition of the file format should read.. &amp;#8220;All Scenarios belong to the preceding Story declaration&amp;#8221;. Which to me is still just as readable.&lt;/p&gt;

&lt;h3 id='scenario_doend_blocks'&gt;Scenario Do/End Blocks&lt;/h3&gt;

&lt;p&gt;These should stay put. To me these are essential for providing clarity amongst your acceptance tests which scenario they are pertaining to.&lt;/p&gt;

&lt;h3 id='story_part_doend_blocks'&gt;Story Part Do/End Blocks&lt;/h3&gt;

&lt;p&gt;Story part (Given, When, Then, And) do/end blocks need to go away completely. They allow for developers to embed code directly into the high level story, which immediately reduces the readability from both a customer and developer perspective.&lt;/p&gt;

&lt;p&gt;It has been mentioned that you can use editors code folding techniques to hide the code, but as pointed out on the rspec mailing list I don&amp;#8217;t want my customer to have to use a code editor to read the acceptance tests.&lt;/p&gt;

&lt;h3 id='argument_passing'&gt;Argument Passing&lt;/h3&gt;

&lt;p&gt;After every story part in the above example you have the ability to pass in arguments to the do/end block. When this adds value it makes sense to do this, but when it is a trivial piece of information it doesn&amp;#8217;t seem to add any value. Instead it detracts readability.&lt;/p&gt;

&lt;p&gt;It detracts readability by creating new tokens a customer has to visually parse, both in the argument list for the story part and also the argument list for the do/end block. It also makes data that may not be important seem important because they are singled out as their own arguments.&lt;/p&gt;

&lt;p&gt;Argument passing should be used to add value to the story part with something that helps identify a behavior that is going to happen that your test is going to depend on. Usually this is not the user&amp;#8217;s name or the root path (&amp;#8221;/&amp;#8221;) of a site, although in some cases it may be.&lt;/p&gt;

&lt;h3 id='the_process_is_flawed'&gt;The Process Is Flawed&lt;/h3&gt;

&lt;p&gt;The ideal process is having a customer write and own the stories and the acceptance tests. As these change the customer should be responsible for updating them. The developers should be responsible for implementing them.&lt;/p&gt;

&lt;p&gt;Given the above format once you add embedded code to a Story part you immediately reduce the readability from a customer&amp;#8217;s perspective to own and maintain that Story and it&amp;#8217;s acceptance tests should it change in the future. Also if a customer changes a Story should he/she be responsible for deleting the developers implementation of last acceptance test?&lt;/p&gt;

&lt;p&gt;So the process is flawed. We shouldn&amp;#8217;t have a format which doesn&amp;#8217;t provide consistency to both the developer and the customer. So we need to tweak the Story format to enable a format which is consistent at both creation and change/update time of a Story and/or it&amp;#8217;s acceptance tests.&lt;/p&gt;

&lt;h3 id='reusable_code'&gt;Reusable Code&lt;/h3&gt;

&lt;p&gt;Embedding code inside a Story part renders it non-reusable. So to combat this you create a helper method and call from within the Story part&amp;#8217;s do/end block. So now you have a nice clean description and with a do/end block wrapping a helper method, like below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Given &amp;quot;a user logged into the system&amp;quot;, &amp;quot;Joe&amp;quot; do |name|
  @user = User.create! name
  login_as @user
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I see this and I want to refactor this. Clearly the description well named. I should be able to rely on a similarly well named helper method to handle creating or finding a user and logging that user in. If I do this then why do I need a do/end block (besides the fact of RSpec using it to trigger a pending Story)?&lt;/p&gt;

&lt;p&gt;It seems so far that you don&amp;#8217;t need a do/end block. It doesn&amp;#8217;t add value. It takes away value.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>alias_method, what would you expect?</title>
   <link href="http://www.continuousthinking.com/2007/09/21/alias_method-what-would-you-expect.html"/>
   <updated>2007-09-21T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/21/alias_method-what-would-you-expect</id>
   <content type="html">&lt;p&gt;What would you expect would happen with the following code?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class A
  def a ; puts &amp;#39;a&amp;#39; ; end
end

class B &amp;lt; A
  def a_with_b ; puts &amp;#39;b&amp;#39;; a_without_b ; end
  alias_method_chain :a, :b
end

class A
  def a_with_c ; puts &amp;#39;c&amp;#39;; a_without_c ; end
  alias_method_chain :a, :c
end

A.new.a
B.new.a&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now run it.&lt;/p&gt;

&lt;p&gt;Let me know if it meets your expectations.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>form_test_helper 1.1.0 released!</title>
   <link href="http://www.continuousthinking.com/2007/09/20/form_test_helper-1-1-0-released.html"/>
   <updated>2007-09-20T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/20/form_test_helper-1-1-0-released</id>
   <content type="html">&lt;h2 id='form_test_helper_110_has_been_released'&gt;form_test_helper 1.1.0 has been released!&lt;/h2&gt;

&lt;p&gt;This update is for those who develop on Rails Edge. A recent update to Rails broke break how the tests run with form_test_helper.&lt;/p&gt;

&lt;p&gt;So if you are on an Rails Edge revision of 7421 or higher then you should use form_test_helper trunk. The plugin repository URL is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://form-test-helper.googlecode.com/svn/form_test_helper&amp;#8221;:http://form-test-helper.googlecode.com/svn/form_test_helper&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are on Rails Edge, but you&amp;#8217;re not up to revision 7421 yet you will want to install and use form_test_helper-1.1.0. The plugin repository URL is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://form-test-helper.googlecode.com/svn/tags/form_test_helper-1.1.0&amp;#8221;:http://form-test-helper.googlecode.com/svn/tags/form_test_helper-1.1.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you are using Rails 1.2.x or a Rails Edge revision that is less then 6474 then you should use form_test_helper-1.0.0. The plugin repository URL is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://form-test-helper.googlecode.com/svn/tags/form_test_helper-1.0.0&amp;#8221;:http://form-test-helper.googlecode.com/svn/tags/form_test_helper-1.0.0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information please refer to the form_test_helper project page:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://code.google.com/p/form-test-helper/&amp;#8221;:http://code.google.com/p/form-test-helper/&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Update Feed Subscription</title>
   <link href="http://www.continuousthinking.com/2007/09/18/update-feed-subscription.html"/>
   <updated>2007-09-18T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/18/update-feed-subscription</id>
   <content type="html">&lt;p&gt;In case you happen to subscribe to this feed, please re-subscribe using the new feedburner URL.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;feed://feeds.feedburner.com/continuousthinking&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Thanks&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Not Testing Views, How Jay Tests</title>
   <link href="http://www.continuousthinking.com/2007/09/18/not-testing-views-how-jay-tests.html"/>
   <updated>2007-09-18T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/18/not-testing-views-how-jay-tests</id>
   <content type="html">&lt;p&gt;Jay Fields mentions in his post &amp;#8220;How We Test&amp;#8221;:http://blog.jayfields.com/2007/09/rails-how-we-test.html that he doesn&amp;#8217;t write view tests.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;View tests, in my experience, aren&amp;#8217;t necessary unless you are putting logic in your view. I prefer to keep the logic out of the view and ignore view tests entirely.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I agree with a lot of what Jay blogs about, but this I don&amp;#8217;t think I do, but it&amp;#8217;s hard to say because he didn&amp;#8217;t post any context or information about his statement.&lt;/p&gt;

&lt;p&gt;Although Jay has a point in keeping logic out of the view, view tests themselves are still an important aspect of testing rails applications. Here&amp;#8217;s why I think you should test your views:&lt;/p&gt;

&lt;h1 id='integration_tests_should_be_lightweight_and_very_high_level_customer_readable_or_as_close_as_you_can_get_to_it'&gt;Integration tests should be lightweight and very high level (customer readable or as close as you can get to it)&lt;/h1&gt;

&lt;h1 id='if_a_customer_wants_information_a_b_and_c_to_be_on_page_foo_then_you_need_prove_that_a_b_and_c_show_up_here_you_can_use_a_view_test_an_integration_test_would_test_going_through_the_application_but_view_tests_would_test_the_details_to_make_sure_the_right_information_is_on_the_page'&gt;If a customer wants information A, B and C to be on page foo then you need prove that A, B and C show up. Here you can use a view test! &lt;em&gt;(An integration test would test going through the application, but view tests would test the details to make sure the right information is on the page.)&lt;/em&gt;&lt;/h1&gt;

&lt;h1 id='controllerfunctional_tests_should_not_test_anything_view_related_so_this_requires_a_separate_view_test'&gt;Controller/functional tests should not test anything view related, so this requires a separate view test&lt;/h1&gt;

&lt;h1 id='view_tests_may_help_keep_your_views_organized_and_manageable'&gt;View tests may help keep your views organized and manageable&lt;/h1&gt;

&lt;h1 id='view_tests_encourage_the_use_of_using_helper_objectsmethods_because_you_dont_want_to_write_tests_to_test_logic_in_the_view_if_you_dont_test_your_views_its_easier_to_put_logic_in_there'&gt;View tests encourage the use of using helper objects/methods because you don&amp;#8217;t want to write tests to test logic in the view. If you don&amp;#8217;t test your views it&amp;#8217;s easier to put logic in there.&lt;/h1&gt;

&lt;p&gt;The thing that makes me want to keep view tests are that, if a customer says I want to see &lt;em&gt;this&lt;/em&gt; information, then it is my job to prove that it show&amp;#8217;s up. There are three options for this:&lt;/p&gt;

&lt;h1 id='put_the_testing_of_that_information_being_displayed_in_your_controller_test_this_is_painful'&gt;Put the testing of that information being displayed in your controller test. (this is painful!)&lt;/h1&gt;

&lt;h1 id='put_the_testing_of_that_information_being_displayed_in_your_integration_test_bloats_your_high_level_customer_readable_integration_test_i_want_to_avoid_this_bloat_at_this_level'&gt;Put the testing of that information being displayed in your integration test. (bloats your high level customer readable integration test. I want to avoid this bloat at this level!)&lt;/h1&gt;

&lt;h1 id='put_the_testing_of_that_information_in_its_own_isolated_view_test_my_preference_of_choice'&gt;Put the testing of that information in it&amp;#8217;s own isolated view test (my preference of choice!)&lt;/h1&gt;

&lt;p&gt;YMMV based on your project. It may also vary based on your team setup and chemistry. On my current project the developers work with a HTML/CSS Builder to build the whole site. Several times we (our developers and HTML/CSS builder) have made pieces of information or links disappear when updating views. Without our view tests we wouldn&amp;#8217;t have caught it as early on.&lt;/p&gt;

&lt;p&gt;I have heard an argument against view testing which has to do with the cost of writing and maintaining view tests against the cost of letting developers, testers or customers find them. The argument is that &amp;#8220;it&amp;#8217;s cheaper to not write a view test and let someone find a bug rather then to write a view test and fix something before someone finds a bug&amp;#8221;.&lt;/p&gt;

&lt;p&gt;I disagree with this because I think there is a lot of risk involved with letting precious information slip through the cracks. Web applications these days often involve a lot of views and a lot of information. The whole point of test automation is to not require that someone remembers to test everything. Automated view tests are faster, they never forget a piece of important information to look for and they don&amp;#8217;t require that anyone remembers everything that needs to be displayed.&lt;/p&gt;

&lt;p&gt;There are ways to test your views which makes them feel unnecessary, brittle and painful, but this can be avoided. You can have easy, meaningful view tests which add value to your project for your development team and for your customer.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Mike Clark's - How Would You Test This</title>
   <link href="http://www.continuousthinking.com/2007/09/18/mike-clark-s-how-would-you-test-this.html"/>
   <updated>2007-09-18T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/18/mike-clark-s-how-would-you-test-this</id>
   <content type="html">&lt;p&gt;Below is my rspec answer to Mike Clark&amp;#8217;s recent post &amp;#8220;How Would You Test This&amp;#8221;:http://www.clarkware.com/cgi/blosxom/2007/09/08#TestingControllers which challenges people to post their own solution to how you&amp;#8217;d test his MenuitemsController.&lt;/p&gt;

&lt;p&gt;One thing Mike doesn&amp;#8217;t mention about the frustration that people have with testing controllers is testing that testing controllers requires you to test your view associated with it (unless you are only redirecting).&lt;/p&gt;

&lt;p&gt;There are ways around testing views, but most install a custom hack or installing a third party plugin or framework like rspec, Test::Rails or view_test.&lt;/p&gt;

&lt;p&gt;Since Mike didn&amp;#8217;t include any views in his original post I haven&amp;#8217;t provided any tests for them in this post.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require File.dirname(__FILE__) + &amp;#39;/../spec_helper&amp;#39;

def do_post(attributes)
  post :create, :menu_item =&amp;gt; attributes
end

describe MenuItemsController, &amp;#39;Creating a new menu item (success)&amp;#39; do

  before do
    attributes = {&amp;#39;name&amp;#39; =&amp;gt; &amp;quot;Enchilada&amp;quot;, &amp;#39;price&amp;#39; =&amp;gt; 4.99}
    @menu_item = mock_model(MenuItem)
    MenuItem.should_receive(:new).with(attributes).once.and_return(@menu_item)
    @menu_item.should_receive(:save).with().once.and_return(true)

    do_post attributes
  end

  it &amp;#39;redirects to index&amp;#39; do
    response.should redirect_to(menu_items_url)
  end

  it &amp;#39;assigns @menu_item&amp;#39; do
    assigns[:menu_item].should be(@menu_item)
  end

  it &amp;#39;sets the flash notice&amp;#39; do
    flash[:notice].should_not be(nil)    
  end
end

describe MenuItemsController, &amp;#39;Creating a new menu item (failure)&amp;#39; do

  before do
    attributes = {&amp;#39;name&amp;#39; =&amp;gt; &amp;quot;Enchilada&amp;quot;, &amp;#39;price&amp;#39; =&amp;gt; 4.99}
    @menu_item = mock_model(MenuItem)
    MenuItem.should_receive(:new).with(attributes).once.and_return(@menu_item)
    @menu_item.should_receive(:save).with().once.and_return(false)

    do_post attributes
  end

  it &amp;#39;renders new template on failed save&amp;#39; do
    response.should be_success
    response.should render_template(&amp;#39;new&amp;#39;)
  end

  it &amp;quot;assigns @menu_item&amp;quot; do
    assigns[:menu_item].should be(@menu_item)
  end

  it &amp;quot;not set the flash notice&amp;quot; do
    flash[:notice].should be(nil)      
  end

end&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Updating Rails Edge From 7292 to 7513</title>
   <link href="http://www.continuousthinking.com/2007/09/18/another-rails-edge-update.html"/>
   <updated>2007-09-18T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/18/another-rails-edge-update</id>
   <content type="html">&lt;p&gt;I just migrated our project from Rails Edge revision 7292 to Rails Edge revision 7513. Some of the things I ran into:&lt;/p&gt;

&lt;h2 id='extracted_plugins'&gt;Extracted Plugins&lt;/h2&gt;

&lt;p&gt;The following common plugins have been extracted and must now be installed as plugins from http://svn.rubyonrails.org/rails/plugins/PLUGIN_NAME:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;acts_as_list&lt;/li&gt;

&lt;li&gt;acts_as_nested_set&lt;/li&gt;

&lt;li&gt;acts_as_tree&lt;/li&gt;

&lt;li&gt;in_place_editing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='broken_functionality'&gt;Broken Functionality&lt;/h2&gt;

&lt;p&gt;The acts_as_modified plugin has been broken with changeset &amp;#8220;[7513]&amp;#8221;:http://dev.rubyonrails.org/changeset/7315 .&lt;/p&gt;

&lt;h2 id='has_many_associations_change'&gt;Has Many Associations Change&lt;/h2&gt;

&lt;p&gt;Changeset &amp;#8220;[7511]&amp;#8221;:http://dev.rubyonrails.org/changeset/7511 made it so you can no longer call &lt;em&gt;create&lt;/em&gt; on a has many association when the parent is a new record. To get around this you need to ensure your parent is saved first.&lt;/p&gt;

&lt;p&gt;That&amp;#8217;s all! Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>rspec's mocking framework is staying put</title>
   <link href="http://www.continuousthinking.com/2007/09/05/rspec-s-mocking-framework-is-staying-put.html"/>
   <updated>2007-09-05T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/05/rspec-s-mocking-framework-is-staying-put</id>
   <content type="html">&lt;p&gt;On the rspec-users mailing list there&amp;#8217;s been talk recently of removing the built-in mocking framework. The idea was that it offered nothing that the existing mocking frameworks like Mocha, Flexmock or Hardmock didn&amp;#8217;t already offer.&lt;/p&gt;

&lt;p&gt;The other day David Chelimsky announced in this &amp;#8220;post&amp;#8221;:http://www.nabble.com/Re%3A-Deprecating-the-mocking-framework&amp;#8211;p12463749.html that it will be keeping rspec&amp;#8217;s mocking framework for the foreseeable future.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>form_test_helper on edge</title>
   <link href="http://www.continuousthinking.com/2007/09/01/form_test_helper-on-edge.html"/>
   <updated>2007-09-01T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/09/01/form_test_helper-on-edge</id>
   <content type="html">&lt;p&gt;Well I&amp;#8217;ve joined the Google Code project for &amp;#8220;form_test_helper&amp;#8221;:http://code.google.com/p/form-test-helper/ . So form_test_helper will now work with Rails Edge, trunk revisions 6764 all the way up to 7393 (todays latest commit).&lt;/p&gt;

&lt;p&gt;If you are using Rails 1.2.x or a Rails Edge revision less then 6764 then please use the 1.0.0 tag for form_test_helper, otherwise use what we consider form_test_helper trunk.&lt;/p&gt;

&lt;h2 id='installing_for_rails_edge_greater_than_or_equal_to_6764'&gt;Installing for Rails Edge greater than or equal to 6764&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;script/plugin install http://form-test-helper.googlecode.com/svn/form_test_helper&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='installing_for_rails_edge_less_than_6764'&gt;Installing for Rails Edge less than 6764&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;script/plugin install http://form-test-helper.googlecode.com/svn/tags/form_test_helper-1.0.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am going to put these notes on the project home page as soon as I get permissions to make that update if &amp;#8220;Jason&amp;#8221;:http://www.jasongarber.com/ doesn&amp;#8217;t make the change himself.&lt;/p&gt;

&lt;p&gt;Enjoy form_test_helper on Edge!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>form_test_helper for Rails Edge</title>
   <link href="http://www.continuousthinking.com/2007/08/26/form_test_helper-for-rails-edge.html"/>
   <updated>2007-08-26T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/26/form_test_helper-for-rails-edge</id>
   <content type="html">&lt;p&gt;The wonderful plugin &amp;#8220;form_test_helper&amp;#8221;:http://code.google.com/p/form-test-helper/ written by &amp;#8220;Jason Garber&amp;#8221;:http://www.jasongarber.com/ hasn&amp;#8217;t worked with Rails Edge since this past spring. I monkey patched it to get it to work a few months ago, and tonight I submitted a patch which fixes form_test_helper with Rails Edge. The plugin has been tested to work with Rails Edge revisions 6764 to 7358.&lt;/p&gt;

&lt;p&gt;The patch can be found &amp;#8220;here&amp;#8221;:http://www.continuousthinking.com/form_test_helper_edge.diff&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;http://www.continuousthinking.com/form_test_helper_edge.diff&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I talked to Jason in July about submitting a patch and I believe it&amp;#8217;ll be accepted and a new form_test_helper released, but in case you don&amp;#8217;t want to wait please apply the patch yourself. You can do this by opening a terminal and following the below steps:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$&amp;gt; cd RAILS_ROOT/vendor/plugins
$&amp;gt; wget http://www.continuousthinking.com/form_test_helper_edge.diff
$&amp;gt; cd form_test_helper
$&amp;gt; patch -p0 &amp;lt; ../form_test_helper_edge.diff

# you should now be able to run rake
$&amp;gt; rake
(in /Users/zdennis/source/opensource_projects/blah/vendor/plugins/form_...
/opt/local/bin/ruby -Ilib:lib &amp;quot;/opt/local/lib/ruby/gems/1.8/...
Loaded suite /opt/local/lib/ruby/gems/1.8/gems/rake-0.7.3/lib/rake/rake...
Started
.................................................................
Finished in 0.372041 seconds.

65 tests, 293 assertions, 0 failures, 0 errors&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>view_test 0.10.0 released</title>
   <link href="http://www.continuousthinking.com/2007/08/25/view_test-0-10-0-released.html"/>
   <updated>2007-08-25T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/25/view_test-0-10-0-released</id>
   <content type="html">&lt;p&gt;view_test 0.10.0 has been released. Install it now:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;script/plugin install http://continuous.rubyforge.org/svn/tags/view_test-0.10.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;#8220;David Chelimsky&amp;#8221;:http://blog.davidchelimsky.net/ asked me the other day if view_test allowed you to write view tests without having created your controller yet. I said yes naively. Last night I fired up the MacBook Pro and looked over my specs to see if I had tested that case (I thought I did), but I didn&amp;#8217;t so I wrote a failing spec and then implemented it.&lt;/p&gt;

&lt;p&gt;You can now create a view test and create the correct app/views/products directory structure and have it work without having to have a ProductsController in existance. &lt;em&gt;(Examples are in &amp;#8220;Behaviors&amp;#8221;:http://behaviors.rubyforge.org format)&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ProductsShowTest &amp;lt; Rails::ViewTest::TestCase

  should &amp;quot;display hello world when rendering products/show.html.erb&amp;quot; do
     render :file =&amp;gt; &amp;quot;products/show&amp;quot;
     assert_select &amp;#39;hello world&amp;#39;
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, David, I didn&amp;#8217;t lie on purpose, and hopefully this release will redeem my answer! Enjoy!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails, introducing view_tests</title>
   <link href="http://www.continuousthinking.com/2007/08/24/rails-introducing-view_tests.html"/>
   <updated>2007-08-24T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/24/rails-introducing-view_tests</id>
   <content type="html">&lt;p&gt;view_test is a lightweight extension to test/unit specific to Ruby on Rails which gives you rspec like controller and view tests. It contains two key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Improved functional tests&lt;/li&gt;

&lt;li&gt;View tests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you&amp;#8217;re developing a rails app and you&amp;#8217;re using test/unit then view_test gives you the ability to achieve a clean separation between functional tests and view tests. view_test is a direct influence of rspec and Test::Rails by zenspider.&lt;/p&gt;

&lt;h2 id='improved_functional_tests'&gt;Improved functional tests&lt;/h2&gt;

&lt;p&gt;Functional tests are now simpler. You no longer have to set things up so your test can successfully render it&amp;#8217;s template. Instead you can make an expectation against an explicit render call or you can render the template that would have been rendered.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a few examples: &lt;em&gt;(all code examples are written with &amp;#8220;behaviors&amp;#8221;:http://behaviors.rubyforge.org syntax which is another extension to test/unit to give it nicer syntax)&lt;/em&gt;:&lt;/p&gt;

&lt;h3 id='expecting_an_implicit_call_to_the_default_template'&gt;Expecting an implicit call to the default template&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;# in the controller you have the action &amp;#39;show&amp;#39;
# Note: there is no call to render
def show
end

# in the test
class ProductsControllerTest &amp;lt; Rails::ControllerTest::TestCase

  should &amp;quot;render the show template on #show&amp;quot; do
    expect_render :action =&amp;gt; &amp;quot;show&amp;quot;
    get :show
  end

# ....&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='expecting_an_explicit_call_to_another_action'&gt;Expecting an explicit call to another action&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;# in the controller you have the action &amp;#39;show&amp;#39;
# Note: the explicit call to render
def show
  render :action =&amp;gt; &amp;quot;index&amp;quot;
end

# Note: the explicit call to render
def list
  render :template =&amp;gt; &amp;quot;blah&amp;quot;
end

# in the test 
class ProductsControllerTest &amp;lt; Rails::ControllerTest::TestCase

  should &amp;quot;render the show template on #show&amp;quot; do
    expect_render :action =&amp;gt; &amp;quot;index&amp;quot;
    get :show
  end

  should &amp;quot;render the template blah on #list&amp;quot; do
    expect_render :template =&amp;gt; &amp;quot;blah&amp;quot;
    get :list
  end

# ...&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='stubbing_the_call_to_render_and_checking_the_rendered_template'&gt;Stubbing the call to render and checking the rendered template&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;# in the controller you have the action #show
# Note: the explicit call to render
def show
  render :action =&amp;gt; &amp;quot;index&amp;quot;
end

# in the test
class ProductsTest &amp;lt; Rails::ControllerTest::TestCase

  should &amp;quot;render the products/index template on #show&amp;quot; do
    stub_render
    get :show
    assert_template &amp;quot;index&amp;quot;
  end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The benefit of this is that you can successfully use mocks in your functional tests without having to try to compensate for things in your views. Your functional tests now only really test your controllers.&lt;/p&gt;

&lt;h3 id='migrating_to_improved_functional_tests'&gt;Migrating to Improved Functional Tests&lt;/h3&gt;

&lt;p&gt;When you use stub_render or expect_render in an individual test only that test will be updated to use the stub or render. This allows you to migrate one test at a time to improved functional tests without having to change everything at one.&lt;/p&gt;

&lt;h2 id='view_tests'&gt;View Tests&lt;/h2&gt;

&lt;p&gt;View tests are isolated unit tests for your views. One important feature of this is that you can expect or stub &amp;#8220;render :partial&amp;#8221; calls inside of a view. In fact you have to expect or stub them. There is no way to allow a &amp;#8220;render :partial&amp;#8221; to pass through to the real view. This is a implementation decision to enforce the convention of keeping a 1:1 test to template ratio.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class ScoreboardsPartialViewTest &amp;lt; Rails::ViewTest::TestCase
  # this is optional if you name your test case well
  controller_name &amp;#39;scoreboards&amp;#39; 

  def setup
	# assign view level instance variables
    assigns[:scores] = [
      stub(:player =&amp;gt; &amp;quot;joe&amp;quot;, :score =&amp;gt; 100),
      stub(:player =&amp;gt; &amp;quot;bob&amp;quot;, :score =&amp;gt; 200)
    ]
  end

  should &amp;quot;format points with commas&amp;quot;
    expect_helper(:format_points).with(100).returns(&amp;quot;joe&amp;#39;s points&amp;quot;)
    expect_helper(:format_points).with(200).returns(&amp;quot;bob&amp;#39;s points&amp;quot;)

    render :partial =&amp;gt; &amp;quot;scoreboard/_scoreboard&amp;quot;

    assert_select &amp;#39;#scoreboard .points&amp;#39;, /joe&amp;#39;s points/, &amp;quot;didn&amp;#39;t call the helper&amp;quot;
    assert_select &amp;#39;#scoreboard .points&amp;#39;, /bob&amp;#39;s points/, &amp;quot;didn&amp;#39;t call the helper&amp;quot;
  end

end&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='downloading__installing'&gt;Downloading / Installing&lt;/h2&gt;

&lt;p&gt;You can install view_tests as a rails plugin. It has been tested with Rails Edge REVISIONS 7155 and later.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;script/plugin install http://continuous.rubyforge.org/svn/tags/view_test-0.9.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can also download the tgz file from &amp;#8220;rubyforge&amp;#8221;:http://continuous.rubyforge.org .&lt;/p&gt;

&lt;h2 id='dependencies'&gt;Dependencies&lt;/h2&gt;

&lt;p&gt;view_test relies on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mocha 0.5.2 or higher - &amp;#8220;rubyforge page&amp;#8221;:http://mocha.rubyforge.org&amp;#8221;&lt;/li&gt;

&lt;li&gt;Metaid 1.0 or higher - &amp;#8220;rubyforge page&amp;#8221;:http://rubyforge.org/frs/?groupd_id=1272 and &amp;#8220;_why&amp;#8217;s metaid page&amp;#8221;:http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='disclaimer'&gt;Disclaimer&lt;/h2&gt;

&lt;p&gt;The goal of view_test isn&amp;#8217;t to stop people from migrating to rspec or Test::Rails. It exists to allow people who have decided to use test/unit on new code or existing code to achieve a better level of testing in Rails.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Agile Conference 2007, Day Four</title>
   <link href="http://www.continuousthinking.com/2007/08/19/agile-conference-2007-day-four.html"/>
   <updated>2007-08-19T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/19/agile-conference-2007-day-four</id>
   <content type="html">&lt;p&gt;Day four was my last day at this year&amp;#8217;s Agile Conference. I didn&amp;#8217;t attend last year&amp;#8217;s, but from what I gather from some coworkers I went with the schedule shifted a half day forward. In the morning I spent my time eating breakfast and listening to Uncle Bob and several other folks from Object Mentor carry on some interesting discussions. (This was not an official talk, I just happened to be eating where the OM team was hanging out.)&lt;/p&gt;

&lt;p&gt;So on the fourth day I spent time at the following sessions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating Change One &amp;#8220;Tic Tac&amp;#8221; at a Time - &amp;#8220;Alistair Cockburn&amp;#8221;:http://alistair.cockburn.us/ and &amp;#8220;Jeffery Fredericks&amp;#8221;:http://www.agitar.com/&lt;/li&gt;

&lt;li&gt;Refactoring Databases : Evolutionary Database Design - &amp;#8220;Scott Ambler&amp;#8221;:http://www.ambysoft.com/ and &amp;#8220;Pramod Sadalage&amp;#8221;:http://databaserefactoring.com/PramodSadalage.html&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='creating_change_one_tic_tac_at_a_time'&gt;Creating Change One &amp;#8220;Tic Tac&amp;#8221; at a Time&lt;/h2&gt;

&lt;p&gt;This session was very group oriented. Unlike some of the other sessions which involved roleplaying this session put about five to eight people at a table. The first goal was to discuss problem or obstacle that was overcome moving to some form of Agile practices. It could be a little win or a big win, but it had to be a win (Alistair and Jeffrey weren&amp;#8217;t interested in the failures).&lt;/p&gt;

&lt;p&gt;Each group had to vote and decide on a winning &amp;#8220;win&amp;#8221; for their group. Each &amp;#8220;win&amp;#8221; had to presented to the whole session audience. After everyone had heard all of the stories people were able to self-organize and go to the tables that had the &amp;#8220;win&amp;#8221; that they were interested in. Each table then had to discuss and list out the challenges and what led to them being overcome.&lt;/p&gt;

&lt;p&gt;At the end Alistair and Jeffrey spent about 10 minutes going through some slides explaining the benefits of small tic tac changes rather then huge sweeping changes. They showed a nice graph which I haven&amp;#8217;t been to find online yet. If anyone has a reference of it please send me a link.&lt;/p&gt;

&lt;p&gt;What the graph portrayed was the effects of making changes and then benefiting from those changes. The idea is that for every change you make productivity goes down, and you stay in a dip and as you master the change your productivity goes back up and eventually surpasses your previous level of productivity. So this means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the bigger the change, the deeper the dip and the longer the dip drags out&lt;/li&gt;

&lt;li&gt;the smaller the change, the shallower the dip and the shorter you are able to surpass your old level of productivity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you make a lot of small changes (one &amp;#8220;tic tac&amp;#8221;) at a time you end resulting getting a much higher level productivity in a shorter timeframe assuming each of your changes leads to better practices and higher efficiency. If you try to do too much you will be less productive then before and for a longer period of time. Alistair and Jeffrey believe that this is what causes so many teams who claim &amp;#8220;Agile&amp;#8221; failed for them.&lt;/p&gt;

&lt;h2 id='refactoring_databases__evolutionary_database_design'&gt;Refactoring Databases : Evolutionary Database Design&lt;/h2&gt;

&lt;p&gt;Scott walked through the slides and Pramod did the real time demos. The &amp;#8220;evolutionary&amp;#8221; part of the discussion and probably their book, &amp;#8220;Refactoring Database - Evolutionary Database Design&amp;#8221;:http://databaserefactoring.com/ is more revolutionary to hard core DBAs who live a sheltered technical life which leads me to assume people from corporate america.&lt;/p&gt;

&lt;p&gt;At the a technical level the presentation focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;incremental changes to the schema&lt;/li&gt;

&lt;li&gt;versioning your database (rollback / roll forward features)&lt;/li&gt;

&lt;li&gt;testing your data (verifying your setup data)&lt;/li&gt;

&lt;li&gt;testing your interaction with the data (triggers, stored procedures, etc.)&lt;/li&gt;

&lt;li&gt;use source control&lt;/li&gt;

&lt;li&gt;developers should be able to check out and run a simple script which builds a development database for them&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At a higher level the presentation focused on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;developers pairing with DBAs and vise versa&lt;/li&gt;

&lt;li&gt;realizing that DBA is a different role, but not necessarily a different position&lt;/li&gt;

&lt;li&gt;doing better database practices all around&lt;/li&gt;

&lt;li&gt;communicating with the rest of the world&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scott has a lot of bundled up frustration with a developers, DBAs and &amp;#8220;agile&amp;#8221; people. He thinks there is too much of a barrier between developers and DBAs. He doesn&amp;#8217;t like it when developers go around the DBAs because DBAs move too slow, although he recognizes that sometimes that&amp;#8217;s just what you have to do. He seems somewhat ticked off about how &amp;#8220;agile&amp;#8221; developers focus on the practices during the application development, but that they slack when it comes to the database development. And this is going to get its own paragraph&amp;#8230;&lt;/p&gt;

&lt;p&gt;I agree with Scott when it comes to application development and database development. I think that too many developers consider the database a big dumb hash. At 40,000 feet I can agree with that analogy, but when you get closer to the ground the analogy stops working (with the current limitations of databases and disk storage mediums that we have today). Premature optimization is evil yes, but understanding SQL and how databases work isn&amp;#8217;t premature optimization. Sometimes things that can be done in some simple SQL is more readable and faster to implement and test then the equivalent ruby or java code. Especially things which can be done with simple joins.&lt;/p&gt;

&lt;p&gt;Back to the presentation&amp;#8230;. Scott and Pramod are pushing for the same type of practices being used at the database level that are being used at the application level. Databases are archaic. SQL is archaic. It&amp;#8217;s not elegant, but it&amp;#8217;s still a very important piece to a lot of applications. Use the database when you should and test the hell out of what you&amp;#8217;re doing. If you&amp;#8217;re not using &amp;#8220;Ruby on Rails&amp;#8221;:http://www.rubyonrails.com one of the best advantages of its framework is its builtin database migration tools. Thee are also plugins like &amp;#8220;Migration Test Helper&amp;#8221;:http://spin.atomicobject.com/2007/02/27/migration-testing-in-rails/ which takes your testing of the database that much further.&lt;/p&gt;

&lt;h2 id='after_refactoring_databases'&gt;After Refactoring Databases&lt;/h2&gt;

&lt;p&gt;I spent some time in the &amp;#8220;Dungeon&amp;#8221; where people were helping on creating a Rails web application for a non-profit group. I had some great discussion with &amp;#8220;Paul Pagel&amp;#8221;:http://www.8thlight.com/main/bios/paul from &amp;#8220;8th Light&amp;#8221;:http://www.8thlight.com and also &amp;#8220;David Chelimsky&amp;#8221;:http://blog.davidchelimsky.net/ who is one of developers for &amp;#8220;RSpec&amp;#8221;:http://rspec.rubyforge.org&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Agile Conference 2007, Day Two</title>
   <link href="http://www.continuousthinking.com/2007/08/15/agile-conference-2007-day-two.html"/>
   <updated>2007-08-15T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/15/agile-conference-2007-day-two</id>
   <content type="html">&lt;p&gt;Agile Conference 2007, Day Two&lt;/p&gt;

&lt;p&gt;For the second day of Agile Conference 2007 I hit two sessions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agile Developer Practices for Dynamic Languages (&amp;#8220;Paul King&amp;#8221;:www.asert.com)&lt;/li&gt;

&lt;li&gt;The Crystal Methods (&amp;#8220;Alistair Cockburn&amp;#8221;:http://alistair.cockburn.us/)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='agile_developer_practices_for_dynamic_languages'&gt;Agile Developer Practices for Dynamic Languages&lt;/h2&gt;

&lt;p&gt;This first session was alright. The presentation revolves around the presenter being well grounded in Java and its related technologies, and recently he has been moving towards dynamic languages. As he and his team are moving towards dynamic languages (he prefers &amp;#8220;Groovy&amp;#8221;:http://groovy.codehaus.org/ and his non-present co-presenter preferred &amp;#8220;Ruby&amp;#8221;:http://www.ruby-lang.org) they are realizing that a lot of design patterns, techniques and requirements of statically typed languages aren&amp;#8217;t required, or are implemented completely different in dynamic languages.&lt;/p&gt;

&lt;p&gt;The talk really focuses on showing people who understand things in java, but not in dynamic languages, that in fact you can do the same things (or in some cases you don&amp;#8217;t need to do it at all) in a different way. He walked through things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;dynamic builders (think &amp;#8220;Markaby&amp;#8221;:http://redhanded.hobix.com/inspect/markabyForRails.html or &amp;#8220;Haml&amp;#8221;:http://haml.hamptoncatlin.com/ in ruby) vs. using builder objects in java&lt;/li&gt;

&lt;li&gt;you don&amp;#8217;t really need factories like you do in java&lt;/li&gt;

&lt;li&gt;delegation is much simpler then it is in java&lt;/li&gt;

&lt;li&gt;DSLs are easier to write then in is in java&lt;/li&gt;

&lt;li&gt;brief examples of &amp;#8220;meta-programming&amp;#8221; and that it sucks to do in java&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Three people in the session couldn&amp;#8217;t get over the fact that with dynamic languages you lose the ability to have auto-completion in your editors with the same level of granularity that you get with Java code and editors like IntelliJ or Eclipse. If their ability to productively program comes down to auto-completion or they think that auto-completion will hinder their ability to effectively solve problems I think there are bigger problems on there team.&lt;/p&gt;

&lt;h2 id='the_crystal_methods'&gt;The Crystal Methods&lt;/h2&gt;

&lt;p&gt;&amp;#8220;Alistair Cockburn&amp;#8221;:http://alistair.cockburn.us/is a great speaker. He started out by focusing on how he believes people learn. According to Alistair people learn in three states: learn (shu), collect (ha), and invent/blend (ri). These stages directly correlate to the level of understanding and experience someone has in a particular area.&lt;/p&gt;

&lt;p&gt;People start in the &amp;#8220;shu&amp;#8221; stage and learn with a clear set of instructions and/or rules. Next people move to the &amp;#8220;ha&amp;#8221; stage where they are able to apply the rules and they are able to understand that the rules aren&amp;#8217;t necessarily giving them the best results. Here they start to experiment with edge/exception cases and they apply different rules. In the &amp;#8220;ri&amp;#8221; stage the person has moved beyond the instructions/rules.&lt;/p&gt;

&lt;p&gt;Moving on from how people learn, Alistair presents Crystal as a collection of methodologies, and he believes that different methodologies are better suited for different types of contexts and number of people. Hence there are Crystal Clear, Crystal Yellow, Crystal Orange and Crystal Red.&lt;/p&gt;

&lt;p&gt;He points out that Crystal methodologies won&amp;#8217;t tell you how-to do something, they will merely tell you the properties that you need to have to be successful, and as a team he expects you to find the best ways to get there, although he does assert that certain key techniques (like Reflection, high visibility, etc) are key to implement Crystal methods.&lt;/p&gt;

&lt;p&gt;Alistair&amp;#8217;s background for coming up with Crystal Clear started back in the early 90s when he started traveling worldwide to to talk to different team about their projects. Through his years of experience he concludes that Crystal is made up of the good things that were common among all of them.&lt;/p&gt;

&lt;p&gt;Alistair also believes that methodologies can be classified by a given genetic code. Here is the code for Crystal:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Mindset&lt;/li&gt;

&lt;li&gt;Design priorities&lt;/li&gt;

&lt;li&gt;Project priorities&lt;/li&gt;

&lt;li&gt;Design principles&lt;/li&gt;

&lt;li&gt;Key techniques&lt;/li&gt;

&lt;li&gt;Samples&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;He also focuses on the seven properties of a successful project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frequent delivery&lt;/li&gt;

&lt;li&gt;Reflective improvement&lt;/li&gt;

&lt;li&gt;Close communication&lt;/li&gt;

&lt;li&gt;Personal Safety&lt;/li&gt;

&lt;li&gt;Focus&lt;/li&gt;

&lt;li&gt;Easy access to expert users&lt;/li&gt;

&lt;li&gt;Technical Environment ** automated unit tests ** automated acceptance tests ** frequent commits and system integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Crystal itself is based on the first three of these properties.&lt;/p&gt;

&lt;p&gt;In the past I had read the Crystal Clear book and I have even implemented many of the properties and techniques in it so the session wasn&amp;#8217;t completely new material, but I feel I was able to take away more from the session from having prior knowledge then if I were to come in with a blank slate.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Agile Conference 2007, Day Three</title>
   <link href="http://www.continuousthinking.com/2007/08/15/agile-conference-2007-day-three.html"/>
   <updated>2007-08-15T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/15/agile-conference-2007-day-three</id>
   <content type="html">&lt;p&gt;Today involved four sessions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean Code 1: Cleaning Up A Mess - &amp;#8220;Uncle Bob&amp;#8221;:http://www.objectmentor.com/&lt;/li&gt;

&lt;li&gt;Clean Code 2: Craftsmanship and Professionalism - &amp;#8220;Uncle Bob&amp;#8221;:http://www.objectmentor.com/&lt;/li&gt;

&lt;li&gt;Open Source Testing Tools to Support Agile Development/Testing - &amp;#8220;Paul King&amp;#8221;:http://www.asert.com/&lt;/li&gt;

&lt;li&gt;Learning to Say &amp;#8220;No&amp;#8221; - &amp;#8220;Stacia Broderick&amp;#8221;:http://www.scrumalliance.org/profiles/32-stacia-broderick , &amp;#8220;Michele Sliger&amp;#8221;:http://theagileblog.net/2_authors/michele_sliger/&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='clean_code_1_cleaning_up_a_mess'&gt;Clean Code 1: Cleaning Up A Mess&lt;/h2&gt;

&lt;p&gt;Uncle Bob delivered a great talk on cleaning up a mess. He asserts that developers want to go fast and that to the only way to go fast is to go well.&lt;/p&gt;

&lt;p&gt;He uses a &amp;#8220;dinner&amp;#8221; analogy to clarify his points on messy code. The dinner analogy starts with a question, &amp;#8220;What is the fastest way to prepare dinner?&amp;#8221;. Regardless of ordering out or preparing it yourself, the fastest way is not do the dishes or cleanup afterwards. However, if you don&amp;#8217;t do the dishes you are directly impeding your ability to quickly prepare dinner the next time.&lt;/p&gt;

&lt;p&gt;There is much more to his talk, but you should really see it to experience it. I believe he&amp;#8217;ll be at the &amp;#8220;GLSEC&amp;#8221;:http://www.glsec.org/ conference in west Michigan later this fall.&lt;/p&gt;

&lt;h2 id='clean_code_2_craftsmanship_and_professionalism'&gt;Clean Code 2: Craftsmanship and Professionalism&lt;/h2&gt;

&lt;p&gt;Uncle Bob&amp;#8217;s second talk was more impressive to me then the first because it hit home a lot principles and practices that he views are required to be a professional developer and an agile developer.&lt;/p&gt;

&lt;p&gt;While I&amp;#8217;m not going to list all of them I would like to list a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short iterations (short feedback loop)&lt;/li&gt;

&lt;li&gt;Avoiding &amp;#8220;solve everything&amp;#8221; architectures (he calls them Turgid Viscous Architectures)&lt;/li&gt;

&lt;li&gt;No Grand Redesign&lt;/li&gt;

&lt;li&gt;Incremental improvement&lt;/li&gt;

&lt;li&gt;TDD (minimal professionalism)&lt;/li&gt;

&lt;li&gt;Code Coverage (strive for 100%)&lt;/li&gt;

&lt;li&gt;Apprenticeship&lt;/li&gt;

&lt;li&gt;and many more&amp;#8230;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I really enjoyed one of his quotes on Grand Redesign:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Programmers like to make a huge mess and then bitch about it so they can make the next huge mess.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I haven&amp;#8217;t read Uncle Bob&amp;#8217;s books yet (real name Robert C. Martin) but that is going to change especially after I saw good reviews on a &amp;#8220;blog post&amp;#8221;:http://www.artima.com/weblogs/viewpost.jsp?thread=32026 from Guido van Rossum back in 2004.&lt;/p&gt;

&lt;h2 id='open_source_testing_tools_to_support_agile_developmenttesting'&gt;Open Source Testing Tools to Support Agile Development/Testing&lt;/h2&gt;

&lt;p&gt;This talk just didn&amp;#8217;t do it for me. It focused on every Java related. I&amp;#8217;ve moved on from Java development, and what is happening in the Java world just isn&amp;#8217;t very exciting (yes Groovy is nice). The presenter seems to know Java and everything associated with it very well. I think I just wasn&amp;#8217;t the right type of audience.&lt;/p&gt;

&lt;p&gt;It would have been nice if the talk was titled &amp;#8220;Open Source Testing Tools to Support Java Development&amp;#8221;.&lt;/p&gt;

&lt;h2 id='learning_to_say_no'&gt;Learning to Say &amp;#8220;No&amp;#8221;&lt;/h2&gt;

&lt;p&gt;This talk just didn&amp;#8217;t do it for me either. The presenters did a lot of interaction and role playing with the audience on topics like saying &amp;#8220;no&amp;#8221; to your boss if he asks you to work late tonight, or this weekend. They gave useful ways to &amp;#8220;preserve your self&amp;#8221; and also work with whomever may be asking you to sacrifice personal time for their needs.&lt;/p&gt;

&lt;p&gt;The techniques they show are useful, but most of it is common sense. This talk seems directly applicable to people who feel stuck in a corporate job who get taken advantage of, but don&amp;#8217;t know the correct avenue to start breaking the cycle while keeping their job.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Agile Conference 2007, Day One</title>
   <link href="http://www.continuousthinking.com/2007/08/14/agile-conference-2007-day-one.html"/>
   <updated>2007-08-14T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/08/14/agile-conference-2007-day-one</id>
   <content type="html">&lt;p&gt;Today&amp;#8217;s the first day (or half day) of Agile Conference 2007. We&amp;#8217;re into the wee hours of the early evening (8:46pm) and the social celebration (aka Ice Breaker) is underway. Whoever said geeks were asocial beings haven&amp;#8217;t been to an Ice Breaker (or they didn&amp;#8217;t serve enough beer).&lt;/p&gt;

&lt;p&gt;I went to two sessions today.&lt;/p&gt;

&lt;h2 id='the_first_session'&gt;The First Session&lt;/h2&gt;

&lt;p&gt;The first was on test driving the development of client/server application which was essentially a Shout/Echo server. It was written in ruby and the first half of the presentation was ok (I didn&amp;#8217;t stay for the second half). The presenter drove the audience through a live coding session of implementing the server using test/unit.&lt;/p&gt;

&lt;p&gt;I didn&amp;#8217;t take too much away from this presentation. I know ruby, I know ruby&amp;#8217;s socket library, I do TDD and I know test/unit very well. It was a good presentation overall and would be a good introduction for someone who perhaps wanted to learn ruby and/or TDD, or wanted to sharpen their skills on ruby&amp;#8217;s socket library.&lt;/p&gt;

&lt;h2 id='the_second_session'&gt;The Second Session&lt;/h2&gt;

&lt;p&gt;The second session was on Agile Myths. It was a collaborative and interactive session. The two presenters presented a list of 20 agile myths that they had heard while consulting. They also added in myths from the audience. After a quick high level overview of each myth they took out large manila folders and listed out each myth, and the audience formed groups of about five and every group picked a few myths.&lt;/p&gt;

&lt;p&gt;The focus of each group was to either support the myth or debunk the myth, and they had to backup their claim. At the end each myth and supporting claim was discussed as a whole audience. This led to some very interesting discussions. After hearing opposing arguments on alot of the myths and claims I feel more confident being a true practitioner of agile methods.&lt;/p&gt;

&lt;p&gt;Some of the myths that were debunked were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agile is all or nothing&lt;/li&gt;

&lt;li&gt;Agile doesn&amp;#8217;t produce documentation&lt;/li&gt;

&lt;li&gt;Agile doesn&amp;#8217;t commit to a deadline&lt;/li&gt;

&lt;li&gt;Agile developers are just Cowboy programmers who don&amp;#8217;t want to follow a process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What agile myths have you heard?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>extract_options bang</title>
   <link href="http://www.continuousthinking.com/2007/07/25/extract_options-bang.html"/>
   <updated>2007-07-25T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/07/25/extract_options-bang</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve seen and used a lot of slightly different mechanisms for grabbing an options hash from a passed in set of arguments. Today the Rails core team has added a helper to the Array class as part of Rails&amp;#8217; core extensions. It&amp;#8217;s a simple addition, but one that I like.&lt;/p&gt;

&lt;h2 id='with_options'&gt;With Options&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;arr = [ 1, 2, 3, { :validate =&amp;gt; true } ]
options = arr.extract_options! 

# arr = [ 1, 2, 3 ]
# options =&amp;gt; {:validate=&amp;gt;true}&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='without_options'&gt;Without Options&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;arr = [ 1, 2, 3 ]
options = arr.extract_options! 

# arr = [ 1, 2, 3 ]
# options =&amp;gt; {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;DHH has removed the method &lt;em&gt;extract&lt;/em&gt;options_from_args_ which used to exist in ActiveRecord::Base in favor of extract_options!. Using extract_options will be preferred over doing things like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;args.last.is_a?(Hash) ? args.pop : {}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id='actual_code_example_1__actionviewhelpersformbuilder'&gt;Actual Code Example 1 - ActionView::Helpers::FormBuilder&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;def fields_for(object_name, *args, &amp;amp;block)
  raise ArgumentError, &amp;quot;Missing block&amp;quot; unless block_given?
  options = args.extract_options!
  object  = args.first

  builder = options[:builder] || ActionView::Base.default_form_builder
  yield builder.new(object_name, object, self, options, block)
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again it&amp;#8217;s on Edge as of today, so if you don&amp;#8217;t live on the Edge you won&amp;#8217;t see it for awhile unless you implement itself for your project. Doing so may keep things tidy as you continue your projects rails development.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Model Conductor Controller Presentation</title>
   <link href="http://www.continuousthinking.com/2007/07/21/model-conductor-controller-presentation.html"/>
   <updated>2007-07-21T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/07/21/model-conductor-controller-presentation</id>
   <content type="html">&lt;p&gt;Tonight at the &amp;#8220;Grand Rapids BarCamp&amp;#8221;:http://barcamp.org/BarCampGrandRapids2 they had open slots for presentations, so I threw up a quick presentation on the Model Conductor Controller ( &amp;#8220;MCC&amp;#8221;:http://mcc.rubyforge.org ) pattern being developed in Rails.&lt;/p&gt;

&lt;p&gt;Although MCC isn&amp;#8217;t officially released yet (available via svn) its goals, ideals and implementation help simplify complex interactions in Rails-based web applications by allowing objects to focus on a single responsibility.&lt;/p&gt;

&lt;p&gt;Here is a link to the Quicktime movie. &amp;#8220;MCC_BarCamp_GrandRapids_07-21-07.mov&amp;#8221;:http://www.continuousthinking.com/assets/2007/7/21/MCC_BarCamp_GrandRapids_07-21-07.mov&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll be updating this presentation and fine tuning it some more for the &amp;#8220;August Grand Rapids Ruby Users Group meeting&amp;#8221;:http://gr-ruby.org/2007/7/19/august-meeting.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.7.0 Released!</title>
   <link href="http://www.continuousthinking.com/2007/07/21/activerecord-extensions-0-7-0-released.html"/>
   <updated>2007-07-21T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/07/21/activerecord-extensions-0-7-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.7.0 is released! Thanks to Michael Flester and Gabe da Silveira for the patches they submitted!&lt;/p&gt;

&lt;h2 id='updates_include'&gt;Updates include:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Oracle support for better finders (but regexps only work with Oracle 10 or higher) and import (Michael Flester)&lt;/li&gt;

&lt;li&gt;created_at/updated_at timestamps are now implemented with import functionality if they exist on the tables (Zach Dennis/Michael Flester)&lt;/li&gt;

&lt;li&gt;fixed padding issue with MySQL by increasing the byte buffer size to 8 bytes. (thanks to Gabe da Silveira)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To install as a gem you can run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;gem install ar-extensions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To update a previously installed gem you can run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;gem update ar-extensions&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To install as a script/plugin you can run:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;script/plugin install http://arext.rubyforge.org/svn/tags/ar-extensions-0.7.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To see information on the usage of ar-extensions please refer to the &amp;#8220;arext page&amp;#8221;:http://www.continuousthinking.com/tags/arext or refer to the &amp;#8220;RDOC documentation&amp;#8221;:http://www.continuousthinking.com/tags/arext/rdoc/index.html&lt;/p&gt;

&lt;h2 id='enjoy'&gt;Enjoy!&lt;/h2&gt;

&lt;p&gt;For questions, comments please feel free to email me, zach dot dennis at gmail dot com or by submitting to &amp;#8220;rubyforge project page&amp;#8221;:http://rubyforge.org/projects/arext for arext.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>The Importance Of Winning (it all wrong)</title>
   <link href="http://www.continuousthinking.com/2007/06/30/the-importance-of-winning-it-all-wrong.html"/>
   <updated>2007-06-30T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/30/the-importance-of-winning-it-all-wrong</id>
   <content type="html">&lt;p&gt;Winning it all wrong is getting it all wrong as it pertains to the concept of winning.&lt;/p&gt;

&lt;p&gt;At an early age most people learn about winning. Whether it&amp;#8217;s early in life playing games, taking toys from other children or socializing in general.&lt;/p&gt;

&lt;p&gt;Toddlers often scream &amp;#8220;mine&amp;#8221; and take the toy of another child. If they get away with it they&amp;#8217;ve started the process of learning the importance of winning.&lt;/p&gt;

&lt;p&gt;Children whose parents emphasize the &amp;#8220;must win&amp;#8221; mentality during sports learn the process of winning at every event.&lt;/p&gt;

&lt;p&gt;Teenagers who undermine and manipulate others succumb to the importance of winning as they climb the social ladder.&lt;/p&gt;

&lt;p&gt;When you think of the &amp;#8220;winning&amp;#8221; mentality, sports will probably come to mind first, but the importance of winning is prevalent in the &amp;#8220;software development&amp;#8221; community.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Have you worked someone who&amp;#8217;s always right (even when they&amp;#8217;re wrong)?&lt;/li&gt;

&lt;li&gt;Have you worked with someone who checks in lots of code during the late night or multi-day-no-sleep coding sessions?&lt;/li&gt;

&lt;li&gt;Have you worked with someone who doesn&amp;#8217;t want pair programming or review of their code (or they don&amp;#8217;t listen to the feedback)?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you&amp;#8217;ve experienced one of the above then you&amp;#8217;ve experienced the &amp;#8220;winning&amp;#8221; mentality in the world of software development. It can be frustrating to work with.&lt;/p&gt;

&lt;p&gt;The best attitude to combat this is one of humility and modesty. There is a time to be right and to stand your ground and there is a time to shut up, listen and learn.&lt;/p&gt;

&lt;p&gt;The best group action to actively employ against the wrong concept of winning is accountability. Accountability requires humility and modesty. Practices and actions that happen continually become habits.&lt;/p&gt;

&lt;p&gt;The true value of winning is not to win in every argument, debate or discussion. It isn&amp;#8217;t to ensure that &amp;#8220;my&amp;#8221; idea is the one that is always employed. Achieving victory triumphantly over everyone else in all circumstances is a short-sighted vision of winning. Unfortunately it&amp;#8217;s the concept that alot of people seem to know.&lt;/p&gt;

&lt;p&gt;A more worthy concept of winning is broader scoped:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;winning involves learning when there are things to be learned&lt;/li&gt;

&lt;li&gt;winning involves teaching when there are things to be taught&lt;/li&gt;

&lt;li&gt;winning involves discipline when doing the right takes longer then the shortcut&lt;/li&gt;

&lt;li&gt;winning involves patience when there is time to be spent&lt;/li&gt;

&lt;li&gt;winning involves honesty when the alternative seems more appealing&lt;/li&gt;

&lt;li&gt;winning involves knowing when to let the other person win&lt;/li&gt;

&lt;li&gt;winning involves strengthening others when others need to be built up&lt;/li&gt;

&lt;li&gt;winning involves listening because no one knows it all&lt;/li&gt;

&lt;li&gt;winning involves humility because humbleness allows you teach more, learn more and ultimately do more&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>acts_as_comparable 1.2 released</title>
   <link href="http://www.continuousthinking.com/2007/06/30/acts_as_comparable-1-2-released.html"/>
   <updated>2007-06-30T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/30/acts_as_comparable-1-2-released</id>
   <content type="html">&lt;p&gt;acts_as_comparable 1.2 has been released with a minor update. This includes a fix to handling additional options passed into the declarative acts_as_comparable call.&lt;/p&gt;

&lt;p&gt;For example with acts_as_comparable 1.1:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# this work
class Model &amp;lt; ActiveRecord::Base
  acts_as_comparable
end

# the options passed in are ignored.
class Model &amp;lt; ActiveRecord::Base
  acts_as_comparable :except =&amp;gt; [:id, :name]
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now in 1.2 this is fixed so you can pass the following options make calls like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;acts_as_comparable
acts_as_comparable :only=&amp;gt;\[:first_name, :last_name\]
acts_as_comparable :except =&amp;gt; \[:id, :name\]&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='installing_as_a_rubygem'&gt;Installing as a RubyGem&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;gem install -r acts_as_comparable&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='installing_as_a_plugin'&gt;Installing as a Plugin&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Installing from a version&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;script/plugin install \
  http://rails.lotswholetime.com/svn/acts_as_comparable/tags/acts_as_comparable-1.2&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Rails Edge Updates (06/28/2007)</title>
   <link href="http://www.continuousthinking.com/2007/06/28/rails-edge-updates-06_28_2007.html"/>
   <updated>2007-06-28T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/28/rails-edge-updates-06_28_2007</id>
   <content type="html">&lt;p&gt;Here are some updates for life on Rails Edge. Kudos to the rails-team!&lt;/p&gt;

&lt;h2 id='additions'&gt;Additions&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Added new date helpers: #since, #ago, #beginning_of_day, #end_of_day - &amp;#8220;8575&amp;#8221;:http://dev.rubyonrails.org/ticket/8575&lt;/p&gt;

&lt;p&gt;&amp;#187; Date.today.beginning_of_day =&amp;gt; Mon Jun 04 00:00:00 -0500 2007&lt;/p&gt;

&lt;p&gt;&amp;#187; Date.today.end_of_day =&amp;gt; Mon Jun 04 23:59:59 -0500 2007&lt;/p&gt;

&lt;p&gt;&amp;#187; Date.today.since(4.hours) =&amp;gt; Mon Jun 04 04:00:00 -0500 2007&lt;/p&gt;

&lt;p&gt;&amp;#187;Date.today + 4.hours =&amp;gt; Mon Jun 04 04:00:00 -0500 2007&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='removals'&gt;Removals&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;find&lt;/em&gt;all_ and &lt;em&gt;find&lt;/em&gt;first_ have been removed entirely&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='rake_tasks'&gt;Rake Tasks&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;db:create&lt;/em&gt; - has been added to create the database for the current RAILS_ENV&lt;/li&gt;

&lt;li&gt;&lt;em&gt;db:create:all&lt;/em&gt; - has been added to create databases for each environment&lt;/li&gt;

&lt;li&gt;&lt;em&gt;db:version&lt;/em&gt; - displays the version number of your database (as shown in script/about)&lt;/li&gt;

&lt;li&gt;&lt;em&gt;routes&lt;/em&gt; - has been added to display route information&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='command_line'&gt;Command Line&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;script/generate can now take the &amp;#8221;&amp;#8211;skip-migrations&amp;#8221; options when generating resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='testing'&gt;Testing&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Test::Unit::TestCase.fixture_path is now a class inheritable attribute in Edge (has been there for a while now). This allows you have different paths to fixtures based on your test case without overwriting other TestCase subclass fixture paths.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&lt;em&gt;collection fixtures&lt;/em&gt; have been added. You can now do things like:&lt;/p&gt;

&lt;p&gt;bob, steve = users(:bob, :steve)&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='enjoy'&gt;Enjoy!&lt;/h2&gt;</content>
 </entry>
 
 <entry>
   <title>Rails Patch 8750</title>
   <link href="http://www.continuousthinking.com/2007/06/26/rails-patch-8750.html"/>
   <updated>2007-06-26T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/26/rails-patch-8750</id>
   <content type="html">&lt;p&gt;Rails ticket &amp;#8220;8750&amp;#8221;:http://dev.rubyonrails.org/ticket/8750 fixes a issue which led myself and a few others to believe that assert_select_rjs was broken.&lt;/p&gt;

&lt;p&gt;Ideally I would expect the following calls and assertions to go together:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;page[&amp;#39;myid&amp;#39;].replace &amp;#39;&amp;lt;div&amp;gt;content&amp;lt;/div&amp;gt;&amp;#39;

assert_select_rjs :replace, &amp;#39;myid&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However this isn&amp;#8217;t the case. Since you are using the &lt;em&gt;page[id]&lt;/em&gt; syntax Rails considers this a &amp;#8220;chained&amp;#8221; selector so you have to use the following assertion:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;assert_select_rjs :chained_replace, &amp;#39;myid&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ritarded, I know. So &amp;#8220;ticket 8750&amp;#8221;:http://dev.rubyonrails.org/ticket/8750 fixes this and you can now use the more intuitive syntax as demonstrated below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;page[&amp;#39;myid&amp;#39;].replace &amp;#39;&amp;lt;div&amp;gt;content&amp;lt;/div&amp;gt;&amp;#39;
assert_select_rjs :replace, &amp;#39;myid&amp;#39;

page[&amp;#39;myid&amp;#39;].replace_html &amp;#39;&amp;lt;div&amp;gt;content&amp;lt;/div&amp;gt;&amp;#39;
assert_select_rjs :replace_html, &amp;#39;myid&amp;#39; &lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>basecamp goes openid</title>
   <link href="http://www.continuousthinking.com/2007/06/26/basecamp-goes-openid.html"/>
   <updated>2007-06-26T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/26/basecamp-goes-openid</id>
   <content type="html">&lt;p&gt;Basecamp releases its support for &amp;#8220;OpenID&amp;#8221;:http://openid.net/ . The official basecamp release notes can be found &amp;#8220;here&amp;#8221;:http://productblog.37signals.com/products/2007/06/basecamp-gets-o.html .&lt;/p&gt;

&lt;p&gt;A long time ago &amp;#8220;Brandon Keepers&amp;#8221;:http://www.opensoul.org was telling me about OpenId but I didn&amp;#8217;t really have a use for it (lack of support by web sites and applications that I use). One of my biggest pet peeves with Basecamp has been that you have to have multiple logins for multiple projects, but now you can have one.&lt;/p&gt;

&lt;p&gt;My favorite feature is the new project navigation toolbar. In the below screenshot you can see the three projects that I&amp;#8217;ve converted to OpenID show up.&lt;/p&gt;
&lt;img src='/assets/2007/6/26/basecamp_openid_navbar.png' /&gt;
&lt;p&gt;Although there are a few OpenID providers out there I decided to go with &amp;#8220;My OpenID&amp;#8221;:http://www.myopenid.com . In seven minutes I had my OpenID up and my basecamp projects converted over.&lt;/p&gt;
&lt;a href='http://www.myopenid.com'&gt;&lt;img src='http://www.continuousthinking.com/assets/2007/6/26/myopenid_logo.png' /&gt;&lt;/a&gt;
&lt;p&gt;For those of you who may be interested in running your own OpenID server you can&amp;#8230; &amp;#8220;Run your own identify server&amp;#8221;:http://openid.net/wiki/index.php/Run_your_own_identity_server gives you some resources to show you how.&lt;/p&gt;

&lt;p&gt;Kudos to basecamp for putting this in place, it is so far the best added feature since basecamp has been released IMO.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Instance Variables In Ruby</title>
   <link href="http://www.continuousthinking.com/2007/06/23/instance-variables-in-ruby.html"/>
   <updated>2007-06-23T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/23/instance-variables-in-ruby</id>
   <content type="html">&lt;p&gt;Instance variables are the heart of an object&amp;#8217;s encapuslated data. In &amp;#8220;ruby&amp;#8221;:http://www.ruby-lang.org all instance variables are hidden behind the walls of an object although their exists ways to access and modify those instance variables from afar.&lt;/p&gt;

&lt;p&gt;This post will go review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating instance variables&lt;/li&gt;

&lt;li&gt;Nil - The default value of an instance variable&lt;/li&gt;

&lt;li&gt;Accessing instance variables&lt;/li&gt;

&lt;li&gt;Checking for instance variable existence&lt;/li&gt;

&lt;li&gt;Breaking encapsulation&lt;/li&gt;

&lt;li&gt;Injecting instance variables into other objects&lt;/li&gt;

&lt;li&gt;Using named parameters to set instance variables&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='creating_instance_variables'&gt;Creating instance variables&lt;/h2&gt;

&lt;p&gt;Instance variables are created with a single @ symbol.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(copy and paste code example)&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# the instance variable @a is initialized to 5
class A
  def initialize
     @a = 5
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='nil__the_default_value_of_an_instance_variable'&gt;Nil - The default value of an instance variable&lt;/h2&gt;

&lt;p&gt;Unlike methods that don&amp;#8217;t exist trying to reference a uninitialized instance variable will return nil rather then raise an exception.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@b # =&amp;gt; nil
@b.nil? # =&amp;gt; true
@b = 5 # =&amp;gt; 5
@b.nil? # =&amp;gt; false&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='accessing_instance_variables'&gt;Accessing instance variables&lt;/h2&gt;

&lt;p&gt;In most languages to access an instance variable you have to write your own get/set methods.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person
  def name=(name)
    @name = name
  end

  def name
    @name
  end
end
joe = Person.new # =&amp;gt; #&amp;lt;Person:0x524f04&amp;gt;
joe.name = &amp;quot;joe&amp;quot; # =&amp;gt; &amp;quot;joe&amp;quot;
joe.name # =&amp;gt; &amp;quot;joe&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In Ruby you can bypass this using builtin the accessor methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;attr_accessor&amp;#8221;:http://www.ruby-doc.org/core/classes/Module.html#M001704 - this writes a getter and a setter for you&lt;/li&gt;

&lt;li&gt;&amp;#8220;attr_writer&amp;#8221;:http://www.ruby-doc.org/core/classes/Module.html#M001703 - this writes a writer for you&lt;/li&gt;

&lt;li&gt;&amp;#8220;attr_reader&amp;#8221;:http://www.ruby-doc.org/core/classes/Module.html#M001702 - this writes a getter for you&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;#8217;s a modified example from the above Person class:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sally = Person.new # =&amp;gt; #&amp;lt;Person:0x4e3a90&amp;gt;
sally.name = &amp;quot;sally&amp;quot; # =&amp;gt; &amp;quot;sally&amp;quot;
sally.name # =&amp;gt; &amp;quot;sally&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we had used &amp;#8220;attr_writer&amp;#8221;:http://www.ruby-doc.org/core/classes/Module.html#M001703 we would have gotten the &amp;#8220;name=&amp;#8221; method for free, but we wouldn&amp;#8217;t have been able to call &amp;#8220;name&amp;#8221;. Likewise, if we had used the &amp;#8220;attr_reader&amp;#8221;:http://www.ruby-doc.org/core/classes/Module.html#M001702 we would have been able to access Sally&amp;#8217;s &amp;#8220;name&amp;#8221; but we would have never been able to set it with &amp;#8220;name=&amp;#8221;.&lt;/p&gt;

&lt;h2 id='checking_for_instance_variable_existence'&gt;Checking for instance variable existence&lt;/h2&gt;

&lt;p&gt;Sometimes it&amp;#8217;s useful to be able to know whether an instance variable has been defined or not. With an instance variable having the default value of nil it&amp;#8217;s hard to rely on &amp;#8220;@varname&amp;#8221; to determine if nil was the defined value.&lt;/p&gt;

&lt;p&gt;So we rely on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&amp;#8220;instance_variable_defined?&amp;#8221;:http://www.ruby-doc.org/core/classes/Object.html#M000367 - can be used to determine whether an instance variable has been defined&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&amp;#8220;instance_variables&amp;#8221;:http://www.ruby-doc.org/core/classes/Object.html#M000364 - an array of instance variables for a given object&lt;/p&gt;

&lt;p&gt;class Person attr_accessor :name end joe = Person.new # =&amp;gt; #&lt;a href='Person:0x1109f40'&gt;Person:0x1109f40&lt;/a&gt; joe.instance_variable_defined?(&amp;#8220;@name&amp;#8221;) # =&amp;gt; false joe.instance_variables # =&amp;gt; [] joe.name = &amp;#8220;joe&amp;#8221; # =&amp;gt; &amp;#8220;joe&amp;#8221; joe.instance_variable_defined?(&amp;#8220;@name&amp;#8221;) # =&amp;gt; true joe.instance_variables # =&amp;gt; [&amp;#8220;@name&amp;#8221;]&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the above example notice that &amp;#8220;@name&amp;#8221; did not exist until we assigned it a value.&lt;/p&gt;

&lt;h2 id='breaking_encapsulation'&gt;Breaking encapsulation&lt;/h2&gt;

&lt;p&gt;You can break object encapsulation in ruby pretty easily due to it&amp;#8217;s dynamic and highly reflective nature. I&amp;#8217;ve seen people instance_eval to get and set the value of an instance variable, but there is a more proper way to break encapsulation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&amp;#8220;instance_variable_get&amp;#8221;:http://www.ruby-doc.org/core/classes/Object.html#M000365&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;&amp;#8220;instance_variable_set&amp;#8221;:http://www.ruby-doc.org/core/classes/Object.html#M000366&lt;/p&gt;

&lt;p&gt;joe.instance_variable_set :@name, &amp;#8216;joe&amp;#8217; # =&amp;gt; &amp;#8220;joe&amp;#8221; joe.instance_variable_get :@name # =&amp;gt; &amp;#8220;joe&amp;#8221;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is also about 70x faster then using instance_eval.&lt;/p&gt;

&lt;h2 id='injecting_instance_variables_into_other_objects'&gt;Injecting instance variables into other objects&lt;/h2&gt;

&lt;p&gt;Frameworks like &amp;#8220;Ruby on Rails&amp;#8221;:http://www.rubyonrails.org use the power of ruby to do magical things. One of those things is injecting variables into a given object, such as in the case of controllers and views. You can do this with what we&amp;#8217;ve just seen with &amp;#8220;instance_variable_set&amp;#8221; and &amp;#8220;instance_variable_get&amp;#8221;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class BlankSlate ; end
class ValueHolder   
  def initialize
    @a, @b, @c = 1, 2, 3
  end
end


slate = BlankSlate.new # =&amp;gt; #&amp;lt;BlankSlate:0x101a224&amp;gt;
slate.instance_variables # =&amp;gt; \[\]
values = ValueHolder.new # =&amp;gt; #&amp;lt;ValueHolder:0x1014ef0 @c=3, @b=2, @a=1&amp;gt;
values.instance_variables # =&amp;gt; [&amp;quot;@c&amp;quot;, &amp;quot;@b&amp;quot;, &amp;quot;@a&amp;quot;]


values.instance_variables.each do |varname| 
  slate.instance_variable_set(varname, values.instance_variable_get(varname))
end # =&amp;gt; [&amp;quot;@c&amp;quot;, &amp;quot;@b&amp;quot;, &amp;quot;@a&amp;quot;]
slate.instance_variables # =&amp;gt; [&amp;quot;@c&amp;quot;, &amp;quot;@b&amp;quot;, &amp;quot;@a&amp;quot;]&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='using_named_parameters_to_set_instance_variables'&gt;Using named parameters to set instance variables&lt;/h2&gt;

&lt;p&gt;A common thing to do in JavaScript is to use object literals when calling functions to ease simulate named arguments. In Ruby the most common construct you&amp;#8217;ll see is people passing hashes into a method call.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Person.new :first_name =&amp;gt; &amp;quot;Joe&amp;quot;, :last_name =&amp;gt; &amp;quot;Gee&amp;quot;, :middle_initial =&amp;gt; &amp;quot;B&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The calling syntax looks great, but what you have to do in the constructor for Person is quite hideous:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person
  def initialize(options)
    @first_name = options[:first_name]
    @last_name = options[:last_name]
    @middle_initial = options[:middle_initial]
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Given this trivial example calling &amp;#8220;options[key]&amp;#8221; may not be so annoying, but if you had a more complex example where you were using dependency injection it can get a little cumbersome.&lt;/p&gt;

&lt;p&gt;We can start to scratch this itch by automatically setting instance variables to their passed in named parameters:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person
  def initialize(options)
    options.each_pair do |key,value|
       instance_variable_set &amp;quot;@#{key}&amp;quot;, value
    end
  end
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This approach has its own set of issues though, but given a good set of tests you could confidently use this approach. You could also add code to verify the arguments being passed in.&lt;/p&gt;

&lt;p&gt;Another solution which would give you closer syntax that you get in JavaScript is forwarding method calls to hash keys:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module ActAsNamedParameters
  def act_as_named_parameters(hsh)
    parent = class &amp;lt;&amp;lt;hsh ; self; end
    hsh.each_key do |key|
      parent.send(:define_method, key) { hsh\[key\] }
    end
  end
end

class Person
  include ActAsNamedParameters

  def initialize(attributes)
    act_as_named_parameters attributes
    @first_name = attributes.first_name
    @middle_initial = attributes.middle_initial
    @last_name = attributes.last_name
  end
end

Person.new :first_name =&amp;gt; &amp;quot;Joe&amp;quot;, :last_name =&amp;gt; &amp;quot;Gee&amp;quot;, :middle_initial =&amp;gt; &amp;quot;B&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here we&amp;#8217;re invoking a helper module to do the dirty work for us. A downside here is that the helper module modifies the hash we pass it. In most cases side effects to method calls is undesired, but if you are using simple hashes for argument passing that may not be a large concern for you.&lt;/p&gt;

&lt;p&gt;Even though there are lots of ways you can accomplish different ways to treat arguments in ruby I&amp;#8217;ll leave you with one last small refactoring to our previous example. Rather then rely on a helper module that we must invoke we could always add the accessors to the Hash itself.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Hash 
  def method_missing(method, *args)
    if self[method.to_sym] and args.empty?
      self[method.to_sym]
    else
      super
    end
  end
end

class Person
  def initialize(attributes)
    @first_name = attributes.first_name
    @middle_initial = attributes.middle_initial
    @last_name = attributes.last_name
  end
end

Person.new :first_name =&amp;gt; &amp;quot;Joe&amp;quot;, :last_name =&amp;gt; &amp;quot;Gee&amp;quot;, :middle_initial =&amp;gt; &amp;quot;B&amp;quot;&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Programmer, Developer</title>
   <link href="http://www.continuousthinking.com/2007/06/13/programmer-developer.html"/>
   <updated>2007-06-13T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/13/programmer-developer</id>
   <content type="html">&lt;p&gt;I used to think that I was a software developer based on the sole fact that I was paid to write code, no matter how crappy it was. Over the past few years I&amp;#8217;ve realized that I was no more of a software developer as a guy who picks up trash on a construction site is a contractor.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve noticed that alot of so called &amp;#8220;developers&amp;#8221; fall into the same camp that I was in. I&amp;#8217;ve mentally made a distinction between a Programmer and a Developer. &lt;em&gt;This is much more generic dictinction of different types of coders then say an Apprentice, Journeyman or Craftsman is.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;A Programmer is someone who codes. They don&amp;#8217;t necessarily take into consideration a whole lot of things outside of fact of getting the job done.&lt;/p&gt;

&lt;p&gt;A Developer is someone who codes with consideration. They consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coding quality and best practices&lt;/li&gt;

&lt;li&gt;program design with natural decomposition&lt;/li&gt;

&lt;li&gt;testability, automated testing, manual testing&lt;/li&gt;

&lt;li&gt;readibility&lt;/li&gt;

&lt;li&gt;maintainability&lt;/li&gt;

&lt;li&gt;refactoring&lt;/li&gt;

&lt;li&gt;code performance (when its time to evaluate performance)&lt;/li&gt;

&lt;li&gt;teamwork&lt;/li&gt;

&lt;li&gt;responsibility to their customer and to their fellow teammate(s)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These definitions are influenced from object-oriented thinking and agile software development practices. You may completely disagree with them entirely. I&amp;#8217;ve raised the bar for how I develop software. If it&amp;#8217;s less for you then we just have different expectations of what makes a Developer. I&amp;#8217;m ok with that. But, is your customer?&lt;/p&gt;

&lt;p&gt;Ever since I started writing code I recognized that my potential was where I wanted to be. I could see the potential of what I could become and what I could accomplish. With this I had a genuine thirst for knowledge and I was eager to quench it. I&amp;#8217;ve spent thousands of dollars and have read tens of thousands of pages from technical books. I&amp;#8217;ve spent countless hours coding.&lt;/p&gt;

&lt;p&gt;I spent too long of a time in the Programmer camp. I could have been much farther ahead early on given a few degrees change in direction.&lt;/p&gt;

&lt;p&gt;So what was my problem? My problem had to do with the following goals when I first started:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;knowledge of multiple programming languages&lt;/li&gt;

&lt;li&gt;knowledge of different types of development: web apps, cgi, standalone,daemons, libraries&lt;/li&gt;

&lt;li&gt;coding speed&lt;/li&gt;

&lt;li&gt;all previous items as soon as possible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to know as much as possible in as little time as possible and I wanted to be able to produce results as fast as possible. A worthy goal, but the goals fell short of what is required of a software Developer.&lt;/p&gt;

&lt;p&gt;When you learn as much as possible in the shortest amount of time with no regard to how you take that information and you end up learning only a small amount of what was there to be learned.&lt;/p&gt;

&lt;p&gt;When you apply what you&amp;#8217;ve learned as fast as possible with no regard to any of the aforementioned Developer &amp;#8220;considerations&amp;#8221; you end up making habits out of bad practices. And it will take alot of time and discipline to break them.&lt;/p&gt;

&lt;p&gt;Developers take on a personal responsibility for the software they write. They don&amp;#8217;t just value the end result. They value the entire process leading up to the end result and then they value the end result.&lt;/p&gt;

&lt;p&gt;While Programmers continually apply bad practices, Developers provide consistently good practices. From what I&amp;#8217;ve seen it goes like the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;while Programmers avoid testing to produce faster short-term, Developers continue test to produce faster and more consistently long-term&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;while Programmers copy and paste over and over again to produce faster short-term, Developers refactor and create re-usable components to produce less buggy software, faster, long-term&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;while Programmers avoid the use of decomposition because everything can be inlined to produce faster short-term, Developers use decomposition to provide a solution which makes more natural sense (this leads to more manageable, maintainable, readable and scalable code for the long-term)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;while Programmers often code by themselves to produce faster short-term, Developers value the input and ideas generated from other people to produce better and more correct solutions (this often leads to avoiding common mistakes from not correctly understanding the problem description and solution requirements)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;while Programmers often code 12+ hours several days in a row to produce more in a shorter amount of time, Developers work a sustainable-pace to produce more correct code in a shorter amount of time (when you&amp;#8217;re brain is tired and you are tired you make mistakes, if you keep on coding you just dig yourself a bigger hole. Staying fresh with a sustainable pace minimizes this.)&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;while Programmers commit to unrealistic customer expectations immediately, Developers communicate why the expectation is unrealistic and work with the customer on determining a realistic set of features in a realistic amount of time.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn&amp;#8217;t to say that Programmers are evil coders. The term &amp;#8220;Programmer&amp;#8221; encompasses alot of people. These people might be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;inexperienced,&lt;/li&gt;

&lt;li&gt;irresponsible,&lt;/li&gt;

&lt;li&gt;lacking discipline,&lt;/li&gt;

&lt;li&gt;or just bad programmers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every coder starts out in the Programmer camp. Whether they evolve to the Developer camp is simply up to them. Who determines whether they&amp;#8217;re out of the Programmer camp? They do.&lt;/p&gt;

&lt;p&gt;Responsible Programmers quickly evolve into effective Developers because responsibility requires discipline and discipline does the right thing in any circumstance. The sooner you take responsibility for your craft as a software developer, the sooner you&amp;#8217;ll enjoy the benefits of being a Developer.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Planning In Software Development</title>
   <link href="http://www.continuousthinking.com/2007/06/13/planning-in-software-development.html"/>
   <updated>2007-06-13T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/06/13/planning-in-software-development</id>
   <content type="html">&lt;p&gt;I was just reading the post &amp;#8220;Quit Planning&amp;#8221;:http://daniel.collectiveidea.com/blog/2007/6/4/quit-planning over at Daniel Morrison&amp;#8217;s &amp;#8220;blog&amp;#8221;:http://daniel.collectiveidea.com/blog/&lt;/p&gt;

&lt;p&gt;His comments seem to be down so I felt the need to post my thoughts here. In response to Daniel&amp;#8217;s article I think he has it mostly right on the money. Although I would like to change the term &amp;#8220;planning&amp;#8221; in his article to &amp;#8220;upfront planning&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Dwight D. Eisenhower may have said it best:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Plans are useless, but planning is indispensable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Unfortunately most definitions of planning involve the upfront and systematic approach rather then focusing on the continuous process which develops daily.&lt;/p&gt;

&lt;p&gt;Developing in short iterations allows for short bursts of incremental progress which when used in combination with a quick feedback loop between the developer and the customer gives the customer an upper hand in defining and planning the needs of his software to meet the needs of his business.&lt;/p&gt;

&lt;p&gt;It works because the process of planning is continuous and incorporates change, while upfront planning to produce a plan ignores that change will occur, which as Daniel points out, will occur.&lt;/p&gt;

&lt;p&gt;If you remove the process of planning (which I don&amp;#8217;t think Daniel is suggesting) then you remove a key component to any software endeavor, agile or not. Agile strives to reduce and minimize the concept of upfront planning in favor of iterative planning.&lt;/p&gt;

&lt;p&gt;As pointed out on the Agile Journal in a &amp;#8220;post&amp;#8221;:http://www.agilejournal.com/content/view/200/9/&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Planning isn&amp;#8217;t bad&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What I believe Daniel is focusing on in his post is that:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8230; the details [should] emerge throughout implementation.&lt;/p&gt;
&lt;/blockquote&gt;</content>
 </entry>
 
 <entry>
   <title>High Jumping Projects</title>
   <link href="http://www.continuousthinking.com/2007/05/29/high-jumping-projects.html"/>
   <updated>2007-05-29T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/05/29/high-jumping-projects</id>
   <content type="html">&lt;p&gt;I spent this past memorial weekend in South Haven with much of my wife&amp;#8217;s extended, extended family. Many of the relatives were individuals that my wife has either never met or has not seen in years. My father-in-law was eager to ask me what I&amp;#8217;ve been up to lately for work. After about two minutes he stopped me and asked me to wait to finish because he wanted me to share the news with everyone else.&lt;/p&gt;

&lt;p&gt;A few minutes later he was introducing me to the extended family and asking me to describe my past few months of events and work. After sharing the past few months of life and work with everyone it seems that the Q&amp;amp;A period started.&lt;/p&gt;

&lt;p&gt;One of the questions sticks in my mind from one of my extended family uncles.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;When you work on your projects do you have hundreds of other developers working with you?&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was pleasantly surprised and eager to answer his question. The answer of course is that no, I have never been on a project of more then six developers. He didn&amp;#8217;t seem entirely satisfied so he asked another set of questions.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;When are you expected to be done with the current project you&amp;#8217;re on? Could you be done sooner with more people?&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This leads me to the example of &lt;em&gt;The High Jump&lt;/em&gt; principle as written in &amp;#8220;Talent Is Never Enough&amp;#8221;:http://www.amazon.com/Talent-Never-Enough-Discover-Choices/dp/0785214038 . The principle is such that&amp;#8230;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Winning the high jump requires one person who can jump seven feet, not seven people who can jump one foot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Some software projects may indeed take large amounts of people (hopefully the large amounts of people are divided into small manageable teams). So far the projects I&amp;#8217;ve been apart of have more in common with The High Jump principle.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Brook&amp;#8217;s Law&amp;#8221;:http://en.wikipedia.org/wiki/Brooks&amp;#8217;_law seems to say it best:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Adding people to a late software project makes it later.&amp;#8221;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As &amp;#8220;John Maxwell&amp;#8221;:http://en.wikipedia.org/wiki/John_C._Maxwell states in his book &amp;#8220;Talent Is Never Enough&amp;#8221;:http://www.amazon.com/Talent-Never-Enough-Discover-Choices/dp/0785214038 , &amp;#8220;More isn&amp;#8217;t always better, and some things are best done by an individual.&amp;#8221; Or in the case of most software projects, done by a small team.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails patch 8277</title>
   <link href="http://www.continuousthinking.com/2007/05/06/rails-patch-8277.html"/>
   <updated>2007-05-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/05/06/rails-patch-8277</id>
   <content type="html">&lt;p&gt;The &lt;em&gt;synchronize&lt;/em&gt; functionality released in &amp;#8220;ActiveRecord::Extensions 0.6.0&amp;#8221;:http://www.continuousthinking.com/2007/5/6/activerecord-extensions-0-6-0-released should probably go in core. So I submitted a &amp;#8220;patch&amp;#8221;:http://dev.rubyonrails.org/ticket/8277&lt;/p&gt;

&lt;p&gt;My reasoning is that is ActiveRecord::Base#reload already works on a per instance level, why not allow it work on a class level where the class can efficiently handle reloads on multiple instances at once.&lt;/p&gt;

&lt;p&gt;The benefit of the class level reload is that you can do one query to the database regardless of how many instances you have rather then having to perform one query per instance.&lt;/p&gt;

&lt;p&gt;If you&amp;#8217;re in favor of the patch please encourage it gets accepted.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.6.0 released</title>
   <link href="http://www.continuousthinking.com/2007/05/06/activerecord-extensions-0-6-0-released.html"/>
   <updated>2007-05-06T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/05/06/activerecord-extensions-0-6-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.6.0 is released! You can install it via RubyGems:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem install ar-extensions&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='whats_new'&gt;What&amp;#8217;s New?&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;li&gt;0 includes:&lt;/li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;support for arrays when using the Hash arguments and the &amp;#8216;_contains&amp;#8217; suffix.&lt;/li&gt;

&lt;li&gt;a &lt;em&gt;synchronize&lt;/em&gt; method which acts like ActiveRecord::Base#reload, but it works on multiple instances. The benefit being that it makes one query to reload all instances rather then one query per instance&lt;/li&gt;

&lt;li&gt;a bug fix for URI encoded strings when using &lt;em&gt;find&lt;/em&gt; with ActiveRecord objects&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='examples'&gt;Examples&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;# synchronize example
post = BlogPost.find_by_author_name( &amp;#39;zdennis&amp;#39; )
columns = [ :author_name, :title ]
values = [ [ &amp;#39;yoda&amp;#39;, &amp;#39;test post&amp;#39; ] ]
BlogPost.import columns, values, :synchronize=&amp;gt;[ post ]
post.author_name # =&amp;gt; &amp;#39;yoda&amp;#39;

# using synchronize option with import
posts = BlogPost.find(:all)
BlogPost.import( columns, values, :synchronize=&amp;gt;posts)

# using arrays with the _contains suffix
BlogPost.find( 
  :all,  
  :conditions=&amp;gt;{ :author_name_contains=&amp;gt;[ &amp;#39;ab&amp;#39;, &amp;#39;oc&amp;#39;, &amp;#39;ed&amp;#39; ] } )&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='questions_comments'&gt;Questions, Comments&lt;/h3&gt;

&lt;p&gt;zach dot dennis at gmail dot com&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>less shift f</title>
   <link href="http://www.continuousthinking.com/2007/04/24/less-shift-f.html"/>
   <updated>2007-04-24T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/04/24/less-shift-f</id>
   <content type="html">&lt;p&gt;If you use a combination of piping to files and using the &lt;em&gt;tail&lt;/em&gt; command with the &lt;em&gt;-f&lt;/em&gt; option and/or using &lt;em&gt;grep&lt;/em&gt; you may want to try just sticking with the &lt;em&gt;less&lt;/em&gt; command and using the Shift-f to tell &lt;em&gt;less&lt;/em&gt; to continue waiting for input from the file.&lt;/p&gt;

&lt;p&gt;Before Shift-f you&amp;#8217;ll see your normal output as shown by &lt;em&gt;less&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Apr 23 20:24:39 elijah com.apple.SecurityServer: Succeeded authorizing &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can tell if its working by looking at the last line of your &lt;em&gt;less&lt;/em&gt; output.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Apr 23 20:24:39 elijah com.apple.SecurityServer: Succeeded authorizing 
Waiting for data... (interrupt to abort)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now &lt;em&gt;less&lt;/em&gt; is going to get updated whenever the file you are &lt;em&gt;lessing&lt;/em&gt; has more data appended to it. Now hit / and start looking for whatever it is you want to find.&lt;/p&gt;

&lt;p&gt;Another way to use one tool rather then three.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Introducing acts_as_comparable</title>
   <link href="http://www.continuousthinking.com/2007/04/21/introducing-acts_as_comparable.html"/>
   <updated>2007-04-21T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/04/21/introducing-acts_as_comparable</id>
   <content type="html">&lt;p&gt;Mark VanHolstyn and Zach Dennis kick out another ActiveRecord plugin. The previous plugin &amp;#8220;ActiveRecord::Extensions&amp;#8221;:http://www.continuousthinking.com/tags/arext now has a smaller, helpful cousin. This plugin has been in use for over a year but not released until tonight!&lt;/p&gt;

&lt;p&gt;&amp;#8220;acts_as_comparable&amp;#8221; is plugin for ActiveRecord which allows you to easily compare and determine the differences between two ActiveRecord models.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person 
  acts_as_comparable :only=&amp;gt;\[:first_name, :last_name\]
end

joe = Person.new :first_name=&amp;gt;&amp;quot;Joe&amp;quot;, :last_name=&amp;gt;&amp;quot;Smith&amp;quot;
joseph = Person.new :first_name =&amp;gt; &amp;quot;Joseph&amp;quot;, :last_name=&amp;gt;&amp;quot;Smith&amp;quot;

joe.same?( joseph ) # =&amp;gt; false
joe.different?( joseph ) # =&amp;gt; true

joe.differences( joseph ) # =&amp;gt; {:first_name=&amp;gt;\[&amp;quot;Joe&amp;quot;, &amp;quot;Joseph&amp;quot;\]}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The usage in the above example shows the &lt;em&gt;only&lt;/em&gt; option, but this also works with no options, the &lt;em&gt;except&lt;/em&gt; option and also the &lt;em&gt;attrs&lt;/em&gt;map_ option. See it&amp;#8217;s ruby doc for more information.&lt;/p&gt;

&lt;h2 id='installing_as_a_rubygem'&gt;Installing as a RubyGem&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;gem install -r acts_as_comparable&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='installing_as_a_plugin'&gt;Installing as a Plugin&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Installing from a version&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;script/plugin install http://rails.lotswholetime.com/svn/acts_as_comparable/tags/acts_as_comparable-1.1&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Communication is essential</title>
   <link href="http://www.continuousthinking.com/2007/04/12/models-methods-and-processes.html"/>
   <updated>2007-04-12T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/04/12/models-methods-and-processes</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Models [charts, diagrams, stories, graphs, etc] are valuable only to the extent that they facilitate communication among human beings. &amp;#8211; David West&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Communication is the most essential part of a project. Sometimes the artifacts that are generated to help facilitate communication end up hindering it. If the target audience can&amp;#8217;t understand the artifacts you&amp;#8217;re presenting them with chances are you need to stop trying to explain it to them and find something that they can understand.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;the effort required to construct the model must be less than the communication value that arises from its user. &amp;#8211; David West&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I was once the project lead on a web-based project management application for a Fortune 50 company. The GANTT chart was deemed by the customer to be the most effective form of communication since everyone else in his company used them. In fact, they all used Microsoft Project to generate them.&lt;/p&gt;

&lt;p&gt;We spent about six weeks of development per the customer&amp;#8217;s direction integrating support to output an exact Microsoft Project GANTT chart replica. At the end of those six weeks the GANNT chart was canceled.&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t know why the GANTT chart was canceled for sure, but during the time of development we discovered that our domain experts and our customers didn&amp;#8217;t really understand a GANTT chart. They sorta knew what it looked like because it was what they gave to their coworkers and bosses every few weeks to report progress, but they didn&amp;#8217;t really understand what they were really trying to capture.&lt;/p&gt;

&lt;p&gt;I think that once they understood what they actually wanted and what a GANTT chart actually was that it didn&amp;#8217;t make sense to use a GANTT chart after all. But that&amp;#8217;s just my speculation of course.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tools like Microsoft Project are evil, mostly&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I don&amp;#8217;t like tools like Microsoft Project or any tool that locks you into their process for how you should do things. Or maybe it&amp;#8217;s that I don&amp;#8217;t like people who use tools but don&amp;#8217;t understand how to use the tool or at least what the outputted artifacts (diagrams, GANTT charts, etc).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Thank you to people who don&amp;#8217;t effectively communicate&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I try to communicate effectively, and I try to constantly improve that communication. People who don&amp;#8217;t either of these things will make my portfolio bigger.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Refactoring ActiveRecord::Base</title>
   <link href="http://www.continuousthinking.com/2007/03/15/refactoring-activerecord-base.html"/>
   <updated>2007-03-15T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/03/15/refactoring-activerecord-base</id>
   <content type="html">&lt;p&gt;ActiveRecord (AR) is one of my favorite programming libraries ever created. I am very thankful that &amp;#8220;DHH&amp;#8221;:http://www.loudthinking.com woke up one day and decided to author it.&lt;/p&gt;

&lt;p&gt;Recently there has been talk in a few threads &lt;em&gt;(How I Monkey Patched AR and ActiveRecord Refactoring)&lt;/em&gt; on the Rails-Core list which are trying to invite AR contributors, plugin authors and all around AR enthusiasts to think about refactoring AR.&lt;/p&gt;

&lt;h2 id='the_good'&gt;The Good&lt;/h2&gt;

&lt;p&gt;AR is the best &amp;#8220;ORM&amp;#8221;:http://en.wikipedia.org/wiki/Object-relational_mapping that I know of and actively use. ActiveRecord::Base is the centralized theme of ActiveRecord. It&amp;#8217;s what you subclass when you need to model an actual database table. It&amp;#8217;s where you declare your associations &lt;em&gt;(has&lt;/em&gt;one, belongs_to, etc&amp;#8230;)_. It connects your application code to your database storage.&lt;/p&gt;

&lt;h2 id='the_bad'&gt;The Bad&lt;/h2&gt;

&lt;p&gt;ActiveRecord::Base dishes off some of the SQL generation tasks to the underlying connection adapter. This means that if you&amp;#8217;re using MySQL then the MysqlAdapter is going to be responsible for quoting valute &lt;em&gt;(for instance the methods quote and quote&lt;/em&gt;value)_.&lt;/p&gt;

&lt;p&gt;Unfortunately ActiveRecord::Base remains to keep some functionality it should most likely give up to the connection adapters. This functionality includes any partial SQL that you see in ActiveRecord::Base, in my opinion.&lt;/p&gt;

&lt;h2 id='the_ugly'&gt;The Ugly&lt;/h2&gt;

&lt;p&gt;Since ActiveRecord::Base is holding onto some implementation it doesn&amp;#8217;t deserve you can&amp;#8217;t get a clean interface for extending aspects of SQL generation without overriding and reimplementing methods on ActiveRecord::Base.&lt;/p&gt;

&lt;p&gt;The downside to this is that it&amp;#8217;s not isolated to even just your adapter. Even more so, it&amp;#8217;s not isolated to just your functionality. &lt;em&gt;Why is this bad? It increases the risk that a bug in your code is going to bring down other parts of the system which may or may not be totally unrelated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Examples of this include how queries are built. The &lt;em&gt;attribute&lt;/em&gt;conditions_ method on ActiveRecord::Base is responsible for handling Array, Range and nil objects specifically. If your object isn&amp;#8217;t one of those then you&amp;#8217;re going to get stuck with an equals &lt;em&gt;=&lt;/em&gt; comparison. An example of this is when you do a :find method call with conditions Hash. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SomeModel.find :all, :conditions=&amp;gt;{  :id =&amp;gt; [ 1, 2, 3 ], :age=&amp;gt;(20..25) }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above code is great, but what happens when you want to use database specific features (or features which use different SQL dialect) like one regular expression searching, database functions, subqueries. Or even supporting additional query modifier statements like the WITH clause that MS SQL, Oracle, DB2 and PostgreSQL8.2 offer, or even the infamous ON DUPLICATE KEY UPDATE functionality that MySQL offers?&lt;/p&gt;

&lt;h2 id='plugins__an_existing_solution'&gt;Plugins - An Existing Solution&lt;/h2&gt;

&lt;p&gt;One solution is to have everyone release plugins which extend, implement, override or re-implement functionality that AR currently offers. Some folks in the Rails community even like to suggest that people create plugins and then if the plugin becomes popular they&amp;#8217;ll consider putting it into core.&lt;/p&gt;

&lt;p&gt;While I see the benefit in this (if no one uses the functionality why does it belong into core?) I also see the need to start considering and refactoring AR to support what some would consider cleaner, more extendable code.&lt;/p&gt;

&lt;p&gt;I have even gone as far as implementing &amp;#8220;ActiveRecord::Extensions&amp;#8221;:http://www.continuousthinking.com/tags/arext which is a plugin that is trying to solve a lot of these issues. And I believe it has in some regards.&lt;/p&gt;

&lt;h2 id='why_plugins_and_method_overriding_isnt_the_final_answer'&gt;Why Plugins and Method Overriding Isn&amp;#8217;t The Final Answer&lt;/h2&gt;

&lt;p&gt;Plugins and method overriding &lt;em&gt;(for all of those calls to alias, you know who you are)&lt;/em&gt; aren&amp;#8217;t the solution for where AR probably should go as Rails starts on its sweep of moving to a 2.0 release.&lt;/p&gt;

&lt;p&gt;The problem is that when several plugins have to forcefully override core methods on ActiveRecord::Base to extend the functionality it screams out to me that ActiveRecord could use a little refactoring love. This would allow alot less method overriding and aliasing while still allowing plugin developers to extend AR&amp;#8217;s functionality.&lt;/p&gt;

&lt;p&gt;&amp;#8220;Fowler&amp;#8221;:http://www.martinfowler.com talks about &amp;#8220;code smells&amp;#8221;:http://www.martinfowler.com/bliki/CodeSmell.html and the continuous overriding of core methods seems to indicate one or possibly more.&lt;/p&gt;

&lt;h2 id='how_can_ar_separate_subjective_desires_from_objective_needs'&gt;How Can AR Separate Subjective Desires From Objective Needs&lt;/h2&gt;

&lt;p&gt;A few simple guidelines to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Domain specific problems shouldn&amp;#8217;t be put into ActiveRecord core.&lt;/li&gt;

&lt;li&gt;Generic database solutions should be put into ActiveRecord core. ** A public interface should be put onto ActiveRecord::Base if it operates on a given table or model objects ** Implementation details should be hidden inside of an adapter somewhere. &lt;em&gt;(ie: no SQL generation in ActiveRecord::Base)&lt;/em&gt;&lt;/li&gt;

&lt;li&gt;Generic solutions which impose different SQL dialect should be put into adapters or another component which adapters know how to use.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A few simple questions to think when deciding to extend AR with a plugin or introduce new ideas to AR core:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is the functionality provided by more then one database even if the &lt;em&gt;how its done&lt;/em&gt; differs?&lt;/li&gt;

&lt;li&gt;Can this functionality be isolated or encapsulated in a way that reduces the risk of breaking other AR functionality should a bug be found? &lt;em&gt;(ie: are you overriding core ActiveRecord::Base methods and aliasing the original? If so this is a very easy bug to introduce here.)&lt;/em&gt;&lt;/li&gt;

&lt;li&gt;Does this functionality make sense in only your problem domain, or does it makes sense in most or all problem domains?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='moving_forward'&gt;Moving Forward&lt;/h2&gt;

&lt;p&gt;I am working on a patch to AR core which removes all SQL code in ActiveRecord::Base and extracts it out into the connections adapters. It will provide an API for creating additional or specific query based modifiers. This will provide things like prefix and suffix modifiers. It will also separate generic query generation &lt;em&gt;(SQL dialect that all databases support)&lt;/em&gt; from non-generic query generation.&lt;/p&gt;

&lt;p&gt;This functionality already exists in &amp;#8220;ActiveRecord::Extensions&amp;#8221;:http://www.continuousthinking.com/tags/arext and you can see its usage examples in Ruby Insiders &amp;#8220;December Article&amp;#8221;:http://www.rubyinside.com/advent2006/17-extendingar.html . The implementation will slightly differ since by patching AR core itself I&amp;#8217;ll be able to introduce simpler code.&lt;/p&gt;

&lt;p&gt;The ability to create and extend custom better finder support will be introduced in this patch which allow core developers and/or plugin developers to isolate their code changes and to &lt;em&gt;include&lt;/em&gt; that support into the adapters of their choice, without overriding AR core methods.&lt;/p&gt;

&lt;h2 id='thoughts'&gt;Thoughts?&lt;/h2&gt;

&lt;p&gt;If you&amp;#8217;ve read this whole post then you&amp;#8217;re most likely interested in AR and it&amp;#8217;s future. What do you think?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.5.2 Released!</title>
   <link href="http://www.continuousthinking.com/2007/03/15/activerecord-extensions-0-5-2-released.html"/>
   <updated>2007-03-15T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/03/15/activerecord-extensions-0-5-2-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.5.2 is released! A rubygem has been born!&lt;/p&gt;

&lt;p&gt;Installation is so easy now for ActiveRecord::Extensions:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;gem install -r &amp;#39;ar-extensions&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Enjoy!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;0.5.1 was also released, but I quickly released 0.5.2 after it to fix a possible bug with method aliasing. This would only occur if you had another plugin or rubygem which used the same alias name for ActiveRecord::Base#quote&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.5.0 Released!</title>
   <link href="http://www.continuousthinking.com/2007/03/14/activerecord-extensions-0-5-0-released.html"/>
   <updated>2007-03-14T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2007/03/14/activerecord-extensions-0-5-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.5.0 is released! This release includes support for querying against Time objects against ActiveRecord columns which are considered :datetime by ActiveRecord&amp;#8217;s standards &lt;em&gt;(this typically include DATETIME and DATE database columns).&lt;/em&gt;&lt;/p&gt;

&lt;h2 id='code_example'&gt;Code Example&lt;/h2&gt;

&lt;p&gt;To find all blog posts within the last week:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;BlogPost.find( :all, :conditions=&amp;gt;{ :created_at_gt =&amp;gt; Time.now-1.week } )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To find all posts within the last year:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;BlogPost.find( :all, :conditions=&amp;gt;{ :created_at_gt =&amp;gt; Time.now-1.year } )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To find all posts over a year old:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;BlogPost.find( :all, :conditions=&amp;gt;{ :created_at_lt =&amp;gt; Time.now-1.year} )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To find all users who logged in within the past 15 minutes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;User.find( :all, :conditions=&amp;gt;{ :logged_in_at_gt =&amp;gt; Time.now-15.minutes} )&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='supported_suffix_modifiers'&gt;Supported Suffix Modifiers&lt;/h2&gt;

&lt;p&gt;This particular query addition supports the following column name suffix modifiers &lt;em&gt;(ie: the &amp;#8220;_lt&amp;#8221; in the &amp;#8220;created_at_lt&amp;#8221;)&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;_lt =&amp;gt; less than&lt;/li&gt;

&lt;li&gt;_gt =&amp;gt; greater than&lt;/li&gt;

&lt;li&gt;_lte =&amp;gt; less than or equal to&lt;/li&gt;

&lt;li&gt;_gte =&amp;gt; greater than or equal to&lt;/li&gt;

&lt;li&gt;_ne =&amp;gt; not equal to&lt;/li&gt;

&lt;li&gt;_not =&amp;gt; not equal to&lt;/li&gt;

&lt;li&gt;_eq =&amp;gt; equal to &lt;em&gt;(this is implied without a suffix present)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='mysql_timestamp_disclaimer'&gt;MySQL TIMESTAMP Disclaimer&lt;/h2&gt;

&lt;p&gt;This does not work on TIMESTAMP columns for MySQL due to an issue with the inconsistency of TIMESTAMP columns in varying versions of MySQL and due to the nature of server configurations which can alter the behavior of TIMESTAMP columns.&lt;/p&gt;

&lt;h2 id='postgresql_support_note'&gt;PostgreSQL Support Note&lt;/h2&gt;

&lt;p&gt;I recently switched to a Mac, I am compiling PostgreSQL 8.1 and 8.2 as I type this. As soon as I can test this functionality against PostgreSQL I will release an update with that support.&lt;/p&gt;

&lt;h2 id='download_it_now'&gt;Download It Now!&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Rubyforge: &amp;#8220;http://rubyforge.org/frs/?group_id=2113&amp;#8221;:http://rubyforge.org/frs/?group_id=2113&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Recapping UI Architectural Patterns</title>
   <link href="http://www.continuousthinking.com/2007/03/04/recapping-ui-architectural-patterns.html"/>
   <updated>2007-03-04T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/03/04/recapping-ui-architectural-patterns</id>
   <content type="html">&lt;p&gt;Here are some recent summarizations and thoughts on classic classic Model View Controller , Model View Presenter and then finally end on the more recent Presenter First pattern.&lt;/p&gt;

&lt;h2 id='model_view_controller'&gt;Model View Controller&lt;/h2&gt;

&lt;p&gt;Model View Controller (MVC) is an architectural pattern used to separate domain objects which model our perception of the real world and the presentation objects used which are the GUI components that we see on the screen.&lt;/p&gt;

&lt;p&gt;A few key points regarding domain objects: * domain objects should be completely self contained and they should work entirely without reference to the presentation.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain objects should support multiple presentations, possibly simultaneously&lt;/li&gt;

&lt;li&gt;domain objects send events when it&amp;#8217;s state changes to allow views and controllers to observe those events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In MVC, the domain element is referred to as the model. Domain objects are to represent their real world counterpart. For example, a domain object for a person would be a Person object.&lt;/p&gt;

&lt;p&gt;The presentation (UI) part of MVC is the view and the controller.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the controller&amp;#8217;s job is to take user input and figure out what to do with it&lt;/li&gt;

&lt;li&gt;the view&amp;#8217;s job is to be the UI &lt;em&gt;(The view should contain as little to no logic as possible.)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a model-view-controller for each element on the screen.&lt;/p&gt;

&lt;p&gt;Some important notes about the design of MVC:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the model object does not contain a reference to the controller or the view&lt;/li&gt;

&lt;li&gt;the controller and the view contain a reference to the model&lt;/li&gt;

&lt;li&gt;the controller and the view do not contain references to one another&lt;/li&gt;

&lt;li&gt;the controller and the view observe the model object for events/changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The design of MVC shows that the controller does not directly update the view. Instead it notifies the model, and lets the observer mechanism take over. Since the view is observing the model object it should update itself accordingly.&lt;/p&gt;

&lt;h3 id='issues_with_mvc'&gt;Issues With MVC&lt;/h3&gt;

&lt;h4 id='issue_1__view_coupling'&gt;Issue #1 - View Coupling&lt;/h4&gt;

&lt;p&gt;Since a model, view and controller exists for each UI element on the screen, MVC can fall short when an update in one view propagates a change in a different view. This is because you can end up with coupling between views:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;having one view update another view couples the views&lt;/li&gt;

&lt;li&gt;you can solve this by creating a new view which is composed of the previous two views&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id='issue_2__view_logic'&gt;Issue #2 - View Logic&lt;/h4&gt;

&lt;p&gt;A second issue which is a variant of the first issue exists when an update in one view propagates a change to itself or another view which is based on criteria based on the change in the domain object.&lt;/p&gt;

&lt;p&gt;The problem with the second issue is that you have logic that makes a decision about the presentation of your model. The logic to do this isn&amp;#8217;t necessarily domain logic so it doesn&amp;#8217;t belong in the model. You also don&amp;#8217;t want to put unnecessary logic in the view.&lt;/p&gt;

&lt;p&gt;You can solve this by: * creating a new model object that is oriented around the screen (presentation) which wraps the original model object. The view logic could go in this model object without affecting the original model object. &lt;em&gt;(this would be equivalent to creating an intermediate Presentation Model object to handle the view logic)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;According to Fowler, the Presentation Model also allows you solve the issue of presentation state, as well as presentation logic. By wrapping the domain model in a presentation model you can maintain view specific logic and state separate from our domain logic. All the while leaving the view very clean.&lt;/p&gt;

&lt;h4 id='issue_3__view_testability'&gt;Issue #3 - View Testability&lt;/h4&gt;

&lt;p&gt;Testing views is extremely difficult. This is one of the reasons why MVC suggests to leave views as simple as possible, because they are hard to test.&lt;/p&gt;

&lt;p&gt;You can reduce the risk of issues in the view by moving most, if not all of the logic outside of the views into domain objects or presentation model objects which can be self-contained and are easier to test.&lt;/p&gt;

&lt;h3 id='conclusion'&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;MVC is the building blocks for breaking out domain logic from presentation logic.&lt;/p&gt;

&lt;p&gt;Testing a strict MVC architecture seems to have its drawbacks especially if complex view logic is kept in the view. The overhead of creating a model/view/controller for each UI element also seems to be a daunting task to coordinate and test.&lt;/p&gt;

&lt;p&gt;Rather then strictly following MVC it seems to be a better approach to utilize a MVP approach.&lt;/p&gt;

&lt;h3 id='links'&gt;Links&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://en.wikipedia.org/wiki/Model-view-controller&amp;#8221;:http://en.wikipedia.org/wiki/Model-view-controller&lt;/li&gt;

&lt;li&gt;&amp;#8220;http://www.martinfowler.com/eaaDev/uiArchs.htm&amp;#8221;:http://www.martinfowler.com/eaaDev/uiArchs.htm&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='model_view_presenter'&gt;Model View Presenter&lt;/h2&gt;

&lt;p&gt;Model View Presenter (MVP) is a architectural pattern similar to MVC. Whereas in MVC there is a controller/view for each UI element, in MVP there is a typically a single presenter/view for each for screen or at the least for each set of complex screen elements.&lt;/p&gt;

&lt;p&gt;MVP and MVC share the commonality that they both rely on the observer synchronization. In MVP the presenter handles user actions and updates the model. In MVC the controller handles user actions and updates the model. In both MVP and MVC the view will then be updated by observing events/changes on the model.&lt;/p&gt;

&lt;p&gt;MVP implementations can vary in a great deal when it comes to how the view gets updated: * one variation maintains the same relationship between the model, view and presenter that is maintained through MVC&amp;#8217;s relationship of the model, view and controller. * a second variation allows the presenter to have access to the view to update the view when complex view logic is required, otherwise view logic would go in the view. Fowler refers to this as the Supervising Controller (aka Supervising Presenter). * a third variation puts all of the view updates inside of the presenter. This implements what Fowler refers to as a Passive View. * a fourth variation of this is implemented in the Presenter First pattern. &lt;em&gt;(this will be describe later)&lt;/em&gt;&lt;/p&gt;

&lt;h3 id='conclusion'&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;MVP simplifies complex view updates by utilizing a Supervising Controller. By extracting out complex view logic is promotes greater testability for your application.&lt;/p&gt;

&lt;p&gt;Allowing a presenter object to handle the user actions for a screen, form or set of UI elements seems to cut down on unnecessary complication and overuse of observers as you could get with MVC.&lt;/p&gt;

&lt;h3 id='links'&gt;Links&lt;/h3&gt;

&lt;h3 id='links'&gt;Links&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://www.martinfowler.com/eaaDev/uiArchs.htm&amp;#8221;:http://www.martinfowler.com/eaaDev/uiArchs.htm&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='presenter_first'&gt;Presenter First&lt;/h2&gt;

&lt;p&gt;The Presenter First (PF) approach is a variant of MVP. In practice the authors emphasize using it in an agile development process which build features into an application given customer stories. It is considered to be a hybrid of process and pattern.&lt;/p&gt;

&lt;p&gt;To outline some of the things PF does:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;separation of business logic and view logic&lt;/li&gt;

&lt;li&gt;separation of complex view logic from the view&lt;/li&gt;

&lt;li&gt;decoupling of the view from the presenter/model&lt;/li&gt;

&lt;li&gt;provide fully testable GUI applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PF works by composing the model and the view into the presenter via dependency injection. The presenter is created, but is never reference throughout the application. It simply glues together the model and view.&lt;/p&gt;

&lt;p&gt;The model nor the view contain a reference to the presenter. Instead they send events that the presenter observes, and the presenter then coordinates those events and updates the model or view accordingly.&lt;/p&gt;

&lt;p&gt;View &amp;#8212;-&amp;gt; Presenter &amp;lt;&amp;#8212;- Model&lt;/p&gt;

&lt;p&gt;PF states that the view is the most complex, tedious and time consuming component to test. PF&amp;#8217;s goal is to leave the view as simple as possible. One way it promotes to do this is to only allow your view to manage simple data types. If complex data types are handled in your view, then your view must contain the ability to process and correctly display the complex data types. Since this promotes additional logic in your view, PF discourages this.&lt;/p&gt;

&lt;p&gt;PF ties user stories directly to a specific MVP triplet. The term &amp;#8220;triplet&amp;#8221; is used to refer to an instance of a model, view and presenter. &lt;em&gt;Triplet is commonly referred to as a &amp;#8220;triad&amp;#8221;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PF takes into account that complex view logic that exists. Often times that logic is mixed in with the domain objects. The problem with this is that the domain objects now contains a mixture of domain logic and view logic. This makes the code harder to read and it complicates the interaction between the model, presenter and view because complex view updates are propagating from the model itself.&lt;/p&gt;

&lt;p&gt;PF solves this by introducing an &amp;#8220;adapter&amp;#8221; object. The adapter object goes in between the view and the presenter. The presenter will now reference the adapter, and the adapter will reference the view. There now exists a place that isolates any logic that is needed for the view. View logic is now fully testable.&lt;/p&gt;

&lt;p&gt;Also, the adapter object may lead to an adapter-model object in which only the adapter would reference. This could be used to maintain view/presentation state. &lt;em&gt;Even if an&lt;/em&gt; &lt;em&gt;adapter object is introduced, the term &amp;#8220;triplet&amp;#8221; is still used.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PF also suggests that the presenter objects have no public methods and that they are stateless. The presenter&amp;#8217;s job is merely to coordinate events between the view and the model (or vise versa).&lt;/p&gt;

&lt;p&gt;PF also suggests that starting with the presenter first is the best place to start the development of a user story. Over time PF suggests it is less expensive to start with the presenter, rather then the view or the model.&lt;/p&gt;

&lt;h3 id='links'&gt;Links&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&amp;#8220;http://atomicobject.com/pages/Presenter+First&amp;#8221;:http://atomicobject.com/pages/Presenter+First&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='conclusion'&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Presenter First promotes a consistent, predictable convention for class naming, and object responsibility. It allows for IDEs or development tools to be created to speed up the development, creation and testing of these objects.&lt;/p&gt;

&lt;p&gt;The interaction between the components in PF is easy to understand and the way that it is approached by the authors seems to remove issues with more classic MVC patterns or other MVP variants.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>So I Got A Mac</title>
   <link href="http://www.continuousthinking.com/2007/02/20/so-i-got-a-mac.html"/>
   <updated>2007-02-20T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/02/20/so-i-got-a-mac</id>
   <content type="html">&lt;p&gt;So I got Mac. A second-tier Mac Book Pro actually. After the past few years of being a dedicated linux enthusiast, it appears to be the best bet out there for a dual business/development box.&lt;/p&gt;

&lt;p&gt;(I&amp;#8217;ll still run Kubuntu for my desktop box at home and Ubuntu server for my server, but as of right now I&amp;#8217;m not having any second guesses about the Mac. )&lt;/p&gt;

&lt;p&gt;The built-in webcam and the iChat video support immediately made it worth it. I got Emacs working in just a few minutes and firefox is downloaded and installed.&lt;/p&gt;

&lt;p&gt;I spent a few hours today installing/compiling a bunch of packages from MacPorts, but so far it&amp;#8217;s been well worth it.&lt;/p&gt;

&lt;p&gt;I am digging the magnetic power adapter as well. Thanks to Brandon, John and Craig for letting me pick their brains about OSX throughout the day!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Moving On</title>
   <link href="http://www.continuousthinking.com/2007/02/14/moving-on.html"/>
   <updated>2007-02-14T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/02/14/moving-on</id>
   <content type="html">&lt;h2 id='well_its_over'&gt;Well it&amp;#8217;s over.&lt;/h2&gt;

&lt;h2 id='after_nearly_six_years_of_working_with_my_current_employer_developing_custom_software_i_have_decided_to_pursue_a_new_direction'&gt;After nearly six years of working with my current employer developing custom software I have decided to pursue a new direction.&lt;/h2&gt;

&lt;p&gt;My passion for developing better software has gotten the best of me. I 100% agree with the &amp;#8220;Agile Manifesto&amp;#8221;:http://www.agilemanifesto.org and that&amp;#8217;s why tonight I became a signatory and part of the reason why I felt it was time for me to pursue a new direction. To iterate the four main points of the Agile Manifesto:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Individuals and interactions over processes and tools&lt;/li&gt;

&lt;li&gt;Working software over comprehensive documentation&lt;/li&gt;

&lt;li&gt;Customer collaboration over contract negotiation&lt;/li&gt;

&lt;li&gt;Responding to change over following a plan&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Individually as a developer and a team member I wake up and do the following every day I go to work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;As a software developer I take pride in the software that I create and that others may have to maintain.&lt;/li&gt;

&lt;li&gt;As a tester I take pride in proving that my software works so it can be changed with confidence to satisfy evolving business needs, even if that change is not going to be made by me.&lt;/li&gt;

&lt;li&gt;As project member I take pride in communicating and collaborating to those I work with to give the project it&amp;#8217;s best possible chance of success and of also solving the right business problem.&lt;/li&gt;

&lt;li&gt;As a person I take pride in respectfully and genuinely treating those I encounter through work and every day life.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wish my previous employer the best of luck.&lt;/p&gt;

&lt;p&gt;To those who read this post, I hope you will either be positively affected in someway by the software that I have or will help create or that you will positively affected by working with me directly for software that will solve your business needs.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.4.0 Released!</title>
   <link href="http://www.continuousthinking.com/2007/02/12/activerecord-extensions-0-4-0-released.html"/>
   <updated>2007-02-12T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/02/12/activerecord-extensions-0-4-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.4.0 is released!&lt;/p&gt;

&lt;h1 id='updates'&gt;Updates&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;added to_csv functionality (works with belongs_to, has_one and has_many relationships)&lt;/li&gt;

&lt;li&gt;added temporary table functionality&lt;/li&gt;

&lt;li&gt;added foreign key functionality&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id='to_csv_functionality'&gt;to_csv functionality&lt;/h1&gt;

&lt;h2 id='example_1_exporting_all_fields'&gt;Example 1, exporting all fields&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt; class Book &amp;lt; ActiveRecord::Base ; end

 book = Book.find( 1 )
 book.to_csv&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='example_2_only_exporting_certain_fields'&gt;Example 2, only exporting certain fields&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt; class Book &amp;lt; ActiveRecord::Base ; end

 book = Book.find( 1 )
 book.to_csv( :only=&amp;gt;%W( title isbn )&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='example_3_exporting_a_model_including_a_belongs_to_association'&gt;Example 3, exporting a model including a belongs_to association&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt; class Book &amp;lt; ActiveRecord::Base
   belongs_to :author
 end

 book = Book.find( 1 )
 book.to_csv( :include=&amp;gt;:author )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This also works for a has_one relationship. The :include option can also be an array of has_one/belongs_to associations. This by default includes all fields on the belongs_to association.&lt;/p&gt;

&lt;h2 id='example_4_exporting_a_model_including_a_has_many_association'&gt;Example 4, exporting a model including a has_many association&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class Book &amp;lt; ActiveRecord::Base
  has_many :tags
end

book = Book.find( 1 )
book.to_csv( :include=&amp;gt;:tags )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This by default includes all fields on the has_many assocaition. This can also be an array of multiple has_many relationships. The array can be mixed with has_one/belongs_to associations array as well. IE: :include=&amp;gt;[ :author, :sales ]&lt;/p&gt;

&lt;h2 id='example_5_nesting_associations'&gt;Example 5, nesting associations&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt; class Book &amp;lt; ActiveRecord::Base
   belongs_to :author
   has_many :tags
 end

 book = Book.find( 1 )
 book.to_csv( :include=&amp;gt;{
                 :author =&amp;gt; { :only=&amp;gt;%W( name ) },
                 :tags =&amp;gt; { :only=&amp;gt;%W( tagname ) } )&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='example_6_using_arrays_returned_by_find'&gt;Example 6, using Arrays returned by find&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt; class Book &amp;lt; ActiveRecord::Base
   belongs_to :author
   has_many :tags
 end

 books = Book.find( :all )
 books.to_csv( :include=&amp;gt;{
                 :author =&amp;gt; { :only=&amp;gt;%W( name ) },
                 :tags =&amp;gt; { :only=&amp;gt;%W( tagname ) } )&lt;/code&gt;&lt;/pre&gt;

&lt;h1 id='temporary_table_support'&gt;Temporary Table Support&lt;/h1&gt;

&lt;h2 id='example_1_using_defaults'&gt;Example 1, using defaults&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt; class Project &amp;lt; ActiveRecord::Base ; end

 Project.create_temporary_table&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a temporary table named &amp;#8216;temp_projects&amp;#8217; and creates a constant name TempProject. The table structure is copied from the projects table.&lt;/p&gt;

&lt;h2 id='example_2_using_table_name_and_model_options'&gt;Example 2, using :table_name and :model options&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Project.create_temporary_table :table_name=&amp;gt;&amp;#39;my_projects&amp;#39;, :model=&amp;gt;&amp;#39;MyProject&amp;#39;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This creates a temporary table named &amp;#8216;my_projects&amp;#8217; and creates a constant named MyProject. The table structure is copied from the projects table.&lt;/p&gt;

&lt;h2 id='example_3_using_like'&gt;Example 3, using :like&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;ActiveRecord::Base.create_temporary_table :like=&amp;gt;Project&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the same as calling Project.create_temporary_table.&lt;/p&gt;

&lt;h2 id='example_4_using_block_form'&gt;Example 4, using block form&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Project.create_temporary_table do |t|
  # ...
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using the block form will automatically drop the temporary table when the block exits. t which is passed into the block is the temporary table class. In the above example t equals TempProject. The block form can be used with all of the available options.&lt;/p&gt;

&lt;h1 id='foreign_key_support'&gt;Foreign Key Support&lt;/h1&gt;

&lt;p&gt;Enables support for enabling and disabling foreign keys for the underlying database connection for ActiveRecord. This can be used with or without block form. This also uses the connection attached to the model.&lt;/p&gt;

&lt;h2 id='example_1_without_block_form'&gt;Example 1, without block form&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Project.foreign_keys.disable
Project.foreign_keys.enable&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you use this form you have to manually re-enable the foreign keys.&lt;/p&gt;

&lt;h2 id='example_2_with_block_form'&gt;Example 2, with block form&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;Project.foreign_keys.disable do
  # ...
end

Project.foreign_keys.enable do
  # ...
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you use the block form the foreign keys are automatically enabled or disabled when the block exits. This currently does not restore the state of foreign keys to the state before the block was entered.&lt;/p&gt;

&lt;h2 id='download_it_now'&gt;Download It Now!&lt;/h2&gt;

&lt;p&gt;&amp;#8220;ActiveRecord::Extensions 0.4.0&amp;#8221;:http://rubyforge.org/frs/?group_id=2113&lt;/p&gt;

&lt;h2 id='check_it_out_from_svn_into_your_rails_project'&gt;Check it out from SVN into your Rails project&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;svn co svn://rubyforge.org/var/svn/arext/tags/ar-extensions-0.4.0 vendor/plugins/&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>Temporary Table Nicety</title>
   <link href="http://www.continuousthinking.com/2007/01/31/activerecord-temporary-tables-and-merging-mysql.html"/>
   <updated>2007-01-31T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/01/31/activerecord-temporary-tables-and-merging-mysql</id>
   <content type="html">&lt;p&gt;A taste of temporary table support for ActiveRecord and MySQL.&lt;/p&gt;

&lt;h2 id='creating_temporary_tables'&gt;Creating Temporary Tables&lt;/h2&gt;

&lt;p&gt;Temporary tables can be created by using two forms. Temporary tables will generate the following SQL:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CREATE TEMPORARY TABLE table_name LIKE base_table&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='the_first_form'&gt;The First Form&lt;/h3&gt;

&lt;p&gt;A block form which manages your temporary table &lt;em&gt;(ie: it creates the table at the start of the block and ensures it is removed by the end of the block, similar to how IO objects work in ruby)&lt;/em&gt; .&lt;/p&gt;

&lt;h3 id='the_second_form'&gt;The Second Form&lt;/h3&gt;

&lt;p&gt;The second form allows you to assign your temporary table to a variable. You are responsible for destroying it. Or you could just leave it around until your ruby process is done and your database will kill it when the connection closes.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example using the block form:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# create our model
class Account &amp;lt; ActiveRecord::Base
end

# perform the update
Account.create_temporary_table do |t|
   t.new.is_a? ActiveRecord::Base # =&amp;gt; true
   t.new.is_a? ActiveRecord::TemporaryTable # =&amp;gt; true

    # You can treat &amp;#39;t&amp;#39; like any model class, and create new records, 
    # add validations, etc.
    record = t.new :name=&amp;gt;&amp;quot;New Account&amp;quot; 
    record.save
    record.create :name =&amp;gt; &amp;quot;Another new account&amp;quot;

    # TempAccount is created to reference this model class as well
     TempAccount == t # =&amp;gt; true

    # the &amp;quot;end&amp;quot; block here will drop our temporary table and remove
    # our TempAccount constant
end&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='checking_it_out'&gt;Checking It Out&lt;/h2&gt;

&lt;p&gt;You can pull it down from trunk right now. It will be included in the next release (which will be 0.4.0):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;svn checkout svn://rubyforge.org/var/svn/arext/trunk/ar-extensions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='like_tables'&gt;Like Tables&lt;/h2&gt;

&lt;p&gt;Like tables are similar to temporary tables. In fact they are created in the exact same way except that they are permanent. They are normal tables until you destroy them. A like table simply generates the following sql:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CREATE TABLE table_name LIKE base_table&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can create this the same way way you create temporary tables, just pass in the :permanent option as a parameter:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Account &amp;lt; ActiveRecord::Base
end

# t is your model class, also aliased as TempAccount.
temp_account_model_class = Account.create_temporary_table :permanent=&amp;gt;true

TempAccount == temp_account_model_class # =&amp;gt; true  

# drop your table
TempAccount.drop&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Foreign Key Nicety</title>
   <link href="http://www.continuousthinking.com/2007/01/24/activerecord-foreign-key-nicety.html"/>
   <updated>2007-01-24T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/01/24/activerecord-foreign-key-nicety</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been busy lately and I haven&amp;#8217;t finished the to_csv functionality for ActiveRecord::Extensions. It&amp;#8217;s coming, but I haven&amp;#8217;t had time to implement all of the tests.&lt;/p&gt;

&lt;p&gt;A new feature that myself and Mark Van Holstyn worked up was because we wanted an elegant solution to this in a problem we had. And it was time to finally put in the foreign key support that I hacked together over a year ago. Now it&amp;#8217;s not a hack, and I think it&amp;#8217;s kind of elegant.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Disable foreign keys altogether
ActiveRecord::Base.foreign_keys.disable

# Enable foreign keys 
ActiveRecord::Base.foreign_keys.enable

# Run some updates in a disable block and have AR automatically re-enable foreign keys
Topic.foreign_keys.disable do
   # ... code here....
end

# Run some updates in a enable block and have AR automatically re-disable foreign keys
Topic.foreign_keys.enable do
   # ... code here ....
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This works on any instance of ActiveRecord::Base, and it works on the connection for that instance. So if you have models which are connected to different databases, no worries.&lt;/p&gt;

&lt;p&gt;This is in trunk right now and works great for MySQL.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>open4status for ruby</title>
   <link href="http://www.continuousthinking.com/2007/01/19/open4status-for-ruby.html"/>
   <updated>2007-01-19T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/01/19/open4status-for-ruby</id>
   <content type="html">&lt;p&gt;open4status which is an adjustment to open3.rb thats found in the standard library returns stdin, stdout, stderr and a Process::Status object of the command that ran. This way you can determine the exit status code of the command that you passed into popen4status method.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;require &amp;#39;open4status&amp;#39;

stdin,stdout,stderr,status = Open4.popen4status( &amp;quot;some command here&amp;quot; )
puts status.exitstatus&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The problem this solves is that when you use Open3.popen3 or Open4.popen4, the $? value isn&amp;#8217;t set. Since the way that $? is set can&amp;#8217;t be done without writing a C extension or patching ruby itself this handles the problem elegantly by returning the Process::Status object.&lt;/p&gt;

&lt;h2 id='the_code'&gt;The Code&lt;/h2&gt;

&lt;p&gt;This is being distributed as a poor man&amp;#8217;s way of code distribution.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;I am waiting to hear back from Ryan Davis on a bug/feature request to Open3 to see if this is something he wants to include in his &amp;#8220;codeforpeople&amp;#8221;:http://www.rubyforge.org/projects/codeforpeople project at Rubyforge.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If not I&amp;#8217;ll release a gem. Until then here&amp;#8217;s the file:&lt;/p&gt;

&lt;p&gt;&amp;#8220;http://www.continuousthinking.com/assets/2007/1/19/open4status.rb&amp;#8221;:http://www.continuousthinking.com/assets/2007/1/19/open4status.rb&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>.screenrc configuration</title>
   <link href="http://www.continuousthinking.com/2007/01/07/screenrc-configuration.html"/>
   <updated>2007-01-07T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/01/07/screenrc-configuration</id>
   <content type="html">&lt;p&gt;I spend most of my time in screen when I&amp;#8217;m coding or doing any system administration work. It gives me the ability to do multiple things in a single window, and never have to remove my hands from my keyboard to switch terminal sessions or split windows. It even provides the flexibility of detaching and reattaching to screen sessions while leaving your terminal sessions in existence.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve been using the below .screenrc file recently to give me some more useful information.&lt;/p&gt;

&lt;h2 id='the_screenshot'&gt;The screenshot&lt;/h2&gt;
&lt;a href='/assets/2007/1/7/screen.png' target='_blank'&gt;
&lt;img alt='Screen_thumb' src='/assets/2007/1/7/screen_thumb.png?1168134393' title='screen.png linux' /&gt;
&lt;/a&gt;
&lt;p&gt;Note the following things in the screenshot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;system hostname&lt;/li&gt;

&lt;li&gt;system ip addresses for each interface configured (see below &amp;#8220;whatsmyip&amp;#8221; file information)&lt;/li&gt;

&lt;li&gt;system load (updates every few seconds)&lt;/li&gt;

&lt;li&gt;date&lt;/li&gt;

&lt;li&gt;current time (this updates every second)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='the_screenrc_file'&gt;The .screenrc file&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;altscreen on
hardstatus on
hardstatus alwayslastline
backtick 1 60 60 /home/zdennis/bin/whatsmyip
hardstatus string &amp;quot;%-Lw %{= kG}Host: %{Y}%H%? %{c}(%1`) \
%{= kG} %-=Load: %{Y}%l%{kG}  %{= kG}Date: %{Y}%m/%d\
/%y%{= kG}  Time: %{Y}%C:%s%a%{= kG}%{W}&amp;quot;
caption always
caption string &amp;quot;%-Lw%{= bw}%50&amp;gt;%n %t%{-}%+Lw%&amp;lt;&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Note: The lines that end in \ note a continuation of the line.&lt;/em&gt;&lt;/p&gt;

&lt;h2 id='the_whatsmyip_file'&gt;The whatsmyip file&lt;/h2&gt;

&lt;p&gt;The whatsmyip file is a simple ruby script which parses out all interfaces configured with an ip address.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/usr/bin/ruby

interfaces = `ifconfig`.scan( /^(\w+)/ ).flatten.delete_if{ |interface| interface =~ /lo/ }
arr = interfaces.inject( \[\] ) do |arr,interface|
  md = `ifconfig #{interface}`.match( /((\d+\.){3}\d+)/ )
  arr &amp;lt;&amp;lt; &amp;quot;#{interface}: #{md.captures.first}&amp;quot; if md
  arr
end
print arr.join( &amp;#39; &amp;#39; )&lt;/code&gt;&lt;/pre&gt;</content>
 </entry>
 
 <entry>
   <title>to_csv update (nearing Round #2)</title>
   <link href="http://www.continuousthinking.com/2007/01/04/to_csv-update-nearing-round-2.html"/>
   <updated>2007-01-04T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2007/01/04/to_csv-update-nearing-round-2</id>
   <content type="html">&lt;p&gt;Round #2 of the to_csv functionality is nearing completion. The updates so far are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;supports associations via the :include option on a per model object basis&lt;/li&gt;

&lt;li&gt;supports custom headers through the model class&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It will work on an ActiveRecord model object itself or an array of ActiveRecord model objects that are returned from any &amp;#8220;find&amp;#8221; method call.&lt;/p&gt;

&lt;h2 id='basic_include_option'&gt;Basic :include option&lt;/h2&gt;

&lt;p&gt;The :include option will bring in an association that is created with belongs_to or has_many declarations.&lt;/p&gt;

&lt;p&gt;Here is a basic example for a belongs_to association to be included in the CSV results with default options:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;csv = People.find( :all ).to_csv( :include=&amp;gt; \[ :address \] )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you haven&amp;#8217;t been following to_csv functionality prior to this posting the to_csv method does support toggling on/off of the CSV headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;:headers=&amp;gt;true&lt;/li&gt;

&lt;li&gt;:headers=&amp;gt;false&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='updated_headers_option'&gt;Updated :headers Option&lt;/h2&gt;

&lt;p&gt;To detour from the :include options for a moment, the :headers option has been updated to accept:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an array of column names as Symbols or Strings&lt;/li&gt;

&lt;li&gt;a Hash of column name to header name mappings as Symbols or Strings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are a few examples of the new headers option in use:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# using symbols
csv = People.find( :all ).to_csv( :headers =&amp;gt; [ :first\_name, :last\_name ]  }

# using strings
csv = People.find( :all ).to_csv( :headers =&amp;gt; [ &amp;#39;first\_name&amp;#39;, &amp;#39;last\_name&amp;#39; ]  }

# using a Hash to supply custom headers
csv = People.find( :all ).to_csv( :headers =&amp;gt; { :first\_name=&amp;gt;&amp;#39;FirstName&amp;#39;, :last_name=&amp;gt;&amp;#39;LastName&amp;#39; }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since Arrays are ordered the CSV columns will be in the order of the Array. Since Hashes aren&amp;#8217;t ordered the order of the columns will be done alphabetically based on the field name.&lt;/p&gt;

&lt;h2 id='intermediate_usage_of_include'&gt;Intermediate Usage Of :include&lt;/h2&gt;

&lt;p&gt;The :include option can take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an Array of Strings or Symbols denoting the name of the association&lt;/li&gt;

&lt;li&gt;a Hash of Hashes mapping the association name to an options Hash&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;em&gt;options&lt;/em&gt; Hash is what you&amp;#8217;re already passing into the to_csv method. If you use the Hash form of :include you get the ability to embed different options per each association included.&lt;/p&gt;

&lt;p&gt;Here are some more intermediate examples:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;people = People.find( :all )

# Using a Hash to specify the column you want from the Address relationship
people.to_csv( :include=&amp;gt;{ :address=&amp;gt;{ :only=&amp;gt;[ :street, :city, :state, :zip ] } } )

# Using a top level options to include only certain fields from each person and
# then options to include certain fields from each person&amp;#39;s address.
people.to_csv( :only=&amp;gt;\[ :first_name, :last_name \],
   :include=&amp;gt;{ :address=&amp;gt;{ :only=&amp;gt;\[ :street, :city, :state, :zip \] } } )

# Modification of the last example to use custom headers
people.to_csv( :headers=&amp;gt;{ :first_name=&amp;gt;&amp;quot;FName&amp;quot;, :last_name=&amp;gt;&amp;quot;LName&amp;quot; } ,
   :include=&amp;gt;{ :address=&amp;gt;{ :headers=&amp;gt;{ :city=&amp;gt;&amp;quot;Hometown&amp;quot;, :state=&amp;gt;&amp;quot;ST&amp;quot; } } } )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;#8217;s a brief summary for where the state of affairs is at for now. If you want more information please read all of the nice tests by &amp;#8220;checking out&amp;#8221;:http://rubyforge.org/scm/?group_id=2113 the SVN repository.&lt;/p&gt;

&lt;p&gt;There are some other usages that you will be able to do like (see below) but the tests and functionality has not been intentionally implemented although it may/may work off from existing functionality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;support multiple :include options for multiple associations&lt;/li&gt;

&lt;li&gt;embed :include options inside of :include options for chaining associations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing I don&amp;#8217;t like about all of this so far is all of the curly braces, brackets and potentially parenthesizes. The more :includes you want to have, the more curly braces you&amp;#8217;re going to have most likely.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m trying to think of a block like declarative syntax to handle this, but I haven&amp;#8217;t come up with any worthwhile yet. If you&amp;#8217;ve got any ideas I&amp;#8217;m all ears.&lt;/p&gt;

&lt;h2 id='upcoming_040_release'&gt;Upcoming 0.4.0 release&lt;/h2&gt;

&lt;p&gt;This will be launched in a 0.4.0 release which should be soon. I&amp;#8217;ve got to be out of town part of this weekend, and the most of next week so I am going to see if I can crunch it in before the next Monday.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.3.0 Released!</title>
   <link href="http://www.continuousthinking.com/2006/12/30/activerecord-extensions-0-3-0-released.html"/>
   <updated>2006-12-30T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/30/activerecord-extensions-0-3-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.3.0 is released! Download it &amp;#8220;here&amp;#8221;:http://rubyforge.org/frs/?group_id=2113.&lt;/p&gt;

&lt;p&gt;There are no functionality changes in this release. There are two changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;thanks to Michael Schuerig for pointing out a potential namespace issue which is fixed in this release&lt;/li&gt;

&lt;li&gt;tests are now loaded in the a new ruby process rather then into the same ruby process as rake tasks when running &lt;em&gt;rake test:ADAPTER&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.2.0 Released!</title>
   <link href="http://www.continuousthinking.com/2006/12/22/activerecord-extensions-0-2-0-released.html"/>
   <updated>2006-12-22T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/22/activerecord-extensions-0-2-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.2.0 is released! Download it &amp;#8220;here&amp;#8221;:http://rubyforge.org/frs/?group_id=2113 .&lt;/p&gt;

&lt;p&gt;Updates include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Changes to the &lt;em&gt;to&lt;/em&gt;csv_ method to support an API compatible with the &amp;#8220;ToCSV plugin&amp;#8221;:http://blog.integralimpressions.com/articles/2006/09/01/tocsv-plugin by Chris Abad&lt;/li&gt;

&lt;li&gt;Added support for SQLite and SQLite3&lt;/li&gt;

&lt;li&gt;Added &amp;#8220;does_not_match&amp;#8221; suffix for :conditions which want to negate a regex&lt;/li&gt;

&lt;li&gt;Added &amp;#8220;not_between&amp;#8221; suffix for :conditions which want to negate a range&lt;/li&gt;

&lt;li&gt;Converted test database schema to use migrations, and added tasks to load test database&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='to_csv_updates'&gt;to_csv updates&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class Developer &amp;lt; ActiveRecord::Base ; end
developers = Developer.find( :all )

# Output default headers, this is implicit if headers is not provided
csv  = developers.to_csv( :headers =&amp;gt; true )

# Output no headers
csv = developers.to_csv( :headers =&amp;gt; false )

# Output only the following columns
csv = developers.to_csv( :only=&amp;gt;[ :id, :name ] )

# Output all columns except the following
csv = developers.to_csv( :except =&amp;gt; [ :id, :name ] )&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='updates_to_better_finders'&gt;Updates to better finders&lt;/h2&gt;

&lt;p&gt;I was typing some code today and I was using Ranges and Regexps. It just felt write to say that &lt;em&gt;something&lt;/em&gt;does_not_match_ when matching between a Regular Expression. And then I decided to add &amp;#8220;not_between&amp;#8221; for Ranges.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Developer &amp;lt; ActiveRecord::Base ; end

# find all developers whose name does not match the regex
Developer.find :all, :conditions =&amp;gt; { :name_does_not_match =&amp;gt; &amp;#39;^Zach&amp;#39; }

# find all developers whose IQ is not between 80 and 120
Developer.find :all, :conditions =&amp;gt; { :iq_not_between =&amp;gt; ( 80 .. 120 ) }&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id='running_activerecordextensions_tests'&gt;Running ActiveRecord::Extensions Tests&lt;/h2&gt;

&lt;p&gt;ActiveRecord::Extensions provides a great testing suite. Just run &amp;#8220;rake -T&amp;#8221; to see all of the supported tasks. In 0.2.0 the ability to load a test database from migrations has been added.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; # Usage
 rake db:test:prepare_&amp;lt;db&amp;gt;

 # IE:
 rake db:test:prepare_mysql

 # Then run your tests:
 rake test:mysql

 # And don&amp;#39;t forget to test against activerecord
 rake test:activerecord:mysql ~/rails_trunk/activerecord &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The only prerequisite of the above is to make sure that your connection is specified correctly for the database you want to test. To do this go into the tests/connections/native_DB/connection.rb file and update the database configuration.&lt;/p&gt;

&lt;h2 id='enjoy_020'&gt;Enjoy 0.2.0!&lt;/h2&gt;

&lt;p&gt;For any questions or comments let me know. * zach DOT dennis AT gmail DOT com&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions SQLite Compatibility</title>
   <link href="http://www.continuousthinking.com/2006/12/21/activerecord-extensions-sqlite-compatibility.html"/>
   <updated>2006-12-21T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/21/activerecord-extensions-sqlite-compatibility</id>
   <content type="html">&lt;p&gt;The upcoming 0.2.0 release is going to include SQLite compatibility, and it looks like that is going to be released before the weekend hits! Any one out there who uses SQLite and wants to leverage the usefulness of ActiveRecord::Extensions, wait no longer (then 1 to 2 more days)!&lt;/p&gt;

&lt;p&gt;The upcoming 0.2.0 release will update the to_csv and to_csv_file method arguments.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# rather then
array_of_models.to_csv( :headers =&amp;gt; [ :field1, :field2, :field3 ] )

# it&amp;#39;ll be
array_of_models.to_csv( :headers =&amp;gt; true|false, :only=&amp;gt; [ :field1, :field2, :field3 ] )

# or
array_of_models.to_csv( :headers =&amp;gt; true|false, :except=&amp;gt; [ :id ] )

# and the same goes for the options that were passed into to_csv_file as well
array_of_models.to_csv_file( filename, :headers=&amp;gt;[ :name, :salary ] )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thanks to Dan Kubb for bringing this up. The API is borrowed from Chris Abad&amp;#8217;s &amp;#8220;ToCSV plugin.&amp;#8221;:http://blog.integralimpressions.com/articles/2006/09/01/tocsv-plugin&lt;/p&gt;

&lt;p&gt;After that I&amp;#8217;ll be on holiday vacation and I hope to kick out some cool stuff, like the :include option that Dan Kubb &amp;#8220;mentioned.&amp;#8221;:http://rubyforge.org/tracker/?atid=8256&amp;amp;group_id=2113&amp;amp;func=browse for the to_csv.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord::Extensions 0.1.0 Released!</title>
   <link href="http://www.continuousthinking.com/2006/12/17/activerecord-extensions-0-1-0-released.html"/>
   <updated>2006-12-17T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/17/activerecord-extensions-0-1-0-released</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions 0.1.0 is released and it&amp;#8217;s getting some press! An article has been &amp;#8220;published&amp;#8221;:http://www.rubyinside.com/advent2006/17-extendingar.html on &amp;#8220;Ruby Inside&amp;#8217;s Advent Calendar&amp;#8221;:http://www.rubyinside.com/advent2006/ . Thanks to Peter Cooper for publishing the article.&lt;/p&gt;

&lt;h2 id='release_notes'&gt;Release Notes&lt;/h2&gt;

&lt;p&gt;ActiveRecord::Extensions 0.1.0 features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;to_csv functionality for Arrays returned by ActiveRecord::Base.find methods&lt;/li&gt;

&lt;li&gt;to_csv_file functionality for Arrays returned by ActiveRecord::Base.find methods&lt;/li&gt;

&lt;li&gt;Custom query object support for ActiveRecord::Base.find&lt;/li&gt;

&lt;li&gt;Official better finder support for MySQL and PostgreSQL&lt;/li&gt;

&lt;li&gt;Generic better finder support for all other database adapter supported by ActiveRecord&lt;/li&gt;

&lt;li&gt;Official import functionality support for MySQL and PostgreSQL&lt;/li&gt;

&lt;li&gt;Generic import functionality support for all other database adapters supported by ActiveRecord&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;li&gt;0 is actually the seventh release of ActiveRecord::Extensions, it&amp;#8217;s version number is so low because as more adapters are officially supported, it will quickly rise towards a 1.0.0 release.&lt;/li&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id='official_support_vs_generic_support'&gt;Official Support vs. Generic Support&lt;/h2&gt;

&lt;p&gt;Official support means that I have tests for the adapter in question, and it without a doubt works with ActiveRecord::Extensions.&lt;/p&gt;

&lt;p&gt;Generic support means that I have implemented default ActiveRecord compatibility with all of the features. It &lt;em&gt;should&lt;/em&gt; work with all supported adapters of ActiveRecord, but there are not tests in my library testing those adapters.&lt;/p&gt;

&lt;h3 id='to_csv'&gt;to_csv&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;to&lt;/em&gt;csv_ has been added as a method to all Arrays returned by ActiveRecord::Base.find. You can now quickly and painlessly turn ActiveRecord objects into CSV format. This functionality does rely on faster_csv (1.0.0 or higher) being installed:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Project &amp;lt; ActiveRecord::Base ; end
projects = Project.find( :all )
csv = projects.to_csv&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can also pass in an array of headers that you want as Strings or Symbols:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;csv = projects.to_csv( :headers =&amp;gt; [ :project_name, :started_on, :estimated_due_date ] )&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='to_csv_file'&gt;to_csv_file&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;to&lt;/em&gt;csv_file_ has been added as a method to all Arrays returned by ActiveRecord::Base.find. It gives you the ability to quickly csv files, much like it&amp;#8217;s sibling function &lt;em&gt;to&lt;/em&gt;csv_. Instead of simply returning a CSV string it writes a file to disk:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;projects = Project.find( :all )

# Writes projects.csv to disk using the &amp;#39;w&amp;#39; file mode operation
projects.to_csv_file( &amp;#39;projects.csv&amp;#39; )

# Writes projects.csv to disk using the &amp;#39;a&amp;#39; (append) file mode operation. 
# Any IO mode is supported as the second parameter.
projects.to_csv_file( &amp;#39;projects.csv&amp;#39;, &amp;#39;a&amp;#39; )

# Writes projects.csv to disk specifying what columns headers to use:
projects.to_csv_file(
     &amp;#39;projects.csv&amp;#39;, 
     :headers=&amp;gt; [ :project_name, :started_on, :estimated_due_date ] 
)&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='refactorings'&gt;Refactorings&lt;/h3&gt;

&lt;p&gt;This release also includes some refactorings of how ActiveRecord::Extensions internals work to support better extensibility down the road.&lt;/p&gt;

&lt;h2 id='download_and_install'&gt;Download and Install&lt;/h2&gt;

&lt;p&gt;&amp;#8220;Download it now from rubyforge!&amp;#8221;:http://rubyforge.org/frs/?group_id=2113 .&lt;/p&gt;

&lt;p&gt;Installation is simple. You can put it in your Rails application by placing the extracted directory in your RAILS_ROOT/vendor/plugins directory or you can put it in any application and require the &lt;em&gt;init.rb&lt;/em&gt; file included in the ar-extensions-0.1.0./ directory.&lt;/p&gt;

&lt;p&gt;Upcoming in the next release will be easier installation via &amp;#8220;gem install&amp;#8221; or installation as a Rails plugin from your rails application using &amp;#8220;script/plugin&amp;#8221;.&lt;/p&gt;

&lt;h2 id='contact_the_developer'&gt;Contact the Developer&lt;/h2&gt;

&lt;p&gt;Any questions, comments or bugs please feel free to use the Project Tracking features on the &amp;#8220;RubyForge project site&amp;#8221;:http://rubyforge.org/tracker/?group_id=2113&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email: Zach Dennis - zach DOT dennis AT gmail DOT com&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>COBOL, A Short Visit</title>
   <link href="http://www.continuousthinking.com/2006/12/06/cobol-a-short-visit.html"/>
   <updated>2006-12-06T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/06/cobol-a-short-visit</id>
   <content type="html">&lt;p&gt;I wrote some COBOL today. I can&amp;#8217;t say it was fun, enjoyable or even breath taking. It was more of a &amp;#8220;oh my gosh, I&amp;#8217;m so glad we have languages better COBOL these days!&amp;#8221;.&lt;/p&gt;

&lt;p&gt;I was working with a vendor who runs a data extract program from a COBOL program. We needed to utilize a non-printable whitespace character as a field delimiter. They didn&amp;#8217;t know how to do that since COBOL treats all whitespace equally, as spaces. I was hoping COBOL would treat \t literals as actual tabs, but it doesn&amp;#8217;t.&lt;/p&gt;

&lt;p&gt;So I ended up with my sample program:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;000100 IDENTIFICATION DIVISION.
000200 PROGRAM-ID. hello.
000300 PROCEDURE DIVISION.
000400 DISPLAY X&amp;#39;09&amp;#39;.
000500 DISPLAY &amp;quot;Hello World!&amp;quot;.
000600 STOP RUN.&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That X&amp;#8217;09&amp;#8217; gave me my binary character for a tab! I can&amp;#8217;t say I&amp;#8217;d want to program in COBOL, but for a very short visit it was fun to read up on it, and write some sample programs. The above six-liner just happened to be the one I needed.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Rails, Creating Tables With Different Primary Keys (PostgreSQL)</title>
   <link href="http://www.continuousthinking.com/2006/12/03/rails-creating-tables-with-different-primary-keys-postgresql.html"/>
   <updated>2006-12-03T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/03/rails-creating-tables-with-different-primary-keys-postgresql</id>
   <content type="html">&lt;p&gt;Say you&amp;#8217;re using PostgreSQL and Rails and you want to create a table with a primary key that is not the field &amp;#8216;id&amp;#8217;. How do you make that work?&lt;/p&gt;

&lt;p&gt;At first thought you might try the below:&lt;/p&gt;

&lt;p&gt;ActiveRecord::Schema.create_table :articles, :id=&amp;gt;false do |t| t.column :title, :string end&lt;/p&gt;

&lt;p&gt;You pass in :id=&amp;gt;false because that tells ActiveRecord that you don&amp;#8217;t want ActiveRecord::Schema to create or set a field for your primary key. So you plug into your application code that actually relies on your new table:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Article &amp;lt; ActiveRecord::Base
end

Article.create :title=&amp;gt;&amp;quot;Test Article&amp;quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You get an ActiveRecord::StatementInvalid error stating that relation &amp;#8220;articles_id_seq&amp;#8221; doesn&amp;#8217;t exist? What gives?&lt;/p&gt;

&lt;p&gt;The first problem is that since you told ActiveRecord::Schema not to create or set a primary key field, you don&amp;#8217;t have one. ActiveRecord (and thus Rails) relies on having a primary key.&lt;/p&gt;

&lt;p&gt;To fix this you&amp;#8217;d simply modify your original code to look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ActiveRecord::Schema.create_table :articles, :id=&amp;gt;false, :primary_key=&amp;gt;&amp;#39;aid&amp;#39; do |t|
  t.column :aid, :serial
  t.column :title, :string
end

class Article &amp;lt; ActiveRecord::Base
  set_primary_key &amp;#39;aid&amp;#39;
end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And now everything works!&lt;/p&gt;

&lt;p&gt;You may notice that we use the column type &lt;em&gt;serial&lt;/em&gt; instead of integer. This is because PostgreSQL is capable of handling auto incrementing integers and ActiveRecord expects it to unless you give it another way of handling unique primary keys (which is a topic for another post).&lt;/p&gt;

&lt;p&gt;PostgreSQL does this with &lt;em&gt;sequences&lt;/em&gt;, by using the &lt;em&gt;serial&lt;/em&gt; (or even &lt;em&gt;bigserial&lt;/em&gt;) column types you hint to PostgreSQL to automatically handle the creation of those sequences.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click &amp;#8220;here&amp;#8221;:http://www.postgresql.org/docs/8.1/static/sql-createsequence.html for information &lt;em&gt;sequences&lt;/em&gt; in PostgreSQL 8.1&lt;/li&gt;

&lt;li&gt;Click &amp;#8220;here&amp;#8221;:http://www.postgresql.org/docs/8.1/static/datatype.html for information on data types in PostgreSQL 8.1&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Thursday Morning Update</title>
   <link href="http://www.continuousthinking.com/2006/12/01/olivia-dennis-thursday-morning-update.html"/>
   <updated>2006-12-01T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/01/olivia-dennis-thursday-morning-update</id>
   <content type="html">&lt;p&gt;Olivia had blood taken first thing this morning. They started her on a new medicine yesterday to help regulate sodium. The blood draw should from this morning should show if it&amp;#8217;s working. She had another spinal tap this morning, too. The doctor said that it went well-they got it on the first try. We should have results from that later this afternoon. As long as there&amp;#8217;s no infection in the spinal fluid, WE GET TO GO HOME TOMORROW!!!&lt;/p&gt;

&lt;p&gt;Her stinkin&amp;#8217; IV popped out again just now. She only has 2 doses of antibiotic left&amp;#8230;too bad it didn&amp;#8217;t stay in&amp;#8230; It was in her ankle this time, wonder where they&amp;#8217;ll try to put it next :-(&lt;/p&gt;

&lt;p&gt;Olivia has a long road ahead of her. She has three medicines to go home with and she&amp;#8217;ll have to see the doctor a few times a week. I&amp;#8217;m sure she&amp;#8217;ll be so happy to be home though! I&amp;#8217;ll send out an email as soon as we get results.&lt;/p&gt;

&lt;p&gt;Again, please forward this to others who want updates&amp;#8230;thank you.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Friday Update</title>
   <link href="http://www.continuousthinking.com/2006/12/01/olivia-dennis-friday-update.html"/>
   <updated>2006-12-01T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/12/01/olivia-dennis-friday-update</id>
   <content type="html">&lt;p&gt;The doctor stopped in just now and gave us good news! WE GET TO LEAVE tonight! His exact words were,&lt;/p&gt;

&lt;p&gt;&amp;#8221;I&amp;#8217;m sure you guys know this, but you are very, very fortunate. She&amp;#8217;s passed MRI&amp;#8217;s that show no brain damage, she&amp;#8217;s passed her hearing tests, and overall she&amp;#8217;s acting like a happy 3-month-old. She had ONE MONSTER of an infection when you brought her in and we were very scared in the beginning. She beat one heck of an infection.&amp;#8221;&lt;/p&gt;

&lt;p&gt;He also said that, although it sounds selfish, he&amp;#8217;s really enjoyed getting to watch her grow. :-)&lt;/p&gt;

&lt;p&gt;We&amp;#8217;re going home!! We have a pile of paperwork, a stack of prescriptions, bags and bags of cards and toys, a wagon full of a month&amp;#8217;s worth of crap, and A HAPPY HAPPY HEALTHY BABY!! Tonight is going to be a great night&amp;#8230;.&lt;/p&gt;

&lt;p&gt;Thanks go out from the bottom of my heart for all the prayers. What an emotional rollercoaster ride we&amp;#8217;ve all been on! We made it&amp;#8230;she&amp;#8217;s making it! We have more tests and appointments over the next few weeks, but it&amp;#8217;s going to be so nice to be home. Thanks again everyone, and I&amp;#8217;ll keep you all posted as she gets better and better! OH- and I attached a picture of her BUSTIN&amp;#8217; OUT OF THIS PLACE!!&lt;/p&gt;

&lt;p&gt;!/assets/2006/12/2/olivia_leaving_hospital_tiny.jpg!:/assets/2006/12/2/olivia_leaving_hospital.jpg&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>olivia dennis, Tuesday afternoon</title>
   <link href="http://www.continuousthinking.com/2006/11/28/olivia-dennis-tuesday-afternoon.html"/>
   <updated>2006-11-28T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/28/olivia-dennis-tuesday-afternoon</id>
   <content type="html">&lt;p&gt;The doctor visited today and told us that they&amp;#8217;re planning on sending us home THIS FRIDAY!!! :-) Olivia has blood-work today and tomorrow, a urine test tomorrow and another spinal tap Thursday. It&amp;#8217;s going to be a busy week, but we see a very very bright light at the end of the tunnel!&lt;/p&gt;

&lt;p&gt;The doctor, however, still does have a few concerns. First, her sodium and potassium levels are still a little off. He&amp;#8217;s not sure why. The wrong levels of sodium in your body can cause seizures. Although he doesn&amp;#8217;t think it will get this bad, he still thinks it&amp;#8217;s something we need to watch. The other thing that worries him is her white blood cell count. To make things simple, he basically said that her white count is down TOO far now. If she were to come in contact with any more bacteria, she doesn&amp;#8217;t have enough white blood cells to fight it off. If she starts running a fever, he doesn&amp;#8217;t think she&amp;#8217;d be able to break it. So, we need to keep an eye on her!&lt;/p&gt;

&lt;p&gt;Overall, he thinks things are going well. He thinks the inconsistencies in her sodium, potassium, and white blood cells are mainly due to her heavy doses of antibiotics. He thinks her body will correct itself once she&amp;#8217;s done with them. When we got home, we&amp;#8217;ll have to take her for blood tests a few times a week to make sure&amp;#8230;&lt;/p&gt;

&lt;p&gt;Please pray that bad germs stay away from her during these last few, very important, days at the hospital!!&lt;/p&gt;

&lt;p&gt;She&amp;#8217;s waking up from a nap-I&amp;#8217;ll post pics later tonight if I have time!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Happy Thanksgiving!</title>
   <link href="http://www.continuousthinking.com/2006/11/23/olivia-dennis-happy-thanksgiving.html"/>
   <updated>2006-11-23T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/23/olivia-dennis-happy-thanksgiving</id>
   <content type="html">&lt;p&gt;We&amp;#8217;ve had a good day today&amp;#8230; Olivia had quite a few visitors today&amp;#8230; good thing she had her cute Thanksgiving outfit on!!&lt;/p&gt;

&lt;p&gt;No new news today. Olivia got a new dressing on her PIC line this afternoon; she wasn&amp;#8217;t too happy. Other than that, she was a smiley happy baby all day today. I think she was happy to be back in her blue jeans-they&amp;#8217;re her favorite&amp;#8230;just like her mom :-)&lt;/p&gt;

&lt;p&gt;Happy Thanksgiving to everyone!&lt;/p&gt;
&lt;div align='center'&gt;


&lt;a href='http://www.continuousthinking.com/assets/2006/11/23/hospital6_006.jpg'&gt;
  &lt;img alt='' height='163' src='http://www.continuousthinking.com/assets/2006/11/23/hospital6_006.jpg' title='with daddy' width='120' /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/23/hospital6_005.jpg'&gt;
  &lt;img alt='' height='163' src='http://www.continuousthinking.com/assets/2006/11/23/hospital6_005.jpg' title='so cute' width='120' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/23/hospital16_018.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/23/hospital16_018.jpg' title='hi!' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>ActiveRecord Extensions, PostgreSQL Support</title>
   <link href="http://www.continuousthinking.com/2006/11/23/activerecord-extensions-postgresql-support.html"/>
   <updated>2006-11-23T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/23/activerecord-extensions-postgresql-support</id>
   <content type="html">&lt;p&gt;PostgreSQL support for ActiveRecord::Extensions is moving along nicely for the better finder support. It includes everything that the better finder support already supported (including Ranges, Regular Expressions and custom made query objects) except for Full Index support.&lt;/p&gt;

&lt;p&gt;To add regular expression support (only case-sensitive at this time, case-insensitivity will come later) the only code I had to write was the below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;module ActiveRecord::Extensions

  # The below supports finder sql for regular expression 
  # support the PostgreSQL adapter:
  # Example:
  #    Model.find :all, :conditions=&amp;gt;{ :title =&amp;gt; /regex/ }
  #
  class RegexpPostgreSQL &amp;lt; AbstractExtension   
    NOT_EQUAL_RGX = /(.+)_(ne|not)/

    def self.process( key, val, caller )
      if val.is_a?( Regexp )
        match_data = key.to_s.match( NOT_EQUAL_RGX )
        key = match_data.captures\[0\] if match_data
        fieldname = caller.connection.quote_column_name( key )
        return Result.new( &amp;quot;#{caller.table_name}.#{fieldname} &amp;quot; +
             &amp;quot;#{match_data ? &amp;#39;!~ &amp;#39;:&amp;#39;~&amp;#39;} ?&amp;quot;, val )
      end
      nil
    end

  end
  register RegexpPostgreSQL, :adapters=&amp;gt;[ :postgresql ]

end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I am really digging the pluggable extensions so far. What do you think of the above code set to add Regexp support for PostgreSQL?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>olivia dennis, wednesday morning</title>
   <link href="http://www.continuousthinking.com/2006/11/22/olivia-dennis-wednesday-morning.html"/>
   <updated>2006-11-22T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/22/olivia-dennis-wednesday-morning</id>
   <content type="html">&lt;p&gt;We received good news last night&amp;#8230; Olivia&amp;#8217;s VCUG came back looking great! They didn&amp;#8217;t see anything wrong with her entire urinary tract!&lt;br /&gt;GREAT GREAT NEWS!! They&amp;#8217;ll still do some lab work on her today. The doctor stopped in this morning. He&amp;#8217;s happy that there&amp;#8217;s no visible problems in the urinary tract, but he&amp;#8217;s still concerned with the low grade fever she has had the past 4 days. Because of the fever, her spitting up CONSTANTLY, and not wanted to eat as much, he&amp;#8217;ll be looking for some type of belly infection in today&amp;#8217;s lab work. Her white blood cell count is still a little elevated, but hopefully there won&amp;#8217;t be any type of infection in there! We&amp;#8217;ll find out Friday&amp;#8230;&lt;/p&gt;

&lt;p&gt;Olivia hung out on her boppy last night, playing with daddy. Then there is the pouty face she gives to her daddy when she wants something&amp;#8230;.&amp;#8221;Daddy, I want a pony&amp;#8221;, she said. :-)&lt;/p&gt;

&lt;p&gt;We meet again with the case manager on Monday. If all is well, we&amp;#8217;ll be going home next week!&lt;/p&gt;
&lt;div align='center'&gt;


&lt;a href='http://www.continuousthinking.com/assets/2006/11/22/hospital15_002.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/22/hospital15_002.jpg' title='hanging out' width='163' /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/22/hospital15_003.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/22/hospital15_003.jpg' title='pony..please??' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Monday afternoon</title>
   <link href="http://www.continuousthinking.com/2006/11/20/olivia-dennis-monday-afternoon.html"/>
   <updated>2006-11-20T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/20/olivia-dennis-monday-afternoon</id>
   <content type="html">&lt;p&gt;After looking at last night&amp;#8217;s blood work, the doctors determined that Olivia was having an allergic reaction to her antibiotic. Yesterday she continued spitting up, had red blotches all over her skin, and was still a little fussy. After switching her meds this morning, she seems to be doing a little better. She&amp;#8217;s still spitting up today, and is pretty fussy, but there isn&amp;#8217;t a skin irritation and she&amp;#8217;s eating better.&lt;/p&gt;

&lt;p&gt;Our doctor decided that rather than waiting for the Ann Arbor doc to do the VCUG, he&amp;#8217;s going to have that ordered today, so hopefully we&amp;#8217;ll be able to get that done within the next few days.&lt;/p&gt;

&lt;p&gt;Along with last night&amp;#8217;s blood work, they started a blood culture to make sure there isn&amp;#8217;t any bacteria in the blood again. The cultures are checked at 24, 36, and 48 hours. We should have the first results later this evening.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ve posted a few pictures from this past weekend, when she was feeling well. She giggled and laughed at mom&amp;#8217;s goofy faces while hanging out in her swing on Friday morning. There&amp;#8217;s also a picture of her getting geared up for the BIG game on Saturday&amp;#8230; she was HIGHLY disappointed in the outcome, just like her grandpa Dave.&lt;/p&gt;
&lt;div align='center'&gt;


&lt;a href='http://www.continuousthinking.com/assets/2006/11/20/hospital14_010.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/20/hospital14_010.jpg' title='ha ha ha' width='163' /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/20/hospital14_013.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/20/hospital14_013.jpg' title='so funny!' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/20/hospital14_046.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/20/hospital14_046.jpg' title='GO  BLUE' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>olivia dennis, sunday evening</title>
   <link href="http://www.continuousthinking.com/2006/11/19/olivia-dennis-sunday-evening.html"/>
   <updated>2006-11-19T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/19/olivia-dennis-sunday-evening</id>
   <content type="html">&lt;p&gt;I&amp;#8217;ve been hesitant to post an update the past few days&amp;#8230;. Olivia hasn&amp;#8217;t been feeling well. Yesterday evening she was very unhappy and irritable for some reason. She had a little tiny bit of a fever and didn&amp;#8217;t want to eat much. She had some tylenol and I gave her a warm bath to try to calm her down. Matt and I can&amp;#8217;t put our finger on exactly what&amp;#8217;s wrong, but we both agree that she just isn&amp;#8217;t acting like herself; something is a little off. She didn&amp;#8217;t sleep much last night, so she slept until 11 this morning!&lt;/p&gt;

&lt;p&gt;Today she&amp;#8217;s been spitting up most of the food she&amp;#8217;s had and we&amp;#8217;re still having a hard time getting her to eat. She&amp;#8217;s had blood drawn twice today, and they&amp;#8217;re thinking of MAYBE another MRI within the next couple of days to make sure nothing is on the brain that wasn&amp;#8217;t there before.&lt;/p&gt;

&lt;p&gt;I just got word that her white blood cells are slightly back up again, we&amp;#8217;ll find out exactly what that means tomorrow morning when the doctor is back in. We had hopes of being home for Thanksgiving; we&amp;#8217;ll have to see what the next few days brings. Please keep praying for our little sweet girl-she&amp;#8217;s come so far, but we&amp;#8217;re not there yet&amp;#8230;&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll post some pictures from the weekend tomorrow when I have more time.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>ruby, class variable or class instance variables</title>
   <link href="http://www.continuousthinking.com/2006/11/17/ruby-class-variable-or-class-instance-variables.html"/>
   <updated>2006-11-17T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/17/ruby-class-variable-or-class-instance-variables</id>
   <content type="html">&lt;p&gt;This is in reference to the topic of class variables or class instance variables in ruby&amp;#8230; it&amp;#8217;s a posting based on the recent post of Stuart Halloway, &lt;a href='http://blogs.relevancellc.com/articles/2006/11/16/use-class-instance-variables-not-class-variables'&gt;click here to read it&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='why_not_class_variables'&gt;Why Not Class Variables?&lt;/h2&gt;

&lt;p&gt;Stuart Halloway hits the problem that class variables has perfectly, &amp;#8220;They are shared across an inheritance hierarchy in a counterintuitive way.&amp;#8221; Although he doesn&amp;#8217;t specifically say ActiveSupport or &amp;#8220;Rails&amp;#8221; that is where this probably exists, and IMO it promotes bad design and a bad usage of class variables.&lt;/p&gt;

&lt;p&gt;The problem is that since class variables are shared across the inheritance hierarchy, if any class in the hierarchy changes the value of the class variable, it changes throughout the whole hierarchy. This is not good.&lt;/p&gt;

&lt;p&gt;It is better to use instance variables on the class, because they work intuitively across inheritance, and if you change the value of class-level instance variable it only changes for that class (it doesn&amp;#8217;t affect the rest of the hierarchy).&lt;/p&gt;

&lt;p&gt;Class variables that are used and relied on throughout a inheritance hierarchy is BAD design IMO. Even if you intend to use class variables for your class only you are forcing people who will extend your code to potentially give in to BAD design. It is better design to encapsulate class variables into class-level instance variables which are accessed via class-level instance methods. This allows any subclasses (or potential subclasses) to redefine implementation if they want to, and it won&amp;#8217;t have negative effects on the the rest of the hierarchy.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s a scenario of BAD use for class variables. This uses the example of keeping track of how many people you have:&lt;/p&gt;

&lt;p&gt;class Person attr_accessor :name&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; @@instances = \[\]
 
 def self.instances
   @@instances
 end
 
 def initialize( name )
   self.class.instances &amp;lt;&amp;lt; self
   @name = name
 end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;p&gt;joe = Person.new( &amp;#8220;Joe&amp;#8221; ) zach = Person.new( &amp;#8220;Zach&amp;#8221; )&lt;/p&gt;

&lt;p&gt;puts &amp;#8220;You have #{Person.instances.size} people in existence!&amp;#8221; # POINT A&lt;/p&gt;

&lt;p&gt;class Paramedic &amp;lt; Person end&lt;/p&gt;

&lt;p&gt;sally = Paramedic.new( &amp;#8220;Sally&amp;#8221; )&lt;/p&gt;

&lt;p&gt;puts &amp;#8220;You have #{Person.instances.size} people in existence!&amp;#8221; # POINT B puts &amp;#8220;You have #{Paramedic.instances.size} paramedics in existence!&amp;#8221; # POINT C&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At POINT A you have two people in existence, which is correct.&lt;/li&gt;

&lt;li&gt;At POINT B you have three people in existence, which is correct.&lt;/li&gt;

&lt;li&gt;At POINT C you have three paramedics in existence which is incorrect!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You only have one paramedic (Sally!), but since Person is using a class variable you are stuck with affecting the whole hierarchy.&lt;/p&gt;

&lt;p&gt;Now this is easy to fix, by using class-level instance variables. Don&amp;#8217;t be shocked by the &amp;#8220;class &amp;#171;&amp;#160;self&amp;#8221;&amp;#8230;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Person
  attr_accessor :name

  class &amp;lt;&amp;lt; self
    attr_accessor :instances

    def instances
      @instances ||= \[\]
      @instances
    end
  end

  def initialize( name )
    Person.instances &amp;lt;&amp;lt; self
    @name = name
  end

end

joe = Person.new( &amp;quot;Joe&amp;quot; )
zach = Person.new( &amp;quot;Zach&amp;quot; )

puts &amp;quot;You have #{Person.instances.size} people in existance!&amp;quot; POINT C

class Paramedic &amp;lt; Person

  def initialize( name )
    super( name )
    Paramedic.instances &amp;lt;&amp;lt; self
  end&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;end&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;sally = Paramedic.new( &amp;quot;Sally&amp;quot; )
puts &amp;quot;You have #{Person.instances.size} people in existance!&amp;quot; #POINT B
puts &amp;quot;You have #{Paramedic.instances.size} paramedics in existance!&amp;quot; POINT C&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;At POINT A you have two people in existence, which is correct.&lt;/li&gt;

&lt;li&gt;At POINT B you have three people in existence, which is correct.&lt;/li&gt;

&lt;li&gt;At POINT C you have one paramedic in existence, which is correct.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now the &amp;#8220;class &amp;#171;&amp;#160;self&amp;#8221; which looks mystikal really isn&amp;#8217;t. It&amp;#8217;s been called a classes singleton class, a metclass, an eigenclass, and the list goes on. _why gives a good description of it at http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html&lt;/p&gt;

&lt;p&gt;The beauty of a metaclass is that one exists for every class created. This is nice because you can inherit functionality created in a parent class&amp;#8217;s metaclass, and you can redefine implementation of that functionality if you want to. If you decide to do that your changes will only affect that class and then everything else on down the hierarchy.&lt;/p&gt;

&lt;p&gt;These is much more POLS then class variables, and it promotes better design, testability and extendability of your code.&lt;/p&gt;

&lt;p&gt;Rails uses class variables to implement methods like cattr_reader, cattr_writer, and cattr_accessor.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Class # :nodoc:
  def cattr_reader(*syms)
    syms.flatten.each do |sym|
      class_eval(&amp;lt;&amp;lt;-EOS, __FILE__, __LINE__)
       unless defined? @@#{sym}
          @@#{sym} = nil
       end

        def self.#{sym}
          @@#{sym}
        end

        def #{sym}
          @@#{sym}
        end
      EOS
    end
  end
# ....&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Along with the use of class variables it defines a class method and an instance method. This bothers me, because it will overwrite an instance method with the same name. cattr_ which I&amp;#8217;ve always took for &amp;#8220;class attribute&amp;#8221; should NOT create instance methods. What does an instance method have to do with &amp;#8220;class attributes|variables&amp;#8221;? This scares me and seems like a nasty side effect for someone unsuspecting.&lt;/p&gt;

&lt;h2 id='the_opposing_view'&gt;The Opposing View&lt;/h2&gt;

&lt;p&gt;Reading up on an opposing view, &lt;a href='http://ola-bini.blogspot.com/2006/11/nooks-and-crannies-of-ruby.html'&gt;click here to read&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ola Bini writes:&lt;/p&gt;

&lt;p&gt;&amp;#8220;Class have instance variables of themselves, these are rarely useful; they usually contribute to hard-to-find-errors. And don&amp;#8217;t confuse them with class variables which is a totally different kind of beast.&amp;#8221;&lt;/p&gt;

&lt;p&gt;I disagree with this. I think modifying class variables throughout an inheritance hierarchy which may be spread out through many files and even directories (if you&amp;#8217;re extending someone else&amp;#8217;s library) is much harder to track down. Essentially you have to do the equivalent of:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;find ./ -type f -exec grep -Hn &amp;quot;@@varname&amp;quot; {} \;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And thats just to find where it could have changed.&lt;/p&gt;

&lt;p&gt;Since class variables are many times accessed directly it&amp;#8217;s easy to lose the benefits of encapsulation. One debugging benefit I find with encapsulation is the ability to alter the method where something is changed, and you can check the caller&amp;#8217;s backtrace to see where the erroneous value is coming from in your application.&lt;/p&gt;

&lt;p&gt;I don&amp;#8217;t see a very good use-case for why @@classvariables are useful. I much prefer class instance variables for what I consider obvious reasons&amp;#8230; what do you folks out there think?&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Thursday afternoon</title>
   <link href="http://www.continuousthinking.com/2006/11/16/olivia-dennis-thursday-afternoon.html"/>
   <updated>2006-11-16T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/16/olivia-dennis-thursday-afternoon</id>
   <content type="html">&lt;p&gt;Nothing much going on today. After yesterday&amp;#8217;s news we&amp;#8217;re all so happy and we&amp;#8217;re feeling a little more relaxed. We still have a few more tests to get through, but the good news yesterday lifted our spirits.&lt;/p&gt;

&lt;p&gt;This morning Olivia had a nice warm bath-she loved it. She loved it so much that she decided to poop all over herself as soon as she got out so we had to wipe her down all over again!&lt;/p&gt;

&lt;p&gt;She&amp;#8217;s been so smiley and alert this morning. We practiced sitting up some more, and we practiced standing up tall. She&amp;#8217;s getting so big in here!! After all that working out, she relaxed with dad and ended up falling asleep just like her daddy! It was cute.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll spend the rest of the week relaxing, getting plenty of rest, and watching Olivia get better and better.&lt;/p&gt;

&lt;p&gt;Thank God for such wonderful miracles!&lt;/p&gt;
&lt;div align='center'&gt;


&lt;a href='http://www.continuousthinking.com/assets/2006/11/16/hospital13_006.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/16/hospital13_006.jpg' title='yummy hand' width='163' /&gt;
&lt;/a&gt;
&lt;/div&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/16/hospital13_007.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/16/hospital13_007.jpg' title='so tall!' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/16/hospital13_004.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/16/hospital13_004.jpg' title='tired out' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/16/hospital13_002.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/16/hospital13_002.jpg' title='nappin just like daddy' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Wednesday afternoon</title>
   <link href="http://www.continuousthinking.com/2006/11/15/olivia-dennis-wednesday-afternoon.html"/>
   <updated>2006-11-15T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/15/olivia-dennis-wednesday-afternoon</id>
   <content type="html">&lt;p&gt;Aunt Lexi came to visit last night! Olivia loves hanging out with her Aunts!&lt;/p&gt;

&lt;p&gt;Olivia had her ultrasound done this morning. It went well; she was very smiley and cooperative. The doctor just came in to let me know that EVERYTHING LOOKS GREAT! The original problem (some kind of kink or pinch in the ureter) that caused the infection isn&amp;#8217;t even showing up on the ultrasound anymore!! The kidney is back to it&amp;#8217;s original size and there is no inflammation anymore. YAY!!&lt;/p&gt;

&lt;p&gt;Although this is VERY VERY exciting, the ultrasound will still be sent to the doc in Ann Arbor to look at. Our next step is to do a VCUG (I forget what this stands for). This test will show the urine flow in her kidneys, bladder, and everywhere else it goes. They&amp;#8217;re just doing this to make sure there aren&amp;#8217;t any other problems that the ultrasound would miss.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;m so happy that not only is the infection gone, but the original defect in her kidney seems to have corrected itself!! Our little miracle baby!!&lt;/p&gt;

&lt;p&gt;Olivia was SO happy to get such good news!!&lt;/p&gt;
&lt;div align='center'&gt;


&lt;a href='/http://www.continuousthinking.com/assets/2006/11/15/hospital12_001.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/15/hospital12_001.jpg' title='Aunt Lexi' width='163' /&gt;
&lt;/a&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Tuesday evening...</title>
   <link href="http://www.continuousthinking.com/2006/11/14/tuesday-evening.html"/>
   <updated>2006-11-14T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/14/tuesday-evening</id>
   <content type="html">&lt;p&gt;Another slow day here. Olivia practiced sitting up for a while, and we read her book again but, most importantly, Olivia is getting all kinds of rest. The doc stopped in this morning to let us know that she&amp;#8217;ll have another ultrasound of her kidney tomorrow morning. This ultrasound will be sent to the specialist in Ann Arbor. He&amp;#8217;ll use this to determine if we can wait to see him until he comes back to Kalamazoo (Bronson Hospital) or if we need to be seen right away in Ann Arbor. He will be back in Kzoo the first week of December. Our doctor told us that we should have that situated by the end of the week.&lt;/p&gt;

&lt;p&gt;Olivia is in the treatment room right now, getting a new dressing put on her PIC line again. All the hair she has makes it hard for the tape and glue to stick. It&amp;#8217;s no fun for her, but I&amp;#8217;m sure a new dressing feels so much better when it&amp;#8217;s done.&lt;/p&gt;

&lt;p&gt;We know for sure that we&amp;#8217;ll be here at least through the week. Next Monday we will meet with our case manager to discuss taking Olivia home with the IV and having a nurse visit the condo.&lt;/p&gt;
&lt;div align='center'&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/14/hospital11_003.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/14/hospital11_003.jpg' title='sittin up' width='163' /&gt;
&lt;/a&gt;

&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Monday afternoon update... posted by mom</title>
   <link href="http://www.continuousthinking.com/2006/11/13/monday-afternoon-update-posted-by-mom.html"/>
   <updated>2006-11-13T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/13/monday-afternoon-update-posted-by-mom</id>
   <content type="html">&lt;p&gt;Things have been slow so far today&amp;#8230; Olivia slept in late (until 9) just as a princess should. Her and dad read a book together last night-she was so interested in the pictures! She was smiling and laughing while she was awake earlier today.&lt;/p&gt;

&lt;p&gt;For 10 days now, Olivia has been on 2 antibiotics. The doc explained them to me like this&amp;#8230;&lt;/p&gt;

&lt;p&gt;&amp;#8220;One is the &amp;#8216;killer&amp;#8217; and the other &amp;#8216;intensifies&amp;#8217; the &amp;#8216;killing&amp;#8217; of the bacteria. Unfortunately, the &amp;#8216;intensifier&amp;#8217; has many bad side effects because it&amp;#8217;s so strong. Now that we truly have the bacterial infection under control, we can get rid of this antibiotic.&amp;#8221;&lt;/p&gt;

&lt;p&gt;Yay&amp;#8230; we REALLY are on our way!! It was good to hear. Today is day 10 of the 28 days she&amp;#8217;ll need to have her IV, so we still have a while, but it&amp;#8217;s so nice to see more progress!!&lt;/p&gt;

&lt;p&gt;Thanks to everyone for the all the love and prayers&amp;#8230; she&amp;#8217;s such a fighter!&lt;/p&gt;
&lt;div align='center'&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/13/hospital10_006.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/13/hospital10_006.jpg' title='cute' width='163' /&gt;
&lt;/a&gt;

&lt;a href='http://www.continuousthinking.com/assets/2006/11/13/hospital10_004.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/13/hospital10_004.jpg' title='so funny' width='163' /&gt;
&lt;/a&gt;

&lt;a href='http://www.continuousthinking.com/assets/2006/11/13/hospital10_005.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/13/hospital10_005.jpg' title='reading with dad' width='163' /&gt;
&lt;/a&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Sunday Noon Update     ...posted by mom</title>
   <link href="http://www.continuousthinking.com/2006/11/12/olivia-dennis-sunday-noon-update.html"/>
   <updated>2006-11-12T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/12/olivia-dennis-sunday-noon-update</id>
   <content type="html">&lt;p&gt;Since Olivia&amp;#8217;s sodium and potassium levels are a little off, the doc&amp;#8217;s decided to limit how much she eats during the day. They cut her intake quite a bit; she&amp;#8217;s allowed less than half of what she normally eats. As you can imagine, she&amp;#8217;s not happy. She&amp;#8217;s been screaming most of the time she&amp;#8217;s awake-she kept Matt up really late last night.&lt;/p&gt;

&lt;p&gt;The doctors decided to do some blood work to check on her potassium and sodium levels today, rather than tomorrow because she&amp;#8217;s so unhappy.. we are waiting for the results on that. Hopefully, her levels have worked themselves out and we won&amp;#8217;t have to restrict her eating again today.&lt;/p&gt;

&lt;p&gt;Over the past three days, Olivia has been awake only a few hours. She&amp;#8217;s been through so much and we think it&amp;#8217;s all catching up with her. She&amp;#8217;s so tired and she needs so much rest so she can keep getting better.&lt;/p&gt;

&lt;p&gt;Toward the end of next week, Matt &amp;amp; I will decide with the doc&amp;#8217;s where Olivia will get the rest of her treatment. Maybe the last two weeks or so of antibiotics will be done at home, by a nurse who visits the condo. This isn&amp;#8217;t anything we have to decide right now, just another thing we&amp;#8217;re talking about with doc&amp;#8217;sâ€¦&lt;/p&gt;

&lt;p&gt;Bath Time&lt;/p&gt;
&lt;div align='center'&gt;
&lt;p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/12/hospital8_005.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/12/hospital8_005.jpg' title='Getting all clean' width='163' /&gt;
&lt;/a&gt; Grandpa J
&lt;/p&gt;
&lt;p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/12/hospital9_001.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/12/hospital9_001.jpg' title='I&amp;apos;m so cute......' width='163' /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Friday Night Update</title>
   <link href="http://www.continuousthinking.com/2006/11/11/olivia-dennis-friday-night-update.html"/>
   <updated>2006-11-11T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/11/olivia-dennis-friday-night-update</id>
   <content type="html">&lt;p&gt;Today was a really busy day for little Olivia. She had two blood draws which showed that the sodium level has elevated. The doctor says that this is a reaction to the bacterial meningitis which causes her to retain fluid. We are waiting for the doctor to determine whether her food in-take and IV fluid would need to be reduced.&lt;/p&gt;

&lt;p&gt;Olivia got a new dressing on her PIC line today which was extremely painful, time consuming and exhausting, but Olivia and Mom toughed it out together! _(see pictures below)_ Olivia is also waiting on an appointment with a doctor from the DeVos Children&amp;#8217;s Hospital or the University of Michigan to determine the next steps for her kidney infection.&lt;/p&gt;

&lt;p&gt;Besides the doctors and nurses Olivia spent most of today smiling and chatting with Mom today.&lt;/p&gt;
&lt;div align='center'&gt;
&lt;p&gt;
&lt;a href='/assets/2006/11/11/olivia_in-my-snugli.jpg'&gt;
  &lt;img alt='' height='120' src='/assets/2006/11/11/olivia_in-my-snugli.jpg' title='Olivia in her snugli' width='163' /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;a href='/assets/2006/11/11/olivia-s--pic-line.jpg'&gt; &lt;img alt='' height='120' src='/assets/2006/11/11/olivia-s--pic-line.jpg' title='A new PIC line...' width='163' /&gt;
&lt;/a&gt;
&lt;/p&gt;
&lt;/div&gt;
&lt;h2 id='changes_to_the_web_site'&gt;Changes To The Web Site&lt;/h2&gt;

&lt;p&gt;The black and gray colors weren&amp;#8217;t really fitting to a cute little girl like Olivia, so in an effort for the web site to be more fitting to Olivia&amp;#8217;s tastes we&amp;#8217;re going to be changing the color themes and adding some more fitting imagery.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Thursday Evening Update</title>
   <link href="http://www.continuousthinking.com/2006/11/10/olivia-dennis-thursday-evening-update.html"/>
   <updated>2006-11-10T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/10/olivia-dennis-thursday-evening-update</id>
   <content type="html">&lt;p&gt;This posting is directly from an email I received from Adrienne todayâ€¦&lt;/p&gt;

&lt;p&gt;&amp;#8221;&lt;em&gt;Final word on hearing test is in! Not only can she hear, she can hear great! I guess she was just ignoring us. More blood was taken this morning, they&amp;#8217;re doing blood work daily. Doc is still trying to get in touch with U of M doctor. We brought Olivia&amp;#8217;s swing and her boppy up here. She&amp;#8217;s finally feeing well enough for us to put her down. She takes naps in her swing and watches TV on her boppy. We used to take her for walks around the floor to see the paintings on the wall, but she&amp;#8217;s confined to the room nowâ€¦ bummer. She&amp;#8217;s happy today and she just drank 8 oz at once!! She&amp;#8217;s eating better! She also wanted me to tell everyone thanks for all her new toys, cards, and their prayers!! Talk later! xo&lt;/em&gt;&amp;#8221;&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/10/olivia_hospital_bed.jpg'&gt;&amp;lt;/p&amp;gt; &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/10/olivia_hospital_bed.jpg' title='Olivia in hospital bed' width='163' /&gt;&lt;br /&gt;&lt;/a&gt; &lt;a href='http://www.continuousthinking.com/assets/2006/11/10/olivia_and_grandpa_dave.jpg'&gt;&amp;lt;/p&amp;gt; &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/10/olivia_and_grandpa_dave.jpg' title='Olivia and Grandpa Dave' width='163' /&gt;&lt;br /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id='more_pictures'&gt;More Pictures&lt;/h2&gt;

&lt;p&gt;Here is a link to Adrienne&amp;#8217;s yahoo photo album for Olivia: &lt;br /&gt;&lt;a href='http://new.photos.yahoo.com/ayjay3636/album/576460762335295823'&gt;http://new.photos.yahoo.com/ayjay3636/album/576460762335295823&lt;/a&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Wednesday Noon Update</title>
   <link href="http://www.continuousthinking.com/2006/11/08/olivia-dennis-wednesday-noon-update.html"/>
   <updated>2006-11-08T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/08/olivia-dennis-wednesday-noon-update</id>
   <content type="html">&lt;p&gt;Adrienne and Matt are still waiting to get the results from the Olivia&amp;#8217;s last hearing test. The doctor stopped in today, and Olivia&amp;#8217;s white blood cell count is down from yesterday, but the doctor still believes the infection to be active. They plan to monitor throughout the rest of the week and go from there.&lt;/p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/8/olivia_and_grandma_dennis.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/8/olivia_and_grandma_dennis.jpg' title='Olivia and Grandma Dennis' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Tuesday Morning Update</title>
   <link href="http://www.continuousthinking.com/2006/11/07/olivia-dennis-tuesday-morning-update.html"/>
   <updated>2006-11-07T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/07/olivia-dennis-tuesday-morning-update</id>
   <content type="html">&lt;p&gt;Olivia had another good night last night. She slept through the night (including the vitals at 4am)! Visitors must now wear masks in the room, so Olivia doesn&amp;#8217;t quite know what to think of all the yellow faces yet. She&amp;#8217;s noticed the TV, and loves watching ESPN.&lt;/p&gt;

&lt;p&gt;The doctor said that there is no final conclusion on the hearing test yet, and he isn&amp;#8217;t happy with the blood results from this morning. Potassium and sodium levels are up in blood which he said means that her brain is telling her body to retain water. Her white blood cell count is up again, and there shouldn&amp;#8217;t be because of all the antibiotics in her system. He is going to contact the doctors at the DeVos Childrens Hospital and the University Of Michigan Pediatrics.&lt;/p&gt;

&lt;p&gt;Olivia is still fighting hard, but she&amp;#8217;s still a long ways away from recovery.&lt;/p&gt;

&lt;p&gt;Mom would like to add, &amp;#8220;Thanks with ALL of my heart go out to all who prayed for my precious little girl. &amp;#8221;&lt;/p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/7/olivia_smiling.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/7/olivia_smiling.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/7/olivia_spitting.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/7/olivia_spitting.jpg' title='' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Monday 2pm Update</title>
   <link href="http://www.continuousthinking.com/2006/11/06/olivia-dennis-monday-2pm-update.html"/>
   <updated>2006-11-06T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/06/olivia-dennis-monday-2pm-update</id>
   <content type="html">&lt;p&gt;Olivia is having a super day today! The specialist who reviewed the MRI said that it looks good! Adrienne said she slept SO hard last night, and she is super happy and awake today.&lt;/p&gt;

&lt;p&gt;The first doctor who did a hearing test today said everything was looking good. There will be a second doctor who will have results sometime Tuesday, but things are looking up.&lt;/p&gt;

&lt;p&gt;Please continue to keep Olivia, mom and dad and the doctors in your thoughts and prayers.&lt;/p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/6/olivia_headphones.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/6/olivia_headphones.jpg' title='' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Week 1 Hospital Pictures</title>
   <link href="http://www.continuousthinking.com/2006/11/05/olivia-dennis-week-1-hospital-pictures.html"/>
   <updated>2006-11-05T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/05/olivia-dennis-week-1-hospital-pictures</id>
   <content type="html">&lt;p&gt;Olivia is doing good today. She had some restless sleep last night, but she&amp;#8217;s been awake and smiling so far today! Tomorrow should be a pretty busy day. We&amp;#8217;ll have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Olivia will get a hearing test&lt;/li&gt;

&lt;li&gt;Olivia will find out about her MRI from the pediatric radiographer&lt;/li&gt;

&lt;li&gt;Olivia will get some more blood work done&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some images from the hospital this last week.&lt;/p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/daddy_you_re_so_cumfy.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/daddy_you_re_so_cumfy.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/go_blue.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/go_blue.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/yum.jpg'&gt;
  &lt;img alt='' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/yum.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/working_on_a_full_belly.jpg'&gt;
  &lt;img alt='' border='0' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/working_on_a_full_belly.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/resting_on_dad.jpg'&gt;
  &lt;img alt='' border='0' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/resting_on_dad.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/I_m_so_cute.jpg'&gt;
  &lt;img alt='' border='0' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/I_m_so_cute.jpg' title='' width='163' /&gt;
&lt;/a&gt;&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/happy_with_mommy.jpg'&gt;
  &lt;img alt='' border='0' height='120' src='http://www.continuousthinking.com/assets/2006/11/5/happy_with_mommy.jpg' title='' width='163' /&gt;
&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Saturday Midnight Update</title>
   <link href="http://www.continuousthinking.com/2006/11/05/olivia-dennis-saturday-midnight-update.html"/>
   <updated>2006-11-05T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/05/olivia-dennis-saturday-midnight-update</id>
   <content type="html">&lt;p&gt;Olivia had a pretty good day today. Her temperature was below 100 degrees all day and she had lots and lots of visitors. From Grandma&amp;#8217;s and Grandpa&amp;#8217;s to Aunts/Uncles to friends and people she&amp;#8217;s never met before.&lt;/p&gt;

&lt;p&gt;Her MRI got pushed back a few hours, and it took up to three tries to get her sedated (she&amp;#8217;s a tough little girl) but the doctors ended up getting it done. The results from the MRI won&amp;#8217;t be in for a day or two though depending on when the special radiologist for Olivia is in next.&lt;/p&gt;

&lt;p&gt;After the MRI, Olivia was still pretty sleepy from the sedation, but she woke up for Mom not to long after happy and smiling. She thought about going back to sleep, but decided she was hungry and ate alot!! 6.5 ounces!!!!!&lt;/p&gt;

&lt;p&gt;A nurse tested her hearing today and although Olivia didn&amp;#8217;t respond to the hearing test, when her Dad came in the room tonight and spoke, her head tilted right in his direction. Right before I left Olivia had taken two laps around the pediatrics floor with her Dad and she was in awe of the lights and the colors on the walls.&lt;/p&gt;

&lt;p&gt;I&amp;#8217;ll post pictures of Olivia from this week at the hospital tomorrow. As always, continue to keep Olivia, her mom and dad in your thoughts prayers, as well as the doctors treating her.&lt;/p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/5/olivia_8.jpg'&gt;&lt;img alt='' height='120px' src='http://www.continuousthinking.com/assets/2006/11/5/olivia_8.jpg' title='Olivia Dennis' width='160px' /&gt;&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Saturday Noon Update</title>
   <link href="http://www.continuousthinking.com/2006/11/04/olivia-dennis-saturday-noon-update.html"/>
   <updated>2006-11-04T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/04/olivia-dennis-saturday-noon-update</id>
   <content type="html">&lt;p&gt;Olivia is doing good today. The second spinal tap from yesterday afternoon relieved some pressure in her little body, and she was able to get a good night&amp;#8217;s rest. Today she&amp;#8217;s going to be getting an MRI, and she&amp;#8217;s not allowed to eat for quite a few hours leading up to it. You can imagine that she&amp;#8217;s quite hungry, so she goes back and forth between crying and sleeping.&lt;/p&gt;

&lt;p&gt;As you keep Olivia, her mom and dad in your thoughts and prayers, please do the same for the doctors treating little Olivia.&lt;/p&gt;
&lt;a href='http://www.continuousthinking.com/assets/2006/11/4/olivia_boppy.jpg'&gt;&lt;img alt='' height='112px' src='http://www.continuousthinking.com/assets/2006/11/4/olivia_boppy.jpg' title='Olivia Dennis' width='150px' /&gt;&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Olivia Dennis, Meningitis</title>
   <link href="http://www.continuousthinking.com/2006/11/04/olivia-dennis-meningitis.html"/>
   <updated>2006-11-04T00:00:00-05:00</updated>
   <id>http://www.continuousthinking.com/2006/11/04/olivia-dennis-meningitis</id>
   <content type="html">&lt;p&gt;My niece Olivia Dennis is in the hospital right now. She&amp;#8217;s eight weeks old and has been diagnosed with bacterial meningitis. The doctors are not 100% sure of the diagnosis, but they are leaning towards the worst form of it. She&amp;#8217;s had two spinal taps, a ctscan, an ultrasound, and several draws of blood. She&amp;#8217;ll be in the hospital for the next 14 to 42 days.&lt;/p&gt;

&lt;p&gt;Please keep Olivia and her mom and dad in your thoughts and prayers.&lt;/p&gt;
&lt;a border='0' href='http://www.continuousthinking.com/assets/2006/11/4/olivia_pumpkin_queen.jpg'&gt;&lt;img alt='' src='http://www.continuousthinking.com/assets/2006/11/4/olivia_pumpkin_queen_thumb.jpg?1162613905' title='Olivia Dennis' /&gt;&lt;/a&gt;</content>
 </entry>
 
 <entry>
   <title>Fixing Sound on eMachines M5405</title>
   <link href="http://www.continuousthinking.com/2006/10/29/fixing-sound-on-emachines-m5405.html"/>
   <updated>2006-10-29T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2006/10/29/fixing-sound-on-emachines-m5405</id>
   <content type="html">&lt;p&gt;While working on my sister&amp;#8217;s laptop (eMachines M5405) tonight I noticed that I couldn&amp;#8217;t hear any sound coming out of it. The fix was simple. In KDE, load up KMix and select the &lt;em&gt;Switches&lt;/em&gt; tab and disable the &lt;strong&gt;External Amplifier&lt;/strong&gt;, and it should work fine.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Finder Extensions and MySQL Fulltext Indexes</title>
   <link href="http://www.continuousthinking.com/2006/10/29/finder-extensions-and-mysql-fulltext-indexes.html"/>
   <updated>2006-10-29T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2006/10/29/finder-extensions-and-mysql-fulltext-indexes</id>
   <content type="html">&lt;p&gt;ActiveRecord::Extensions has been turned into a pluggable extension registry to support better finder methods across multiple database platforms more easily. Very little ActiveRecord::Base code actually gets touched now. ActiveRecord will now query an extension registry and if an extension can answer the request it will take the result otherwise it will default to ActiveRecord&amp;#8217;s original behavior.&lt;/p&gt;

&lt;p&gt;The API interface that developers use is still the same, it&amp;#8217;s just the underlying architecture that changed.&lt;/p&gt;

&lt;h3 id='extension_example'&gt;Extension Example&lt;/h3&gt;

&lt;p&gt;Here&amp;#8217;s an example which is pulled straight from the source. It adds Range support for ActiveRecord find methods.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# EX: Model.find :all, :conditions=&amp;gt;{ :number =&amp;gt; (1..100) }

# EX: Model.find :all, :conditions=&amp;gt;{:created_on =&amp;gt; ( Date.today â€“ 30 .. Date.today ) } 
class RangeExt &amp;lt; AbstractExtension NOT\_IN\_RGX = /(.+)\_(ne|not|not\_in)/ def self.process( key, val, caller ) if val.is\_a?( Range ) match\_data = key.to\_s.match( NOT\_IN\_RGX ) key = match\_data.captures

if match\_data fieldname = caller.connection.quote\_column\_name( key ) min = caller.connection.quote( val.first, caller.columns\_hash[ key ] ) max = caller.connection.quote( val.last, caller.columns\_hash[ key ] ) str = &amp;quot;#{caller.table\_name}.#{fieldname} #{match_data ? &amp;#39;NOT &amp;#39; : &amp;#39;&amp;#39; } BETWEEN #{min} AND #{max}&amp;quot; return Result.new( str, nil ) end nil end  
end 

register RangeExt, :adapters=&amp;gt;[ :mysql, :postgres ]  &lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All an extension has to support is the &lt;em&gt;process&lt;/em&gt; method which takes the key and val from the :conditions hash, and it gets the context of the caller passed in (the AR model).&lt;/p&gt;

&lt;p&gt;Once you create an extension you can add it to the ActiveRecord::Extensions registry by calling the &lt;em&gt;register&lt;/em&gt; function on ActiveRecordExtensions. &lt;em&gt;This code is called in the context of ActiveRecord::Extensions so the register function is available.&lt;/em&gt; This takes an array of database of adapters which are supported or the symbol :all.&lt;/p&gt;

&lt;p&gt;This should open up ActiveRecord to receiving better finder support without having to hack up ActiveRecord itself since it&amp;#8217;s pluggable.&lt;/p&gt;

&lt;h2 id='mysql_fulltext_indexes'&gt;MySQL Fulltext Indexes&lt;/h2&gt;

&lt;p&gt;Fulltext index support has been added for MySQL.&lt;/p&gt;

&lt;h2 id='example'&gt;Example&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;class Project &amp;lt; ActiveRecord::Base fulltext :title, :fields=&amp;gt;%( project\_name project\_description )
end 
Project.find :all, :conditions=&amp;gt;{ :match_title=&amp;gt;&amp;#39;query string&amp;#39; }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Boolean&lt;/strong&gt; and &lt;strong&gt;Query Expansion&lt;/strong&gt; based fulltext index searches will be supported _(they are not committed to trunk yet)_ . It is not concrete whether these will be supplied via the declaration, the :conditions hash or allow to be supported by both.&lt;/p&gt;

&lt;h2 id='this_aint_released_yet'&gt;This Ain&amp;#8217;t Released Yet&lt;/h2&gt;

&lt;p&gt;Right now these changes exist in trunk. You can download them by visiting the &lt;a href='http://rubyforge.org/scm/?group_id=2113'&gt;rubyforge project page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These should be out in a 0.0.6 release later this week.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>import benchmarks for mysql</title>
   <link href="http://www.continuousthinking.com/2006/10/27/import-benchmarks-for-mysql.html"/>
   <updated>2006-10-27T00:00:00-04:00</updated>
   <id>http://www.continuousthinking.com/2006/10/27/import-benchmarks-for-mysql</id>
   <content type="html">&lt;h2 id='intro_to_this_'&gt;Intro To This &lt;b style='color:black;background-color:#99ff99'&gt;Benchmark&lt;/b&gt;&lt;/h2&gt;
&lt;!-- &lt;div&gt;
TODO: FIX this
  &lt;br /&gt; &lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt;::Base has been given an &lt;i&gt;&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt;&lt;/i&gt; method which supports optimized inserts through the methods like multi-value insert statements. Below are the benchmarks for several sets of data across the two most common MySQL storage engines. &lt;br /&gt;&lt;br /&gt; &lt;p&gt;
    &lt;p&gt;
      This functionality can be found in my &lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt; Extensions package which can be found &lt;a href=&quot;/ARE&quot;&gt;here&lt;/a&gt;. The current version as of the time of this &lt;b style=&quot;color:black;background-color:#99ff99&quot;&gt;benchmark&lt;/b&gt; was 0.0.3.&lt;br /&gt;&lt;br /&gt;
    &lt;/p&gt;
  &lt;/p&gt;
  
  &lt;p&gt;
    This &lt;b style=&quot;color:black;background-color:#99ff99&quot;&gt;benchmark&lt;/b&gt; test compares the speed of two identical tables (besides the storage engine in use) with the following three columns:&lt;br /&gt; &lt;ul&gt;
      &lt;/p&gt; &lt;li&gt;
        id int(11) unsigned not null auto_increment
      &lt;/li&gt;
      &lt;li&gt;
        my_name varchar(20) not null
      &lt;/li&gt;
      &lt;li&gt;
        description varcharr(255) default '' &lt;/td&gt; &lt;p&gt;
          &lt;/ul&gt;
        &lt;/p&gt;
        
        &lt;p&gt;
          It utilizes the following three methods:&lt;br /&gt; &lt;ul&gt;
            &lt;/p&gt; &lt;li&gt;
              &lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt;::Base.create â€“ included with &lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt;
            &lt;/li&gt;
            &lt;li&gt;
              &lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt;::Base.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; â€“ which uses model validation. This is included with &lt;a href=&quot;/ARE&quot;&gt;&lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt; Extensions&lt;/a&gt;
            &lt;/li&gt;
            &lt;p&gt;
              &lt;li&gt;
                &lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt;::Base.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; â€“ which doesn't use model validation. This is included with &lt;a href=&quot;/ARE&quot;&gt;&lt;b style=&quot;color:black;background-color:#a0ffff&quot;&gt;ActiveRecord&lt;/b&gt; Extensions&lt;/a&gt;
              &lt;/li&gt;
            &lt;/p&gt;
            
            &lt;p&gt;
              &lt;/div&gt;
            &lt;/p&gt;
            
            &lt;p&gt;
              &lt;h2&gt;
                How to Read This &lt;b style=&quot;color:black;background-color:#99ff99&quot;&gt;Benchmark&lt;/b&gt;
              &lt;/h2&gt;
            &lt;/p&gt;
            
            &lt;p&gt;
              &lt;div&gt;
                &lt;/p&gt; The &lt;b&gt;titles&lt;/b&gt; of each table are identified with the black background color. They read something similar to &lt;i&gt;ModelName.method_name (number_of_inserts) Description&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt; The &lt;b&gt;times&lt;/b&gt; of each table are represented in seconds. They are rounded to the nearest thousandth for display purposes. &lt;br /&gt;&lt;br /&gt; The &lt;b&gt;speedup&lt;/b&gt; you see in columns two and three enxt to the time in seconds is how much faster this method is when compared to the &lt;i&gt;create&lt;/i&gt; method. &lt;br /&gt;&lt;br /&gt; The model name can be used to determine the storage engine in use. The method name can be used to determine what method was called on the model. The number_of_inserts can be used to determine how many inserts we're talking about. The additional description can be used to determine when validation on the model was performed or not.&lt;br /&gt;&lt;br /&gt; &lt;table&gt;
                  &lt;tr&gt;
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestMyISAM.create (10)
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestMyISAM.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (10) With Validations
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestMyISAM.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (10) Without Validations
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  
                  &lt;tr&gt;
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.032
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.005 (6x speedup)
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.003 (12x speedup)
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  
                  &lt;tr&gt;
                    &lt;td&gt;
                      Â 
                    &lt;/td&gt;
                  &lt;/tr&gt;
                &lt;/table&gt;
                
                &lt;table&gt;
                  &lt;tr&gt;
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestInnoDb.create (10)
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestInnoDb.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (10) With Validations
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestInnoDb.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (10) Without Validations
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  
                  &lt;tr&gt;
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.044
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.006 (7x speedup)
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.004 (12x speedup)
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  
                  &lt;tr&gt;
                    &lt;td&gt;
                      Â 
                    &lt;/td&gt;
                  &lt;/tr&gt;
                &lt;/table&gt;
                
                &lt;table&gt;
                  &lt;tr&gt;
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestMyISAM.create (100)
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestMyISAM.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (100) With Validations
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkTitle&quot;&gt;
                      TestMyISAM.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (100) Without Validations
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  
                  &lt;tr&gt;
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.336
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.044 (8x speedup)
                    &lt;/td&gt;
                    
                    &lt;td id=&quot;benchmarkCell&quot;&gt;
                      0.009 (36x speedup)
                    &lt;/td&gt;
                  &lt;/tr&gt;
                  
                  &lt;tr&gt;
                    &lt;td&gt;
                      Â 
                    &lt;/td&gt;
                  &lt;/tr&gt;
                &lt;/table&gt;
                
                &lt;p&gt;
                  &lt;table&gt;
                    &lt;/p&gt; &lt;tr&gt;
                      &lt;td id=&quot;benchmarkTitle&quot;&gt;
                        TestInnoDb.create (100)
                      &lt;/td&gt;
                      
                      &lt;td id=&quot;benchmarkTitle&quot;&gt;
                        TestInnoDb.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (100) With Validations
                      &lt;/td&gt;
                      
                      &lt;td id=&quot;benchmarkTitle&quot;&gt;
                        TestInnoDb.&lt;b style=&quot;color:black;background-color:#ffff66&quot;&gt;import&lt;/b&gt; (100) Without Validations
                      &lt;/td&gt;
                    &lt;/tr&gt;
                    
                    &lt;tr&gt;
                      &lt;td id=&quot;benchmarkCell&quot;&gt;
                        0.366
                      &lt;/td&gt;
                      
                      &lt;td id=&quot;benchmarkCell&quot;&gt;
                        0.112 (3x speedup)
                      &lt;/td&gt;
                      
                      &lt;td id=&quot;benchmarkCell&quot;&gt;
                        0.011 (35x speedup)
                      &lt;/td&gt;
                    &lt;/tr&gt;
                    
                    &lt;tr&gt;
                      &lt;td&gt;
                        Â 
                      &lt;/td&gt;
                    &lt;/tr&gt;
                  &lt;/table&gt;
                  
                  &lt;br /&gt; &lt;table&gt;
                    &lt;tr&gt;
                      &lt;td id=&quot;benchmarkTitle&quot;&gt;
                        TestMyISAM.create (1000)
                      &lt;/td&gt;
                      
   
