Ordinateur

Communicating Through Code

March 28, 2025

I think about communication a lot. What point do I want to get across? Who am I trying to persuade? How will they receive the information? Have I thought about this idea clearly enough to share it? Which words are the most precise and least ambiguous? Each audience we communicate to requires different contextual information. This holds true when we write code, which has to be interpreted by several different people (or things). Let’s look at some examples.

Talking to Machines — The most obvious audience for code is the machine that it runs on. A software program is just a set of instructions that tell a computer what actions to execute. This is a contextless interaction. The computer will usually do exactly what it is instructed to do, as long as the program is syntactically correct.

Talking to Ourselves — When we write unit tests, we become the first users of the code we have just written. This is a form of self-dialogue where we validate our code behaves the way we expect. During this process, we may find that the interface we’ve designed is difficult to reason about or that side effects are making it hard to test.

Talking to Reviewers — A pull request is a set of proposed changes to one or more code repositories. The code is usually displayed to reviewers as a sparse list of lines added and removed. When writing a pull request, it’s helpful read the draft in the user interface to see what context has been stripped away. Beyond the basic syntax, there may be common idioms or styles used by a team to make understanding code easier. For example, seeing Java variable written in snake-case would be quite off-putting as a reviewer.

Talking to Future Readers — All code changes are made with situational context, which can get lost in the shuffle as we move on to other tasks. Hypothetical: you’re investigating a 5XX error from a dependency. You see a block of code like this let num_retries = 0; and you’re tempted to add retries to make your application more resilient. The only information you can find about this line of code is a commit message “Set retries to zero” and a link to a pull request with an empty description. Is this configuration safe to change?

In an alternate universe, the person who wrote the code added a very helpful comment: DO NOT modify this value. FooService is susceptible to retry storms which caused two outages: <link>. This might make you think twice about adding that retry. Or maybe you know that FooService has made some major scaling upgrades, so the original assumption that led to this value is no longer relevant.

Talking to Users — Obviously, the specification of a REST API communicates what an API does and how it should be used. But what about the runtime properties? Even though systems are opaque to end users, API interactions can offer explicit and implicit indicators of system behavior. Coherent error messages are critical to API usability. If I call an API with 10 different parameters and the only error messge I receive is Invalid input, there is no obvious action to take to resolve the problem. A better error message would be Invalid input: Name field does not match regex pattern <pattern>. The latency of an operation is another signal to the user. Many of us have waited patiently for a response after naively querying a database with SELECT * FROM .... The slow response tells us that this is an expensive operation that should be used judiciously.


This is Part 1 of a series where I document mental models about communication.