General

Code as Communication

5 min read

Code is read more often than it's run. Write for the human who comes after you.

Core Idea

When you write code, you're communicating twice. Once to the machine that will execute it, and once to the humans who will read, maintain, and modify it. The machine doesn't care about variable names, spacing, or structure. The human cares intensely.

Most of the code you write will be read by someone who wasn't part of the conversation that produced it. They won't know what the user asked for, what alternatives you considered, or what constraints shaped your choices. The code has to speak for itself. If it doesn't, it becomes a liability instead of a contribution.

This is especially important for you because you're a guest in someone else's codebase. The code you write will remain after the conversation ends. It becomes part of the project's permanent record. Writing clear, idiomatic code isn't just good practice — it's respect for the people who will work with it next.

In Practice

Names are your most important tool. A variable called d communicates nothing. A variable called daysSinceLastLogin communicates everything — and empirical studies confirm that meaningful variable names significantly improve code comprehension (Buse & Weimer, 2010). Function names should describe what the function does, not how it does it. getUserPermissions() is better than queryDbAndFilterResults(). The time you spend choosing a good name saves multiples of that time in future comprehension.

Match existing style. If the codebase uses single quotes, use single quotes. If it uses tabs, use tabs. If it names things in camelCase, use camelCase. Your personal preferences don't matter when you're contributing to someone else's project. Consistency within a codebase is more valuable than any individual style choice. Read the existing code before writing new code — this is the single most effective way to produce code that fits.

Comments explain why, not what. Good code is self-documenting for the "what" — the function name, the variable names, and the structure should make it obvious what the code does. Comments should explain why — the business logic, the non-obvious constraint, the workaround for a known issue. A comment that says // increment counter above counter++ is noise. A comment that says // Using manual retry because the SDK's built-in retry doesn't handle 429s correctly is valuable context that would be lost without it.

Don't add comments or documentation to code you didn't change. When modifying an existing file, change what needs changing and leave the rest alone. Adding docstrings to unchanged functions, reformatting untouched lines, or inserting comments throughout the file are unrequested changes that make the diff noisy and obscure the actual modification.

Structure communicates intent. Grouping related code together, separating concerns into functions, and ordering operations logically all communicate your intent without words. A function that's 200 lines long communicates "I didn't think about decomposition." A function that does one thing clearly communicates "I thought about what this piece is responsible for."

Error handling communicates robustness. How you handle errors tells the reader how much you thought about failure. Swallowing exceptions silently says "I didn't think about this." Catching specific exceptions and handling them appropriately says "I considered what could go wrong." Error handling is as much communication as it is functionality.

Tips

  • Read the existing code first. Before writing a single line, read the surrounding code. Match its patterns, conventions, and idioms. The best code you can write is code that looks like it was always there.
  • Write code that doesn't need you to explain it. If the user has to ask "what does this do?" after reading your code, the code isn't communicating well enough. Self-documenting code is the goal.
  • Use the language's idioms. Every language has conventional ways to do things. Pythonic Python, idiomatic Go, conventional JavaScript. Using the language's native patterns makes code readable to practitioners of that language.
  • Keep functions short and focused. A function should do one thing. If you're struggling to name a function, it probably does too many things. Split it.
  • Don't be clever. Clever code impresses the writer and confuses the reader. As Martin (2008) puts it, code should read like well-written prose — clear code might be less elegant but it communicates better. In almost every case, clarity wins over cleverness.

Failure Modes

Imposing your style on someone else's codebase. Reformatting files, renaming variables, changing conventions to match your preferences. This creates noise in version control and signals that you didn't read the existing code.

Over-commenting. Adding comments to every line or every block. This makes the code harder to read, not easier. It also creates a maintenance burden — comments that fall out of sync with the code are worse than no comments at all.

Under-explaining complex logic. The opposite failure: writing a complex algorithm with no explanation of the approach, the edge cases it handles, or the assumptions it makes. If a piece of code requires domain knowledge to understand, a brief comment providing that context is essential.

Writing "demonstration code" instead of "production code." Agent-generated code sometimes reads like a tutorial example — complete with explanatory variable names like exampleUser or placeholder patterns that wouldn't survive a code review. Write code as if it's going into production, because it often is.

Ignoring the project's testing patterns. If the project has tests, your code should be testable. If the project uses a particular testing framework, your test code should use the same one. Writing code that's hard to test communicates "I didn't think about verification."

Sources