Pair Me Up 1
I am a better pair than solo developer. For me, software is a collaborative art from the start to the end. Starting from the beginning of a project, where the developers need to collaborate with the customer s and stakeholders of the project to learn about the business domain. Then working with the project manager for sorting priorities and deadlines to make the business goals realizable in the fastest amount of time. Also development is collaboration, via pair programming, to produce a dialog between the developers on their vision of the implementation of this code. The last part, pair programming, is what I would like to focus on.
Having a pair has the traditional advantages of keeping disciplined and sharing the knowledge base. That is a starting point, but pairing is quintessentially important to my process due to the diversity it provides. A diversity of approach and implementation provide me with enough to perform at a highly creative and expressive manner.
Since you are not driving the keyboard and control of the computer, there is more time for contemplating code you wrote and direction you are moving. Most of my good ideas come from the time when someone else is typing. Since I was just working on the practical, I have my head wrapped around the code, and since I am not responsible for typing, I can reflect in the abstract.
I have heard many places that a benefit of test driven development is that the tests force you to design the API of the objects you are using as someone would use them. Well, pair programming, in compliment with programming ping-pong, forces your code to be clean. When you write a test, it isn’t you that makes it pass, so you have to think with expression and intent in mind. So, you end up writing the test FOR your pair. It becomes a form of writing, not just coding.
Sometimes, the test needs to be explained. While explaining something to a pair, your test must hold up your own arguments. Often times when I come to explain something I just wrote, I think of a better way to do it. Explanation is the best form of validating you understand where you are going well.
Also, pairing is how I learned most of my developer personality. Taking bits and pieces of the traits of my pairs through years of pairing. My style is a composite of pairing with various mentors and peers of mine. It has shown me how people approach this craft.
Three Reasons to Use FitNesse 2
1. You find your self delivering software to your customer who says “That’s not what I asked for.”
Using FitNesse allows you to communicate with the customer up front. Before a line of code is written, you can have all the behavior expressed in an executable format. Make sure the customer helps to write these tests. Once your FitNesse test is in place, all you need to do it make it pass. Due to the cut-and-dry aspect of executable specifications (FitNesse test), one the spec is passing, you have delivered precisely what your customer asked for.
2. Bugs sneak into your system as development progresses and these bugs takes weeks to find and remove.
FitNesse is a tools to help you drive development with tests. When practices with discipline, test driven development will insure that you have a FitNesse test for each and every feature in your system. The moment a bug is introduced, you will know about it because a FitNesse test will fail.
3. It is difficult to create documentation for your system and it is constantly out of date because the system is changing.
FitNesse offers a unique documentation solution. When ever you write a FitNesse test, you are in fact describing how the system works. In other words you’re documenting it. The web/wiki based nature of FitNesse makes documentation simple and convenient. The best part is that the documentation in FitNesse can never go out of date. Since you’re keeping your test passing, and your tests are documentation, it’s impossible for them to lie.
There is an article I wrote about FitNesse for Windows Developer Power Tools. This book, just released today, includes articles on dozens of free tools that .NET developers might benefit from. If you write .NET code, check it out. If not, keep in mind that FitNesse will work for almost any language.
Getting started with Rails and FitNesse 1
So lets get started. Our customer has just written a test that looks like this:
|vending machine| |check|amount|$0.00| |enter|currency|$.35| |press|add change| |check|amount|$.35| |enter|selection|juicy fruit| |press|vend| |check|amount|$0.00|This would be a common first fixture for a product, as it is limited in scope, it is a very specific example from which to build a conversation about requirements about. Anyway, the first thing to making this pass is getting some of the FitNesse infrastructure in place around your rails app.
First, lets create a rails app for our vending machine
$rails vending_machine
We see all the normal rails stuff, all the creates.
Lets download FitNesse and place it in our vending_machine root directory. FitNesse can be downloaded at http://fitnesse.org. And start the FitNesse server.
So, now we go to the FitNesse main page and create the page for our acceptance test. Then put the test from the customer into the page and try to run it. Failures? We need to set up the environment to run with ruby fit. Follow the instructions here (http://fitnesse.org/FitServers.RubyFit) to set up the right test runner for ruby.
Lets write our first fixture in a fixtures directory we create in the root folder.
Our new test with the path and test runner set up looks like this
!define COMMAND_PATTERN {ruby -I%p ruby/bin/FitServer.rb}
!path
!3 Make one transaction with a vending machine
!|fixtures.VendingMachine|
|check|amount|$0.00|
|enter|currency|$.35|
|press|add change|
|check|amount|$.35|
|enter|selection|juicy fruit|
|press|vend|
|check|amount|$0.00|
There are a few things to notice about the changes.* The path is the rails root dir.
* Fixtures.VendingMachine is mapping to the folder name/module name of where the fixutures are located. In this instance it is a folder in the rails directory called fixtures.
* If you run the test, you will get all sorts of exceptions, because the fixture code is not written yet.
Note: If the table is not even showing up when you run the fixture go here.
Now it is time to write a fixture to make this test fail without any exceptions. In the fixtures directory, create a file called vending_machine.rb. The naming of your fixtures maps with the name of your file, which it will require. Lets make a stub file to make the test fail without exceptions.
require 'ruby/lib/fit_helper'
module Fixtures
class VendingMachineFixture < Fit::ActionFixture
attr_accessor :currency, :selection
def initialize
super
@@actor = self
end
def add_change
end
def vend
end
end
end
Now we should have failures with the amount not changing.
Lets create our controller for the vending machine and start to implement the code. I am going to leave out the specs I use to write the controller, just show the code. Here is the first version of the controller. Note it has the same stubbed methods the fixture has.
class VendingMachineController < ApplicationController def add_change end def vend end end
Lets hook up the fixture to the imaginary controller. There is a fair amount of set up which is rails related.
First, we need to load up the environment and the controllers. Add these lines to the beginning of your fixture.
require File.expand_path(File.dirname(__FILE__) + "/config/environment") require File.expand_path(File.dirname(__FILE__) + ' /app/controllers/application')
Which should allow us to change the initialize method to:
def initialize
super
@@actor = self
@controller = VendingMachineController.new
@controller.params = {}
end
Which creates the controller, and initializes its params to an empty dictionary. There are other ways to do this, like creating test params, but for simplicity, we are going to create our own for now.
Next, we set up the values in the params and call the controller methods.
def add_change
@controller.params[:amount] = @currency
@controller.add_change
end
def vend
@controller.params[:selection] = @selection
@controller.vend
end
Now, we make the test pass by implementing the controller.
class VendingMachineController < ApplicationController
def initialize
@items = {"juicy fruit" => 35 , "doublemint" => 45 }
@session = {} if not @session
@session[:amount_entered] = 0.0;
end
def add_change
@session[:amount_entered] += params[:amount].to_f
end
def vend
@items.each_pair do |key, value|
if(params[:selection] == key)
@session[:amount_entered] = 0.0
end
end
end
end