Archive

Posts Tagged ‘TDD’

Word Wrap Kata in Python

Last month at Dallas Hack Club, we did the Word Wrap Kata from Uncle Bob Martin’s “Clean Coder”. I got there a touch late and rapidly figured out that we were doing it in Ruby. Now, my Ruby skills are right up there with my Mandarin Chinese skills which is to say, I can’t even order a scotch or find the restroom so I quickly figured out that if I followed along, I’d be sitting in a puddle of pee wishing I was drunk. So I made the executive decision to ignore most everyone else and do it in parallel with the group but in Python since I can at least code like I’m drunk in Python.

My experience was surprisingly similar to the post linked above, e.g. I went down the hardest path trying to solve the wrong test. I’ve since gone back and deleted the code but the pseudocode went something like this:

Break text into a list using a list comprehension based on the length of the column
Start looking for words with spaces
Try to repiece things together based on the column length and the last space
Cry

Clearly, this wasn’t going to work. About that time, we ran out of time and went to the Flying Saucer to drink beer and pretend like we weren’t geeks. But I decided to finish the kata this week during a slow period at work. Since I didn’t have Jerry there to talk me through how dumb I was, I started reading the post up until the point where it describes writing the wrong test and spending too much time trying to solve it. So I backed up, deleted everything and started down the easier path of solving all the non-space related issues first. Once I did that, and once I figured out that recursion was going to be a big help, the project really got easier.

The final solution is below:

def wrap(text, num):

  if len(text) <= num:
    return text
  elif text[num-1] == ' ':
    return text[:num].rstrip() + '\r\n' + wrap(text[num:], num)
  elif text[:num].find(' ') > -1:
    rightSpaceIdx = text.rfind(' ')
    return text[:rightSpaceIdx] + '\r\n' + wrap(text[rightSpaceIdx:].lstrip(' '), num)
  else:
    return text[:num] + '\r\n' + wrap(text[num:].lstrip(), num)

It’s fascinating how quickly the algorithm starts to come together when you write the correct test. The problem is, I’m terrible at all this so it’s going to take some time getting enough experience to correctly select what test to write next. I was writing a ton of code trying to solve a problem that was too hard and the solution I eventually would have come up with would have been effective but brittle.

The more I do TDD/BDD, the more I realize that it is *THE* way to develop software, especially if you’re working in a dynamic language. I’m currently working through the tutorials at Ruby Tutorials and it’s great to see that TDD is a fundamental part of the process. As I learned Python and Pylons, it was up to me to figure out best practices it seemed like and that’s workable but frustrating in the long run. I’m planning on doing more katas in an effort to improve my craft.

Categories: Programming Tags: , ,

Pragmatic TDD

Tim Bray writes about when and how he does TDD. I think he’s exactly right when he talks about not doing TDD for green-field, beginning development. When I’m first writing a cut at a new project, I’ve got almost no idea what I’m doing. Doing TDD at this stage in the game is super expensive and really gets in the way of the exploration necessary for a new project. Having to rewrite my code as it evolves is expected but having to rewrite my code AND my tests because both were completely off base is pretty inefficient.

However, once things are pointed in the right direction, TDD is critical. It makes the incremental evolution of the software much safer, easier and efficient. Without the tests, iterating over your software is painful and liable to introduce bugs in code that was once working. TDD is at its best in the situation where the code, while not stable, is in a state of incremental evolution and not the general state of random upheaval that it is in the beginning of the project.

Like most things, pragmatism is useful. There are shades of gray around everything and saying that there is one true way makes no sense at all. TDD is useful as a tool but hammering every nail you see with it probably isn’t the best way to do things.

I’ve also started to see TDD as a tool to allow those of us who aren’t geniuses to actually produce good code. I’ve known a few true code geniuses in my career and like Picasso, their art tends to spring fully formed out of their heads. They may go back later and write tests around the code. However, they don’t need TDD to be good. For the rest of us, the incremental evolution that TDD supports and encourages helps us to write code that is functional and clean because we have to focus on the client of our software. Those of us who aren’t masters use TDD to fake it, to produce works of art that might not eventually hang on the walls of the Louvre but that make customers at art fairs all over the world reasonably happy.

Categories: Programming Tags: