Thursday, February 17, 2005

Need Driven Development

In "Mock Roles, Not Objects" [1], Freeman, Pryce, Mackinnon, and Walnes say:

A core principle of Lean Development is that value should be pulled into existence from demand, rather than pushed from implementation: The effect of ‘pull’ is that production is not based on forecast; commitment is delayed until demand is present to indicate what the customer really wants.

This is the flow of programming with Mock Objects. By testing an object in isolation, the programmer is forced to consider an object’s interactions with its collaborators in the abstract, possibly before those collaborators exist. TDD with Mock Objects guides interface design by the services that an object requires, not just those it provides. This process results in a system of narrow interfaces each of which defines a role in an interaction between objects, rather than wide interfaces that describe all the features provided by a class. We call this approach Need-Driven Development.

I recently experienced the opposite of this approach. I had done some initial design, and come up with a list of classes and their responsibilities. I picked the most important class and started implementing it.

So how did I mess up?

You need to start at the edge of the system, from the external interfaces and work your way in. My "important class" was not nearly as important as I thought it was, and certainly was not more or less important than any of my other business objects.

When I finally got around to implementing my external interface, which was a messaging layer, I found that some of my earlier assumptions did not hold true. I had over-implemented some of the business objects. It is easy to fall into this trap with TDD, because you can implement your objects before anyone actually needs them.

If I were to do it over again, I would not forgo that initial design, because it certainly helped the process along, but I would always start my implementation with the classes that are closest to the business requirements.

[1] http://joe.truemesh.com/MockRoles.pdf

Tuesday, February 15, 2005

We’ll ship when the product is ready.

From the Internet Explorer team:

I’ve gotten questions about the ship date. Yes, we have a date in mind. I’ll talk about the date after we get feedback from customers and partners. We’re going to release a beta and listen, then refresh the beta and listen some more. We’ll ship when the product is ready.

This is a refreshing point of view, that you don't hear too often. I imagine that the IE team is under a certain amount of pressure, due to Firefox's increasing marketshare.

Monday, February 14, 2005

This is my brain in....

del.icio.us

You can map your del.icio.us tags with this handy tool.

Pilers vs. Fliers

This is a great posting about the importance of not letting your inbox pile up.

If Your Inbox Has More Than a Screenful of Messages In It, You’re Rude

I totally agree with Jason Clarke. My own system is to move every e-mail that I have read to a folder called "Read Mail". If I don't have the time to immediately respond, I hit the "Reply" button and save the reply in my "Drafts" folder. If I need to do some research before replying to the e-mail, I copy it to my "Tasks" folder which automatically creates a new Task.

Sunday, February 13, 2005

The Gates in Central Park


The Gates in Central Park
Originally uploaded by JohnDunne.
We took a walk on Central Park yesterday to view "The Gates."

Here is a satellite image of The Gates.

2/15/04 - Added satellite image.

Friday, February 11, 2005

Get Your Code Head On

Ever since I adopted test driven development, I have noticed a subtle shift in my development patterns.

Before TDD, I used to make a lot of effort to get into a "code head", a place where the code would just flow. To get there, I would eliminate all distractions and think about nothing but the code. Any lengthy interruption would set me back by an hour or two, because I needed to remember everything.

Now, I don't bother to remember anything. I maintain a to-do list of tests that I need to write, and I cycle continuously through "write test --> write code --> check-in". If I forget something, the tests tell me immediately.

This has meant a lot to my productivity as I get interrupted a lot. ;-)

2/12/05 - Updated wording.

Tuesday, February 08, 2005

Creating Abstractions

To properly write testable code, you need to be able to test your objects in isolation. In practice, this means that your objects must only depend on abstractions that can be easily stubbed out.

Wagging the Dog

How do you know what to pull out into an abstract interface? Let's look at an example.
class Dog
{
void bark();
void setOwner( PetOwner* o );
PetOwner* getOwner();
}
You might want to just abstract the whole thing, like this:
struct IDog
{
virtual void bark() = 0;
virtual void setOwner( PetOwner* o ) = 0;
virtual PetOwner* getOwner() = 0;
}
This is often referred to as the pimpl idiom , but it has some problems.

- It presupposes that all clients want to deal with a Dog, forcing clients to write different implementations for cats and parakeets.
- It is harder to mock, requiring you to mock the whole beast rather than the one part that you care about.

We have achieve physical isolation of the Dog code, but have not logically decoupled anything.

