The One Tech Concept Everyone Should Learn

There is a mental model that has gained some traction recently called chesterton’s fence. The moral of the story is that we should figure out why something exists before we change or remove it. This is a useful piece of wisdom. Of course, the next question that naturally follows is “How?” How do we ensure that we are only removing redundant fences? How do we ensure there isn’t a bull waiting to trample us on the other side?

The answer to this question is not embedded in the mental model. But I think one concept from the tech world can facilitate answering the question of “How?”. It is a concept worth understanding even if you consider yourself nontechnical and never plan to get technical.

That concept is called refactoring.

Refactoring: What Is? 🐝

“Perfection is achieved not when there is nothing left to add, but when there is nothing left to take away.”

~ Antoine de st. exupery; wind, sand, and stars; 1939

When done well, refactoring is really a thing of beauty. The process is illustrated wonderfully in this gif of the evolution of office desk tech:

1

Envisioning how an entire system operates is a challenging thing to do – sometimes impossible to do in totale. So processes of refactoring were developed to aid software developers in cleaning up systems and making them more intelligible to those that must work with and within them.

Refactoring is often compared to the editing process when writing and this is a useful metaphor to get the gist of it. But there are some key points that I’m not convinced are readily derivable from the editing analogy:

Refactoring (often) includes building external scaffolding around the system in order to verify that the system is operating as intended. These specific processes (can) also ensure the behavior of a system isn’t changing while the system is updated.

These differences strike me as strategies society sorely needs to safely remove Chesteron Fences, because these techniques can assist in deriving answers the question “Why is the fence here?”

Differences: A Close-Up 🐝

If you are curious, there are entire blog posts and books written about how refactor code, but for the purposes of this post we’ll focus on those high-level principles that inform the overall process:

  1. Verbalize assumptions and verify them: This includes adding automated tests to validate the code’s functionality.2
  2. Don’t add new stuff now (if possible): The goal is to improve the function of the system, not to change the system’s behavior.
  3. Make it understandable and mind your levels: The main purpose is to improve the readability (or efficiency) of code by placing logic at appropriate levels of abstraction.3

1. Verbalize Assumptions and Verify Them 🐝

When building a software system, it is wise to include a test suite. The point of a test suite is to ensure that the system is actually doing what you think the system is doing. This is often compared to double-entry book keeping because it shares the attribute of essentialy doing more or duplicate work to increase the likelihood that your expectations are accurate.

Automated tests are particularly useful because they force the engineer to explicitly state what they expect to happen and then the system tells the engineer if that in fact is happening. This makes the goals of the system explicit and validates that the system is actually accomplishing those goals.

Some engineers may argue that this is a part of testing and not refactoring. But I beg to differ, because by having a reliable test suite a developer can make changes to a system with a higher degree of confidence that they have not accidentally changed the behavior of the system, which gets to my next point…

2. Don’t Add New Stuff Now (If Possible) 🐝

Editing a paper, updating legislation, or refactoring a codebase all involve making changes. But a new principle was birthed with refactoring in particular: When changing how goals of a system are reached or expressed, the goals themselves should not change.4

Countless hours of painful debugging in software has resulted in the wisdom that additions and changes should typically be performed as completely separate operations. It is all too common for a developer to try to add a new feature that depends on a pre-existing one that – whoops! – they or their colleague changed, which caused the new feature (and perhaps others) to break.

There are largely two reasons for this: 1. Cause and effect are often trickier than we think it will be to tease apart5, so limiting the number of possible causes can relieve the difficulty in identifying the correct one. And 2. We only have so much attention and it should be allocated prudently. By drawing a dividing line between additions and changes, focus can be more efficiently distributed between them at the appropriate time.

3. Make It Understandable and Mind Your Levels 🐝

The one guiding principle I’ve come to rely on to make things more understandable is to answer the question: At what level should this live?3

The answer to this one question is a pretty good guide, because it forces the consideration of how any single point is situated within multiple varying scopes at various levels at once. What words or variables are used? How are the sentences nested in paragraphs in chapters, or functions inside of classes in modules?

Our minds work via chunking so by creating clearly delineated chunks, moving from file to file, or project to project, becomes trivial for our brains to handle. It also provides clear dividing lines between who or what is responsible for any particular chunk.

Remodeling Fences 🐝

Systems are extraordinarily complicated. But once we get used to a system, it’s easy for its quirks and behaviors to fade into the background. Similarly, we tend not to think about how and why cultural norms, laws, and regulations shape the way we live…Especially when they just work. But this is a mistake and it is dangerous. We should get in the habit of making these norms explicit, to understand what’s going on under the hood, and verbalize what we think is happening and check it against reality.

The principles outlined here help to bring invisible norms out into the foregorund in order to improve understandability and reduce the number of inaccurate assumptions. We should not only be doing this when we build web applications or machine learning pipelines, but in society writ large. The hard-won lessons of refactoring software could guide and inform the creation of a framework that helps us better innovate government, society, and culture.6

We must not forget that if we can’t describe why the fence is there, we won’t know what we will unleash when we try to take it down.

With regard to societal systems, this post is best read in conjunction with [[2023-09-12-forget-pos]].

  1. gif src

  2. There may be developers who disagree with this definition. True, testing is not always assumed in the steps of refactoring. But I would equate not using tests to not inspecting the other side of Chesterton’s fence. Say hello to Toro for me. 

  3. For more on levels: townhouse; how to move between them: compressed explanation; and the process of building them up and breaking down: [[break-chunk]] 2

  4. Experts can seem to be multi-tasking, but even so, they likely can draw distinctions around which specific commits go with which intended additions and changes. 

  5. #todo [[probl-pool]]

  6. Occasionally you will hear someone say they want to start society over from scratch. But even in software, experienced developers will vehemently warn against this. If we can’t reasonably expect to start a technical project over with less effort than it takes to refactor it, how do you expect to do so with something as vast as society?