In her Digital Body Language, Erica Dhawan writes about low and high-context languages. We need a detailed understanding of the culture to process a message in a high-context language. The message has to be interpreted in its social context to be understood. When we communicate, certain things are not said because they are apparent, even if not explicit.
English language and the cultures associated with it are low-context. It doesn’t mean we always say what we mean, but we are used to having things spelt out.
Which one is better? I am not planning on settling this argument here. In the book, the debate is not settled either. Instead, the author offers practical tips on communicating online with people from different backgrounds. However, the distinction could help us understand why we struggle to read and work with “legacy” code.
And yes, I mean “legacy”, not as an obsolete code written in long-forgotten, unsupported technology. That would be legacy code. I mean the code written a couple of months earlier by me, which I cannot read or comprehend anymore. We call it “legacy”, a “tech debt”, and argue for rewrites or at least very extensive refactoring “tickets” to be put on the product backlogs… don’t we?
Refactoring, rewrites and sacrificial architecture.
Rewriting your code can be an essential part of software engineering. This sacrificial approach to software architecture worked well for many. For example, an ex-eBay Chief Engineer and Distinguished Architect, Randy Shoup, often says that if you are not rewriting from time to time, you are over-engineering. But it should not be done because we don’t understand the code or the problems. There are plenty of examples. Last week this showed up in my feed – an excellent and high-profile example of when not to do it.
If you don’t understand the problem how can you be sure that you won’t replicate it when starting from scratch?
So, how about refactoring? For me it’s part of coding. It’s something that should be done all the time as a standard way of working with code. If we practice Test Driven Development (TDD), it happens in every mini cycle red-green-refactor. I often do it when reading code too. When things are not obvious, I refactor to help me and those coming to the code behind me understand the code better. I use refactoring to help me understand things. Unlike rewrites, I think it should be used to help us understand. But it shouldn’t be on backlogs!
Coding is communicating.
And this brings us back to low and high-context languages. When we write computer programmes, we codify our solution to a problem. In some languages, we focus on the shape of the solution – that’s the declarative approach. In imperative languages, we focus on the steps to get us to the solution. What we omit, almost always, is the description of the problem. We forget that the code is not only something machines will execute. We will eventually have to read and try to understand it too.
We code as if programming languages were high-context. At the time, we don’t have to express the problem, the reasons, or the technical and business constraints behind our decisions. They are obvious. We have had to understand them to shape the solution we are crafting. But that high-context communication style works only if the person receiving our message also has access to the context in which it was created.
Digital Body Language explains how it is reasonable to expect others who live in the same culture to have that context. Communications can be very effective even if it appears to us low-contexted English speakers that some things are missing. But in programming, the context is often gone forever. Even if we go back to our own code, we look at it thinking, “what was I thinking?”
Is it engineering or archaeology?
I used to think that we struggled to read other people’s code because we didn’t practice it enough. Programming courses (universities, boot camps, online tutorials, they all) focus on writing code rather than reading it. But it could be because writing code is Software Engineering, and reading it is Software Archaeology. (check the episode of Software Engineering Radio with Dave Thomas on the subject). It is an apt description but only because we create artefacts devoid of context. Our digital products might as well have been created thousands of years ago by unknown cultures. We know what tools they have produced. But why? And why didn’t they do something else?
So perhaps the lack of practice is not the issue here. We struggle to understand what we build because we live in a low-context culture, speak in a low-context language, and yet build our digital services as if we operated in a high-context environment.
What can we do about it?
Should we comment on our code more? Should we document our solutions more? I don’t think so! Instead, we should have a screaming architecture that doesn’t need additional comments or documentation of the solution.
But we should document the problem better!
We can do it with refactoring. We can use design patterns – not as part of solutions but as a common language to hint at how we see the problem we are trying to solve. If working in the open, we can write, blog or create video walkthroughs about the situation we faced and solutions we have chosen not to apply. We need to capture not what is already in the code but what is not there and why it is not there.
Software archaeology problem affects the whole of digital products.
The problem is wider than just code. It affects digitally enhanced services as a whole. We build roadmaps to meet the needs of our users. We prioritise our backlogs by choosing and recording what we will do. But we don’t often record what we decide not to do and why. Our roadmaps look into the future showing us where we want to get to, but they rarely show where we are, what our surroundings are, and how we got here in the first place. Without all of that, our roadmaps look more like marching orders. Without it all, our products, as our code, need archaeologists to unpick the past before every next step we take.