I thought I'd start blogging about something I think I'm pretty decent at - programming. Yeah, yeah, I know, everybody thinks they are the best programmer, but I think I have some decent stuff to share. I wanted to start with programming tips. I'll try one tip per blog entry.
The first tip is coding by intention. The first time I learned of this was in college. I was reviewing some code with a professor of mine, Dave Binkley of Loyola College. We were reviewing a long method of mine and Professor Binkley said something equivalent to, “I like to extract a method here to make it more clear what I’m doing.” The light came on. I learned that programming was more than just a science, but an art. This was back in the early 90s, before the Extreme Programming/Agile folks coined terms like “extract method”, “refactor”, and “code by intention”.
Now, I'm a big fan of Test-Driven Development (TDD). Since I've got to write a test first, I start there. The real code doesn't exist yet. The intent part starts here. I think, "I've got this piece of functionality to implement. What would I call if I could write anything? What would the method name be and its arguments? How would I call this functionality as a client so that what I'm doing is crystal clear? The world is my oyster."
Coding by intention from the point of view of the test is pretty obvious. What I wanted to emphasize in this blog entry is to continue coding by intention all the way through until you've completely implemented everything. So after you've created a new call in the test, you start implementing it. It'll most likely be a public method. When you're implementing this, you continue coding by intention. You could just crank out a possibly long method to get the functionality implemented, but that's not what I'm talking about – that’s what I did in the early days of college. The public method now becomes like another client. You code by intention here, asking yourself what you would call if what you needed already existed. You keep doing this with every method you need to implement, creating lots of small, but communicative and easy to understand methods. Eventually, you'll get to a level where the implementation is small and simple and you're done. What you've done is created some possibly reusable and very easy to maintain methods along the way.
It’s time for an example. Suppose I’m working with the usual Order/Line Items web site shopping example. One coding by intention technique I use when I need to process a collection like LineItems looks like this:
public void processLineItems(List lineItems) {
Iterator it = lineItems.iterator();
while (it.hasNext()) {
process((LineItem) it.next());
}
}
Instead of writing all the code in the while loop to process an item, I code by intention, pretending that the process(LineItem) method already exists.
Here’s another, albeit obviously contrived example. Suppose I’m working on Goldilocks’ Porridge class and need to implement the isJustRight() method. Right now I just have:
public class Porridge {
private double currentTemperature = 0.0;
public Porridge(double currentTemperature) {
this.currentTemperature = currentTemperature;
}
}
To implement isJustRight(), in coding by intention style, I would do:
public boolean isJustRight() {
return (notTooHot() && notTooCold());
}
So why code by intention? There are several reasons I can think of off the bat. The first is, as I’ve stated above, you end up creating small, possibly reusable methods. My first tip was going to be “create small methods”, but I realized that coding by intention drives that. In my next entry, I’ll go into more detail on why I think creating small methods is really important. There’s a process to crafting elegant software and this is the first step.
Another reason is that the top level methods become really easy to understand.
They describe the algorithm in almost pseudo-code level. They communicate your intent of what you’re trying to accomplish step by step.
Yet another reason is that it is sometimes hard to get started on a task and by coding by intention you are delaying all the details, but still getting things done. That is, not everything you need is available, but you’re coding like it is. You’re working top down, drilling down into the details level by level until your done, making progress along the way.
Now, if you’re doing true TDD, you are writing just enough test to get a failing test, and just enough code to pass that test. Remember, compiler errors count as failures. I’m a little lenient on this practice. I like writing an entire test method for one test case scenario before going to the code. So in the isJustRight() method above, I’d first write a complete test method for a Porridge object that is too cold with all its calls and assertions. Then, I’d write just enough code to get the test to pass, but still coding by intention in the Porridge class. So, in this case, the isJustRight() method would just call notTooCold() for now.
I suppose if you truly wanted to follow TDD, and in particular, get a passing test as fast as you could, you could just write the code in isJustRight(), then extract a notTooCold() method. Just remember to do this. Sometimes, we as programmers get a little lazy. Still, I favor coding by intention top down from the beginning.
Well, that’s it for my first blog. Hope you enjoyed.
No comments:
Post a Comment