The recipes in previous chapters focus on writing code to do what you want. This chapter focuses on verifying that your code really works, and on fixing it when it breaks. We start off simple and move to more advanced debugging techniques.
What happens when your program has a bug? The best-case scenario is that you discover the bug before it affects anyone, including other developers. That’s the goal of unit tests (Recipe 17.7). Ruby and the Ruby community promote a philosophy of writing automated tests as (or even before) you write the corresponding functionality. At every stage of development, you know that your program works, and if you make a change that breaks something, you know about it immediately. These tests can replace much boring manual testing and bug hunting.
Suppose a bug slips past your tests, and you only discover it in production. How’s it going to manifest itself? If you’re lucky, you’ll see an exception: a notification from some piece of Ruby code that something is wrong.
Exceptions interrupt the normal flow of execution, and, if not handled, will crash the program. The good news is that they give you a place in the code to start debugging. It’s worse if a bug doesn’t cause an exception, because you’ll only notice its byproducts: corrupt data or even security violations. We show code for handling exceptions (Recipes 17.3 and 17.4) and for creating your own (Recipe 17.2).
Successful debugging means reproducing ...