The next day, before starting the day s effort, Chet and I did a quick retrospective of the last day s, um, experience. We drew a couple of additional lessons over those above.
We try always to write code that expresses our intention. (See, for example, the Test First, by Intention chapter in Extreme Programming Installed [Addison- Wesley, 2001].) Good code has methods with names that reveal their intention. And a good method that does two things procedurally needs to be refactored, using Extract Method, to express what those things are.
When we program, we all generally have some intention in mind: First, I ll scan through all the files, looking for the ones that are updated. Then I ll make copies of those. When programming by intention, we make ourselves aware of these intentions as they come to us. Sometimes we then immediately write, first, a few lines of code to get the files and then a few more to make the copies. When we do this, the code does not express our intention. Here s an example of some code, from our CustomerTest.cs, that doesn t express intention as well as it might:
private String[] ArrayToEnd(StringReader reader) {
ArrayList result = new ArrayList();
String line = reader.ReadLine();
while (line != null && line != "*end") {
result.Add(line.TrimEnd());
line = reader.ReadLine();
}
String[] answer = new String[result.Count]; result.CopyTo(answer);
return answer;
}
Let s figure out this code. First we build an ArrayList containing all the lines of the input StringReader, up to "*end" or the end of the reader. Then we allocate an array of Strings of the right size and copy the ArrayList into it. Then we return the array.
That code might be better if it looked something like this:
private String[] ArrayToEnd(StringReader reader) {
ArrayList result = ArrayListToEnd(reader);
return ArrayListToArray(result)
}
It might be even better with better names ”we could discuss that. In any case, we could argue that we should use Extract Method to refactor out those two methods, and Compose Method to create the new version of ArrayToEnd.
Programming by intention goes a step further than expressing intention after the fact. When we program by intention, we reflect on what we intend to do and we write the simple method first. If we know that we re going to create the array of strings by first creating an ArrayList and then copying it into an array of Strings, we say so. We write the short version of the method first, and then we write the two submethods .
Proceeding this way has a number of advantages. First, we don t have to remember so much. As soon as we know what we intend to do, we write it down. Then we just refine it until the code is there. Second, the code comes out well- factored without as much refactoring. We get better code, and it takes less time!
So why don t we do that all the time? We re not sure. We think it has to do with unfamiliarity with the language. We re so focused on how we might write legal statements in C#, and on which objects in C# might help us, that we forget to play our best game. Our first resolution is to return to programming by intention. Keep an eye on us, and see if we live up to our resolution.
I might not have mentioned it before, but we have a simple code manager that we use as we develop this application. It s written in Ruby, and all it does is this: whenever we type cm in a command window, all the files of the source directory are copied to an archive directory. The file foo.cs, if dated today at 3:47:21 PM, will be named foo.cs.20020821154721 in the archive. All we have to do is type cm once in a while, and all our code is backed up. Works well enough for most of what we do, which is typically small programs. We have a little restore function, of course, that copies all the files back, with their value as of some given time.
You re probably asking yourself, if they used this cm thing, why did they have to Ctrl+Z yesterday to get back to a safe point? Did they have six saved versions or only five? Well, to tell you the truth, in all the excitement, we lost count ourselves. We forgot to type cm at crucial points in the development, so we didn t have a good point to restore to, other than the beginning of the day.
That was today s second resolution: have more points to back up to. That will make it easier to back up when we make a mistake, and we ll be less encouraged to keep plunging on, deeper and deeper into the depths of coding depravity.