Discover more from Software Design: Tidy First?
Coding in the Debugger
Originally published September, 2007
In-situ coding extends test-driven development (TDD) by letting you code in the presence of real data. Here’s a cheap implementation in Eclipse. From a test, Eclipse helps you create stub methods. Changing two settings in Eclipse allows you to code with real data with a minimum of keystrokes.
Change the method body template to throw an UnsupportedOperationException and set a breakpoint on all UnsupportedOperationExceptions. When TDD-ing as usual (generating stub methods from tests), run the tests with debugging turned on and you will quickly be able to code in the debugger with all the details of the test fixture visible.
Test-driven development (TDD) reverses the traditional flow of programming work. In TDD, the developer starts by writing an automated test that will only be satisfied when the as-yet-imaginary code is written correctly. Each test is a microscopic analysis and design document. From the design information in the test—the names of types and operations—a good development environment can help the developer quickly generate stub implementations.
One of the advantages of the TDD cycle is that filling in the implementation is easier once you have figured out a test. Some of the many variables developers juggle as they work are, at least temporarily, fixed when the test is written. While filling in the code, the developer no longer has to worry about choosing the method signature or checking the results for correctness. The test specifies that information. When writing a test-driven method, the developer can focus on designing the internal logic.
Even with TDD, writing code requires considerable mental effort. The developer has to hold in their mind the fixture created in the test in order to write correct code. If the fixture is complicated and the logic is complicated, this can still be too much to effectively juggle at once. In-situ coding, where the developer writes code while looking at real data, reduces the need to mentally hold so much information.
Early dynamic programming environments like LISP and Smalltalk supported programming in the debugger. Java and similar pessimistic languages refuse to even attempt to execute programs until the compiler is convinced that they are correct, making such debugger-based programming impossible. However, advances in programming environments for Java have made programming in the debugger possible, coinciding nicely with the limitations of TDD that make in-situ coding attractive.
In implementing in-situ coding, one goal is to reduce the number of information-less keystrokes. Keeping the developer focused on the task of programming instead of the operation of the programming environment results in more efficient coding. Eclipse provides settings that allow the developer to shift from test-writing to in-situ coding with a single keystroke.
First, in the global preferences change the method template used when generating method stubs to throw an UnsupportedOperationException. I chose this exception because it is unlikely to be thrown during normal operation and it is part of the standard runtime environment. If you wanted to be sure of not getting any false alarms, you could use your own InsertCodeHereException instead.
Next, in the debug perspective set a breakpoint on all thrown UnsupportedOperationExceptions:
Now use the usual TDD process: write a test and generate stub types and methods. When the test compiles, you can begin in-situ coding by running the test with debugging on. The keyboard shortcut for this is alt-shift-D, T, but you can start in-situ coding for subsequent tests in the same test class by pressing F11.
Next you will see the stub method you need to fill in, but with an example of the context in which the real code will execute: fields, parameters, and the call stack:
With this context visible, the developer can focus on coding the needed logic instead of remembering the details of the test fixture. They can try little snippets of code using real data, accelerating the feedback loop for coding. Once the code is satisfactory, they can continue execution (F8) and immediately see if the code matched the test.
One of the advantages of this implementation of in-situ coding is that it doesn’t impose any overhead if the developer wants to fill in the code for a stub method without using the debugger. Control-clicking on the name of the method in the test navigates to the implementation where they can replace the throw statement with the real code.
In-situ coding is a way to manage the complexity of coding by reducing the demands on a developer’s short-term memory. Eclipse provides the necessary flexibility and configurability to implement it easily and efficiently.