Understanding the value in automated testing
December 22, 2016
Work has been really interesting lately because the grand list of features has been nearing completion. Not that our product is really ever done due to the nature of the beast, but a lot of the big features we wanted have been mostly completed. Since we’re a startup, we were happy to build up a lot of technical debt in order to optimize the time to market. Just like any other software engineer, I have an eternal itch to refactor, to optimize, and to just make the code better.
I mainly work on our Android app, and there’s Android libraries that I really want to try. Uber just recently published a blog post about a rearchitecture of their mobile apps. They mention an architecture that I’ve never even heard of, and my first impression is that I need to make our Android app follow these conventions. It sounds really impressive.
Firstly, this is a waste of my time right now. A grand rewrite provides our users almost no benefit. The engineering argument that I have is that it would provide them a better experience because the app might be smoother performing. In reality, users don’t care about what architecture you use, what libraries you use, what your coding philosophies are, etc. But these topics are for another time.
I recently purchased the master package of The Effective Engineer. While I can’t recommend you spend the amount of money that I had to, the book and accompanying interviews were very informational about truly leveraging your abilities as a software engineer and a problem solver. One of the concepts that Edmond talks about is how programmer tools can really help you become the most productive and impactful engineers that you can be. One of the tools in the arsenal of a Software Engineer is automated testing, combined with continuous integration and continuous deployment.
Automated testing gives you a safety harness to write as much code as you can while ensuring that your code stays correct. It’s very difficult to verify that code does exactly what you expect it to. This is especially true in multithreaded and concurrent systems. When working on large bodies of code, it’s very difficult to keep all of the working parts in your mental model. Your brain’s cache just isn’t large enough to remember everything.
A big concept of writing clean and effective code is to have repetition be minimized. You don’t want to copy paste the same code in multiple places, because this is innefficient and leads to problems when trying to modify the code, let alone other problems. A solution to this of course is to abstract away complexity and redundancy into a nice and contextually aware interface. One of the problems with doing so is that you start to introduce dependencies within your code. Code relies on other code, and everything becomes intertwined. If you work on the code within an abstraction, the other code using said abstractions might now have incorrect assumptions.
Take the story from my previous blog post. My intention was to add a new feature, and I modified very little of the existing code, yet I still rendered a product useless. In this case, although I was adding code, I still broke things. Imagine what might happen if you change the code lower down in the abstraction tree. Having an automated test suite with a reasonable amount of code coverage could have prevented that. Automated testing is the harness that allows you to rampage forward without needing to be so aware of all of the other parts of code that you might be affecting. If you think you might affect something negatively, you just run all of the tests. Continuous integration amplifies that productivity further because now you don’t even need to think about running the tests. When you push a change, the tests are run for you and if code you wrote broke something, you’ll be notified immediately.
Having a good suite of automated tests really helps you become a highly impactful engineer because you won’t be hesitant in the same way other teams might be. Writing tests is a wonderful way to pay back all of that technical debt, because trust me, when you’re refactoring some of the gross code away, you’re bound to find that you’ve broken something. With features slowly coming to an equilibrium, I’ve shifted to increase my focus on writing automated tests because it keeps me happy, it keeps me sane, and it keeps me effective.
Thanks for reading.