#+TITLE: Always include units
Whenever I give advice as a software engineer I couch it with a
softener: it /always/ depends on the context. Always include units
is one of those rare pieces of advice I feel comfortable giving
unconditionally (and consistently request while reviewing code).
This applies across variable names, database column names, UI elements
and any other place storing otherwise unlabelled numeric values.
In practice, being pedantic about naming units correctly has saved me
from several gaffes and being off by large factors without realizing
it. Of course, these are opinions born of experience; and I'm in
distinguished company. Errors like adding seconds and pixels also
tend to stand out in the code.
The other valuable payoff I've observed is that consistently naming
units is excellent for communication: it makes it significantly easier
for someone new to the space to pick up on the code and data piece by
piece; particularly if they're only looking at one particular part of
a large and complex piece of software.
One unfortunately -- but unsurprisingly -- consistent bug I've
observed across codebases is not accounting for the fact that PHP and
milliseconds. These often manifest as timestamps set in 1970: a
seconds-based timestamp passed in to a surface that expects milliseconds.
The mechanism you do end up relying on to include units does depend on
context. I don't have very strong -- or well enough informed --
opinions here, but there are several patterns I've observed in the wild.
They all have different tradeoffs between simplicity, correctness at
runtime or compile-time and potential performance trade-offs. I would
recommend that you do any of these, as long as the information about
the unit of the numerical quantity is somehow passed along with the
At the most basic -- and accordingly most portable -- level, I recommend
relying on consistent naming to identify a variable. For example,
long current_time_ms = System.currentTimeMillis(); long current_time = System.currentTimeMillis(); #+end_src
I generally prefer this approach because it costs nothing to add
beyond perhaps one extra iteration: and generally receives minimal
push-back for adoption. It works directly and consistently across
languages and user-interfaces, and has no performance impact.
This becomes particularly relevant where it's not entirely obvious
what the quantity being measured is (clearly someone should have
consulted me while designing language level APIs):
let current_time_ms = Date.now(); let current_time = Date.now(); #+end_src
current_time_s = time.time() current_time = time.time() #+end_src
$current_time_s = time(); $current_time = time(); #+end_src
Java has the TimeUnit class which can be passed along with a numeric
value. It encapsulates conversions between different units, but
doesn't own the value directly.
You end up avoiding the allocation but don't get the encapsulation:
it's still possible to ignore the time-unit or find it inconvenient to
pass it along.
Lock lock = ...;
Several languages completely encapsulate the quantity and unit in a
single class, in a perhaps obvious pattern.
Python has the timedelta object to represent time: they end up
encapsulating the time value completely and you don't need to
explicitly think about the units. The trade-off would be the extra
object being created.
year = timedelta(days=365)
Rust has a Duration class as well, which does something fairly
similar. Rust being rust, I suspect it doesn't cost too much. All the
functions are inlined. I prefer the explicit from_<x> API for creation
instead of the default constructor for obvious reasons.
let hour = Duration::from_secs(3600);
C++ has std::chrono::duration, based off the same idea, but appears to
be much more clever with fractional numbers.
Surprisingly -- and happily -- enough, CSS does pay a lot of attention
to units and using them is surprisingly natural -- as long as you do
include the units.
And of course, sufficiently advanced type systems are
indistinguishable from magic. As far as possible, it's valuable to
use types to prevent adding ids with quantities, or seconds and
kilograms with whatever compile time mechanisms the language affords