Consider Your Clients When Creating Abstractions

When you create an abstraction, remember that you are defining an interface between two units of code. You need to take into account both classes, rather than just one. Sometimes, this can be tricky, but fortunately, TDD helps us to learn what the needs of both classes are.

And we have some rules of thumb to guide us. When we create abstractions, we may want to consider abstracting capabilities and roles.

Capabilities

A capability is an interface that, you guessed it, denotes the ability to do something. By convention, capability class names end in "-able", like ISerializable or Serializable.

By pulling a capability into its own interface, you make it easy for clients to get only what want.
struct IBarkable
{
virtual void bark() = 0;
}
It makes it possible for me to write a re-useable client, that works with anything that barks, and not just dogs.

void makeThemAllBark( std::vector& barkers );

Roles

A role is an interface that has a meaning to a particular audience. The same object may fulfill many different roles.

In our Dog example, having an owner is not a quality which is intrinsic to dogs. You can pull that out and say that this is a quality of a pet.
struct IPet
{
virtual void setOwner( IPetOwner* o ) = 0;
virtual IPetOwner* getOwner() = 0;
}
You can add this interface to any class that needs to support "pet ownership" semantics. You might see an opportunity to create one standard pet implementation which you can mix-in to different animal classes.
class PetImpl
: public IPet
{
virtual void setOwner( IPetOwner* o );
virtual IPetOwner* getOwner();
}
The Abstract Dog

Our final class looks like this:
class Dog
: public IBarkable,
public IPet,
public PetImpl
{
// IBarkable
virtual void bark();

// IPet is implemented by PetImpl
}

Wednesday, February 02, 2005

Things to Say When You're Losing a Technical Argument

A useful list of ready made arguments, when you find yourself in one of "those" situations.

Things to Say When You're Losing a Technical Argument

How to Organize Your Blogs

When I first got into reading blogs, and the number of blogs to which I subscribed started to become unmanageable, I organized them by topic. This seems to be a pretty common method, as I see it whenever someone publishes their OPML file.

The problem with topic-based organization is that no one ever stays on topic, as proved by this very same posting to a blog entitled "Reflections on Programming."

Even if every blog did stay on topic, you are faced with a ever growing list of blogs where only some of them are truly important. By nature, you will be more interested in some topics than others. You wind up with 50 subscriptions under "Programming" and just one subscription under "Snow Boarding". You never miss a posting about "Snow Boarding", but you frequently skip Raymond Chen's latest posting, because it gets lost in the noise.

The solution is to organize your blogs, based on their relevance to you. I have three categories: "Must Read", "Should Read", and "Whenever". I meticulously read the stuff in the first category, while I only skim the stuff in the last category. As the blogs evolve, I move them up and down in the list. Sometimes, they fall off the bottom when I am no longer interested them.

Here are my subscriptions on bloglines: http://www.bloglines.com/public/JohnDunne

Note to bloggers: These are organized based on their relevance to me, and should not be construed as a judgment about the overall quality of your blog.

Note to RSS Reader authors: My ideal feed reader would allow me to view my blogs by both category and relevance.

Tuesday, February 01, 2005

TDD Meets GTD

In David Allen's "Getting Things Done" [1], tasks are organized in terms of Next Actions. A next action is the absolute next thing you need to do to advance towards a particular goal.

For example, a goal might be to organize your finances. The next action might be to balance your checkbook.

As you complete each next action, you figure out what comes next, and add it to your list. You organize your next actions in terms of the context in which they will be done. This might seem counter-intuitive, but it make sense when you think about it. If you have a big requirements meeting coming up, wouldn't you rather have a list of issues to discuss in the meeting in one place? Other forms of organization, like chronological or topical, fall apart, because there is no guarantee that the timing will work out the way you expect or that you will be able to remember the topics that you created from one day to the next.

In Test Driven Development [2], you constantly cycle between writing tests and implementing the functionality that they test. I find that I sometimes lose my place, and over implement a class, writing code that will never really be needed.

So I started maintaining a "test to-do list". Whenever I encounter a situation where I think I am going to need another test, I just add it to the list. This keeps me focussed on getting tests to pass. When I eventually get back to the to-do list, I sometimes find that I did not need that functionality at all.

Like GTD's Next Actions, I store my to-do list with the test suite itself, so whenever I turn my attention back to that suite, I have a list of outstanding issues.

[1] http://www.davidco.com/
[2] http://c2.com/cgi/wiki?TestDrivenDevelopment