Home » Blog » “Code should be readable first, flexible second, and efficient third”

“Code should be readable first, flexible second, and efficient third”

by Marcin Wieclaw
1 comment
Code should be readable first, flexible second, and efficient third

Jake Boxer is a software engineer living in Cambridge, MA. He graduated summa cum laude from UMass Amherst with a Bachelor’s degree in Computer Science. He is 23 years old. He feels strange about writing in the third person, and is going to stop now.

Here are my views on programming (for what they’re worth):

Code should be readable first, flexible second, and efficient third

Rigid readable code can easily be modified so it’s flexible.

If an area of code is readable and flexible, but is performing slowly, it’s a piece of cake to profile it, find the high-traffic areas, and sub in more efficient algorithms (or, for really critical areas, lower-level languages).

If these priorities are followed out of order, you end up wasting time (and possibly ruining your code base). Code written “flexibility first” is often overcomplicated; make it simple and readable first, then refactor to make the rigid parts flexible. And of course, we all know why we shouldn’t write “efficiency first”.

Not following these priorities will waste your time. Maybe you’re working on a game engine, and you know it needs tip-top performance, so you write efficiency-first. Bad. You’re missing the point. If you write it efficiency first, and something goes wrong a couple months in and you need to rethink some design choices, guess what? You’re probably going to need to rewrite your entire code base, or deal with a horrible spaghetti code mess for the rest of the project.

If you’d written it readability-first, flexibility-second, that design decision change shouldn’t be much of a setback. All the code makes sense, and it’s probably pretty flexible (and if it’s not, you can make it flexible, since it all makes sense), so the changes are straightforward.

Now of course, when you write it readability-first and flexibility-second, it’s going to run like molasses the first time you’re able to fire it up. Guess what? Now you can optimize. Abstract the inefficient high-traffic parts into their own functions/methods and write your code as ugly as you want, so long as it’s fast. You can even extract parts into C or Assembly if they’re really performance-critical (Python has a fantastic library for integrating with C and doing just this).

The important part is, each performance-critical area is kept in its own little bubble. Those performance-critical areas, though they might end up being less than 10% of your lines of code, will probably end up representing 90% or more of the work done by the computer when the program’s running. With that in mind, it makes perfect sense to keep them in a bubble. You don’t waste time optimizing things that don’t need to be optimized (no one will notice if the routine for switching weapons takes 1000 more instructions than it could), and thus, you have more time to optimize the things that do need to be optimized (people will definitely notice if the routine for drawing a new frame takes 1000 more instructions than it could).

Furthermore, this allows you to keep your non-performance-critical code pristine (readable and flexible). I would go as far as to suggest prefixing the names of optimized functions/methods with optimized_, so others know what to expect.

Unit testing is a requirement

Any piece of software worth using is going to have some interdependencies, and no one in the world has enough brain capacity to remember what they all are. Even if they did, it would be a waste of time for them to manually test each one every time they make a change. This, above all other reasons, is why we need unit tests. Without them, we are doomed to forever introduce new (and reintroduce old) bugs in old code.

Unit tests also force us to keep our code modular. If a class or method or function can’t be unit tested, it’s probably because of some dependencies (global variables, databases, etc.) that it shouldn’t have in the first place. Untestable code is almost always inflexible, and unless we’re on a tight deadline, we should fix it (and if we are on a tight deadline, we should repay the technical debt and fix it as soon as we can after the deadline is up).

User-facing software should be usable

Some user-facing software is specifically designed for “power users”. These folks are guaranteed to have used tons of similar software in the past, and will instantly understand what’s going on. High-end video editing software is in this category, as are many other things I’m sure you can think of.

Most user-facing software is not like this. Most user-facing software shouldn’t require training. A user should be able to start it up and achieve exactly what they want without reading a manual or attending a training session 95% of the time. If there are some advanced features that are too involved for the average user, they’re probably badly designed. On the extremely rare occasion that they aren’t, they should never clutter an interface and make the common features harder to get to or use.

I guess this “About” page ended up being more of a “What I think about programming” page. My bad 🙁

Recovered from: https://web.archive.org/web/20100304113225/http://jboxer.com/

You may also like

1 comment

Khaim Waarum 2024-04-10 - 16:45

Khaim Waarum

Reply

Leave a Comment

-
00:00
00:00
Update Required Flash plugin
-
00:00
00:00