I’ll be honest, out of all the code I’ve had to work with over the years more than 75% had me asking questions. “Why did they build feature X like this and not in an easier way?” “This code will work, but in the future edge-case Y will break it” or the classic “Why did they reinvent the wheel?”
Sometimes I just laugh (or cry) at badly implemented code or unsuitable patterns that have been chosen. Calling in a co-worker just to smother at some divine (that’s always the way I imagine a writer of bad code depicts his poetry) code occasionally happens and it’s actually the stuff that reinforces our ambition to create good, readable and useful code. At the same time we’re realistic enough to know that sometimes there is no other way than to go quick and dirty.
The ambition and ability to code on a poetic level is not something we were born with. It’s on account of countless tribulations that we’ve conquered over the years that we’ve gotten to this point. I’ve written this article to share our learnings in a few key pointers that will help you out when the ‘stakes are high’.
Where does mediocre code come from? Surely the developers that made it were guided by a software architect or at least had a rubber ducky during the process? The truth is, creating the perfect code straight from the bat rarely ever happens, some might deem it impossible. Time or budget to refactor your code to perfection is not available in each project nor is it a favourite pastime for most developers. I wrote this article to tell you: that is OK. Simply put; Sometimes a ‘stick figure’ is good enough, and in other cases you most definitely need a ‘Picasso’.
Granted, comparing less gifted developers to children that only draw stick figures is somewhat exaggerated but it illustrates the tradeoff perfectly.
If I draw two stick figures, a house and one smaller stick figure, most people will for sure recognise this as a family. If we’d let a brilliant art painter draw this same scene it will probably look better and be worth more money but the concept remains the same.
People understand what it illustrates and what the person that drew the painting had in mind. In some cases the stick figure might even be more clear, since there is less noise in the image. Hence the use of simple illustrations in many public places.
This ‘stick figure vs Picasso’ principal also applies to writing code. Your application needs to do X within the constraints of Y and basically fulfil the end user’s needs. The end user could care less about the modularity of your code, the amount of database normalisation you’ve done or the 50ms decrease of page loading time on mobile devices you just spent 2 weeks of your life on. Mind you, these things ARE important, but they are not always equally relevant. Determining what is and what isn’t important is something experience will teach you and by listening very well to your client’s needs.
At the end of the day there are a few key pointers that I use on a daily basis to guide developers and myself in choosing priorities (especially who does what) and marking a thing as ‘done’ or ‘good enough’.
A beginning developer will make mistakes (haven’t we all) and learn from them. He or she will usually not apply DRY, which is a shame, but if the project is a one-off and won’t require any hardcore maintenance afterwards or if it will have a short lifespan (campaign websites e.g.) this is not a problem. Reviewing this code is useful since junior developers can learn a lot from this and rise to, and possibly surpass, the same level as the experienced devs. Completely rewriting this code is not needed, it will most definitely have a negative impact on the developer’s confidence and would defeat the purpose of learning by doing.
If the application is tested thoroughly before launch and there will not be any continuous development done afterwards it’s acceptable to not refactor certain code that might make your eyes bleed otherwise. This might happen when there were shortcuts taken just to get something online quickly. If the output is acceptable, then so is the code that makes this happen.
If you need perfect code, and let a junior coder write it, you need to start rethinking how you assign tasks to developers. Application critical code should be well written and in an ideal world documented well. Juniors usually do neither, so that’s a mistake we can and should learn from. However, extending existing code is a good way to learn the ropes, especially when guided by a senior developer you will learn a lot in little time. And let’s be honest, nobody learned to ride a bike without training wheels right?
These questions are hard, and in practice refactoring code tends to be something that rarely comes up in quotes as a separate cost. Funny thing is that design iterations are usually part of a quote and they are essentially the same thing as refactoring code. Convincing a non tech-savy customer of this importance can be time and energy consuming. You can avoid this pain by making smart decisions and having no problems with looking at yourself in the mirror even after you just deployed non-DRY code simply because it saved you 8 working hours.
There is a caveat here, inform your client. They need to be aware of the choices made, especially if this will mean that maintenance will become more expensive or more cumbersome. As long as you’re transparent about this there is no reason for them to complain later on.
In our studio we don’t refactor the code written in a project that much. Our big trick is to make code reusable, since a lot of core code is similar across projects we can improve this every time we work with it. It’s logically a wise choice to let experienced developers work on the core code, but there is no reason why a less experienced developer cannot get his hands dirty with this. They will probably learn a ton, so reviewing this code together with them is something that will make them better developers.
Monica Lent summarises my final thoughts on this perfectly in her article on tings she learned as junior developer: Good enough is good enough. There’s a degree of diminishing returns when it comes to how “good” code needs to be. It doesn’t have to be perfectly clean to get the job done and not be a total disaster to maintain. Often code that is a little more repetitive or a tiny bit more verbose is easier for other people to understand. Also, “good code” is not the same as “code that looks like I wrote it”.Responsive design: how to make your grids and images even smarterRead the tips from our Tech lead Marko about responsive design. Marko Kruijer13 februari 2017Back