
How to reduce the cognitive load of your code - ingve
http://chrismm.com/blog/how-to-reduce-the-cognitive-load-of-your-code/
======
hbt
There are so many similarities between writing code and writing English.

\- Thinking of paragraphs as functions with one purpose

\- keeping sentences short to reduce load on working memory and increase
comprehension

\- create visual breaks to help the reader by grouping common stuff together
as mini-functions

\- reduce intimidation factor of reading by removing convoluted stuff

\- remove cognitive noise (dead code, unnecessary comments, variables declared
out of context or too soon etc.)

\- keeping terminology consistent across the code (domain language)

\- not using double negatives e.g a = !notLocked

\- using automated systems to simplify expressions (e.g weird boolean
conditions
[http://www.wolframalpha.com/input/?i=a+%26%26+b+||+c](http://www.wolframalpha.com/input/?i=a+%26%26+b+||+c)
)

etc.

Unlike English, it is less difficult to have a program reorganize your code to
make it more readable based on a set of cognitive principles.

But, beyond the readability and understanding of a function, we should also
learn from other engineering fields. For example, system thinking helps
tremendously in organizing code if the cost of refactoring code wasn't so
risky in dynamic languages.

~~~
ergothus
I agree with everything you said. As an old Perl guy, I found it hilarious
that Perl has a reputation for illegibility, while I find it easier to read
than most Java, because in Perl I can express my intent, and in Java it's
buried in the noise.

One cognitive problem I've not yet found a good solution to:

So I have a high level routine to, say, sort the items in a display. Said
sorting has some cascading effects, so I'll have a high level function that
calls some mid level functions that call some lower level functions.

But at some point I get a name clash between a high level function and a low
level one. Like...I'm calling the high level sortDisplayedItems, (or
sort_displayed_items) and there's a low level function that ACTUALLY sorts
them (as opposed to handling the other bits). Sure, I can give it a distinct
name (e.g. sort_items), but when skimming the code, it's unclear which is
which. If I have to mentally parse the code to understand what is happening,
I've failed at readability/maintainability.

How have others handled this?

~~~
Retric
One approach that can help is to name things based on what the functions
actually do.

    
    
      validateSortDisplayedItems
      {
       validation Logic
       ...
       sortDisplayedItems(); //Actually sorts items.
      }
    

This can be harder to maintain, but really long names end up a useful code
smell.

~~~
ergothus
I find it a bit...incorrect.

I mean, your above code LIES. If I call validateSortDisplayedItems, I don't
validate, I validate AND sort. Plus, what do you do if you have
"validateItems" and "sortItems", and then one function that calls them each in
turn? call it "validateAndSortItems"? Yuck.

~~~
Retric
Depends on the Validation Logic. I like the style that basically works like
this:

    
    
      validateSortDisplayedItems
      {
       if(!DisplayedItemsValid())
       {
         CorrectDisplayedItems();
         if(!DisplayedItemsValid())
         {
           DisplayValidationError();
           return;
         }
       }
       sortDisplayedItems(); //Actually sorts items.
      }
    

AKA validate means try and make valid, not verify that data isValid. So, you
can't just do if(isValid) sort; the bonus is unrecoverable errors end up at
leaf nodes vs. the happy path.

At the high level, your function might be sortClicked, which can then respond
to that by calling a wide range of functions.
(userCanSort,SortData,UpdateDisplay)

PS: I find the validate > correct loop is generally the important and error
prone part of code, so I give it priority. The happy path where everything
works is more or less an addendum.

------
matthewtoast
Code clutter is much more consequential than it gets credit for. Poor
formatting, inconsistent whitespace, snips of unused code, and misleading
filenames are speedbumps (or worse, spike strips!) that a developer is going
to hit every time they sit down to code.

And unlike bad abstractions -- which you can "learn" about and mentally model
-- the friction of clutter is a constant damping to your productivity.

Building features in a cluttered codebase is like being asked to install
plumbing in a hoarder's basement.

Understanding a cluttered codebase is like reading an advanced math textbook
by candlelight that was written with broken typewriters by a group of
modernist poets.

De-cluttering is the first thing you should do, and you should stick to it
above all else. Before you add tooling, before you refactor, before you
abstract and framework-ize, get rid of the clutter. That means format your
code, and use a linter whose rules are based on widely adopted community
conventions.

~~~
emiliobumachar
What's a Linter?

~~~
tekromancr
It's a tool that finds things that aren't strictly errors in your code, but
are likely to cause problems.

see also:
[https://en.wikipedia.org/wiki/Lint_(software)](https://en.wikipedia.org/wiki/Lint_\(software\))
(this article refers to one particular (original?) lint tool, but there are
numerous others for various other languages)

------
naringas
I used to think that a lot of bad code out there was made by lazy, incompetent
programmers...

But then, after a certain job, I realized that this is probably not the case.

Now I belive that most bad code out thare is made by overworked and tired
programmers in a rush to deliver something that works.

~~~
reacweb
Most of the bad code was made by very productive developers.

~~~
maze-le
This leads to the question what 'productive' really means. If a productive
programmer writes a lot of code that isn't maintainable at all, can you really
call that person productive? Maybe... but the poor sob tasked with maintaining
the code later, will certainly not be called productive.

Maybe productivity should not be regarded isolated from other metrics and/or
certain style-considerations.

~~~
bcheung
What is the true measure of productivity? If you include things like
maintenance and other developers' time are they really being productive?
There's individual productivity and team productivity. Also a quick one time
job is different than something that needs to be maintained. Everything is
relative to the goals.

------
norswap
Like often with this kind of article it barely scratches the surface.

"null != variable" will confuse people is downright silly. People confused by
this won't have an inkling of what any non-hello-world program does.

The rest has some validity, but it focuses on syntax and programming in the
very small. It might take a bit of effort, but I can make sense of a tangled
function (that's not an excuse to code sloppily though).

The real challenges are architectural: understanding how an application is
structured is often a daunting task, and yet there are some very simple things
one can do to combat this, starting with grouping things thoughtfully,
generous pointers in the documentation, and a few paragraphs of architecture
overview in the readme file.

~~~
njharman
yeah, I'm not even sure what's suppose to be confusing? That the "constant"
comes first, before the comparison operator?

~~~
mc808
Yoda speak, it is confusing like. Most people think "if the variable is not
null" rather than "if null, the variable is not". It's easy enough to adapt to
the style if it's used consistently throughout a code base, but that effort
yields no benefits in most languages.

~~~
JustSomeNobody
_Most people think "if the variable is not null"_

Only because this is how people are traditionally _taught_ to think. This can
be untaught easily enough.

~~~
firethief
So you can unteach your developers to think... for what purpose?

------
jimbokun
"Avoid using language extensions and libraries that do not play well with your
IDE. The impact they will have on your productivity will far outweigh the
small benefit of easier configuration or saving a few keystrokes with more
terse syntax."

This is the main reason to avoid Spring.

Having so much critical code in XML and properties configuration files,
annotations, and magical interfaces that somehow sprout implementations with
no source code, make it impossible to debug using the normal techniques of
Java development.

"Show me all of the implementations of this interface method"

"Show me where this object is instantiated"

"Show me the code being invoked when I call this method"

In my day to day work, Spring's only purpose often seems to be hiding the code
that will actually execute when my program runs.

~~~
JustSomeNobody
Because it is much better to let misspellings get caught during run time than
compile time. /s

Same with a lot of the DI frameworks that were so popular for a while. New guy
doesn't wire something up correctly, checks it in and everyone spends the next
3 hours debugging a rabbit hole. (OK, slight exaggeration.)

~~~
retbull
I spent 3 weeks on a spring rabbit hole as a new dev. Not exactly the easiest
thing to get a hang of.

------
euske
If I was to describe the essence of clean code in one word, I would say
"balance".

Yes, yes, readability and problem separation and stuff is important, but so is
efficiency and usability and security and deadline and everything. Bottom
line: balance.

And it's the hardest thing to achieve.

~~~
Klathmon
I've always worked through the idea that "Extremism is harmful".

Literally anything taken too far is a bad thing. And just about everything in
life is a matter of finding the right balance.

------
igl
No one ever mentions formatting.

I really like aligning multiline blocks, adding whitespace and useless braces
here an there. e.g: Having just a single space between function name and
arguments makes it look less like a call. Yet almost all lint presets/defaults
forbid this. Typography is all about the whitespace between letters forming
easily recognizable shapes.

~~~
eterm
All this is solved by a linter though, there's no point even trying to
remember this, just define your linter rules and let it deal with it.

It might not be the default linter styles, but set up your linter for your
project and give your mind more important things to focus on.

~~~
hire_charts
A linter is also a great way to jump start learning a new language. If you
encounter a warning that doesn't make sense to you, look it up. You'll start
to get familiar with common language pitfalls without actually getting burned
by any of them.

------
lostcolony
'Avoid using language extensions and libraries that do not play well with your
IDE'

I'm of the opinion this should be extended to "does not play well without an
IDE". Because even in projects that said "everyone, use
Eclipse(/IntelliJ/whatever)", and tried to share project files, there was
constant pain in ensuring that everyone had the same development environment
("Oh, yeah, I made a local change to my project file, but then I also made a
change that needed to be shared, and whoops, I broke everyone" and the like).
Not to mention trying to work with code deployed onto boxes without an IDE.
I've gotten to where "if I can't make sense of it and be productive in it with
just vim, grep, and find, your code is too complex".

~~~
msluyter
Well, sure, but that's why you don't share project files.

I think that if you do things correctly, your concern is mostly mitigated. My
last job was Java/Spring. As someone noted above, you really don't want to be
working with Java/Spring _without_ IntelliJ.

But we never had issues with anyone breaking builds due to screwing up project
files, because those weren't shared and the project would run/build/test
immediately after import into the IDE without any additional tweaks.

I think it's sort of odd that many folks complain about IDEs, but then use vim
with a million plugins. Isn't vim + plugins = IDE? Or, if the overall point is
"java sucks, don't use java" then fine, but if you _have_ to use it, I
couldn't even imagine using plain old vim without any language support...

~~~
lostcolony
Sure. Does it require a specific IDE then? Does it cleanly import, from
scratch, with working tests and etc, regardless of whether they're using
Eclipse, IntelliJ, Netbeans, etc? Or is there One True IDE? Is that IDE
available everywhere you have to touch code? Is it straightforward to
integrate it with your CI/CD tools, despite conforming to that IDE convention?
Will it continue to cleanly import after you've left the code to rot for a
couple of years in production, and then have to come back in to maintain it?
Etc. I've been bitten by all of these.

Whereas I've gone to projects that were written without all of this, and even
without getting the code to even compile locally (because of dependency hell
that I didn't want to suffer through if I didn't have to), was able to
diagnose and fix issues, because the code was written to be understood with
only a text editor.

~~~
lotyrin
The idea is that you still conform to the convention of the project (Rails,
Spring, etc.), not the IDE, and the FOSS CLI tools etc. can still understand
the project, but so does the IDE (because it is made to understand the
convention, e.g. how the annotations/XML files work, how to get a list of all
your Rake tasks).

By not sharing IDE project files, not having any IDE-specific machinery in the
project, but still expecting CI to be able to run it, being able to
theoretically hack on the project and get results (build, test) even with just
bash and grep and nano, you get the best of both worlds.

Modern IDEs are better at this than they ever used to be. I was really anti-
IDE for a long time, but JetBrains' products made it make sense finally.

------
pklausler
I didn't appreciate how much of a difference it would make until I tried it,
but now I know that one of the best ways of making code more comprehensible is
to eliminate any questions about interactions between components by using a
language with referential transparency. The results of functions should be
determined solely by the values of their arguments, with no contamination by
shared state and no side effects.

~~~
enraged_camel
In other words, a pure function.

[https://en.wikipedia.org/wiki/Pure_function](https://en.wikipedia.org/wiki/Pure_function)

~~~
pklausler
In mathematical words, a function.

------
boothead
Biggest thing for me: have a small number of fundamental, composable
abstractions. Be able to reason about how their properties interact when you
combine them.

This is the main reason that Haskell is such a force multiplier for me. All
the small minutia is well defined and it frees you to think about the big
picture. Sure, it's a big learning curve, but so worth it :-)

------
awinter-py
The variable name you choose when writing a function may not make any sense
when reading it a month later, or to a third party. These rules are as useful
as feng shui -- if you have a good design sense, you can produce good results
with FS.

The readability wins I've seen come from using common tools; I'm going to be
much more productive on a codebase written in a library ecosystem I
understand. More generally, a powerful standard library with consistent
calling conventions can help a language be useful. It's not productive for me
to spend 10 minutes reading a function only to realize 'oh, this human wrote
their own string split'.

Tests help too because they make clearer the dependent typing of a function's
call signature; stuff like 'don't pass both of these variables' or 'a must
always be > b' are never clear (and I've never used a design by contract
langauge). Tests are sometimes better than documentation because you can
sometimes get alerted if they're wrong.

Most important rule for readable code: hire programmers who know how to read.
Reading a large project is a skill and lses people can read than write code.
Every project is going to have a quirk of its evolution that's hard to
understand without a close reading. (Every large C project contains a buggy
partial implementation of LISP). Hire programmers who can survive that.

------
hinkley
I spend a lot of energy discussing this at work, and mostly that has been
"continue talking while people look at you like you have two heads"

It feels like maybe people are almost ready to listen now. I don't know how
this relates to the number of libraries we use now, or the StackOverflow
culture, but I have my suspicions that they are related. Maybe we should start
talking about Library Fatigue...

------
freekh
Not sure I can say I always write clean code but when I do, in non-trivial
cases, I often start to write a comment, delete it and replace the code I
wrote with something that does not need a comment... I suppose it only works
for people who (think they) know(s) what good code looks like, but (I think)
it works as a good guiding principle (for me).

~~~
kungtotte
This is one of my guiding principles too. If I find myself wanting to comment
the code to make it clearer or understandable, I refactor the code.

The one time I let comments slide is when they document unexpected and
unavoidable behavior that I can't fix in code. For example working with an
inconsistent data set and having to add some convoluted code because what is a
string in 95% of the rows might parse as a tuple in the remaining lines, so I
need to account for that. This is so that I, or the next guy, knows why the
code was written as such and won't go off trying to fix it.

------
iamleppert
Developer cognitive load is one thing that kills projects, teams, and,
eventually organizations. In the various companies and projects I've worked
on, you can usually spot the culprit: a single person, or small group of
people who take pride in making things more difficult for others to
understand, or actively creating insider systems that serve to entrench
themselves and make them seem important and the center of attention.

------
HerpDerpLerp
He advocates prefixes on variable names. I would like to see good examples of
this as I have never seen them as helpful (especially the tblUsers and
intUserId type that can be common) .

~~~
jt2190
Christian points to Joel Spolsky's example of using prefixes to add meaning,
not type information like your examples. From Joel's essay:

 _All strings that come from [user input] must be stored in variables (or
database columns) with a name starting with the prefix "us" (for Unsafe
String). All strings that have been HTML encoded or which came from a known-
safe location must be stored in variables with a name starting with the prefix
"s" (for Safe string)._

    
    
        us = Request("name")
    
        ...pages later...
        usName = us
    
        ...pages later...
        recordset("usName") = usName
    
        ...days later...
        sName = Encode(recordset("usName"))
    
        ...pages or even months later...
        Write sName
    

_The thing I want you to notice about the new convention is that now, if you
make a mistake with an unsafe string, you can always see it on some single
line of code, as long as the coding convention is adhered to:_

    
    
        s = Request("name")
    

_is a priori wrong, because you see the result of Request being assigned to a
variable whose name begins with s, which is against the rules._

[1]
[http://www.joelonsoftware.com/articles/Wrong.html](http://www.joelonsoftware.com/articles/Wrong.html)

(edit: formatting, citation)

~~~
noelwelsh
In modern type systems (Haskell, etc.) you can define a new type that wraps an
existing type with zero runtime cost. In Haskell you could write

newtype UnsafeString = Unsafe String

(UnsafeString is the name of the type. Unsafe is the constructor you use to
create an UnsafeString from the String).

With this and other techniques you can lift these characteristics of you data
into the type system, which is IME much more useful than using hungarian
notation.

~~~
marcosdumay
I don't think the Haskell typing system is powerful enough for completely
replacing prefix labels.

Marking something unsafe is a best case scenario. Separating lines from rows
would require a huge amount of boiterplate to preserve the numeric operations,
and one still can not create a library that will check something like:

    
    
        let
        l = 5 :: Meter
        w = 4 :: Newton
        in l * w :: Joule

~~~
noelwelsh
Representing constraints in the type system is always an engineering tradeoff
---how much type level machinery do you want to build vs the effort required
to build that?

Not sure what you mean by separating lines from rows. In the example you give
of computing with units, I've seen examples of such systems in Scala (e.g.
[http://www.squants.com/](http://www.squants.com/)) and F# comes with
something built-in for this (IIUC). You might be interested in checking them
out; it's quite neat.

~~~
marcosdumay
> Not sure what you mean by separating lines from rows.

It's the example Joe Spolsky used on the blog post about prefixes that
everybody keeps pointing to. He showed code that worked on rows and columns
(not lines, sorry) on a table, using prefixes to avoid mixing them.

Haskell types do support this use, but you'll have to declare both types as
Integral and Numeric, with the resulting boiterplate. I'm not sure exactly how
to solve this, maybe a way to "lift" typeclasses out of a newtype declaration
would be general enough. It is probably possible to do with template Haskell,
but that is already outside of the language.

That Scala library is interesting, although it looks like lots of the work is
done at run time. Also, it looks like Haskell is able to do it [1]. (It's a
recurring theme of mine, to complain that something can not be done on
Haskell, just to discover somebody that did it.)

[1]
[http://hackage.haskell.org/package/dimensional](http://hackage.haskell.org/package/dimensional)

------
bcheung
I've thought about this quite a bit from a language design standpoint. I've
come to realize the following:

1) Reduce the number of variables that need to be kept track of in order to
make a function easier to understand.

2) Avoid metaprogramming unless there is a clear need for it (doing something
over and over).

3) DRY isn't always good. Sometimes being more verbose is easier to read than
being clever so you don't have to type as much. Concentrate on readability
first.

4) When there are a lot of interacting components consider the DCI pattern. It
will save the developer from bouncing from file to file, module to module,
just to understand the flow of an algorithm. Each time a developer needs to
look up a different file more cognitive load is introduced. An algorithm
should be easy to follow in a single file with code in sequential order. The
opposite of this is message passing and having components pass messages to
other components.

5) Syntax matters. Unfortunately once you choose your stack there isn't much
you can do about this. Some syntaxes are much noisier than others. Every
little bit of noise adds more cognitive load. Don't believe me, try do long
division with Roman numerals.

6) Compress complex concepts into shorter ones. This builds on the Sapir-Whorf
hypothesis. This might be a moving a part of an algorithm into its own
function or storing an intermediate state in its own variable (as opposed to
function composition 4 levels deep). `map` is much simpler to understand than
`for (var i=0; i<arr.length; i++) { doSomethingWith(arr[i]) }`.

7) Spend time getting to know your editor. When you can reduce the amount of
muscle movement required to perform an action it generally reduces the
cognitive load as well. Not to mention making you more productive.

------
jernfrost
One thing I like which nobody ever seems to mention, is that when you divide
your code into smaller functions it helps to have your functions actually take
inputs and give outputs. It is very hard to read code which is just line after
line of functions taking no arguments and returning nothing. No matter how
descriptive your method names are, it will just end up being more confusing
than if you simply wrote out all the code contained in those functions
instead.

People need to see how the code flows and how things are logically connected.
That is impossible to do with reams of methods operating exclusively on member
variables.

I guess this is just another way of stating the benefits of functional
programming. People do modularization at the function/method level so badly so
often that I often think talking about modularization at class level, is
beginning at the wrong end.

So many struggle with modularization at small scale.

------
erikpukinskis
Honestly, while I love these articles as food for thought, they really aren't
the solution to the problem.

In my experience, programmers generally have a sense of what parts of their
code need to be cleaned up. If they are a newer developer their ideas might be
a _little_ screwy. They might not see the root problems, but they know which
closets are producing ghouls.

The issue I see is that developers don't think refactoring is a good a use of
their time, or someone up the food chain doesn't think it's a good use of
their time, or there's just so much institutional inertia making people
question whether it's a good use of their time.

