A while ago I stumbled upon one of those ‘advertising’ blog posts. Those posts in which people write about something that is – sometimes only loosely – related to their new startup, book, app or whatever they are trying to sell. Normally I don’t continue reading when I get the feeling that the post I’m currently looking at is one of those. But this time it made me angry what I was reading there. The blog post I am talking about here is When To Write Bad Code by Brandon Savage. So before I start my rant about what is wrong with this blog post let me make my point clear. Let me tell you what my opinion is. When are you not allowed to write bad code?
Basically when you are planning to run your code. I totally understand the initial idea of Brandon here but there are some serious problems with writing bad code. Even – or especially – if it is for some prototype you are developing.
The problem with quick and dirty…is that dirty remains long after quick has been forgotten
~ Steve McConnell
So imagine you have to develop this really important component for the delivery next month using that new technology you are not experienced with. But the project is already late and so you decide to stop reading all these pages of documentation and example code but jump right into action. Hands-on coding is far more fun anyway you think. And indeed, only two weeks later you have a prototype up and running. Your boss is happy since it now looks like the project can be shipped in time. In fact he asks you to also implement these two optional features which were cut out before to hold the deadlines. But you explain to him that you will need another two weeks to polish your code. He looks at you in disbelieve and demands that you implement these features anyway. If you really need to polish the code you can do so after the delivery.
So teeth-gnashingly you start to do as you were told. Maybe you can tidy up your code a little bit while implementing those additional features. But a few days later you realize that your current architecture can’t handle what you need to implement the new features. Deadlines are not far away, so you start to “rebuild” your application without putting too much thought in the new architecture. In fact you add a few more ugly lines of code to circumvent the problems – you need to tidy up the code later anyway. Somehow you successfully finish everything before delivery date. Your boss is happy. The code gets shipped. But your boss has already forgotten about the need to beautify the code. Your working power is needed in another project. A few weeks later nobody remembers that your code was dirty and needs to be cleaned.
Until the day the customer complains about some strange crashes of your application. Since you wrote the initial code you get assigned this ticket. The bug needs to be fixed as soon as possible, says your boss. This customer was just about to order an additional bunch of licenses for this application – a huge amount of money is involved. But it needs to run stable. So you sit down and start investigating. It has been some time since you wrote that piece of code; it is ugly and poorly documented so it takes you a whole week to pinpoint the problem – thanks to the small code base. It points out you just did not check a return value of an API call to that new technology you used. During your rudimentary tests everything worked fine because this problem only occurs in some rare cases. You knew this could happen back then but handling this error would have taken a lot of time and you were just writing an ugly prototype, right? However, to correctly handle also this rare case you need to write a bunch of additional code and while doing so you realize that your current architecture, again, can’t handle this in an appropriate manner. So you start to rebuild your architecture. But this obviously takes a lot of time if it should be done right this time. In order to not lose the important customer your boss adds more manpower to this redesign. In the end, after several weeks of planning, designing, refactoring and testing the new architecture is implemented, the bug is fixed and the application can be shipped again. The customer, however, already bought the competitor’s product. It is more expensive but it was well designed and tested from the beginning. Therefore it contains fewer bugs and the bugs it does contain can be fixed in a timely fashion since a lot of effort was put into designing the architecture, making the code readable and maintainable and easy to adapt to changing requirements.
So bottom line writing bad code, in my opinion, is only allowed when you throw it away afterwards. No refactoring, no beautification – reimplementation. You wrote a prototype, you learned how to handle this new technology, now start over from scratch and use that knowledge to build an even better version.
Refactoring and rewriting code is just a part of our jobs.
Yes, it is. But only to fix what was already screwed up by others. To fix bugs or to adapt an existing piece of software, already well designed, to new requirements.
But, Brendon is right that
Telling people they have to write perfect code from the beginning is like telling an author that they can’t have any mistakes in their rough draft.
But no one expects that. All I ask for is putting effort into your first draft. Think on points in your program that might change at a later time and design your architecture to be prepared for those changes. For example you might only think of displaying your output as HTML in a browser. But what if it needs to be stored in a database later? Or your customer wants it to be in a pdf file? A spreadsheet? Some yet unknown proprietary file format? What if your program right now talks to a piece of hardware by vendor X but in a few months your boss switches over to vendor Y because this one offers hardware with the same functionality for half the money? Chances are very low that the API to control this new hardware is exactly the same as for the old one. These might be trivial examples but even small programs often have a lot of these variation points and often they are not that obvious.
Also let’s face the truth. Most of our bosses and customers don’t have insights into developing software. Therefore it is very hard for them to not think that an application that they can already see on the screen with a nice UI and all the features working still needs a lot of work under the hood. You simply can’t see that return values do not get checked. That your software does not handle unavailable resources well – leading to a race condition. Stuff like that is something they don’t know about. And they don’t have to. It is none of their business.
So believe me, you are well advised to design your application with future changes already in mind. It is crucial for the maintainability of your software. You would not build a car where you are unable to change a tier if it gets flat, would you? I guess not. Or if you have ever worked with hard drive removable frames you know how handy it is to not have to open the case of your computer to change a HDD. If it is even hot-swap enabled…wonderful. The benefits to your software will be equally beneficial. The additional time it needs to come up with an elegant architecture design for your new software will pay off later. That is something you should also make clear to your boss if he/she is not from tech or does not already know it for some other reason.
So keep in mind: The answer to “when to write bad code” is “when you are going to throw it away“.