I was looking for inspiration for my next blog topic and read through some of my old posts. I came across one called Confidence From Your Code that originally appeared on Femgineer in 2014. I thought: “Perfect! It’s been a few years since I wrote that, I now work with Corgibytes and have even more legacy code experience, I’ll update my thoughts.”
Turns out my thoughts haven’t changed much. Except that I agree with my former self even more, if that’s even possible.
The legacy world is pretty much the same as well. We still get asked the same questions we used to: Is that feature done? Has that bug been fixed? Usually from a product manager that has a timeline and needs things done. Don’t hate on them. It’s their job. Just like ours is to provide the end result and know that what’s been developed works!
But sometimes, we’re not so sure.
We’re lucky here. Andrea and Scott, our CEO and our CTO, respectively, always want what’s best for both the client AND the team members. They recognize that quality takes time. You may be fortunate as well and have a manager that pushes back for you to give you the time you need for development. If not, how do you manage these expectations? How do you go about gaining this confidence in yourself and the code? And what can you do to bring about change?
Start with focusing on small gains and what you have the most control over: the code you write.
One of the ways to gain confidence in your code is to test it. Often developers approach testing by placing debug statements in their code to make sure something works correctly. However, that is an ad hoc approach. It makes the code less readable, plus it doesn’t provide the reader (a future developer and maintainer of the code) any context!
Instead, you want to take a test-driven development approach. You start by writing the test cases, along with the conditions that need to be satisfied to pass the tests, before you write your code.
The benefit of this approach is that you can repeatedly run that test to know your code still works the way you expect it to. The lesser-known advantage is that when a bug shows up two-three weeks later (or longer), when you look at that code, you’ll have a basis for how it functions and can fix it quickly.
There are many approaches to test-driven development and many different ways to write your tests. In Pyramid of Tests, Scott took us through his process of introducing automated testing into an app where coverage needs to improve, and in Embracing the Red Bar: Safely Refactoring Tests, he explored the technique of refactoring against the red bar, and how you can employ this technique to confidently refactor your test code.
If you’re not sure where to start in terms of approach, I highly recommend you give those a read.
Applying It to Legacy Systems
A while back, I was tasked with adding a feature to a legacy Classic ASP site. I knew making changes was going to be difficult. With very little structure, and pages consisting of 1,000+ lines, introducing new code could easily cause things to break. That code was a proverbial house of cards. Realizing this, I decided that a small library would be helpful. But how would I write any tests?
In doing some research to test this new library, I came across the blog of someone who had done something similar. I decided to start with his code as a basis for testing.
The first few tests were just to validate that a method call would produce a certain set of HTML tags.
Then, I included some tests to handle both fetching and submitting data into the application’s database.
Once I had the pieces in place, I wrote some helper methods so inserting the code was as close to a single line as possible.
This code later went into production, and I considered all was well. But it wasn’t. About a month later, the senior developer pinged me to let me know there were two issues that had come up from the feature I had written.
After looking at the examples, I went straight to the tests. In both cases, I had not written a test for using this code in the way that was causing an issue in production. These tests were written (red), and then the functionality was implemented (green). I even got to refactor some of the duplication. All of this took only a few hours.
The final time there was an issue, I had it resolved in under an hour. All because I took the time to provide my future reader – in this case a slightly-older me – some context.
Taking a test-driven development approach saves you time, making you a more productive developer. And it improves your code quality and boosts your confidence as a coder. Who doesn’t want to be a better, more confident developer?