When is code "too clever" / how do you think about readability/cognitive load?

・1 min read

Usually, it's quite clear to me whether code I'm writing is clean and easy to understand, but lately, I find myself doing the following a lot in JavaScript:

When a function needs to do something only when a certain option is passed in, I do this:

function foo(shouldBar){

    shouldBar && bar();

I find it quite clear, but I'm probably going to try to kick this habit because

  • is more explicit,
  • is easier to understand or devs with less JavaScript experience.

How do you decide whether a particular line of code is "too clever"?


I think this question can't really be answered without knowing who will be working on the code.

Let's take something really basic like loops. Depending on the case, we could replace loops with, say, recursion, higher order functions (map, fold), or list comprehensions. I would say that I usually try to replace loops in my own code with something like the above if it is reasonable to do so. I consider the resulting code more expressive, and there is usually less boilerplate.

However, all of these constructs require a more complicated mental model of what's going on than just following a loop. If the people maintaining the code aren't familiar with these constructs, they may find that the resulting code is actually harder to understand and harder to debug.

If I'm just writing the code for myself, I can do whatever feels right to me. If I'm writing code as part of a team, we need to build up a set of practices together that reflect the capabilities and proclivities of the team.

In general terms, I think it's good to always ask oneself if one's code is more complicated than necessary, and to avoid adding logic only because "maybe it will be needed in the future." It doesn't take very many steps to go from code that is quick to write and easy to understand, to something that's all of a sudden rather complicated. I think the latter can happen when one tries to optimize prematurely for performance or because one takes into consideration the most general case possible when that may not actually be required.


I feel a very important point in a project is figuring out the convention being followed.


If you find the code using

function foo(shouldBar){
    shouldBar && bar();

^ everywhere, then nobody cares whether it is too clever! you should stick to using the style for any commits you make. In my experience, most of these tricks are reminiscent of past, when a certain pattern was the new cool.

To give you an example of past, let's look at an example which I have seen frequently used in old projects but not used that frequently in new projects. The following code is taken from an old code base:

  var base = this.base(),
            i, j, k, id;

In my opinion, folks of today would rather use a new line for each definition than jamming all of them in one line.


In some places, you will identify a clever trick which is an anti-pattern in disguise. Now, this is a tricky one, you should voice it with the maintainers of the project about the feasibility of ditching the anti-pattern in favour of something else. Now it's up to the maintainers to decide whether time invested in porting the entire code to remove the clever trick is worthwhile or not. As the common saying goes don't fix if it ain't broke

Mix of too clever and readable code

If you are in this situation, I have bad news as this is the worst case for anyone to be in. As I said consistency is pretty important for collaborating and overall health of a project. If you find the project using a mix of clever code at some places and a more readable code at some places, it becomes difficult to reason about with code. You should definitely voice it out and try to get rid of too clever code as soon as possible.

You are starting a new project

Note that the line between clever code and readable code keeps changing year after year. What you think is readable today might not be readable tomorrow for the new kid, so decide to go for whatever you and your team find readable today and please stick with it.

Refactoring is a costly affair! pick your coding style and keep it consistent and predictable.

It is indeed heavily depends on what we are calling “clever code” here. “I find it very easy to understand” is not the best benchmark by any mean.

My point is “the more complicated target is, the harder the code is to reason about.” I personally prefer the clever code everywhere, I’d better spend an extra couple of minutes to figure out what the author had in mind introducing this level of abstraction, rather than will stumble here and there on if clauses.

But that’s not true for everybody. And complicated systems/libraries should not be easy to reason about, they should be easy to use. That said, the good interface is a must, while the inner details might be less clear for the sake of flexibility and extensibility.


The language that you're using can play into this as well. In Ruby, I'd have no problem with:

def foo(should_bar)
  bar if should_bar

In Ruby, such shortenings are idiomatic (and easy to understand). In JavaScript I'd find the equivalent (your first example) to be too potentially confusing to leave in. I'd be thinking of future-me, who might be tired, or future-other-dev, who might not know the trick with sequential execution using &&. I'd want that person to be clear that I was making a conditional statement, without having to guess at my intent.

As for the general question of what makes a line of code "too clever", I like to stick to the old adage:

Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?
The Elements of Programming Style, 2nd edition, chapter 2


The principle of least surprise is typically a good guideline. As such, the explicit if statement will usually be the obvious choice. Unless of course the situation is atypical and both are equally unsurprising e.g. when you are the only one who will ever work on the code (say, a hobby project) or there are clear conventions in your team, and the && conditional made it on that list.


Hopefully I don't develop in python, otherwise this would be considered "normal" :))

On a serious note, I usually follow this guidelines, I refactor when:

  • the code would not be understood by a junior, this is a good threshold overall
  • it cannot be tested
  • it will be impossible to find the error source in production (one-liners are the best example, they throw an error in the middle of the line, but there is no way to find out which operation in the pipeline failed)
  • "compiler wannabe optimization" some devs like to pre-optimize and do the same (or worst) than the compiler/runtime already does, sacrificing readability with no real gain
  • when the IDE/linter throws a warning, usually suggesting something better, usually he found an anti-pattern.

Some languages and frameworks have bizarre ways to do things (RoR is a good example of this) and it may take someone else with less experience in the framework a long time to understand.

Which brings me to my answer; Always ask the question beforehand - Will the person who maintains the code understand what I did here easily? If no, then refactor. If yes, then keep it as is.

Where I work people have often moved around between projects, and not all of them have the same amount of experience with the vast amounts of frameworks and languages that these projects are written in. So I always consider who will be reading the code before I write something. Kind of like writing a layman's article vs. writing an academic article.


In the magical ideal world, where unicorns and fairies live, everything might be coded in a clean and understandable by everyone way. If one is developing software in such a world, I can only envy. Because I am not.

For the team as a whole, it’s always better to use clean, readable abstractions, that can be easily understood by any junior. The implementations of these abstractions might be harder to read, though. And they usually are. Ruby source code is open. NodeJS source code is open. Nowadays almost every language is open sourced. And you know what?—the code is rarely if never is ready to read. It often requires to rack your brains to understand it.

That said, while we are talking about development of another form in our CRUD application, using the framework (that in turn consists of not easily understandable code)—I am all-in for avoiding too clever code. Even more, I hope in a decade the AI will be able to produce this kind of code and the question on how is it easy to read will not be crucial anymore.

The most libraries I wrote, that are currently heavily used by our team to simplify the code and produce easy readable applications, are indeed full of too clever code. Which is fine, since it’s fully covered with tests and just works.


Sounds better indeed, is not about the person or its capabilities, it's actually about how fast you can load that piece of code in your head.

This problem is usually a sign that another problem on the list is present, usually what is hard to understand quickly is "smelly code", other devs had issue understanding it so the risk of having a bug is greater.

Every second that is added to this process is multiplied by the number of reads, for each team member.


I prefer the short-circuiting approach. The second one is okay if you remove the block.


I'm the opposite. I'll use the short-circuit in a shell script, where it's common practice, but in JS I'll write it all out the long way, and I'll always include the block.


My preference for the short-circuit is b/c I think it's important to understand short-circuiting (as opposed to some things, which could be called "trivia"), and the short-circuit has the best signal to noise ratio.

My preference for removing the block is mostly because of better signal to noise ratio (ie less spammy), but also because I think it facilitates syntactic misunderstanding to use the block.


I frequently choose to write code that is 'too clever' intentionally so that it is harder to understand.


Have you ever tried to read linux kernel code? Have you blamed Linus?


While I get your point; Linus writes bad code like anyone else.


I totally identify with this. When I started I felt the same. Worse was the code examples for alogrothims at school. Just happy that I finally realize what the real issue was.

Classic DEV Post from Mar 15

What was your win this week?

Got to all your meetings on time? Started a new project? Fixed a tricky bug?

I'm never sure what to put in a bio. If there's anything you want to know, don't be afraid to ask!