Should I write tests? Two real life examples

a monster in the mirror
Source

I will have this problem, and you will too. At some point a project will not be your project anymore, but someone else’s. This person will look at your code and say a lot of bad things about you. And it’s very likely that this person will be you in the future.

So yes, you should start to write tests for your app now. There are a lot of “theoretical” articles on the internet that will explain you the benefits of doing it.

Instead I’ll tell two stories that happened to me. I hope they will help you resolve to start writing tests now.

Case 1: When I inherited my own code

Of course I wrote my first app without caring for tests. I was the only dev on the project, so why should I write tests? I know how MY app works. Of course I know it works, and in case it doesn’t, I will know how to fix it, right?

Wrong. Unless you abandon the app (more on this in Case 2), your app will stop working at some point (organisms survive by evolving). You will waste a lot of time trying to figure out WTF is going on and fix it.

Even if you are a freelancer, your client won’t like to pay for your mistakes. In the long run, you will lose a client (and connections to find new ones). You’ll lose time and/or money.

In my particular case, the app stopped working every now and then simply because it grew. The client asks to change a bit here or add a new functionality there, so you break something else, the client is pissed and now you have wasted twice the time you allotted on the task. I was yielding half of the money off my time.

I wanted to add tests, but procrastinated because I always had other (paid) gigs to attend.

Luckily at some point the client asked how we could avoid such regressions. I explained them about automatic tests and they agreed to pay for them. In the end I billed only half of the hours, because I was responsible for the issue.

Still, it was worth every penny. Errors in the app are down 95%. Sometimes I don’t hear from the client for weeks, unless it is about a new (billable) feature that makes the client happy.

Lessons learned

Start with tests in mind. Put them in the project’s budget (of both time and money): explain why they are important. The client pays a bit more upfront, but will save later.

If they don’t understand, and don’t want to pay, or if you really need this client, state clearly that you cannot guarantee the app will not stop working at some point, and you will bill them for those regression fixes.

You can even just add tests, without telling the client, because this is how a job should be done. I don’t think a bricklayer will ask for an extra for a wall to be straight, will they?

As a rule of thumb, dump unreasonable clients that want more and pay less: they are not worth your time (unless they pay a lot – in which case you can add tests for “free”).

Of course the above applies to employees as well. Tests should be embedded by default in the early stages of any project. Stakeholders should be informed of their benefits and drawbacks of not having them. The latter range from bad reputation because of a badly written app to delays of new features to missing deadlines important for investors and shareholders in general.

Case 2: When I inherited someone else’s code

For years a client’s app was written by one of the founders, then some freelancers, and finally a consulting firm, before establishing a product team.

None of those people ever wrote tests, of course, or even update the app. Due to some very bad choices, at some point you couldn’t upgrade the app, and you couldn’t stop its development, because the startup needed to grow to survive.

Among other things, this means that when there was the need of adding a new functionality (something stupid, like CORS), you had to reinvent the wheel instead of using a well-established but incompatible library (or use an old, buggy version of it).

Best case, (part of) the app will just stop working (which means delays in order to fix it). Worst case, someone will exploit some old vulnerability and make damages. You can even face legal action because of it. Clients and investors will be scared away, money will drain off and stuff like that. At the very least, the reputational damage would be huge. A dumb way to die indeed.

Thanks to Git we know exactly who made those choices and then abandoned the ship. We talked about what they did, also outside the company, because we have to learn from every mistake. They will be famous in the field, and not for a good reason. And this has consequences.

For example, I crossed paths with one of those freelancers. I needed to use a WordPress plugin and I noticed they was the author. I decided to go a different path as soon as I read their name.

It was the right choice, because later they had to abandon the plugin. They didn’t write tests, so every release broke something else: the issues page was a battlefield. A nightmare, and a shame, because the plugin was a good idea. I would’ve gladly helped its development.

Another example: the same company from before rehired the same consulting firm to develop a microservice. The reason: thay already knew the app, so they could do it fast.

Not a very good reason. They kept writing batshit, unreadable and untested code, and the new CTO fired them as soon as they could. It was my first week in the company, and the CTO was working in front of me when they made their decision: it was and still is the only time I saw them lose their temper. The company lost money and that microservice is still nowhere.

A few months later a former client of mine was looking for developers for a new product (I wasn’t available). He saw this consulting firm’s advertisement somewhere, and asked me if I had an opinion about them.

Let’s just say I wasn’t gentle, and the consulting firm didn’t get the chance to have the job…

Lessons learned

Bad code is understandable and forgivable. One of the first rules to survive in business is “you shall deliver”. I read somewhere that companies die more often because they never delivered a perfect product, than because they put an imperfect product on the market and improved it later.

We all write bad code, that’s fine. I don’t like code I wrote a year ago, sometimes even a week ago, and I always want to start over. I made mistakes and was forgiven, and I forgave others’ mistakes. I’m sure you’ve been there too.

If you start with tests in mind (it doesn’t necessarily mean TDD), you or other devs can easily improve your code, by you or someone else, with a limited risk for the business. Future you and other devs will be sympathetic and even grateful for that technical debt: you delivered something (which usually means growth… and paychecks) and also allowed other people to build on your work.

On the other hand, bad code left untested burns bridges, especially if you insist doing it: technical debt compounds fast, and as opposed to what happens to other kinds of debt, you will be blamed for it.