Types and obviousness

The importance of a strongly typed codebase.

Iguazu Falls, Brazil/Argentina

The software development world, just like other expressions of human society, lives through cycles. A most notable one is the typed/not-typed trend.
Data types were a critical concept of early computer languages. High level languages and frameworks inherited this approach, until we saw a massive rise of weakly or non-typed languages.

From a developer’s perspective, typing variables can seem like an unnecessary burden. Under this light, non-typed languages would provide a fluid, fast developing experience. This flexibility gained momentum alongside trends like startups, rapid prototyping, and the ‘fail fast’ mentality.

All of these are valid approaches, but they have a time and place to be put to practice.

Good code is obvious

Having worked on many different codebases over the years, there’s one value in particular that I strongly advise my team and everyone else to pursue: code should be obvious.

This means that one should be able to read a piece of code and not have to guess or assume anything (as much as possible). Also, the less amount of brain power needed to keep track of a piece of code, the better.

Take this pseudo-code example:

return user?.accountType === 1 || user?.shift === null ? true : inShift(user?.shift);
  • What’s the intent of this line of code?
  • What’s accountType: 1?
  • What’s the meaning of a null shift?
  • How many brain cycles did you use to keep track of this code?

Here’s another attempt:

if(!user) return false; 
 
const isAdmin = user.accountType === 1; 
const unrestrictedShift = user.shift === null; 
const isInShift = !unrestrictedShift && inShift(user.shift); 
 
const loginAllowed = isAdmin || unrestrictedShift || isInShift; 
 
return loginAllowed;

While ternary operators might be considered more elegant by some, striving for fewer lines of code isn’t always beneficial.
Your code does not need to be cool. It needs to work and be easy to understand.

Notice how naming each part of the logic made it obvious to understand the requirements and what was going on.
Even the return value, that could easily be swapped to return the or directly, adds clarity by naming it. And don’t worry about performance - most modern compilers will take care of optimizing this code.

Now, suppose you have been tasked to improve this logic by also checking the user’s subscription level. You hover your mouse over user and the IDE shows you: any. Next thing you know, you’re 5 files deep, logging everything to understand the shape of the user object.

Strongly typing your variables adds heaps in code clarity and error safety. If you’re able to use runtime typing, even better. This ensures your code won’t have to deal with objects different from the expected shape.


Take some tips from self-documenting code and make sure your code is obvious. Try reading it as a newcomer, someone completely new to the codebase. This will immensely help every part of the process — from writing, reviewing all the way up to troubleshooting.