Test, Code, There is no Step Three!
Occasionally even great developers fall into bad habits, and the rest of us do it more than occasionally. This is especially true when under deadline and suddenly everything you’ve ever learned is thrown out the window in a desperate effort to get something to finish. I’ll share a story from a recent project to demonstrate just how much trouble rushing can get you into, and why we shouldn’t chuck our good habits at the first sign of adversity.
The story was relatively simple. Multiple XML documents needed to be generated based on information from another application in the system. My pair and I sat down and wrote our first test, which looked a little something like this:
specify “valid data should generate valid document†do data.valid = true doc = doc_generator.generate(data) doc.valid?.should eql(true) doc.header.should eql(“Valid Headerâ€) doc.text.should eql(“Valid Textâ€) doc.footer.should eql(“Footerâ€) end
So then we wrote a little code:
def generate(data)
if data.valid
doc = Document.new
doc.header = “Valid Headerâ€
doc.text = “Valid Textâ€
doc.footer = “Footerâ€
end
end
Okay we’ve got a passing test, with the simplest thing that could possibly work.. Great. Now let’s do the next one. Looking at the acceptance test we need to generate a different document when the data is notifying us of inaccessible data. Unfortunately there isn’t a flag for that, so we’ll have to figure it out from a combination of booleans. We write another test, we get it to pass with this code:
def generate(data)
if data.valid
doc.header = “Valid Headerâ€
doc.text = “Valid Textâ€
doc.footer = “Footerâ€
elsif data.invalid and data.accessible
doc.header = “Different Headerâ€
doc.text = “Different Valid Textâ€
doc.footer = “Footerâ€
end
end
That’s getting pretty ugly, but hey all the tests pass and we’re under deadline. We could replace the boolean checks with a query, but we’ve really got to finish and can’t be bothered with that kind of change. It would take almost a minute! Of course the big problem isn’t this code, it’s that we have quite a few more acceptance tests to go. Eventually this code looked something like this:
def generate(data)
if data.valid
doc.header = “Valid Headerâ€
doc.text = “Valid Textâ€
doc.footer = “Footerâ€
elsif data.invalid and data.accessible
doc.header = “Different Headerâ€
doc.text = “Different Valid Textâ€
doc.footer = “Footerâ€
elsif data.reset and not data.invalid
if data.new
doc.header = “Yet more Different Headersâ€
doc.text = “Valid Textâ€
doc.footer = “New Footerâ€
else
doc.header = “Another Different Headerâ€
doc.text = “Random Textâ€
doc.footer = “a completely different Footerâ€
end
else
doc.header = “Yet more Different Headersâ€
doc.text = “Oh for crying out loud.â€
doc.footer = “Good god another Footerâ€
end
end
What do all those boolean combinations check for? Heck I don’t know. On top of that we’ve got several messages that are sent by this class that don’t use the data passed in, which look like this:
def send_error(message) doc.header = “Error Header†doc.text = message doc.footer = “Footer†end
Clearly we had a problem, and my pair and I knew it the entire time, yet each time the refactor step in TDD arrived we would grin and bear it, with that deadline looming. Each time the step would take longer and longer, as the code became more complex, but we wouldn’t change because of the immediate “benefit.†It’s always quicker to just change the one piece of code, right?
Obviously the answer is no, it isn’t. My pair and I demoed our code, made the customer happy and than frantically began rewriting the code. After about two more days of broken tests we had a reasonably clean and elegant solution, and I didn’t have to hide the code from Micah anymore. How long did the first “draft†take? Oh, about two days all told. So we laugh and realize we could have made our deadline even if we had done the job right the first time, but even that isn’t true. Remember the code became more and more complex as we worked through the story, and began to resemble legacy code. Each new document required us to figure out each boolean check, and usually led to us breaking old tests as the fragile code changed. I firmly believe that if we hadn’t continues using the blunt tools of conditional code and implemented the object-oriented solution we later refactored to we would have actually been done more quickly. Furthermore while cleaning up that ugly code I wasn’t providing business value to the customer, thereby hurting the following iteration. A few days later I needed to add a new document to the system. What had previously taken a half-hour or so for each case took seconds. Imagine if we had done that the first time. The moral of the story clear. CleanAsYouCode, and don’t let deadline pressure cause you to abandon your own principles. In the long run and short run you’ll improve your codebase, make your customer happy, and probably enjoy your job more too.
Understanding Statemachines, Part 4: Superstates 6
Superstates
Often in statemachines, duplication can arise. For example, the vending machine in our examples may need periodic repairs. It’s not certain which state the vending machine will be in when the repair man arrives. So all states should have a transition into the Repair Mode state.

Diagram 1 - Without Superstates
In this diagram, both the Waiting and Paid states have a transition to the Repair Mode invoked by the repair event. Duplication! We can dry this up by using the Superstate construct. See below:

