Software development is a mentally challenging activity. Recently, I was thinking about this when I came across a psychology theory called cognitive load.
Cognitive load comes into play any time you’re trying to learn something new. It may be a skill, a subject in school, or the architecture of the software project you’ve just joined. Or it might be a module of code that a co-worker has just written and that you must now understand.
The way that that code was written influences how well and how long it takes to learn it. There’s nothing earth-shattering about that statement, but I think it’s interesting to ponder why that is the case.
Cognitive Load in Software Development
There are three types of cognitive load:
- Intrinsic cognitive load represents the inherent difficulty in learning something. It cannot be avoided or directly influenced. However, it does vary based on the learner’s pre-existing knowledge or experience. For instance, a senior developer with many years of experience may quickly recognize a well-known design pattern, whereas a junior developer may have to process each part of that pattern individually.
- Extraneous cognitive load involves any unnecessary additional processing that a learner must do in order to understand the material. This may stem from a deviation from established patterns, inconsistent naming, or other special cases. It is directly affected by the way code is written, is completely avoidable, and results in wasted effort on the part of the learner.
- Germane cognitive load refers to the work of organizing what has been learned into schemas. A schema is a person’s mental map of a concept. Things tend to be easier to learn when they fit into a pre-existing schema. Germane cognitive load is necessary for long-term retention, so it’s usually desirable, but it does require the allocation of some mental resources.
The goal is to eliminate extraneous cognitive load as much as possible.
Cognitive Load & Special Cases
Extraneous cognitive load in a software system is often caused by special cases. These are things that deviate from established patterns (“one of these things is not like the others…”), and they can appear pretty much anywhere, from overall system architecture down to variable naming. Note that this category doesn’t include edge cases, which are unavoidable inputs that must be handled in some way.
An average person can keep seven (plus or minus two) units of information in short-term memory. What constitutes a “unit of information” varies, often based on experience, but a special case always occupies at least one of those spots. Extra mental effort must be given to the special case because it doesn’t fit into any existing schema.
Therefore, a good way to reduce extraneous cognitive load is to eliminate special cases. Here are a few ways you can do that:
- Don’t use the same name for different concepts, even if they’re in totally separate parts of your application.
- Take a step back and look at the big picture. Notice any patterns (not necessarily design patterns, although those are good to watch for, too) that tend to emerge as the system develops, and reuse them.
- Be ruthlessly consistent when developing interfaces for a class, library, or API. This can be difficult to do until after the interfaces are already in use, but it’s worth refactoring for future maintainability.
I’ve found these guidelines help to reduce my cognitive load. What steps do you take to avoid special cases in your projects?