IEEE Software - The Pragmatic Designer: Programming as Extended Cognition

This column was published in IEEE Software, The Pragmatic Designer column, September-October 2025, Vol 42, number 5.

ABSTRACT: Programming is an example of extended cognition: A developer’s ability to program is enhanced by source code that is a suitable external representation and by tools to manipulate it. When structures are aligned between mind and code, they can be swapped in and out like virtual memory pages; using external tools can be quicker and more accurate than thinking alone. A developer, source code, and tools fuse into a coupled system, which enables work on bigger problems, more quickly, and with fewer errors. However, the extended cognition phenomenon is fragile. Code is typically treated as a machine that can be left alone unless new features are desired. As a consequence, the coupling between developer and code slips away, taking productivity with it.


Pre-publication draft. Please click this official link so your view counts in the IEEE's records of article views – plus the IEEE site has profesionally typeset PDFs.

Software engineering is an intensely cognitive activity. Faced with millions of lines of code, however, no developer tries to memorize it all, nor do they try to use their minds alone to test, typecheck, or compile it. To enable their work on anything larger than tiny programs, developers amplify their minds by externalizing their memory and reasoning with external tools that are larger, faster, and more accurate than their own minds.

Software engineering is an intensely cognitive activity. Faced with millions of lines of code, however, no developer tries to memorize it all, nor do they try to use their minds alone to test, typecheck, or compile it. To enable their work on anything larger than tiny programs, developers amplify their minds by externalizing their memory and reasoning with external tools that are larger, faster, and more accurate than their own minds.

Few developers or managers notice the extent to which productivity depends on collaboration with the environment. Consequently, they may take developer productivity for granted and focus exclusively on financial concerns to steer projects. To steer well, it’s important to understand where developer productivity comes from and how it slips away.

Our own culture is invisible to us until we can step outside of it. To see programming as the remarkable feat that it is, we must shift our perspective. I’ll show a few simple examples – Tetris, Rubik’s cube, and addition – so we have a clear view of the cognitive phenomenon called extended cognition, then it will be easier to see programming as extended cognition.

What is extended cognition?

Extended cognition is the idea that “… parts of the world can be parts of cognitive processes and that cognitive processes are not all in the head.” [1] Philosophers have a variety of names for variations on this idea: extended cognition, embedded cognition, embodied cognition, and enactive cognition. [2]

Playing Tetris is a simple example of extended cognition. You could play the game fully in your head, deciding how to rotate a shape and where it will fit. That’s not what players do, however, because the game will instantly and flawlessly rotate the shape for you, much faster than you can do it in your head. The same thing happens with Rubik’s cubes: it’s faster and more accurate to rotate the cube face in the world than it is to imagine rotating it in your mind. Your mind speeds up by collaborating with an external tool.

Tetris and Rubik’s cube have another similarity: There’s a lot of detail to keep track of. A Rubik’s cube has nine squares per face and six faces – quite a lot to keep in your head – and each turn of the cube rearranges those squares. In Tetris, the accumulated shapes at the bottom change as the game progresses. Players remove a burden from their memory by collaborating with the world around them. They give their memory a rest and let the world remember it. Your mind speeds up because the external representation is quicker and more accurate than your own memory.

Extended cognition works because a mind can collaborate with the world in two ways: perception and action. People perform better when they can speed up their Observe - Orient - Decide - Act (OODA) loop. If it takes less time to push a key so the computer rotates a shape than it does to rotate a shape in our heads, then we’ve sped up our OODA loop and boosted our productivity.

A fragile superpower

Extended cognition gives us a superpower, but that superpower is fragile: The productivity boost can disappear when there are minor changes in the world that break the alignment between our thoughts and the world. The difference in productivity is called the representation effect. People can add small numbers in their heads, but after a few digits it’s hard to keep straight, so they use extended cognition to add big numbers. [3] Children are taught how to make marks on paper so that adding huge numbers becomes easy.

Consider the two sets of marks on paper in Figure 1. Both the left and right have exactly the same text, but only one of them is a suitable external representation.

Addition using proportional and fixed-width fonts

Figure 1: Two external representations for adding numbers. The right side is a more effective external representation for extended cognition.

In hindsight, it’s obvious that, for superpowered addition, we need to have the marks line up in columns, so using a proportional font disrupts the columns and productivity collapses.

Consider how extended cognition might break for a Rubik’s cube or Tetris. If a cube had different shades of the same color, not distinct colors, we’d likely be much slower to solve it. The Tetris game is fully playable if a shape could be rotated at most three times, but a player would need to know in advance what rotation they want, which means they’d need to use their mind.

The basic finding [of psychological studies on the representation effect] is that different representations of a problem can have dramatic impact on problem difficulty even if the formal structures are the same. [3]

There are two distinct lessons here. The first lesson is that seemingly innocuous changes can break extended cognition and collapse productivity. The second, non-obvious lesson is that it’s hard to imagine extended cognition being different than it is today. We anchor our expectations on how we can think now. Accountants using Roman numerals didn’t complain that they were being held back and computers (the name for people who manually calculated without machines) thought that what they did was natural. Just a few decades ago, developers could not imagine the productivity boost we enjoy today from automated testing, integration, and deployment. History tells us that we should not anchor to the present and should expect that a changed environment will bring us new superpowers.

Developers can thrash too

Success at programming depends on extended cognition. Programs are too big to fit into our heads and programs require analysis – such as typechecking, testing, and compiling – that far exceeds our minds. The only reason we can program is because of the extended cognition enabled by tools and a suitable external representation in code; unsuitable tools or code destroys that superpower.

As a thought experiment, imagine a program that would take you a month to write, then consider what happens when you take away the environment you depend on: an external record of the source code, tools like searching and replacing, semantic cross-referencing, automated regression tests, compilers, linters, type checkers, production monitoring, and so on. How long would it take you to write that same program take with just pen and paper? Or entirely within your mind? Your ability to program is intricately linked to externalized source code and its tools.

A computer has a hierarchy of memory that varies in speed of access and size: registers are small and fast, spinning disks are big and slow. To operate on data, it first moves data into registers, and it may use special-purpose hardware, such as matrix multiplication. Developers using extended cognition work this way too. They turn their attention to a relevant subset of the external representation, much like loading data into registers, and they use external computation instead of their slow and error-prone minds.

Thrashing happens when a computer’s working memory is smaller than the working set of data it needs. Instead of running at the speed of electronic memory, it runs at the speed of the hard drive – the slowest link in the chain – shuffling data from there into electronic memory.

Developers can thrash too. When their thoughts are misaligned with the source code or tools, the system becomes hard to understand and evolve. Consider: when automated tests are working reliably, developers can quickly decide if recent code changes are working as intended, but a few flaky tests will reduce productivity to a crawl. Using just their minds, developers must decide if the test failures are genuine or false alarms. Instead of (automatically) evaluating thousands of tests per second, a developer (manually) takes minutes or hours to decide that a test failure is erroneous. When extended cognition fails, developers drop back to operating at the speed of their minds – the slowest link in the chain – not the superpowered speed they can reach with extended cognition.

Ur-technical debt

Today, the term technical debt is used to describe any code that’s undesirable. I believe that Ward Cunningham meant something different when he coined the term, so I use the term ur-technical debt (where the prefix ur- means original) to discuss the narrower meaning. [4] To me, the way he described tech debt sounds like extended cognition. [5]

[I]f you develop a program for a long period of time by only adding features and never reorganizing it to reflect your understanding of those features, then eventually that program simply does not contain any understanding and all efforts to work on it take longer and longer.

There are two ways to keep alignment between an external representation and a mind. The first is curation, where you adapt the external representation to match the mind. That’s what I think Cunningham was talking about. The second way is retraining, where you adapt your mind to the external representation. In practice, you must do both curation and retraining. Like gardeners, a team must continually curate their code so it is a suitable external representation and a new developer must retrain their mind to match a team’s existing code.