Diagram 2 - With Superstates
Here we introduce the Operational superstate. Both the Waiting and Paid states are contained within the superstate which implies that they inherit all of the superstate’s transitions. That means we only need one transition into the Repair Mode state from the Operational superstate to achieve the same behavior as the solution in diagram 1.
One statemachine may have multiple superstates. And every superstate may contain other superstates. ie. Superstates can be nested.
History State
The solution in diagram 2 has an advantage over diagram 1. In diagram 1, once the repair man is done he triggers the operate event and the vending machine transitions into the Waiting event. This is unfortunate. Even if the vending machine was in the Paid state before the repair man came along, it will be in the Waiting state after he leaves. Shouldn’t it go back into the Paid state?
Superstates come with the history state which solves this problem. Every superstate will remember which state it is in before the superstate is exited. This memory is stored in a pseudo state called the history state. Transitions that end in the history state will recall the last active state of the superstate and enter it.
You can see the history state being use in diagram 2. In this solution, the history state allows the vending machine to return from a repair session into the same state it was in before, as though nothing happened at all.
Code
The following code builds the statemachine in diagram 2. Watch out for the _H. This is how the history state is denoted. If you have a superstate named foo, then it’s history state will be named foo_H.
require 'rubygems'
require 'statemachine'
vending_machine = Statemachine.build do
superstate :operational do
trans :waiting, :dollar, :paid
trans :paid, :selection, :waiting
trans :waiting, :selection, :waiting
trans :paid, :dollar, :paid
event :repair, :repair_mode, Proc.new { puts "Entering Repair Mode" }
end
trans :repair_mode, :operate, :operational_H, Proc.new { puts "Exiting Repair Mode" }
on_entry_of :waiting, Proc.new { puts "Entering Waiting State" }
on_entry_of :paid, Proc.new { puts "Entering Paid State" }
end
vending_machine.repair
vending_machine.operate
vending_machine.dollar
vending_machine.repair
vending_machine.operate
Output:
Entering Repair Mode Exiting Repair Mode Entering Waiting State Entering Paid State Entering Repair Mode Exiting Repair Mode Entering Paid State
Next we should cover pseudo states.
Sharing a Database Among Multiple Rails Applications 4
A sign of the success of Ruby on Rails is the size of applications being written with it. Currently, we are working on a project with many interconnecting modules that we split up into separate Rails applications. However, the business domain was the same among the projects, resulting in the different projects sharing the same database. This article discusses the way we’ve accomplished this.
Create a Lib Project
We first need a place to pull our common classes into. This will not be a Rails application; it will just be a Ruby module that your Rails application will require. Our directory structure will look something like this:
/projects/my_lib --> lib --> spec
Now we can move on to the actual refactoring.
Pull the Models Out
The first step is the easiest: pull out the models from the app/models directory of your Rails application into the lib directory of your new library. In the config/environments.rb file within your Rails application, you will need to add this new directory to your Ruby search path by adding this line to the end of the file.
$: << File.dirname(__FILE__) + '/your_lib_path'
More on the Ruby search path later.
Pull the Tests Out
Let’s move on to making our specs pass. Now that we don’t have the Ruby environments loaded up as part of our test helpers (spec_helper for the rspecers out there), we need to establish an Active Record connection ourselves. Create a spec helper for our lib specs and start it with the connection to the database like so.
require 'rubygems' require 'active_record' ActiveRecord::Base.establish_connection( :adapter => "postgresql", :host => "localhost", :username => "rails", :password => "", :database => "_test" )
This is the same way Rails sets up your database connections for active record when you load the Rails environment. Now your specs just need to require this new spec_helper in order to get Active Record functioning.
Use Models Across Projects
Now you are free to use the same database across many projects. To do this, you just need to either require a single lib file that loads all the models, or you could put the lib directory in your Ruby search path.
Ruby Search Path vs. Lib Require File
The new common library will need to be included in your rails application. There are two methods we have used to do this. The first is to create a library file that does nothing more than requires all of the common lib files, looking something like the following.
require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_a' require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_b' require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_c' require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_d' require File.expand_path(File.dirname(__FILE__) + '/my_lib/lib/file_e'
The problem with this approach is it requires you to sequence the require statements in the appropriate order, or else you will get errors about missing objects. The benefit is that you load the entire environment in one place rather than adding require statements at the top of each file to include the needed external dependencies. These code files that do nothing but require files are no stranger to Ruby; however, they must be managed properly as they become temperamental and irritable when dependencies are mixed up.
The other approach we have used is what I recommended above. In your Rails application’s environment, add the lib directory to your search path, and include the require statements as needed in each model file. Of course, by including one file you will be implicitly including all of the dependencies. Using this technique, you can eliminate files that just require other files.