Your code isn’t as clear as you think it is, but there’s things you can do to help

Christopher Laine
Jun 16 · 7 min read
Photo by rawpixel.com from Pexels

I just got through reading Cindy S Cheung’s great article on technical documentation and why devs need to explain their code better, and I have to say I completely agree.

I’ve been at this IT game a long bloody time, and in my experience, there is one self-delusion which developers and engineers just can’t help but cling to.

My code is self-documenting — The Delusional Dev

The theory here is that an engineer’s code is so clear, so easy to read, that is doesn’t require documentation.

Yeah, this is nonsense…mostly.

Why is ‘self-documenting code’ nonsense?

Look, you might be the Ernest Hemingway of programming. Your code might be super-duper clear and easy to read (to another dev). The fact remains that it IS code, and no matter how concise and clear your work might appear, it is not meant for non-programmers to access without a lot of squinting and muttering of “wtf does that mean?!”

So why is self-documenting code nonsense? Let me lay it down for you.

Reason 1: There are all kinds of gotchas in programming which do not self-document

Simply, because most people, including developers, are not machines. Yes, I can most likely muddle through your code, yes I can read your method and class names. I can even see what you’re doing in each method.

Code is written FOR machines. They know what the heck to do with it, and thus why we have programming languages. People, on the other hand, need a more human way of accessing what your software is doing.

Reading code and seeing what it does is a long way from documentation. It might have all the elements of what your code is doing, but are all those things self-documenting? I think we all know the answer is ‘no’.

Check out this simple blob of C#. I’m reading a file, getting its contents, and getting the file encoding, using a StreamReader.

var fileContents = “”;
Encoding fileEncoding;
using (var reader = new StreamReader(filePath, Encoding.Default, true))
{
reader.Peek();
fileEncoding = reader.CurrentEncoding;
fileContents = reader.ReadToEnd();
}

Ignoring the fact that what a StreamReader is might not be clear, that’s reasonably simple code, right? So…what in the hell is with this line?

reader.Peek();

It turns out this is required on the reader if you wish to get the file’s encoding. Huh, well that’s not self-documenting at all, now is it? If we simply took another 10 seconds to write this, we’d have made the code more clear.

reader.Peek(); //This peek is required to get the file encoding.

This is just one example, and a damned simple one at that. As your code grows in complexity, these kinds of little details pop up everywhere, slowly muddying the clarity of what is taking place, and making it harder and harder for anyone to know precisely what is going on.

Reason 2: Complexity is not natively self-documenting

If you’ve ever written a BASH or BAT file, you know that the actions taking place in it are sequential. One task flows to the next. It’s like a little story, leading from the first line all the way to the last.

However, if you are writing a program, especially a web application, there is no such sequential story, beyond perhaps the startup / configuration of the overall web services.

The actual classes which make up a modern web application are not run in a sequential flow, but are instead a collection of web or API controllers, called when a client calls the web app itself. Each web / API controller can have flows which spawn off new processes, send messages to other services, wait on responses in order to fire web hooks back at listeners. None of this reads in anything approaching a story format. For all your “self-documenting” code, what a novice or non-programmer will get from it is a sense of “I guess I understand what that does”. This, again, is hardly documentation one can trust.

The more complex your application, the more likely it’s classes, methods, and framework will operate in a non-sequential fashion. The likelihood that anyone will make sense of what the application is doing is an ever-decreasing slippery slope.

Reason 3: Coding syntax is not fundamentally an easy read

Just look at this jquery function to call an API endpoint.

var myURL="https://some.url/path?access_token=my_token";

$.ajax({
url: myURL+"&callback=?",
data: "message="+someOtherData,
type: 'POST',
success: function (resp) {
alert(resp);
},
error: function(e) {
alert('Error: '+e);
}
});

Uh…

In no way am I saying there is anything wrong with this syntax. For a jquery call, this is totally acceptable. What I will point out is that if you look at this from the point of view of a novice jquery programmer, or from the point of view of a non-developer, this might as well be in bytecode. It makes about as much sense.

