How abstractions encourage good thinking
by Jim Gay
Many times, as developers, we grow our code in ways we don’t intend. We live with quick decisions a little too long and end up with a problem where, well, we don’t see the problem. With too much of this, our code becomes our unkempt bedroom or messy desk.
Working against your brain
A few years ago I saw an excellent presentation at Rocky Mountain Ruby by Michael Feathers about a phenomenon he called “code blindness.” In that keynote he raised the point that despite the fact developers may know how to, or know why our code should be structured differently, we become used to seeing things the way they are and no longer recognize real or potential problems. We become blind to it.
This type of behavior is a result of how our brains react to visual clutter. As we add more information, more objects, and more variablity to the environment we’re creating, our brains will dampen the signals from each part and hide their influences on our attention.
The dampening of each stimulus is a way we cope with too much information. The NIH released a news advisory in 1998 which explained how our brains can counterbalance the dampening effect with focused attention. So what exactly does this mean and how does it apply to programming?
Our programming languages are merely ways of representing concepts. Our brains translate characters to representations of things, to describe iteration, to define decisions and outcomes, and more. The more variation and number of concepts we require our brains to translate, the harder it becomes to maintain focused understanding of any individual concept.
This, of course, leads to the development of ideas such as separation of concerns, the single responsibility principle, and others in which we aim to remove visual clutter form our code and reduce the cognitive load on our brains required to translate stimuli into ideas.
By dampening the effect of stimuli, our brains are able to better focus on the immediate task. The studies at the NIH revealed that by placing effort to focus on a particular aspect of our environments we are able to counteract the dampening feature of our brains. This makes quite a bit of sense: pay attention to something and you’re more likely to notice it. But as the NIH points out that while we may only partially cancel-out the effects of nearby stimuli, the amount of the attention required increased in tandem with the amount of visual clutter.
Living with complexity and clutter in our code is often a way we decide to get work done faster now and come up with a better solution later. Unfortunately it is also a decision to create an environment where we’ll have to work harder in the future to focus on the right thing.
Working with your brain
The more we have in our environments demanding attention, the more our brains will dampen our attention to them.
Abstractions, such as the presenters we’ve reviewed in previous articles, are a way we can remove visual clutter and unnecessary stimuli. Separating our programs into layers of responsibility is a way of working with our brains to ensure they’ll only need to place just enough effort required to maintain focus and understanding of a particular concept.
The act of building these layers in our programs is how we make decisions to work with our brains' ability to manage focus and prevent the dampening effect from slowing down our work.
This introduces to our program our idea of habitable code. What we consider to be a place where our brains will function well will be expressed in our program code. Often, the place I find the most trouble is with view templates. As a result I work to treat these as much as possible like configuration where logic and number of distinct objects are kept to a minimum.
Transformations of data are often a place where confusing details can cause us to filter out valuable concepts from our minds. View templates which contain multiple objects, transformations of data, control structures such as
if/else/unless blocks or iteration are a source of clutter.
Visual clutter can appear all over or merely in a single line.
link_to timeslot.in_time_zone(@timezone).strftime("%l:%M%p"), new_profile_appointments_calendar_event_path(@calendar.profile, @calendar, :event_slot_id => event_id, :timezone_name => @timezone.name), :class => "open", rel: 'nofollow'
When we write code we create the environment in which our brains must function and react. Often, we end up creating these cognitive barriers in our view templates like this. Fortunately, we’re able to simplify them with techniques like pushing complexity into a presenter layer.
If you review the code sample above, you’ll need to spend quite a bit of time, far more than you should, just to understand what will be output.
It’s important to make decisions to remove the parts unimportant to us. The abstractions which we create can remove as much information as we decide. Leaving parts for our brains to compose can be a feature:
link_to time_display, new_event_path, class: "open", rel: "nofollow"
Or creating a small footprint to handle a concept at a higher level allows us to remove visual clutter and removes the need to compose parts.
presenter.new_event_link(class: "open", rel: "nofollow")
These sample bits of code show no implementation, but the great thing about programming is that we get to choose. The choices we make might work with our brains or might work against them. We can push away noisy details like which timezone to use for formatting and how how to
Our divide and conquer approach with abstraction layers helps us to filter out noise from signal. Of course, with too much abstraction we may become mired in the noise created by divided ideas but we get to decide and experience what fits best.
Work with your brain and consider what ideas belong in which places. Write the code you wish to have.