Nothing beats pair programming when the heat is on and you have a critical bug to fix. Earlier today, when regression testing an application after fixing a concurrency bug, I discovered an edge-case error in the communication between two systems. Component A was dependent of some customer data from component B, but for certain customers some of the data was not returned causing component B to mistakingly place order on products already possessed by the customer. I paired up with my good colleague Andreas to solve the problem together….
Reproducing the error
We decided that we needed to reproduce the error, just to make sure this wasn’t a one-off. Taking our time, we managed to re-produce and establish the circumstances where this error occurred. Being the most heavily used service in our infrastructure, we wanted to make sure that we got the fix right. Luckily, the service had pretty good test coverage.
Fixing the error
We quickly identified the problem and decided on a strategy. The problem was that for a specific set of products, configured features were not set. It turned out that we had the code already, but where it was now meant we couldn’t reuse it. We could easily copy the code into the class we needed to use it, but that would clearly leave some duplication in our code.
This is where pair programming really starts to pay off. When you’re two, the chances of ending up on a poor solution like code duplication is severely decreased.
After studying the code we decided that the correct thing to do was to extract the methods we wanted to use into a separate class. In fact, it turned out that the code we wanted to extract really didn’t belong in the class it was currently located. So from being in a situation where we could potentially clutter up the code, we were now in a situation were we could improve it. Perfect.
We located the unit tests covering the classes we wanted to re-factor (remember: never fix a bug without a failing test). We then went on to:
- Extract the methods we would like to use out into a separate class. Re-run tests, still green.
- Write a failing test exposing the error to fix. Red bar
- Add the production code to make the test pass. Re-run test. Green bar
When finished we had added one line of production code to fix the error! In addition, we had improved the existing code. Not bad! Next step: Pair testing of the interaction between the two components.
Testing the bug fix
Having tested the bug fix in a component test we felt relatively confident that this fix was it. But surely we were disappointed. The component consuming the data still produced an error. Nothing we could do but to register an error in bug tracking system. As we were trying to formulate the error precisely, we suddenly realized that the component could be fetching cached data from the cache. Rightly so! Refreshing the data did the trick and we could end the day on a high.
This is an interesting observation. The fact that we were two people, taking care to formulate a good description of the error, helped us identify that we probably were experiencing a caching problem in our environment. No need to register the error after all. Would I have come to the same conclusion if alone? Probably not.
Key takeaway points
- Pair programming is a great way to work, especially when solving complex problems and when you’re feeling the pressure to deliver
- Always write a failing test before fixing a defect
- When registering defect, take pride in providing a good description of it and giving as much context as possible. You will make the job easier for the person trying to fix it.