Syntactically, programming languages are designed to use the constraints of the language itself, coupled with helpful shortcuts to keep your code compact and easy to change as needed. This is not supposed to be a robust language in the sense that anyone can make sense of what is happening. It is intended for those people who know this language, its syntax, and its shortcuts.

For everyone else, it just makes things unclear.

What can you do to help?

There are things you can do to help non-developers with your code.

Step 1: Actually write some documentation

I know, sacrilege, right? Write documentation?! Of all the ridiculous ideas!

Seriously, no one is asking you to write War and Peace. But, what you can do is write down the primary actions, validation, and error-handling, in a simple flow.

  • The client calls the API endpoint /someurl/object/{id}
  • The API controller uses {id} (an int) to search for the object in question in the database.
  • If the object comes back null, the API controller returns a 404 (File Not Found) HTTP response to the client. The API controller logs this as a warning.
  • If the object is NOT null, the API controller converts the object to JSON format, and returns it with a 200 (OK) HTTP response to the caller.

That’s hardly difficult, and also means that you’ve made someone else’s life easier. If you’re interested in more selfish motivations, then writing this down means when people want help, you can point them to the doc, and not have to explain it again and again every time someone asks.

Step 2: Make some diagrams

If writing simple documentation is too difficult (please!), then at the very least, consider creating some diagrams, as these often give the glue necessary for someone to bridge your code with what is going on.

Have a look at websequencediagrams.com, which offers a simple textual format for creating great sequence diagrams.

The text

title Service one to service two
Service two requester -> Service two http client: Get Contract
Service two http client -> Service one REST API: GET /api/contracts/{123}
Service one REST API -> Service one app logic: get Contract with id 123
Service one app logic -> Service one REST API: Contract
Service one REST API -> Service one REST API: Serialise to JSON / XML / etc.
Service one REST API -> Service two http client: Serialised data
Service two http client -> Service two http client : Deserialise to Contract
Service two http client -> Service two requester: Contract

The diagram this produces

That’s nice!

The old adage about a picture being worth a thousand words is correct. Diagrams like this and others (such as a flow diagram) mean that non-programmers can learn about your app’s behaviour by reviewing a picture. That’s value to your co-workers, and with little investment on your part.

Step 3: Use Ubiquitous Language to help the naming of your classes and actions

As I outlined in another post, a Ubiquitous Language is a concept from DDD in which the team and users define a language of terms for all the classes and their interactions. Such a language is human-understandable, so that customers, testers, trainers, and business people can agree upon and understand what our software is doing to fulfill our user’s problem domain.

Once you have your Ubiquitous Language, you should make sure to name your classes, their methods, their events, everything, as closely to your Ubiquitous Language as possible.

This ensures that anyone reading your code (even non-programmers) can at least muddle through to some extent, as the programming structures align with terms and business concepts which they understand.

/// <summary>
/// The Customer is responsible for their own login / logout, as well as retrieving their profile information, and management of their
/// settings
/// </summary>
public interface ICustomer
{
Task<AuthenticationResult> Login(string username, EncryptedString password);
Task Logout();
Task<CustomerProfileInformation> GetMyProfile();
Task SaveMyProfile(CustomerProfileInformation);
Task<CustomerSettings> GetMySettings();
Task SaveMySettings(CustomerSettings);
}

While still in code, the description at the top, coupled with the use of terms which are familiar to everyone, make it easy to understand what is taking place, because the terms already exist in our Ubiquitous Language

Step 4: Just add some comments

If all of this sounds far, far too onerous, then at the very least, just add some meaningful comments in your code. You may not need them right now (you are down in the weeds, so of course the code makes sense to you), but in the future, you very well might.

A few well-placed lines of comments, a class comment, method comments, these go a long way to making what’s going on in the code far more understandable. I’m not talking about commenting every line (that actually makes the code harder to read), but just hit the main or complex areas of the code, so someone can come along and work out what is afoot.

Hope this helps

IT Dead Inside

IT is a cesspool, but its home

Christopher Laine

Written by

Writer, sci fi / Lovecraftian nutbag, "master' chef, gym rat, martial artist, Dungeon Master, and programmer. I cover all the useless bases

IT Dead Inside

IT is a cesspool, but its home

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade