The tests all run. Were nearly theremaybe even there. Close enough, anyway, to reflect on our main concern: would some kind of up-front planning, some big design decisions at the very beginning, have made this job easier? We have run into a number of interesting problems, so we need to reflect carefully . It would have been perfect for my story had we encountered no problems at all, but that didnt happen. Lets first look at the big picture of the implementation and then at the problems we encountered .
Even the detailed flow of the implementation is pretty simple:
First we think. We thought a bit about what would work, and whether we could get away with saving the whole file on every keystroke. We decided that it might work. We surely would have needed to think first, no matter how much thinking we had already done.
Simple snapshot. We did a single-level Snapshot and Restore. This got us started and showed that the concept was viable . No wasted time here.
Move to stack. In a few short steps, we had a Stack implementation in the model. Just what we need, and a very elegant structure. No waste here.
Experiment for viability. We did a quick experiment where we stacked on every character, just to see whether performance would kill us. We didnt die. No waste here.
Weird character things. Experimenting with the Undo side, we ran into trouble with the TextBoxs handling of characters and with repeating keys that were held down. Once we recognized the problem, we fixed it with a simple guard clause. At this point we had Undo basically working. It was time to build it in. This was tricky but would have occurred in any case.
Build an end-to-end test. We decided to use the customer test style to build a test. To do this, we needed to add a couple of new features to the framework. We would have to do this for Undo, no matter how prepared we were for it.
Put snapshot calls in. We began with three or four calls to Snapshot() in a few different Insert methods . We noticed the duplication immediately, of course, since we were typing it it. Might we have avoided typing these three lines by more up-front design early in the project? Frankly I doubt it, but even if so, how much would you pay to avoid typing and later deleting three lines?
Removing the experiments. I wasted a tiny bit of time removing the experiments: it would perhaps have made more sense to revert the code, but I didnt think of it. Not likely that more design weeks ago would have solved that problem.
Remove the duplicates. The duplication of the Snapshot() calls was irritating , and we found nearly the right place for a single call: in the keyboard handler. If we had started end to end, we might have done this initially. Perhaps we would have saved typing and deleting those three lines by starting with a Customer Acceptance Test instead of our experiment, but frankly we didnt have the courage to commit this approach without trying it.
Keyboard problems. We went into a bit of a debugging frenzy handling the keyboard issues. This is certainly evidence that we dont know everything we would like to, but it wasnt due to a design problem, just to solid ignorance about how the TextBox really works. It did go on for too long, but I dont see, even now, how we could have designed more. We just had to learn things about running and testing the system without opening the GUI.
System works; test does not. We were in that odd state where the Undo was working fine, but the tests didnt work. It was tempting to let it be, but that would have left us with untested code in a critical area. Better to go on and get the character push to work. That was tricky, but nothing to do with Undo.
Negative one in cursor line. This took us a bit of time, and there can be no doubt that it is a design issue. But its not a design issue related to Undo; rather, its a hack that has been with us for a while. It is fundamentally due to the interface between the TextBox and the TextModel, and the TextBoxs insistence on handing out a value that it cant take back. Irritating, but not entirely our fault. Im inclined to put it on the list to clean up just because the code is a bit tricky.