Sander Hoogendorn

By Sander Hoogendoorn

March 2023

Upcoming events by this speaker:

Apr 21, 2023:
Designing, developing and deploying a Microservices Architecture

 

A glimmer of hope

In September 2003 I visited the friendly city of Arhus in Denmark to deliver a talk at the famous JAOO conference.  

At that time, JAOO was an established software development conference, with well-known speakers such as Martin Fowler, Kent Beck, Linda Rising, and Erich Gamma. And me.


When I arrived at the venue, a conference center on the edge of the city center, one of the organizers offered to give me a guided tour of the building. While we strolled through the center, she enthusiastically pointed out the major rooms where the conference would take place. Then all of a sudden, the organizer stopped at a wooden door in a small hallway. She opened the door respectfully and we looked in.

An ill-lit room with furniture stacked to the walls. “Do you know what happened in this room?” she asked me almost whisperingly. I shook my head. Of course, I had no idea. She continued mysteriously. “This is where during JAOO last year, Kent Beck and Erich Gamma conceptualized unit testing and conceived JUnit.”

Well, you could say that this my first introduction to unit testing.

The necessity of unit testing

The impact that JUnit had on the industry of software development was tremendous. It was the first viable unit testing framework out there. Consequently, people slowly started to adopt unit testing. Still, it took a long time to gain traction. Even today in 2022, when I ask audiences at keynotes or talks I do at conderences for a show of hands about who writes unit tests, many people still don’t raise their hands. And that’s a shame.

Not too long ago, I was coaching a development team that had come to a complete standstill. They didn’t dare to change another line of code, afraid that their five million lines codebase would break.

Not a single feature had been delivered to their clients in over ten months. When we investigated their codebase, we found a few unit tests, with an almost non-existing level of code coverage, high cyclomatic complexity, and many untested paths in the code. And even in this team, when I stressed the importance of solid unit testing for maintaining quality and speed of development, the developers stared at me with long faces and asked if writing all these tests was really, really necessary.

It is.

It does take time

To be totally honest, it took me quite some time to get convinced of the effects and benefits of unit testing and, further down the road, test-driven development.

For authors Kent Beck and Erich Gamma, the number one goal for creating JUnit was “to write a framework within which we have some glimmer of hope that developers will actually write tests.”

They built JUnit with already existing, familiar tools so that there was little new to learn. Plain Java. As they said: “It has to require no more work than absolutely necessary to write a new test.” Gamma and Beck made writing unit tests as simple as possible.

So why is it so hard to start writing unit tests?

From my own experience, despite the simplicity of the tooling, with Jest being my current poison to test my TypeScript and JavaScript code, one problem I think lies in the fact that writing unit tests still require skills and understanding.

It takes time to learn to write proper unit tests.

And time is something we are always short of in software development. There is constant pressure from stakeholders, managers, and product owners to add and improve features in our products. We never seem to have time available to work on the quality of our architecture and our code. Hence, we tend to skip writing unit tests.

For the long run

Another challenge is that the benefits of having good unit tests are reaped in the long run. It only appears to you when you have had a codebase under control for maybe six months to a year. The ease and confidence with which you can change and extend a fully tested codebase is a joy. But only after time.

People are not good at preparing for long term benefits. Not having unit tests is like smoking.

We all know smoking is bad for us. Nonetheless, people find it extremely hard to stop smoking. This is because the drawbacks of smoking are usually not felt until years later. With unit testing, this is quite similar.

Having unit tests for everything pays back in the long run. It pays back after six months when you notice you can change your code without pain. And it pays back after one year when you can still change that code almost effortlessly and without side effects. Even after multiple years, your code remains stable and has even become more robust than it ever was.

Unfortunately, too many people postpone writing unit tests until it’s (too) late, and the consequences of not having tested code have become big. Like with smoking.

Keeping your code healthy

And it becomes worse when you work with modern software architectures, such as microservices or serverless, where you usually do not have a single codebase, but rather work on a vast collection of small codebases.

With one of my recent clients, the total landscape consisted of around forty micro-applications, fifty microservices, and about the same number of serverless functions, each of which with its own codebases, pipelines, and infrastructure. In environments such as these, it becomes even more critical to keep your codebases in good health.

Not keeping such complex landscapes healthy quickly results in endless bug solving, creating workaround that no-one can remember the next day, a steep productivity decline, demotivated people who are only maintaining poor quality code instead of building new features. And eventually a full stop in an organization’s innovation.

Unit testing is essential in keeping your code healthy.

As an example, while I’m writing this article, my team and I are looking at a small, but a rather delicate change in the core library of my client’s platform. This library contains around fifteen hundred lines of code. Around thirty applications and microservices running in production depend on it hugely.

Without even giving it a second thought, we made the change; we ran the three-hundred-eighty-five unit tests on the library; we saw that these all turned green; and we checked in the code. No pipelines broke in the process.

Without proper unit testing, we would not have had the confidence or the guts to make a radical change such as this one. We would just let it slide. And we would just let it slide over and over again. Until we would not be able to guarantee the quality and maintainability of our codebases anymore. Just like I’ve seen at so many clients and with so many codebases before.

Stop postponing

My advice? Stop whining about the effort and time it takes to start writing unit tests. And stop complaining that writing unit test is boring. Get over it.

And even though unit testing might not seem to deliver on its promises immediately, it will benefit you massively in the long run. For sure. Don’t wait until your code becomes unmaintainable. Just like you can better stop smoking today than to wait for your package to be empty, or until the first of January of next year.

There is no excuse to postpone.

It is always better to start writing unit tests today. Actually? Stop reading now, start unit testing.