Background
Here’s the thing, the company that I’m currently working at has a massive codebase. Massive as in – maaaassive. Windows 95 had around 15 million lines of code and we surpassed that a while ago. Now, like any code that was, is, or will be written, our code has bugs as well. And occasionally you have to trace those and try to fix them. What this means is that, on regular basis, we have to skim through other people’s code, debug it and try and fix bugs. As you can imagine, this involves reading lots and lots of code really.
As with any skill, by constantly doing it, you eventually just get better at processing other people’s code. What I noticed though, is that some of it seems to be easier to digest than the other. As in – “easier on my brain”. What’s the trick? Surely, the way the code was written plays a big part, but I think there’s something else in play here as well.
Two examples
Here’s what I’d like you to do. I’d like you to stare for a bit at the code below. Take like 5-10 seconds and just observe it. Here it is:
<?php
$a = foo();
$ab = fooBar();
$aAndAbSummed = $a + $ab;
$aAndAbDividedByTwo = ($a + $ab) / 2;
$this->logger->debug(sprintf(
"This is some ridicolously long line that has no point except to showcase my point. %s and %d.",
"foobar",
5
));
$this->logger->debug(sprintf(
"Another pointless message with no real point except to be used as an example. %s and %s and %s",
"foo",
"bar",
"baz"
));
$a = foo();
$ab = fooBar();
$aAndAbSummed = $a + $ab;
$aAndAbDividedByTwo = ($a + $ab) / 2;
$this->logger->debug(sprintf(
"This is some ridicolously long line that has no point except to showcase my point. %s and %d.",
"foobar",
5
));
$this->logger->debug(sprintf(
"Another pointless message with no real point except to be used as an example. %s and %s and %s",
"foo",
"bar",
"baz"
));
Yeah, it’s the same code pasted twice. But the code itself doesn’t matter really. Now, take another 5-10 secs and stare at the following code:
<?php
$a = foo();
$ab = fooBar();
$aAndAbSummed = $a + $ab;
$aAndAbDividedByTwo = ($a + $ab) / 2;
$this->logger->debug(sprintf("This is some ridicolously long line that has no point except to showcase my point. %s and %d.", "foobar", 5));
$this->logger->debug(sprintf("Another pointless message with no real point except to be used as an example. %s and %s and %s", "foo", "bar", "baz"));
$a = foo();
$ab = fooBar();
$aAndAbSummed = $a + $ab;
$aAndAbDividedByTwo = ($a + $ab) / 2;
$this->logger->debug(sprintf("This is some ridicolously long line that has no point except to showcase my point. %s and %d.", "foobar", 5));
$this->logger->debug(sprintf("Another pointless message with no real point except to be used as an example. %s and %s and %s", "foo", "bar", "baz"));
Now scroll up & down and see which code do you find to be “easier” on your brain. It’s the same code really, but it’s just written differently.
I will take a risk here and assume that you find the second example to be “easier” on your brain. The code is the same, but the second one is easier to digest. But, why? Well, to be honest, I have no clue; but I have some assumptions.
We are wired to solve problems
What I think is at play here is the weird nature of our brains. As in – our brains just love solving problems. So even if we are not really trying to process each and every line in the first example, our unconscious part is actively doing so. And there are just one too many lines to digest, even though many of those could have been processed just by looking at the first part of it.
Let me give you one more example. A shorter one. Check these two snippets:
$this->logger->debug(
"This is some irrelevant text with bunch of params - %s, %s, %s, %s, %s, %s and %s",
$a,
$b,
$c,
$d,
$e,
$f,
$g
);
$this->logger->debug(
"Another pointless log - %s, %s, %s, %s",
$a2,
$b2,
$c2,
$d2
);
Compare that to the following one:
$this->logger->debug("This is some irrelevant text with bunch of params - %s, %s, %s, %s, %s, %s and %s", $a, $b, $c, $d, $e, $f, $g);
$this->logger->debug("Another pointless log - %s, %s, %s, %s", $a2, $b2, $c2, $d2);
Even though you are aware that it’s just a log and that you can skip it the remaining lines – you can’t. You just have to process each and every line. There’s no way around it. We are wired to solve problems and each new line is something that our brain is trying to make sense of. Hence, in the first example, you are processing 18 lines, while in the second example it’s just 3. And that adds some load. And that load has a name on its own – cognitive load.
Cognitive load
Here’s what Wikipedia has to say on the subject:
In cognitive psychology, cognitive load refers to the used amount of working memory resources.
Cognitive load theory has been designed to provide guidelines intended to assist in the presentation of information in a manner that encourages learner activities that optimise intellectual performance
Source: Wikipedia
If you’re too lazy to read the whole article, I’ll give you the tl;dr – Cognitive load is the amount of resources you need to use in order to process some piece of information. As simple as that. If you look at my last two examples, we are talking 18 lines vs 3 lines. That’s 6 times more expenditure for exact same piece of code!
Also, you probably figured that the concept of “expenditure” implies that there is a limited time of the resource being consumed. And you’re right – there is. The more cognitive load you consume, the dumber you become. Seriously. Eventually you end up feeling tired and having to take a break from debugging and analysing the code at hand.
So, what am I suggesting?
What I’m suggesting is that we should optimise readability of our code for human beings and their (im)perfect brains. Optimise the information that you are transferring (your code) so that people have easier time processing it. The code you are writing should be written for human beings, not for computers.
Here are some real simple actions that you can take immediately to reduce the cognitive load (and eventual overload) of anyone reading your code:
1. Use one line per statement
One line should be a single piece of cognitive unit (yeah, I just made up that term …). Favor this:
$this->logger->debug("This is some irrelevant text with bunch of params - %s, %s, %s, %s, %s, %s and %s", $a, $b, $c, $d, $e, $f, $g);
$this->logger->debug("Another pointless log - %s, %s, %s, %s", $a2, $b2, $c2, $d2);
over this:
$this->logger->debug(
"This is some irrelevant text with bunch of params - %s, %s, %s, %s, %s, %s and %s",
$a,
$b,
$c,
$d,
$e,
$f,
$g
);
$this->logger->debug(
"Another pointless log - %s, %s, %s, %s",
$a2,
$b2,
$c2,
$d2
);
2. Indent and align assignments
Again, it comes to readability and processability of information that you are trying to present. Favor this:
$a = 5;
$ab = $a + 6;
$aAndB = $a + $b;
$aMinusB = $a - $b;
over this:
$a = 5;
$ab = $a + 6;
$aAndB = $a + $b;
$aMinusB = $a - $b;
3. Read about Code Calisthenics
The suggestions I made above are rather easy to implement. As in – they don’t really require additional cognitive effort in order to implement them. However, if you want to pimp up your game, I’d highly recommend you read about object calisthenics. It boils down to 9 rules that you can (and should!) follow in order to make your code more readable, maintainable and testable. Here’s a great article written by William Durand on the subject.
Conclusion
Cognitive load is the amount of effort that we need to exert in order to digest the information being presented. As information presenters, or, programmers if you will, we need to aim at making our code as easily digestible as possible. Effects of cognitive (over)load are a real thing and both your colleagues and your future self will be thankful for not having to experience it.
Appendix
Concept of cognitive (over)load is applicable to many other spheres as well. One perfect example that we can all relate on is – meetings and other artefacts of software development. But I will be writing another article on that subject 😉
Nice article. I do agree with you you’ve mentioned above.
Thanks for this nice article, and I agree with everything except maybe the 2. Indent and align assignments:
Let’s have a compley formula split into different steps for readability. There might be a block with two variables, which differ in length (e.g. $finalSum and $integrationBySubstitutionResult). When I stumble upon such code, It happens quite often that I lose the line I am reading and have to re-check the line with the shorter variable.
I am also interested in the line of code, not the aligned column of a block of code. Even if it looks nicer 🙂
Other variable names could prevent this issue, but it could lead to wasting a lot of time with finding a fitting name at all.
Having methods for each of the variables (e.g. calculateFinalSum(…) and integrateBySubstitution(…)) would help, as left and right side of the assignment tell us exactly what they are doing and we would debug and fix the very method. But the problem still exists and it is also quite rare to find such “clean” buggy code.
So my conclusion: I would leave that very point simply up to discussion with the team. 🙂
Good point that really could/should be applied to everything we do in our everyday lives if you think about it- simply make life easier.