How to Write Future-Proof Code

A handful of tips on writing more maintainable software

Adam Boro
Daftcode Blog

--

Illustration by Magdalena Tomczyk

If you’ve been coding for a while, you’re probably familiar with the git blame command. It answers a question that sometimes arises when finally nailing down a source of a bug in the code, namely: “Who wrote that terrible monstrosity!?”. And sometimes, if working on a project for a long time, there is this strange moment when the answer is… you.

Writing maintainable and readable code is equally important to writing code that works. Because what good is a program that works, if adding a new feature is a painful procedure consisting mainly of deciphering some garbled mess of spaghetti code?

I think that programmers often forget two very important things:

  1. The software is never finished and requirements tend to change
  2. The code is meant to be read by a human being

Keeping that in mind when coding is important and will surely help, but below are a couple of more specific suggestions:

If there is more than one thing, iterate an array

They say that there are only three numbers in programming — zero, one, and infinity. When you see two or more things, iterate an array, you’ll thank yourself later. For example, look at this React component:

Seems ok, right? But then you need to add some new links, and then the Link component interface changes… I’d say a more future-proof way would be this:

Use defaults

If you did some front-end development, you’re probably familiar with webpack. It became famous for it’s flexibility but also because it was hard to set up:

The version 4 of the tool, which just came out (more than two years after the tweet above), finally allows for zero-configuration builds. This approach of convention over configuration has been one of the core parts of the philosophy behind the Ruby on Rails framework, and probably a big contributing factor to its success.

But how does this apply to coding something that does not rely on configuration? It’s all about the defaults. Suppose that for a user of an app, we have two avatar versions — a small one and a large one. Looking at the design, you can see that only the small one is used. Consider the following story:

Isolate code smells

Sometimes writing some ugly code is inevitable — looming deadlines, sudden changes in requirements, and hotfixes can force a programmer to write something they aren’t particularly proud of. The best one can do in such a situation is isolating the smelly parts so that when refactoring time comes, only the internals have to be changed, and the interface stays the same.

It’s also a good idea to put temporary changes in a separate commit — so then when the change is no longer necessary, you’ll just need to revert a single commit.

xkcd on smelly code

Name things appropriately

There are only two hard things in Computer Science: cache invalidation and naming things.

Phil Karlton

And that is very true. As I said before, the code is meant to be read by other people. Descriptive variable names are a quality mark on a codebase, unlike indecipherable abbreviations which only attest to programmer’s laziness:

If you’re still unconvinced, read this short post by Ruby on Rails creator.

Use external code indirectly

Imagine we have a database, which provides the following method of accessing a record:

const user1 = DB.getById(1)
// => {name: 'Bob', age: 42}

Super simple, right? So you start using getById method everywhere. But then a new version of the database comes along, which is much faster and more reliable, but there is one breaking change: getById now returns an object with a value method:

const user1 = DB.getById(1).value()
// => {name: 'Bob', age: 42}

It might be easy or very cumbersome to implement that change across the codebase, but it would be a single line change if the way of accessing the record was interfaced in the first place:

- const getById = id => DB.getById(id)
+ const getById = id => DB.getById(id).value()

This tip is similar to the one about isolating code smells. You should also isolate external code because it might change, become deprecated, or it may turn out that there is a much better solution. In the long run, it pays to be cautious and isolate code which is not under your control.

the reality of writing good code

Keep it DRY

The principle of Don’t Repeat Yourself is well-known but worth reiterating. A lot of frustrations and bugs stem from not adhering to it. Some duplications may seem innocuous at the time of writing, but remember — software is never complete, and somewhere down the road every violation of DRY principle is gonna bite you.

DRY is hardest to adhere to when some data is needed across domains, for example, an API endpoint address that has to be included in code as well as some configuration file. In a lot of cases, familiarity with simple bash scripting will be a huge help.

This principle can also be extended to tasks. If you find yourself going through the same series of steps to set up every project, why not prepare a template project, or create a project generator?

Conclusion

The above are just a couple of suggestions — learning to write maintainable and readable code is probably a lifelong process. In general, remember this famous advice:

Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

Yeah, that about sums it up.

Recommended reading:

  • “The Pragmatic Programmer, From Journeyman To Master” by Andrew Hunt and David Thomas
  • “Code Complete” by Steve McConnell

If you enjoyed this post, please hit the clap button below 👏👏👏

You can also follow us on Facebook, Twitter and LinkedIn.

--

--