
Bob Martin, on the TDD list expounded some more about the Green wrist band he wears:
I wear a green wrist-band that says “Test First”. This green band is a symbol of my committment to a minimum standard of professional behavior. Part of that minimum standard is: “I will not release code that I have not tested.”A committment like this changes the sense of the decision you referred to above. Testing becomes a discipline, not a trade-off, a committment to professional behavior, as opposed to a convenience.
When we accept that writing unit tests first is simply part of standard professional behavior, then the quandry of whether it takes too much time or not will diminish.
On a recent post on Slashdot perhaps one of the funniest comment threads ensued that I have seen in a while.
It started with Jeremy’s post:
So, they give me a laptop… I get multple T3 internet connections, pay me to work… free bagels on Fridays, free coffee every day, and they can’t fire me for searching for funny pictures and adding them to http://users.mtrx.net/funnypics [mtrx.net]?
Wow… cool!
Which got replied with:
This is Jerry, you know, your boss? You’re fired. Be sure to return your office supplies to Karen on your way out.
Which got replied with:
This is Kevin, your boss. You can given Karen your office supplies too. I am not going to babysit kids posting on Slashdot during working hours.
Which got replied with:
This is Karen, your office manager. I don’t want your damn office supplies, putting them away distracts from my time spent surfing the web. Just pretend that you used them up and throw them in the trash can on your way out…
Which got replied with:
Hi Karen, this is Ed, the CEO.
Sorry your web surfing was interrupted by fired employees trying to hand you old office supplies. Please, please, don’t quit. As you know, without a good office manager, the whole company is doomed because all executives are helpless children. A fruit basket has been sent to your desk, and your clothing stipend will be doubled. Also, your job title has been escalated yet again, from “secretary” to “receptionist” to “office manager” to “company overlord.”
Thank you for your patience, and also for helping me write this. Why don’t you take the afternoon off for another massage? We’ll get a temp to handle the phones for you, as usual.
Which got replied with:
Hi, this is Joe, your ex loyal customer.
Since you lot spend so much time posting on slashdot, I found another vendor.
Which got replied with:
Joe, this is your wife.
Since you spend all your time posting on slashdot and looking for vendors, I’m leaving you for the metermaid.
Which got replied with:
And Joe, this is the metermaid. I’m skipping town with your wife. Don’t forget to drop the check for last months bill in the mail. It’s expensive in Hawaii this time of year.
Which got replied with:
Joe’s wife, this Jerry Fallwell. You know you’re going to hell, right?
Which got replied with:
Jerry? This is God. I know what you do in the basement with the donkey and the swing. Stop talking for me or I’ll persuade Conchita (you know, the maid you imported from San Salvador?) to drop those tapes off at CNN.
Whew! Who knew a bunch of random people could keep a conversation up so long?!
A brilliant job opening post came across the XP Jobs mailing list today. Shame it’s all the way in France, because how could you not want to work for a company whose job posting looks like:
LEIRIOS is looking for 2 senior java developers for its R&D; department based in Besançon (France). (French-speaking and fluent with technical English)
We develop our products using eXtreme Programming and we are looking for developers mastering agile methodologies and willing to improve development processes.
Our acceptance tests are the following:
class SeniorDeveloperAcceptanceTest extends TestCase{
Developer candidate;
Collection team;
public void setUp() {
candidate = new Developer();
team = Leirios.getTeam();
}public void testTechnicalSkills() {
assertTrue(candidate.isJavaExpert());
assertTrue(candidate.canDesignLargeApplication());
assertTrue(candidate.canReduceTechnicalDebt());
assertTrue(candidate.practiceTDD());
}public void testTeachingSkills() {
assertTrue(candidate.canImproveTeamSkills());
assertTrue(candidate.canArgueAboutAgility());
}public void testHumanBehavior() {
assertTrue(candidate.canPairProgram());
assertTrue(candidate.canIntegrateWith(team));
assertTrue(candidate.hasPositiveAttitude());
}public void testMethodologySkills() {
assertTrue(candidate.knowExtremeProgramming());
assertTrue(candidate.canImproveTeamVelocity());
}
}class SeniorDeveloperBonusAcceptanceTest extends TestCase{
String[] bonusSkills = new String[]{
”canDevelopEclipsePlugins”,
”knowSoftwareEdition”,
”isReallySmart”};public void testAcceptedCandidate(){
Collectioncandidates = Leirios.gatherCandidates();
Developer toBeHired = Leirios.selectCandidateWithMaxBonus(bonusSkills);for(Developer candidate: candidates){
if (candidate.equals(toBeHired))
assertTrue(Leirios.willHire(candidate));
else
assertFalse(Leirios.willHire(candidate));
}
}
}LEIRIOS is an innovative software editor, founded in 2003.
(25 people, offices in Paris, Besançon and München).
http://www.leirios.comSend your application to job at leirios.com
Good look Leirios!
Over the past few months, we’ve had the chance to explore getting up and running with Fitnesse and .NET and the chance to check out how to implement ActionFixtures. While both Column and Action fixtures are great ways to express requirements, there is another fixture which is extremely powerful, and allows your customer to write incredibly expressive fixtures. These are called DoFixtures. In this 2 part article, we’ll explore the basics of the DoFixture, and then move into some more advanced features.
The concept behind a DoFixture is to write your tests as user-readable sentences. For example, if a requirement for a chat application was that a user was supposed to enter his username, enter a room name, and click the “Create” button, we’d have a table that looked like:
|User enters username of|John|
|User enters room name of|baseball|
|User presses|Create|
So right away we can see the expressiveness of the DoFixture. The three rows above would be mapped to the methods:
public void userEntersUsernameOf(string username);
public void userEntersRoomNameOf(string roomName);
public void userPresses(string buttonName);
In addition, you can have multiple parameters. For example, we could have written the above as:
|User|John|enters room name of|baseball|
which would map to the method:
public void userEntersRoomNameOf(string username, string roomName);
Finally, you can mix other fixture types into your DoFixtures, even having your methods return Fixture types.
But, before we get too far, let’s get an example working. We assume that you have already been through the Fitnesse tutorial for .NET, so you have a working Fitnesse server and have been able to get it to talk to your .NET classes.
Make sure your Fitnesse server is running, and fire up a browser. Create a page called DoFixtureExample, and type in the following:
!define COMMAND_PATTERN {%m %p}
!define TEST_RUNNER {dotnet\FitServer.exe}
!define PATH_SEPARATOR {;}
!path C:\fitnesse\fitlibrary.dll
|User enters username of|John|
|User enters room name of|baseball|
|User presses|Create|
|User|John|is in room|baseball|
As you can see, we have a user named John who wants to create a new chat room called baseball. Once he presses create, we should be able to tell that he is in the room baseball. Once you have the code in there, save it, change the properties of the page to be a Test, and then run it. You should get something like:
So let’s get these to pass. Fire up Visual Studio, and create a new project called DoFixtureExample, and create it in location c:\. (I created mine as a Class Library). Next, add fit.dll and fitlibrary.dll to your references (FIT Library can be downloaded from the SourceForge). Now, create a class called ChatRoom.cs, and have it extend fit.DoFixture. Finally, compile your project.
Now that we have our project shell built, let’s get it added to our Fitnesse fixture. Go back to your DoFixtureExample test, and add a path reference to your new project’s DLL:
!path C:\DoFixtureExample\bin\Debug\DoFixtureExample.dll
We also need to tell our test what is going on. Before, we would preface the tables with the name of our Fixture class. But since DoFixtures are a series of steps that apply to the same group of objects, we need to tell Fitnesse what to use. We do that by “Starting” our application. So, edit your Fitnesse test and add the following after your path and other declarations, but before your first test:
|!-DoFixtureExample.ChatRoom-!|
So, your fixture should now look like:
and running it gives us errors like:
fit.exception.FitFailureException: Unknown method: userentersusernameof with 1 argument(s).
at fit.Method.FindFirst(Object[] theTargets, String theMethodName, Int32 theParameterCount)
at fit.FlowFixtureBase.FindMethod(CellRange theCells)
at fit.FlowFixtureBase.FindRowMethod(Parse theRow)
at fit.FlowFixtureBase.DoRows(Parse theRows)
So, now we know that our Fixture is talking to our code, but not finding the methods. So, let’s create methods for each fixture. In your ChatRoom.cs, add the following methods:
public void userEntersUsernameOf(string username)
{
}
public void userEntersRoomNameOf(string roomName)
{
}
public void userPresses(string button)
{
}
public void userIsInRoom(string user, string room)
{
}
Now, compile and run your test. All of your tables should stay gray. For now, that means success! Your fixture is talking to all of your methods – they just aren’t doing anything. So let’s make them do something. For our contrived example, let’s have the username go into a hashtable with the room name as the key. When we find out if a user is in that room, we’ll simply look up the username with the room name.
To do this, we’ll add a Hashtable, getting a new instance in the constructor, and modify our methods to use this. Your code should look like:
using System;
using System.Collections;
namespace DoFixtureExample
{
///
/// Summary description for ChatRoom.
///
public class ChatRoom : fit.DoFixture
{
private Hashtable roomList;
private string user;
private string room;
public ChatRoom()
{
roomList = new Hashtable();
}
public void userEntersUsernameOf(string username)
{
user = username;
}
public void userEntersRoomNameOf(string roomName)
{
room = roomName;
}
public void userPresses(string button)
{
if(button.Equals("Create"))
{
roomList.Add(room, user);
}
}
public void userIsInRoom(string user, string room)
{
if(theUserIsInTheRoom(user, room))
{
}
}
private bool theUserIsInTheRoom(string user, string room)
{
if(roomList.ContainsKey(room))
{
string roomsUser = (string)roomList[room];
return roomsUser.Equals(user);
}
return false;
}
}
}
We now have a problem. if the user is in the room, we want to turn the table green. If they aren’t, we want to make it red. Normally we’d do that through using this.Right() and this.Wrong(), but both of those need access to the Parse, which we don’t seem to have. Luckily, getting the Parse is pretty straightforward – we just need to override a method so we have access to it. So we’ll add the following to our ChatRoom.cs:
using fit;
private fit.Parse currentParse;
protected override System.Collections.IEnumerable MethodCells(CellRange theCells)
{
currentParse = theCells.Cells;
return base.MethodCells(theCells);
}
Next, we’ll modify our userIsInRoom method to look like:
public void userIsInRoom(string user, string room)
{
if(theUserIsInTheRoom(user, room))
{
this.Right(currentParse);
return;
}
this.Wrong(currentParse, "User was not found in the room");
}
Compile and run your test. It’s Green! Congratulations!
In our next segment, we’ll go over a different way to test the users in a room by embedding fixtures inside our code, and go into some more advanced features of the DoFixture. Enjoy!
Monday night’s talk at the Mid-MO XP User’s Group on Fitnesse and .NET was a great time. Some good questions and discussions came out of it. For those who were there, or those who weren’t and want to see it, I’ve put the presentation and code examples online. (Edit: I put the Fitnesse files below as well. Drop them in your $FitnesseInstall/FitnesseRoot directory. I also fixed the BusinessRules project download link)
One of the great things about Extreme Programming is that the customers get to decide exactly how to spend their money. We as developers work with our customers to create a set of stories, prioritize them according to the business need, and then go to work, getting constant feedback and course corrections as we go.
One problem I’ve seen lately is that our customers have correlated units to time, and so they do things like put a pair on a project for a day, and then perhaps not authorize a pair for the project again for another few days.
The problem, of course, is that each time a pair comes back to a project that is on hold, they have to ramp back up to the tasks, figure out where they were, and generally try to get back into the flow. This constant flux for projects can lead to longer time to release, but it also can lead to more mistakes being introduced.
Today, I was flipping through CNN.com and stumbled on a real life example of this very thing. Here’s the quote:
One explanation for the accidents may be that workers have been out of the rhythm of preparing for [releases], since there has been only a single [release] since…early 2003, Parsons said.
“I think anytime you have big gaps in between doing something…you are always concerned that you’ve lost a little bit of your edge,” Parsons said.
Who’s Parsons? He’s Bill Parsons, Deputy Director of the Kennedy Space Center, talking about the string of accidents that has plagued them over the past few months. The [release] brackets replaced “shuttle launches” from the quote. Luckily we aren’t doing anything quite as high profile as that, though millions of users would see the effects of our mistakes.
So how do you manage your customers to prevent this from happening? In the case of KSC, they can’t release anything else, so they are stuck with the gap. But in software projects, one has to be very careful not to count towards velocity any project that wasn’t delivered during the iteration with running, tested features that delivered value to the customer. This also includes bugs, meetings, research, and other activities that aren’t providing real value for your customer.
Of course, sometimes you as developers have to just tell your customer that you just need to work on a project in whole pieces, and the business value why. In our case, it was causing a higher bug rate and slower adoption for several projects, and by serializing them they were able to get them all finished and released. Our customer listened, and understood, where he didn’t before.
I don’t know how to help NASA and the KSC, but hopefully you have an environment where you can help you and your customer from making mistakes just because of parallel development.
I’ve been invited by the Mid-Missouri XP User’s Group to give a talk this Monday, April 10th on Fitnesse and .NET in Columbia, MO. We’ll be starting right at 6pm, and it should be a good time. Get all the details and RSVP info in Gary’s message.
Ed Gibbs has two great posts with quotes from Bob Martin. In the first, Bob compares TDD to Dual-Entry Bookkeeping:
One common issue I have found is that developers drop the discipline of TDD in the face of schedule pressure. “We don’t have time to write tests” I hear them say. Before I comment on the absurdity of this attitude, let me draw the parallel. Can you imagine an accounting department dropping dual entry bookkeeping because they’ve got to close the books on time? Even before SARBOX such a decision would be such a huge violation of professional ethics as to be unconscionable. No accountant who respected his profession, or himself, would drop the controls in order to make a date.
– Bob Martin
In the second, he eyed Bob wearing a Green Rubber Band:
I wear a green band on that I put on about six months ago. This band is a statement of professional ethics. The band signifies that I unit test my code and I know it works.
– Bob Martin SD West 2006
Even without Bob Martin quotes, Ed’s got a great blog, and I am subscribed now!
The thing about being in the midwest is that everyone cares a *lot* about basketball. I more of a baseball or football guy myself, but since I have to hear all the time about basketball: Yay, Florida! for winning the 2006 NCAA championship last night.
An annoying – and silent – thing happened today. I was working on one Rails site, and switched to work on a second one. I fired up the WEBrick server, went to my site, and got…nothing but a blank page.
Looking at the server logs, it was clearly having a 500 error of some sort, but there was nothing to tell me one way or the other what was going on. My development log looked clean (it was, in fact, empty), and I was quite baffled.
A little bit of Googling got me to this great Gotcha’s page on the RubyOnRails wiki:
App Silently Failing (HTTP 500 Errors)
Getting no errors but nothing is loading?
Try clearing the session cookie for the host (0.0.0.0 in most cases).
Make sure the sessions table exists (rake create_sessions_table) if you are using ActiveRecord for the sessions store.
If your app is not using AR for sessions, try removing the sess_ files from your temp directory.
In other words, if you don’t either close your browser, or delete the localhost cookie, Rails won’t be able to understand the session information you are handing to it, and will just silently die with a 500 error in the logs.