E42: The offloaded brain, part 2: applications
Download MP3Welcome to Oddly Influenced, a podcast for people who want to apply ideas from *outside* software *to* software. Episode 42: The offloaded brain, part 2: applications
Last episode, I gave five design principles, which I’ll boil down to three key points:
1. Perceptions aren’t built up from fundamental values like length or weight. It’s more that we grasp complex, relevant information instantly, as a whole. It’s not often particularly useful to put in the effort to decompose that whole into its smaller parts.
2. Perceptions that signal opportunities for behavior are called affordances. There’s frequently a “direct control link” between the perception of an affordance and the behavior it affords. Often, it’s a reflex, or close to one.
3. Animal behavior is frequently directed toward maintaining invariants or rhythmic activities. That can be tied together with perception and affordances by considering a behavior like, say, walking as a multi-stage, cyclical behavior, where each stage positions the body to receive the affordance that will prompt the next behavior in the cycle. That allows activities like walking to be mostly automatic. Non-automatic actions are prompted only by large and unusual affordances.
In this episode, I’ll reflect on what all that might mean for the design of software workspaces. To that end, I was helped by a video call with Steve Doubleday, Ron Jeffries, and Ted M. Young. Assume all the good ideas are theirs and all the mistakes are mine.
≤ music ≥
In episode 19, I used the example I’m perhaps most known for: bright and dull cows. To summarize, “bright vs. dull” is a diagnostic distinction veterinarians use. Student veterinarians are not extremely good at distinguishing between bright and dull cows, and so they seek to learn rules to make such judgments. In the process of veterinary education, students learn to make the right judgments, but in that process, they “lose the rules”. That is, what was once a reasoning process becomes *perception*. A cow simply *is* either bright or dull. They can’t not see it.
Now, you could argue that it’s all rule following “underneath”: that somewhere in the brain there’s an engine that’s learned the rules and applies them, but merely presents the judgment to the veterinarian as if it were perception.
Ecological and embodied cognition researchers – who I called EEs in the last episode – doubt that because it’s wasteful of expensive neurons. I’m going to doubt it too. I’m going to suppose that recognizing brightness and dullness is a *learned perception*, akin to how a baby learns to recognize faces. (Recall from the last episode that babies don’t seem to be programmed to recognize faces; rather, they’re programmed to be able to *learn* to recognize faces, starting from their inherent interest in face-like configurations of visual features.)
I’m not claiming that you can learn *any* perception. When I became a parent, I got fairly good at detecting what Dawn and I called “sick eyes”: a sort of undefinable look that said the child was getting sick (even if the child would *always* deny it – hi, Sophie!). I rather suspect that humans are built to learn quickly how to perceive a sick child, and I also suspect that the veterinarian’s ability to look at a cow and say, “that’s a dull cow” is built on top of that evolutionary feature.
The equivalent of “dull cow” or “sick eyes” in programming is “code smells”. I want to claim programmers learn to perceive bad code in a learning process that is, for practical purposes, the same as babies learning to recognize faces or veterinarians learning to recognize dull cows. (Or, for that matter, fire chiefs learning to recognize when a burning building is about to collapse – that’s covered in Gary Klein’s /Sources of Power/, which I hope to have an episode on someday.)
I used to think that “smells” was a good metaphor because I believed smell is the most direct sense: when you open a container of bad food, you *immediately* react. However, as I talked to Doubleday, Jeffries, and Young, I got the impression that the all-or-nothing character of smell is misleading. It seems that – for at least some people – perceiving a code smell is a scanning or searching process. I imagine that eye trackers would show such people attending to “hot spots” in the code’s display before they made a judgment, even if that judgment seems quick.
Code smell detection is possibly built on top of our visual system’s innate ability to attend to symmetry, density, or other patterns. According to Andy Clark’s 1997 book /Being There/, “the macaque monkey possesses at least 32 visual brain areas and over 300 connecting pathways.” The areas are not arranged particularly hierarchically – pathways will transmit signals from “higher level” areas that summarize back down to lower level areas that perceive. And there are all sorts of sideways connections between not-obviously-related areas. All these connections lead to a variety of semi-innate, semi-learned patterns of neuron firing. For example, macaques have particular neurons that “light up” more strongly in the presence of, say, spirals.
I’d venture to say that many, many programmers have come to recognize the distinctive indentation pattern of deeply-nested control flow. It’s a pretty obvious pattern, and it doesn’t take much experience with such code to understand why it makes life awkward.
But there’s no reason to suppose that someone like Ron Jeffries doesn’t have neurons trained to recognize more subtle patterns with more subtle effects – meaning he can see code smells that I can’t.
How did he come to learn these patterns? Surely part of it was like a vet student learning a cow is dull: trying to change code, finding it annoyingly difficult, and looking for a reason why – a concept attached to a name like “primitive obsession” or “feature envy”. But I suspect plain old “fiddling around” must play a part, because people who are good at refactoring and code smells often seem to have a sort of tactile approach. For example, Ward Cunningham has compared working with code as feeling akin to a potter’s working with clay.
I’m encouraged in this thinking by another fact about macaques: groups of neurons stimulated by vision are connected to groups stimulated by touch and vice-versa. So that, “the reciprocal pathways would allow the goings on at one to become usefully correlated, over time, with goings-on at the other site. Such correlations could come to encode higher-level properties, such as the combinations of texture and color distinctive of some particular class of objects.”
To me, that suggests there’s a connection – probably subtle – between the code smell and the refactoring that fixes it. I realized some of the subtlety at a conference I attended just around 20 years ago. For a session, I decided to put up some code of mine and ask for help refactoring it. Four people in the audience – Ron Jeffries, James Newkirk, J.B. Rainsberger, and someone I forget – took the lead in telling me what to do, and I distinctly remember them telling me things like “move that code, there, closer to that other code over there”, talking about the similarities between the two, having me tweak the two chunks of code to make them more visually similar, and then a hidden commonality just sort of popped out.
My advisors told me similar stories in the conference call. Jeffries told of Kent Beck turning a loop into a doubly-nested loop to make it look more like a nearby doubly-nested loop. Young told of adding an unnecessary arithmetic operation to make one method look more like the others, and then building a refactoring from that.
What strikes me is that detecting code smells is spread out in both space (the layout of the code in front of you) and *time*: a sequence of actions that reveals new perceptions – or let us call them affordances – that guide the next action.
That plays into a mailing list post of Ron Jeffries that I made the epigraph of my only academic contribution to sociology: a book chapter called “Agile Software Development: a Manglish Way of Working”, in a collection of responses to Andy Pickering’s /The Mangle of Practice/ (another book to cover in the podcast).
Here’s that post, in a dramatic reading by Ron Jeffries himself:
“Beck has those rules for properly-factored code: 1) runs all the tests, 2) contains no duplication, 3) expresses every idea you want to express, 4) minimal number of classes and methods. When you work with these rules, you pay attention only to micro-design issues.
“When I used to watch Beck do this, I was sure he was really doing macro design ‘in his head’ and just not talking about it, because you can see the design taking shape, but he never seems to be doing anything directed to the design. So I started trying it. What I experience is that I am never doing anything directed to macro design or architecture: just making small changes, removing duplication, improving the expressiveness of little patches of code. Yet the overall design of the system improves. I swear I'm not doing it.”
≤ short music ≥
You may take a computational approach to Jeffries’ claim. Just as you could say there really are rules beneath the judgment that a cow is dull, you could say that the Beck process has more thinking behind what’s presented as a mere set of reactions to affordances. And you might be right.
But you might also hedge your bets and spend some time practicing being less analytical and more reactive as a way of building up your pattern-matching muscles. Be more aesthetic, keeping in mind that the point is to *expand* your aesthetic perceptions, not just to reiterate prepackaged and value-laden perceptions like “elegance” and “simplicity.”
Now, it might seem odd to compare fiddling with code to working with clay. You’re not *actually* touching the code: you’re touching a keyboard. I want to argue, though, that humans are very good at, um, “projecting touch”. Three points:
1. Neurologically, poking at something with a stick is quite similar to touching it directly. It almost seems as if the neurological system is extended outward to include the tool.
2. In his /Action in Perception/, Alva Noë pushes back against our tendency to think of vision as the exemplary perception. He favors touch because touch is more obviously exploratory: in the dark we figure out the shape of an object by moving our fingers around it, and by moving the object itself. We don’t completely map out the surface of a cube: we make a minimal-ish succession of touches that are enough for us to conceive of the cube as a solid object with a particular shape, even though we don’t *know* that there aren’t gaps and holes everywhere we didn’t touch.
Noë points out that vision is a lot like touch. We *think* we’re passive perceivers of a panorama laid out in front of us, when in fact that’s an illusion the brain presents to us. In reality, our vision is goal-directed, with our eyes, heads, and bodies moving to actively seek out relevant perceptions (or affordances). In a metaphorical way, the ancients’ idea that we see by emitting rays from our eyes that bounce back to us is more correct than eyes just passively receiving a visual field.
3. As noted before, touch and vision – and perhaps other senses – are connected together at all sorts of levels, developing joint patterns of activation that represent (in some sense) frequent experience.
This combination of multi-sensory inputs and active perception as a kind of search for relevance suggests to me that the old MIT AI lab hackers were onto something with their jargon. From the original Jargon File:
“FROBNICATE v. To manipulate or adjust, to tweak. […] Usually abbreviated to FROB. […] Usage: FROB, TWIDDLE, and TWEAK sometimes connote points along a continuum. FROB connotes aimless manipulation; TWIDDLE connotes gross manipulation, often a coarse search for a proper setting; TWEAK connotes fine-tuning. If someone is turning a knob on an oscilloscope, then if he's carefully adjusting it he is probably tweaking it; if he is just turning it but looking at the screen he is probably twiddling it; but if he's just doing it because turning a knob is fun, he's frobbing it.”
Frobbing, tweaking, and twiddling are part of learning to code well. Just reading code, or reading definitions of code smells, isn’t sufficient for learning.
≤ music ≥
*On the other hand*. I don’t want to diminish the importance of actual objects. Sure, we can piggyback imaginary direct manipulation of code on top of our abilities to manipulate real, concrete objects. That doesn’t mean that we don’t benefit from *actually* manipulating real, concrete objects. My example is the venerable 3x5 card, once the mainstay of planning and design in the lightweight methodologies. It was popular in large part because it was so physical. I have three stories, the first two involving Ron Jeffries, perhaps the 3x5 card’s greatest fan.
The first is when I was doing some joint consulting work with Ron at a company in Emeryville, California. We arrived early one morning. The product owner was already there, and he was fretting about a meeting he’d have later that morning with his boss or his boss’s boss. The problem was that he had a spreadsheet with a vast number of requirements or stories summarized, one per line, and he was going to have to explain that the big release couldn’t include them all. There was going to have to be a painful process of separating out the must-have requirements from those that no-really-we-*must*-have. Ron proposed a way to reduce the pain.
The three of us sat down and wrote each requirement on its own 3x5 card. I joked that we probably right there had the most expensive hourly rate ever for mindless transcription services. By the time we were finished, some other team members had arrived, so I went off to work with them while Ron and the product owner went off to the meeting.
They were back amazingly fast, and the product owner was awestruck. The expensive transcription had paid for itself. They’d laid all the cards out on the table and explained to the Big Boss that he had to separate them into two piles of different importance. He did that by glancing at each card and either pushing it away to the edge of the table or pulling it in closer, thus creating the “we need it” and “we don’t need it” groups. Easy-peasy.
It seems the physicality of the cards and the affordance they have for pushing around made the decision-making easier. You might think that the mental process was the same, just illustrated with an external prop. EEs ask you to consider that the thinking *isn’t* the same, that so manipulating a physical environment is a different *kind* of thinking.
(I expect it also helped that all the cards were visible at once, could be pushed into groups of related cards, and that particular cards could be found fairly quickly by remembering their location. More benefits of materiality.)
Another example of that is the venerable Class-Responsibility-Collaboration (or CRC) cards, so called because, in the original form, a class’s name, its responsibilities, and its collaborating classes were written on the card. In fact, it’s often unnecessary to do any writing. You pick up an empty card, name it out loud, put it down on the table. Now it’s a thing in the system you’re designing. Collaboration is indicated by putting collaborating cards near each other. The responsibility can just be remembered. (Though, if it turns out to be useful, you can always scribble notes on the card.)
Discussions are then structured by how people relate to the physical cards. For example, I want to claim that three different ways of indicating a card have different effects on the participants. Speaking the class name is weak. Tapping the card with your finger while starting to talk about it is stronger. Picking the card up and speaking is the strongest. In our video call, Ron illustrated that by picking up an (imaginary) card with a flourish, miming holding “it” upright next to his head. He also mimed talking about collaboration by picking up two imaginary cards and tapping their imaginary edges together.
People would also move cards around. Here’s Ron:
“Pretty soon people would start talking about something that had to happen. And they would point to an empty place in the table where that thing was.
“And everybody knew that the thing was there, and they didn't know what it was yet, and that was where it belonged. There was something magical, which is what we're looking for, I think, about the cards and the moving them and the table and you know, you would slide them around until they would seem to be arranged right in some way.”
Again, you could quibble that the physical cards are just annotations or flourishes attached to the same underlying mental process. Maybe so, but it *is* striking how well physical cards caught on compared to later attempts to computerize the experience. Interacting with a virtual canvas and sliding around pictures of cards just doesn’t seem to have the same oomph. I speculate a lot of that is that you can’t see a particular person moving the card, which weakens the association between particular ideas and particular people who are their advocates or representatives.
Here’s Ted:
“One of the things I struggle with is: CRC cards are great when they're tangible. I see people do that with Miro boards and for me, I haven't done it enough where I feel like it's been able to replace [CRC cards]. I don't know if it can, but given the world we're in I kind of have to figure that out. But there is definitely something that the physical environment, having those cards on a table and being able and people sitting around it that I miss.”
My final example is fairly trivial. Back in the day, when I worked with teams in team rooms who had tasks or stories tacked up as cards on a wall, I was a fan of having people finishing a task get up, take the card down, and ostentatiously tear it up.
The reason I like tearing up cards is: what does a torn-up card afford? Answer: nothing. You’re done with the card. The follow-up behavior is to throw it away and move on to something else. Now, what’s a perennial problem with finished tasks or stories? *Not* being able to move on. Programmers thinking they’re done when they’re not. If you use Jira or some other task tracker, it’s trivial to say “Oops, I guess I wasn’t done” and revert the task to the “in progress” state. I speculate – *speculate* – that the concrete finality of tearing up the card reinforces the old ethic of “done means done”. It *means* something different than fiddling with Jira. (Which, blissfully, I’ve never had to do, but I do hear stories…)
Anyway, tearing up cards is fun.
≤ short music ≥
My card stories were mostly about the environment, though they do involve the body – holding up the card, using your ability to scan a visual scene and remember by position. But here’s an example that’s all about the body.
As I’ve mentioned before, my wife and I used to dance tango, specifically close-embrace tango, where there’s no space between the partners’ chests. For an example, see this episode’s custom image. That’s my wife, Dawn, embracing a man who is not me.
Before the music starts, the partners “enter the embrace.” That’s a little ritual that involves putting your arms in the right place, but – more importantly – is about inhaling, raising the chest up and out, and leaning forward for contact. To me, it changes my state from my normal one of intense self-absorption to one where I’m attentive to the movements and reactions – the body language – of my partner. (Note: in the picture, the man embracing Dawn isn’t leaning forward enough to lead well. He’s projecting tentativeness.)
One time when I was about to start an in-person pairing session, I decided to begin by doing a sitting-down version of entering the embrace. (Chest up, lean forward, but no embracing arm movement – I’m not a *weirdo*.) It seemed to help, so it became a habit of mine. It’s not a direct control link – it’s more akin to the contextual information that determines *how* a cockroach skitters away once the direct control link starts it moving. (See the previous episode for the cockroach story.)
For me, posture affords collaboration. That’s a minor example, but as I look back over a career that started when people still worked in two person offices and later saw the fads for open plan offices (boo!) and dedicated team rooms (yay!), and now has a lot more remote collaboration, I’ve been endlessly amazed by how little attention people pay to what the environment affords.
One of my hopes for this series of episodes is that the idea of “affordances” is sticky in your brain. Michael Feathers once said something like “Once you learn about confirmation bias, you start seeing it everywhere”. That’s reminiscent of the way, once you have a baby yourself, you start seeing strollers everywhere. They were always there, but you never consciously noticed them. If I’m lucky, you’ll now start noticing that your environment is full of affordances and you’ll wonder how you can tweak them – or twiddle them – or frob them – to improve your work-life.
≤ music ≥
Let’s move on to rhythm, another thing I used to not notice but now I see all over the place.
Test-driven design is my favorite example. Toward the end of the last century, I was a proponent of writing tests first, but I meant *all* the tests first. I thought TDD’s loop – “write a test, see it fail, make it pass, do some cleanup” – was equivalent. I was wrong, as I learned when I actually tried TDD instead of reasoning about it.
TDD is much better for creatures like us, because it has a cyclical rhythm like that of walking. My style did not, so was inferior.
Here’s Ted, who links quick cycles to Csikszentmihalyi’s idea of flow:
“And that sort of brings me to the flow thing. I wonder if having the rhythm, having these tiny steps, these quick cycles, getting into flow, conserves our energy, our working memory, because we don't have to think about the next step. We just do it. And taking the bigger steps means we have to now plan.”
The classic unit test runners make good use of affordances. With jUnit, you started with the classic “green bar”: a strip of green that grows across the screen as the tests run. The finished green bar affords writing a new test. You would then rerun the suite, looking for a new affordance: the green bar growing then turning red as the newest test failed – as it should, since you haven’t written the code to make it pass. That red bar affords the behavior of trying to make the test pass. And you’re now looking for the affordance of a fully green bar. If you see it, you’re prompted to either do some cleanup (if you’d noticed or implemented a code smell) or move on to the next test: the next step in the cycle. Or, more alarmingly, the bar would start green as old tests passed, but wouldn’t stay green – it unexpectedly turns red, prompting you to reconsider your code, which is failing.
I spent most of my programming life without green and red bars, as I used test runners that printed a period for a passing test and an F for a failing test. The green bar was replaced with a row of periods, the red bar with a row of dots with at least one F. That’s a weaker affordance – it pushes you less, except in the case when you’ve broken something but good, in which case a flood of intermixed periods and Fs provides a nice jolt. The distinction between periods and Fs stands out enough to be a decent affordance, though.
I have on at least one occasion used a test runner that printed a single monochrome line of text for each test, quickly filling the whole screen with lines that didn’t clearly signal either success or failure, and which in any case quickly scrolled up past the top of the screen. The final, summary line discretely indicated success or failure. This is crazypants. Affordances are supposed to *push*; here, the process relied entirely on the programmer’s decision to be scrupulous and *pull* information out of data.
≤ short music ≥
To me, the explicit TDD loop – with each step ending by looking explicitly for an affordance for the next step – has something of the nice pulsing rhythm of tango. Other people prefer a smoother transition where they move without waiting from step to step. (They probably prefer waltzes, too, but hey: it takes all sorts to make a world.)
The mechanism for doing that is test autorunners, where tests are run whenever a file is saved. You continue in the TDD loop unless something unexpected interrupts your rhythm. James Shore has a neat way of doing that. He’s hooked up his test runner to a sound generator. When the test suite passes, it makes a happy sound; if it fails, it makes a sad sound. Shore doesn’t have to glance anywhere to see the status of the test suite. He can focus on the test and product code except when an unexpected sound interrupts him.
≤ music ≥
The long-dead Greek poet Archilochus once wrote that “a fox knows many things, but a hedgehog knows one big thing”. That’s not really true, because a hedgehog that knew just one big thing would be a dead hedgehog. Hedgehogs *can’t* only attend to one big thing, because the foxes would kill them and eat them.
Just like you, a hedgehog is *built* to automatically and continuously pay attention to a complex environment with lots of affordances, like: “that movement I see in my peripheral vision might just be a fox wanting to eat me.”
What I want to suggest is that the ecological and embodied cognition researchers I’ve cited could give us practical hints for how to arrange our work so that we work *with* the reality of us as embodied creatures, rather than blithely assuming we can ascend into some etherial realm where all that matters is thought.
But that itself is a lofty, etherial statement. My own ethic can’t possibly let me leave it there. So here’s a final example.
The Pomodoro method is another of those techniques that once surged in popularity. I still hear it mentioned occasionally, and I think it’s retained its popularity more than a lot of others. It’s named after the Italian word for “tomato”, specifically after tomato-shaped kitchen timers. The idea, briefly and over-simplistically, is that you set the timer for (typically) 25 minutes. When it goes off, you take a short break (five minutes, say) and then resume.
The timer gives you a larger rhythm that aims to interrupt the shorter rhythms of programming, to prompt you to attend to some larger picture (or at least to stop putting off going to the bathroom).
I’ve never been able to adopt the Pomodoro technique. I’m not proud of that; it’s just true. The reason is that I’m by nature a compulsive programmer of the sort described here by Ron:
“When I am programming and it is not going well... my neck starts to hurt. And I generally ignore it because I've been ignoring it for 83 years. But if I allow myself to become aware of how my body feels about what's going on, it will tell me you should do anything but continue what you're doing. You should get up and walk around. You should go listen to music. You should lie on your back, kick your feet crying, anything.
“But I have to pay attention to it. [I don’t] because I'm concentrating. When you're concentrating, people could set you on fire and you wouldn't notice until the smoke got in your eyes and you couldn't read anymore. But the body knows that I'm not doing well. Long before my brain knows it.”
≤ short music ≥
What I need is not a larger rhythm but rather a “hey! there’s maybe a predator here!” affordance or interruption, something akin to James Shore’s unexpected unhappy sound.
So here’s what I’m going to do. I’m telling you this in hopes that it might be an example that inspires you to try similar things.
I’m about to embark on a big programming project in which I’ll learn Mac and iPad programming, with the goal of writing a podcast script-writing app tailored to my idiosyncratic and radically messy workflow. I figure that, with only a few months of work, I’ll be able to save hours of effort.
While coding it, I’ll make a pomodoro-inspired attempt to produce a version of Ron’s neck pain that actually works for me.
Step one will be to have a timer play an unhappy sound at periodic intervals. However, this is not the cue for a five-minute break. It’s *only* to ask me to attend to whether my body is telling me I’m stuck in a rut. If not, I’m not obliged to stand up and stretch and think; I can dive right back into the flow. That is, this is akin to my catching sight of a predator-like movement out of the corner of my eye and acting to check for danger. Most of the time, such movements are benign: there is no danger.
I’ll also somewhat randomize the timing. Rhythm means your body comes to expect certain events at certain intervals, which is contrary to the surprise that’s essential to meaningful interruptions. Habituation is part of the story of The Boy Who Cried Wolf; it’s part of the reason why he gets ignored when it matters.
Then, I’ll try to figure out a way to delay the timer, almost reflexively, if I’m truly on a roll rather than pigheadedly trying to pursue a bad idea, somehow working around the fact that the whole *problem* is that I have trouble knowing the difference. Hmm… MacOS touts its machine learning packages that app developers can use – perhaps I can train the XCode test runner to deduce the tensions I ignore and provide appropriately-timed interruptions?
I don’t know if this will work, but it’ll be fun. In any case, I hope it gives you an idea of the kind of thinking that embracing ecological and embodied cognition might prompt. Thank you for listening.