Among the programming videos I've watched in the last few months there was a entire multi-day workshop given by Robert "Uncle Bob" Martin. He's an entertaining speaker. Of course, most of the presentation covered the topics he's been writing about for the last couple of decades, but the part that really caught my attention was his demonstration of the coding process for test-driven design.1 I'd like to take the idea for a test drive.
Now, I've been conscientiously adding testing to my personal process for years, and I've long included bug-report-as-test in my toolbox but I've never used the "write a failing test first" scheme that Uncle Bob demonstrated. I completely buy his claims that (a) you have to practice to learn how to do it and (b) you can't learn it on the job. I need an exercise.
Probably there are sample problems out there, but I've thought of one of my own: I'm going to write a bracket nesting validator. Moreover, I'm going to do it in stages as if I were refining an agile project. In all cases the program will accept a arbitrary number of files to process.2 The stages I intend are:3
- Work on a fixed set of bracket pairs (
()
,[]
, and{}
) and reports the filename of each file that has an error. The program will be silent by default on correct files. A report-on-correct switch is optional. - Expand the error report to include the line and column number at which the error was detected.
- Expand the error report to include the class of error (close doesn't match open, close with no open, reach end-of-file with one or more open brackets). Bad match reports should also include the line and column number of the non-matching open bracket; end-of-file reports should include the line and column numbers of the unmatched open bracket.
- Allow the user to specify arbitrary character pairs to be treated as open/close pairs (including canceling or overriding the default pairs). Attempting to specify a single character more than once represents a error and suitable diagnostic must be produced.
- Allow a single character (such as
'
or"
) to server as both open and close for a pair; note that these pairs can not nest without an intervening scope. That is'a'b'c'
has two single levels pairs not one pair inside another, but'a"b'c'd"e'
is three levels deep.
I haven't even set up a repository yet and I'm already struggling with the conflict between by habitual way of working and the Process-with-a-capital-P I'm suppose to be exploring. On the white-board in my home office is a sketched out scheme for five data structure that will collectively support at least version (4) of the spec which I started drawing automatically almost as soon as the idea occured to me. But I think I'm suppose to let most of that "just happen", aren't I?
Argh! This is going to be, uhm...fun?
1 I've also adopted his "Yeah! I'm a programer!" bit as pick-me-up for those days when even the little victories seem few and far between.
2 I'm intending to do a command-line tool, but there is nothing in here that requires it. Feel free to get that list of files from a file-picker widget and report in GUI list of some kind.
3 The professor in me feels obliged to note that there are even more basic versions of this exercise available. Notably:
- Perform the matching on exactly one kind of pair. This can be done without a stack.
- Just count that the number of open characters equals the number of close characters without caring about order.
However, I'm not going to bother with these variants unless the "do as little as you can" process happens to pass through one of them along the way.