No Clever Code

Read this first

Be Kind to Future-You

An early mentor of mine described the starting point of a development effort, feature implementation, or a debugging session as

The Point of Maximum Ignorance

Besides it being the point where the client wants a fixed-price bid, it is also the point where Past You can do the most good for Future You

When one is coding a feature and comes to the error handling, one has a choice: throw an Exception("Something went wrong") or pay some of the debugging work forward. That point of error handling is The Point of Penultimate Wisdom1(PoPW)

The code knows

  • what it was trying to do
  • what step went wrong
  • what values it was using at that step
  • (in many cases) what code was calling it and the values it passed in
  • and more

One can find wisdom after something went wrong by furiously2 instrumenting the code and deploying it into production, by swimming upstream in the logs to find the butterfly...

Continue reading →


It’s All About the Emersons

A foolish consistency is the hobgoblin of little minds

A wise consistency is the obsession of system architects

Humans like patterns. We even see them when they are not there1. Much of poetry is the patterns of word sounds and rhythms and even the patterns of grammar and meanings

Patterns can help optimize construction: standard sizes of materials and tools, as well as construction and assembly standards (“codes”), allow various environments to be predictable, familiar, and productive. Beyond the namesake Software Patterns, common computer languages, frameworks, protocols, and idioms allow software developers to move from project to project and organization to organization, pausing only to learn about the new specifics before diving into work

As with most things, extremes of standardization are generally a Bad Idea. An absence of patterns and consistency makes cooperation and task...

Continue reading →


Efficiency and Flexibility Are Inversely Proportional

E ∝ F-1

In almost all things, a reciprocal relationship between efficiency and flexibility exists. In some cases, it’s obvious why: assembly language runs faster, and Python codes, changes, and debugs faster. Depending on one’s context or priorities, the definition of “efficiency” and “flexibility” change

Efficient Flexible Software execution speed Software development speed Domain-specific software languages General software language Software monolith deployment Separate APIs, UIs, and data stores deployment Strictly following a recipe Dash of this and a bit of that Measuring carefully to a cut-list “feeling” what the wood wants to be

One can optimize flexible systems to be as efficient as possible (e.g. compiling Python), and one can make efficient systems as flexible as possible (assembler macros and debugging). The actual characteristics of efficiency and of...

Continue reading →


Mindful Functions

TL;DR: break code into short functions with scalar parameters and good names, and coordinate them

Mindful means, for a human, to focus on the immediate environment, task, and intention: to be “present in the moment”. For a function, it means to do one operation and to return the consequence of that operation. This is quite close to Functional Programming’s definition of a pure function (side-effects withstanding). F.P.‘s prime benefit is the isolation of the operation; mindfulness’ prime benefits are attention, modularity, and scope

Each function or method should do one thing1. The implementation of that one thing might be calling other functions. For example, a function prepare_order() calls other functions to process every step of the order; it never actually changes or creates data itself, yet it completes a single conceptual task by orchestrating sub-functions

Hierarchical Code

...

Continue reading →


Righteous Naming

If names are not correct, language will not be in accordance with the truth of things — Confucius (attributed)

Good names take effort[1]. Bad names, eventually, take more effort. Good names help code look like (awkward) prose[3] instead of mathematical formulas. Good names help readers focus on what the code is getting done rather than “WtF is this coding doing‽”. Good names reduce the need for comments or the readers to drill into the functions’ code[4]

Think of a big pile of tools, materials, and supplies. To find anything, one has to dig through, on average, half the pile. It’s like one big function or script

Think of the same stuff in unlabeled drawers and boxes. One looks through boxes unnecessarily because the contents are not obvious from the boxes’ labels (or one does not understand or does not trust the labels)

Think of the same stuff in labeled boxes grouped by some...

Continue reading →


We Can Afford To Buy Vowels

TL;DR Programs must be written for people to read, and only incidentally for machines to execute —Harold Abelson

In the old days <eyeroll/>, we had 26 variables: the letters of the alphabet. The next leap in programming, we could add one digit after the letter. That was not good enough for development then, and it surely is not now

With no restriction on the length of names, the vestigial traditions of opaque naming cannot hide behind brevity or idiom, and certainly not consistency1. The only measure for names is their utility in communication

A line of code like r.Get(true) is opaque. While IDEs can help decode what the r and the true mean, using descriptive names allows the code to speak for itself: orderReader.Get(CacheDataOk)

Multi-letter abbreviations harken back to Hungarian notation: abjad2 type names prefixed or suffixed to a (presumably) descriptive name (e.g. submitBtn). Or...

Continue reading →


A Function’s Interface Is It’s Bond

TL;DR: A function must respect all arguments or return an error

The Arguments

The only realistic way a function can fail its interface is how it treats arguments as mis-typed arguments or return values are usually caught by a framework

All The Arguments

Be they required or optional arguments that are present, functions must respect all the arguments; they cannot ignore some because they are inconvenient or contradictory

“I’d like a number four with no cheese”

One cannot stop paying attention just because we know what a 4 is. Functions and especially REST endpoints often accept resource ids or primary key values, which implicitly identify specific resources. Tempting as this easy lookup is, the function must apply all the arguments even if they are additional criteria. With a key value in hand, the function does not need additional criteria, but it cannot ignore them

A function...

Continue reading →


Walk, Don’t Race

TL;DR

Don't Race.png

Cha-Cha-Changes

Breaking changes happen, and the breaking occurs between the layers (e.g. UI and API, API and database). Rather than trying to release new layers simultaneously (especially with edge distribution), commit the time and effort to a four or five-step pattern that ensures the layers work perfectly at all times, losing no data

1. Create the Change You Want To Be

Create the goal: the new schema; the new endpoint; the new protocol. Test it, benchmark it, and be happy with it. Copy and translate the old system’s data to the new system (handle the subsequent data changes in step 4)
For example, instead of changing the data type of a column, create a new column of the desired type

2. Embrace the New While Respecting the Old

The Problem With Data

It’s always the data

The transition depends on how the old and new systems share data

  • Type A: if the clients are making...

Continue reading →


A Simple Caching Pattern in Go

One might use it like this:

var myCache = NewOurCache(0, calculateTimestamp)
// ...
var myValue time.Time = myCache.Open(dateText, timeText, Location)

OurCacheType is an alias for the actual data cached. It can be any type including a structure or pointer. composeKey() is an example how to consistently create a string key from whatever identifies the data. These parameters usually match the parameters of the createAValue function (if used)

Use the cache by Write() values if the Read() cannot find them, or you can use something like the Open() function, which returns the cached value if found in the cache or it generates the value (using the createAValue function), caches it, and returns it[1]

[1]: My naming convention is:
find("key") returns the value and a boolean (like aMap["key"])
get("key") excepts/panics if it cannot return the value
open("key") returns an existing instance or...

Continue reading →


Single Responsibility Lines‽

From Wikipedia:

The Single Responsibility Principle (SRP) is a computer programming idea: every module or class should have responsibility for a single functionality. All its services should be narrowly aligned with that responsibility. I leave the discussion about SRP in modules and classes to the plethora of sources addressing them

Yeah, But Every Line

Yes, every line should perform a single1 task. Even if you are using Perl, every line should have one specific goal. Complex expressions are ¡very impressive¡, but such preening makes the code hard to understand2. Breaking complex expressions and commands into informational variables and steps makes them easier to read3, easier to debug, and easier to refactor

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated...

Continue reading →