This book is new. If you'd like to go through it, then join the Learn Code Forum to get help while you attempt it. I'm also looking for feedback on the difficulty of the projects. If you don't like public forums, then email firstname.lastname@example.org to talk privately.
Exercise 27: tr
This exercise is continuing the study of doing TDD (aka Test First) style development. It's important to know how to do this kind of programming since it is used in many places, but as mentioned before it does have its limitations. You'll be doing one more exercise using TDD while implementing the tr command. Be very sure that you are being strict about writing your test first, then the code, then audit both.
In the previous exercise I told you to build your test case and your code incrementally. This is usually the least error prone method of development, but it doesn't help you get better at analyzing your own code. In this exercise you're going to do things slightly differently as I'll have you write a whole test case, audit it, then write the whole code, audit it, and confirm your audit by running the tests.
That means in this exercise your process is this:
- TDD a test case, attempting to write most of it.
- Audit the test case and confirm it is written correctly.
- Run the tests to ensure they fail, but look for any syntax errors. You should not have syntax errors at this point.
- Write the code for the test case, but do not run the test.
- Audit your code, and try to see how many defects you find before you run your test.
You'll be using this procedure in the next exercise to track metrics on your auditing skills, your testing skills, and to be more controlled in how you write code.
The tr tool is a useful way to translate character streams. Despite being very simple it can do some very complex things to characters. For example, you can use tr to get a frequency of words used in your history with one line:
history | tr -cs A-Za-z '\n' | tr A-Z a-z | sort | uniq -c | sort -rn
Seems amazing, but this one line was used by Doug McIlroy to contend that a similar program written by Donald Knuth was much too involved and long. Knuth's implementation was "10 pages" and constructed everything from scratch. Doug's single line just uses standard Unix tools to do the same thing. This demonstrates the power of both the Unix use of piped discrete tools and tr's capability to translate text.
Use the man page and anything else you can to figure out what the tr command does. There is also a Python project by the same name, but I'll tell you to avoid that until you've done your implementation so you can compare this project with it later. Also don't forget that you'll need a whole project for this, and it should have the tests done TDD style as I've described in the beginning.
A Criticism of 45 Minute Blocks
I want you to continue to use 45 minute blocks of time, but there is one significant criticism of this way of working: you can't get into extended concentration flow. Working in short blocks of time like this helps when you need to grind through a large amount of work and must pace yourself. This happens when the work is really boring and not fun. I'm having you use 45 minute blocks just to pace yourself, but we'll also be using them later to gather metrics about how you work in the blocks for later analysis.
But I'll caution you that the very best programming is done in the zone, the flow, the groove. It's where you are sunk deep into concentration for hours at a time and lose all track of time until you look up at 5am and realize you were up all night. This kind of intense concentration is what makes programming very enjoyable for me, but it's really only sustainable when you are very interested in what you're doing. When you need to work on someone else's terrible code base, the zone tends to just not happen. In those cases you need a different strategy that paces your work and chips away at it without grinding you down. That's what the 45 minute blocks are for.
Finally, one way to build your ability to get in the zone and concentrate for hours is to start with a few short little blocks of time, then slowly increase them until you can do it for longer periods of time. Keep doing 45 minute blocks, but if you simply forget yourself and end up hacking for hours on end, enjoy yourself. Nobody will say you did this wrong. That's actually normal.
- How did this way of working feel? Do you prefer it or not? Try to articulate why, then read some of the current writings on TDD or it's cousin Behavior Driven Development (BDD).
- Do you think you found more or fewer defects by working in a way that required auditing your own code first rather than building it incrementally? Make a guess and then write it down.