August 2007
Monthly Archive
Developer Testing and /Glover and Agile30 Aug 2007 10:03 am
RSpec is the ultimate bed check
Behavior Driven Development (or BDD) is a slight modification of Test Driven Development (or TDD) in that BDD stresses the term “should” over “test”– and as it turns out, by focusing on behavior through a focus on should, you can more easily specify behavior early. TDD, as you may know, also stresses verification early, but because it focuses on the term “test” there are challenges, such as getting developers to think in terms of testing first. Don’t get me wrong, there are a number of passionate TDD gun slingers throughout our industry who have readily adopted a strict notion of testing up front; however, they are unfortunately a minority.
Interestingly, BDD has spawned a number of frameworks that aim to make this up front specification based verification easy to create. One particular framework is Ruby’s RSpec, which has put to use an innovative DSL for specifying behavior quite straight forward. For example, imagine a customer has tasked you with creating a zip code verification service. This service is ultimately intended to permit valid zip code and deny invalid ones. Working with your customer, you both come up with a series of requirements regarding this service:
- The zip code validation service should accept 5 digits in a row, like 22101
- It should accept 5 digits followed by 4 digits (with a hyphen separator), like 22101-5051
- It should deny any characters found in a zip code, like 221o1
- It should deny any pattern that has fewer than 5 digits in the first phrase, like 2210
- It should deny any pattern that has fewer than 4 digits in the second phrase, like 22101-5
Note that these requirements don’t specify how this verification will be carried out. They are written from a user’s point of view– they ultimately don’t care how you implement it, so long as it works, right? The nice thing about the list above is that using RSpec, I can essentially copy and paste them into code. Watch:
First, I need to create a file and use RSpec’s describe clause, which declares what this behavior is intended to model.
require 'zipcode_validator'
describe ZipCodeValidator do
end
Next, using the it phrase, I can literally paste in my requirements and wrap them with a do and an end as shown below.
it "should accept 5 digits in a row, like 22101" do
end
it "should accept 5 digits followed by 4 digits, like 22101-5051" do
end
it "should deny any characters in a zip code, like 221o1" do
end
it "should deny any pattern that has fewer than 5 digits in the
first phrase, like 2210" do
end
it "should deny any pattern that has fewer than 4 digits in the
second phrase, like 22101-5" do
end
With my behaviors defined, I can now create a context– in it, I define a reference to my, as yet to be defined, ZipCodeValidator service object. The before(:each) method means that a new instance will be created for each behavior.
before(:each) do
@validator = ZipCodeValidator.new
end
Next, I can implement the first behavior and ensure that the service permits the valid zip code. Note how RSpec allows me to use the should method on my object.
it "should accept 5 digits in a row, like 22101" do
@validator.validate("22101").should == true
end
If I run my behavior class now, it’ll fail as I haven’t even coded any implementation yet. That’s ok though as I’ve been focused on the specification of the object. I can show my customer the behaviors if they speak geek (or Ruby) and engage in some collaborative verification to ensure that I’m going down their desired route as well. Once everyone is on the same page, I can then turn to implementing the ZipCodeValidator service.
class ZipCodeValidator
def validate(zipcode)
if (/^d{5}([-]d{4})?$/ =~ zipcode) == 0 then return true
else return false
end
end
end
With the ZipCodeValidator object coded, I can code the other behaviors to ensure the negative path works, that is, that the object “should deny any pattern that has fewer than 5 digits in the first phrase, like 2210″ for example.
it "should deny any pattern that has fewer than 5 digits in
the first phrase, like 2210" do
@validator.validate("2210").should == false
end
Putting it all together yields a behavior class with 5 behavior methods corresponding to the requirements from earlier. Plus, this exercise also resulted in a functional ZipCodeValidator object.
require 'zipcode_validator'
describe ZipCodeValidator do
before(:each) do
@validator = ZipCodeValidator.new
end
it "should accept 5 digits in a row, like 22101" do
@validator.validate("22101").should == true
end
it "should accept 5 digits followed by 4 digits, like 22101-5051" do
@validator.validate("22101-5051").should == true
end
it "should deny any characters in a zip code, like 221o1" do
@validator.validate("221o1").should == false
end
it "should deny any pattern that has fewer than 5 digits in the
first phrase, like 2210" do
@validator.validate("2210").should == false
end
it "should deny any pattern that has fewer than 4 digits in the
second phrase, like 22101-5" do
@validator.validate("22101-5").should == false
end
end
Running the behavior shows that things work as planned!
aglover$ spec zipcode_spec.rb
.....
Finished in 0.007737 seconds
5 examples, 0 failures
RSpec’s intuitive DSL for defining behavior makes BDD a breeze; plus, the elegance of defining the specification in concert with a behavior class drives development in a rapid manner that builds confidence quickly, while also facilitating collaboration with customers and domain experts.
Join us for the Continuous Integration book signing plus release party
If you’re a fan of Continuous Integration (and local to the Washington DC area) you’ll want to clear your calendar the evening of Thursday, August 30th to celebrate with the authors of “Continuous Integration: Improving Software Quality and Reducing Risk” at their book signing.

Book signing at Barnes and Noble (map)
with Paul Duvall, Andrew Glover, and Steve Matyas
Thursday, August 30th
7:30 - 9:00 p.m.
Immediately following the signing, Stelligent and 5AM Solutions are throwing a release party at McCormick & Schmick’s. So…if the book isn’t enough to get you out of the house, the complimentary drinks and appetizers should.
Release party at McCormick & Schmick’s
Reston Town Center
9:00 - 11:00 p.m.
If you’re interested, please make sure to RSVP prior to August 27th. Oh, and feel free to spread the word, far and wide!
Continuous CI interlocution
The Continuous Integration road-show continues this September in both Boston and Minneapolis where I’ll be speaking at the SD Best Practices Conference & Expo and the Twin Cities Java Users Group. I’ll be giving a presentation at both locations entitled “Monitoring Software Quality with Continuous Integration”– I always enjoy giving this presentation as it shows CI in action and elaborates on three key points that are paramount to a successful CI process, which are:
- Expanding your definition of a defect
- Ensuring defects have a short lifetime
- Extending visibility to all stake-holders
If you’re able to attend either of these events, stop by and say hi!
Fire your best people…reward the lazy ones
Fire your “best” people…reward the “lazy” ones
In my experience, what most people consider to be their “best” people are often the root of most problems. It’s the difference between troubleshooters and troublepreventers.
Let me explain…

Bill is a troubleshooter (only). Many consider Bill to be the best employee in the company because he solves almost any problem that comes into the door. However, unbeknownst to many (especially management), Bill is the one causing most of the problems. Bill knows the purpose of every hard-coded lookup value and is the fastest to manually deploy the application to WebLogic using its web console. For instance, he knows that “14″ means a “transaction that is waiting for approval by second-line management”. However, instead of creating a human-readable constant, Bill hard codes the number “14″ in the source code. Therefore, Bill is the only one that can easily maintain these methods. In my personal experience, someone like Bill doesn’t do this for nefarious reasons, he’s just not thinking about how the next developer may need to maintain it. For every time a method is written, it’s read (and maintained) ten times (10:1). Therefore, people like Bill need to be writing source code for other humans, not the computer.
Let’s have a look at Peter…

Peter is a “lazy” developer (a troublepreventer). Because Peter is “lazy”, he hates doing the same thing twice, so he generalizes common functionality into a delegating class, creates interfaces for implementing classes to adhere to, or he writes build scripts that compile, integrate the database, runs tests and inspections, and deploys the software the same way every time. Peter finds it mind-numbing to repeat himself. Again, Peter is lazy so he doesn’t mind spending two hours automating something that normally takes 10 minutes to run manually. Why? Because, he very quickly reaps the benefits of this extra effort since every time the process is run he gets those 10 minutes back and even more importantly, he eliminates the possibility of human error (which, again, saves time and money).
The (”lazy”) troublepreventer thinks ahead. He extracts variable information into common properties files, seeks to reduce complex code, and automates repetitive, error-prone activities such as the build and deployment processes. He also ensures that others can very easily repeat what he has done. Anyone that has worked with me for even a day knows that I often sound like a broken record when I say “Is it in Subversion?” or “Have you updated the Wiki?” To me, if the knowledge is locked in your head, you are a less valuable, not more valuable, resource. Troublepreventers put their knowledge in the system, not just their heads, so that it runs the same way every time.
People like troubleshooters because they can solve a problem when a project is under pressure such as getting that emergency fix out the door immediately. Without question, you need troubleshooters on your project. However, many times the (exclusive) troubleshooters are the ones that cause the problem in the first place, be it a hard-coded value, duplication of code or a large complex method only they can understand.
Before you start thinking that I’m trying to gather together a group of slackers, I’m suggesting the complete opposite of this. I just want people to think about the total time involved, not just fixing the symptom. There are people that are both troublepreventers and troubleshooters. These are the people you want to keep and reward. However, on a given team, I’d opt for more troublepreventers than troubleshooters as they save everyone time, money and headaches.
For Want of a Nail
In his excellent book, Customer Centered Selling, Robert Jolles relays a poem about consequences:
|
FOR WANT OF A NAIL
For want of a nail, a shoe was lost
For want of a shoe, a horse was lost
For want of a horse, a rider was lost
For want of a rider, a message was lost
For want of a message, a battle was lost
For want of a battle, a war was lost
And all for the want of a nail…
Ben Franklin
|
A recent client lacked concern about building software regularly and successfully. In his mind, build failures were equal to the annoyance of a hobbled horse: something resolved easily when a release date approached.
But this same chain of events could be applied to the software business. My crude version of the poem – adopted for software development – lacks the poetic prowess of Mr. Franklin. Hopefully, though, it illustrates a point.
|
FOR WANT OF A BUILD
For want of a build, a test case was not executed
For want of test case, a defect was not detected
For want of a defect report, a bad release was promoted
For want of a good release, a strategic customer was lost
For want of a customer, a development team was reduced
For want of developers, a product stagnated
For want of a product, a company was lost
And all for the want of a build…
|
We would all be well served to remember the potential impact of small problems as we consider where to spend our resources. Little annoyances like failed builds or test cases can be very early indicators that you are “losing the war” in your development efforts.
How important are the little annoyances in your software organization? Do you get concerned if a particular build effort fails? Do you have developer test cases? Are they executed regularly? Who gets heartburn if they fail?