Thursday, May 31, 2007

But how could a test drive design??

Good question, I'm glad you asked...

Actually, I asked myself during my long a** commute, which gave me a lot of time to reflect.

The weird thing about TDD is that there is no design.

You don't design tests. You write them, one at a time.

This is something that makes TDD difficult. Even after I understood the basics, it was still a challenge to stay with it. I had to stop thinking about how to solve the problem and focus only on how to test the solution.

It's not that I don't think about designs at all, but I'll only design up until the point I know I'll be able to start my first test. This design is focused on high level interactions and the goals of my solution.

When the TDD light bulb went off above my head, my thinking changed to this:
What can I do to make this test as easy as possible to write?

Thats it. Kinda lame looking at it now, but really, thats it. When I focused on testing and that alone, that's all that remained.

If you have difficulty dispelling design noise, pretend you are Harry Potter and have your very own pensieve (that would be pretty cool, no?). Put the thoughts in the pensive. They will be there when you have the focus they deserve (In real life this works well with index cards)

Unless it is a new user story, I throw it out. I don't worry about it, because if I need it, it will happen.

But what if I forget? Are my user stories satisfied? Are my acceptance tests passing? I guess I don't need it.

But I need to refactor my code! Well, I should be doing this all the time! If I didn't have a chance for whatever reason, next time I am in the test, it will be so painful, I'll refactor. I trust myself and my team. When this happens a lot, I need to think about what done means (this is another topic)

How do I make tests easier to write?

When I can't make a test without getting frustrated or overwhelmed with what-ifs or setups, I introduce a mock and encapsulate the behavior. Using that mock just made my life a whole lot easier.

Did I just drive the creation of a new interface? Is there a new interaction that didn't exist because it was the easiest thing? Will my class be more simple because its not doing something too complicated? Will the new class be cohesive because it was created for a specific purpose?

Wow, not only am I creating a new design as I go, but all other things happen because I'm trying to make my life easier.

Anyone else see the beauty here?

Or the power?

When I have a very complicated problem, I break it up organically by test driving. Each part not only makes sense, but is easier to implement because I am able to focus on small pieces. I have instant gratification that each worked on its own, as it was created, without any integration.

Sweet bonus, the solution doesn't do anything extra and I didn't go on any tangents because I didn't want to write extra tests.

Extra sweet -- I spoke to coworkers, took a lunch break, wrote a blog post and had NO fear my momentum or focus would be lost.

Writing tests is more difficult than writing code, but when I focus on making my tests as easy as possible to write, it keeps me in the test, drives my design and simplifies my thinking.

7 comments:

Udi Dahan - The Software Simplist said...

I sometimes describe the process this way:

"One way I'd know if I was done writing the code would be if this 'test' passed."

Then just Red, Green, Refactor.

Finish it off with some Single-Responsibility Principle, and Dependency-Inversion Principle.

Simple.

Not easy.

wunda said...

Udi,
Its funny you mention single-responsibility and dependency inversion. I really wanted to include those (and had) since they are so closely related, but decided to save them for another day :)

Charles Dexter Ward said...

When I first had to learn Prolog, I was told to think about 'what I needed to do' and not 'now to do it.' TDD seems to be much the same in that you have to focus on 'testing the solution' and not on 'now to write it.'

Do you think that we, as developers, have been taught and trained to think like our computers? And, do our tools and languages affect the way we think?

wunda said...

CDW -- What do you mean by "taught and trained to think like our computers?"

As for the second question, definitely. A person with different tools will come up with unique solutions to the same problem -- they will have to approach the problem differently based on the tools they have, not just their mind. Also, when we are given new tools and languages, we are able to be creative in new ways -- ways most wouldn't have imagined without the tools or languages. I don't think this is unique to software.

At the same time, when we become dependent and attached, our creativity may be hindered by our inability to adapt to other tools, languages, people and needs.

Charles Dexter Ward said...

I think, when given a problem to solve, most developers jump into the mindset of “if” statements, “for” loops, objects and classes. These are all low level constructs (okay, I guess OO isn't a low level construct, but it is something that really exists only within the machine). All of these tasks are telling the processor how to go about the task you need to accomplish.

What you seem to be saying, and please correct me if I'm wrong, is that to do TDD you need to almost pretend that some helpful soul has handed you the solution up front and all you're doing is validating/testing it. So you’re not thinking about telling the computer how to do something, since someone has kindly done that for you, you’re only focused on testing what the functionality does. Focussing on the end result as apposed to the process. So it would appear to be a more top down approach then most developers are use to.

wunda said...

CDW,

I agree, developers can get stuck on solving small problems of larger solutions, especially if they don't have strong OO skills to abstract these problems.

Your insight about using your imagination to assume the solution already exists is interesting and I like it. There are aspects in the implementation of TDD that don't fit this paradigm, but you're not talking about learning how to write test first, you're talking about changing the way people think, so I don't think technical details are a priority :)

sea said...

very nice blog :)