Developers can compensate for ur-technical debt, but it hurts their extended cognition. They can memorize quirks (“when the code says X, think Y”) but that mental translation is slow and error-prone. If a method is named save but sometimes doesn’t save then, sooner or later, a developer will mistakenly assume it does what its name says. So, developers can compensate but they have cognitive limits and each compensation hurts productivity.

Systems start out small and easily within our cognitive limits, so it’s easy for developers to cope. They can look at code that disagrees with their thoughts, yet stay productive. Adding features and fixing bugs makes the system more complex, which accumulates ur-tech debt and pushes developers closer to their cognitive limits. I’ve seen teams transition quickly: One month they’re mostly adding features and the next they’re mostly fighting fires. I’ve also seen them improve productivity by investing in the code and automation.

Code as machine and as thought

To see our own culture, we must shift our perspective. If the examples here have done their job, you may now have a different perspective on ur-tech debt: it hinders extended cognition and developer productivity. You can recognize that code has two natures. Code’s first and obvious nature is that it’s a machine that does valuable work. Code’s second and less obvious nature is that it’s the external representation of developers’ thoughts. [6] Ward Cunningham contrasts code’s machine nature with its thought nature this way [7]:

Although immature code may work fine and be completely acceptable to the customer, excess quantities will make a program unmasterable, leading to extreme specialization of programmers and finally an inflexible product. … Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation …

Code can “work fine” because of its machine nature and yet be “unmasterable” because of its thought nature. Code’s machine nature is easy to measure; code’s thought nature, like anything related to developer productivity, is stubbornly resistant to measurement.

Leaders can fall into the McNamara Fallacy: they measure what they can and discard what’s not measurable. They treat ur-tech debt, developer productivity, and extended cognition as unmeasurable and therefore irrelevant. This is a mistake because, sooner or later, it steers every project into low productivity. Focusing exclusively on what’s measurable isn’t practical or hard-nosed; it ensures a bad outcome.

So, how do you create and maintain good conditions for extended cognition? The answer is simple: train your developers, keep track of where the code diverges from their thoughts (i.e., ur-tech debt), allocate time to clean up that ur-tech debt, and invest in automation. There’s lots of nuance but that’s the gist. On a well-managed project, both natures are nurtured.

If your team has fallen into the McNamara Fallacy or you’ve inherited code with a lot of ur-technical debt, you can recover. First, gain consensus about the situation, specifically that ur-tech debt and extended cognition isn’t measurable but it’s still important. Second, gather evidence including anecdotes. The trauma of a recent system outage or loss of a developer isn’t quantitative, but it can inform a rational decision. Finally, strengthen your team’s ability to make apples vs. oranges decisions. By starting small, you can calibrate your instincts and build a track record that leads to good conditions for extended cognition.

Pre-publication draft. Please click this official link so your view counts in the IEEE's records of article views – plus the IEEE site has profesionally typeset PDFs.

References

  1. Chalmers, David J., Extended Cognition and Extended Consciousness, in Matteo Colombo, Elizabeth Irvine, and Mog Stapleton (eds), Andy Clark and His Critics (2019; online edn, Oxford Academic, 23 May 2019), https://doi.org/10.1093/oso/9780190662813.003.0002.

  2. Sprevak, Mark. Extended Cognition, 2019, doi:10.4324/9780415249126-V049-1. Routledge Encyclopedia of Philosophy, Taylor and Francis.

  3. Jiaje Zhang, Donald A. Norman, Representations in distributed cognitive tasks, Cognitive Science, Volume 18, Issue 1, 1994, Pages 87-122, ISSN 0364-0213.

  4. George Fairbanks, Ur-Technical Debt, IEEE Software, Vol 37 number 4, July/August 2020.

  5. Ward Cunningham, Ward Explains the Tech Debt Metaphor, February 14, 2009, Video transcript.

  6. George Fairbanks, Code Is Your Partner in Thought, IEEE Software, Vol 37 number 5. September/October 2020.

  7. Ward Cunningham, The WyCash Portfolio Management System, OOPSLA 92, Vancouver, British Columbia, Canada, Addendum to the Proceedings, Experience Report, 5 - 10 October 1992.