If you want your code to be better though, don't read about architectural
problems, just take some time to fix the stuff you know is bad in whatever way
you know how.

That's better than any article or class and it pays you money and it makes
your code more fun.

------
noxToken
I've found that diagrams help. Young developers (in my experience) tend to
laugh at the thought of making UML diagrams. At the very least, a class
diagram will tell what classes references what. Using some custom stereotypes
can help give further meaning.

Ideally, sequence diagrams (or a similar type) can help shed light on just how
the project comes together. Explaining how a project works from a high level
can leave unintended knowledge gaps. The great thing about these diagrams is
that they can largely be automated with very few inaccuracies.

Diagrams are definitely now a silver bullet. I have found that they can easy
grow unwieldy when attempting to incorporate too much information into a
single diagram. Much like separation of concerns or the single responsibility
principle, I believe that diagrams work best when they're focusing on a single
piece of major functionality.

~~~
ionforce
What is a stereotype?

~~~
noxToken
Stereotypes are an extension of UML to include extra information about the
class. This[1] is a class diagram (albeit, overly detailed) I created for a
library that we used. Above the class names are stereotypes. I know which
classes came directly from the library, which are service classes, etc.

[1]: [http://i67.tinypic.com/33xyaz4.png](http://i67.tinypic.com/33xyaz4.png)

------
jimjimjim
one programming style that i think makes things worse is the "how many calls
can i make on a single line" programming style.

    
    
      MyObjecter.GetObjectRelatativeThingy(ThingyHolder.WhatsMything(IndexKeeper.Get(), OtherWhatsIt.BuildOther( MoonCheese.Intensify(true)))
    

It's probably a result of the letterbox effect of widescreen monitors and IDEs
with horizontal toolbars and status bars.

Is there anything wrong with expanding the idea of 'one purpose per function'
into 'one purpose per line' and split it all up into multiple lines with temp
vars inbetween.

this gives you benefits of:

\- short lines and simple ideas

\- easier to set break points

\- allows for adding logging between calls.

\- allows for setting debug watches on the temp vars

\- the compiler tidies any temp vars away so there shouldn't be any extra
copying.

~~~
kungtotte
I like Raymond Hettinger's idea of one _concept_ per line. Sometimes that
means having two or even three functions on a single line, sometimes one.

------
ryandev
Would recommend reading 'Code Complete' than this article

~~~
HerpDerpLerp
He does reference it in both the first and last paragraph!

my fave is clean code... though uncle bob seems divisive these days for some
reason.

[http://www.amazon.co.uk/Clean-Code-Handbook-Software-
Craftsm...](http://www.amazon.co.uk/Clean-Code-Handbook-Software-
Craftsmanship/dp/0132350882)

------
couchand
The article is well-intentioned but misses the point in a few places. For
example, the suggestion to have, in an MVC project, three top-level
directories: one each for models, views, and controllers. This works fine for
small projects, but larger projects can see significant benefit by keeping
related code together. As with everything, it's a judgment call. The simple
"one folder per type of thing" rule may not be applicable in all situations.

~~~
Can_Not
Yeah, where do you add queues, events, observers, helpers, traits, interfaces,
etc.?

~~~
awinter-py
Each of those should be a separate module uploaded to NPM. That was the
versions can vary independently (for max compatibility).

This technique is named 'carbo-loading' (because of all the spaghetti).

------
JoeAltmaier
Its not about understanding a line of code - anybody can do that. Its about
absorbing kilo-lines of code and gaining an understanding of the whole thing.
Without having to draw attention to every line.

I can read code by the page, hitting next page at about a 1Hz rate. If the
code is not overheated. That means, avoid lots of syntactic bloat, keep it
concise, keep it modular, with low branching. Just about what the OP says.

------
Yhippa
One thing I appreciate about .NET are the conventions around project
structure. When digging into an ASP.NET project I know where I can reliably
find assets, models, views, and controllers. Also like conventions like
prefixing interfaces with "I". Little things but makes diving into random
codebases easier as a Java developer.

------
tremguy
+1 for avoiding frameworks and extensions that don't play along with the IDE.
I've only recently realized just how much the supposed productivity gains of
those tools evaporate when your workflow gets bogged down.

------
raverbashing
Very good

Until you have some code reviewer that thinks otherwise because of some
"stupid reason" and you can't get around their hard heads.

One example, breaking a 81 char line because it goes over the limit and
getting two shorter lines that are awful to read

So yeah I'll go for this when I'm working with reasonable people

~~~
berntb
So, what do you do if you get a job with Java or iOS and 30++ char method
names?

(Not being snarky, I would like to do some iOS development for fun but want
lines under 78 chars, so it don't go over 80 with diff.)

~~~
kilink
Sorry, it's just not practical to keep lines under 80 characters in some
languages.

------
fnordsensei
Good advice, but it still seems like just cosmetics compared to the real
brainkiller: (incidental) complexity.

It's kind of how legible handwriting is desirable, but not really the most
important factor, when it comes to the amount of brain required to solve a
math problem.

------
jordanlev
> There are four main concepts I will talk about here.

There are 5 concepts in the article. Off-by-one error? :)

~~~
pjmorris
Cognitive load is a harder problem than we give it credit.

------
poofyleek
Is there a program that rates other programs in terms of Flesch Kincaid score
or the equivalent? Old Man and the Sea F-K score is 4. Code isn't much
different than other writings. I prefer to read code written like a Hemingway.

------
zwieback
Some good tips in this article but for me the problems usually start when I
have to tie two or three APIs with different coding conventions together.

------
davidhariri
Nothing about division of concerns and organization?

------
hyperhopper
Even the first example is a bit silly. Nobody is going to not understand that
(null == foo) is the same as (foo == null).

~~~
bnegreve
It does increase the cognitive load for no particular reason. Which is what
the author is trying to avoid.

~~~
Freaky
It's the difference between, say, length(foo) and foo.length() - any
difference in cognitive load should be lost in the noise next to "this
variable can be null".

And given most languages in use today use = to mean assignment instead of
equality, it's hardly "no reason".

~~~
retbull
Except if you do if(foo = null){} it won't compile in java which is exactly
what you want to happen. So using it in java is just cognitive load and
provides 0 benefits.

~~~
lkbm
Habits are hard to break. Switching back and forth between habits leads to
mistakes. There's a trade-off here. I'm not going to say one is definitely
worth it vs. the other, but if we pretend the disadvantages of one option
don't exist, we lose the ability to make appropriate judgements.

~~~
retbull
I guess I didn't think about people using C/++ and Java together regularly.

------
diskcat
Isn't this just a fancy phrasing for "make your code easy to read"?

~~~
hintingonwhoiam
+1 This whole blog post reeks of elitism and over confidence.

The blog post over states its own importance as after learning these clean
code would be easy. Like fade diets, magic paradigms etc... another example of
someone believing or trying to convince others that there is a "magic path".
"Just remember these four concepts", "get a six pack with just 20 minutes a
day"...

There are a few good tips in here but really nothing new. A nice reminder that
there are some simple steps to help improve your own code.

A large devil of clean code is not just in nitty gritty "have one line per
logical action" but rather the deconstruction of a problem into easily
followable steps.

In that way this is definitely not an exhaustive description.

------
sklogic
The best way to minimise the cognitive load is to always use DSLs.

~~~
heisenbit
Especially if there are objects that correspond to something real.

