Nuance Decay (Software)
Nuance decay is really obvious and useful to spot in software. In normal life it is an occasional problem, but in software it is everywhere.
Why does this code do that? Why was this the best way? Why this formatting? Why this style? Why this protocol design? Why was it right to treat this edge case as an error? Why not do it this other way that seems just as good? Every bit of decision-making that went into the code, that matters but could be done differently without becoming immediately obviously wrong, broken, or worse - nuance.
The most obvious example of nuance decay in code is code copied without its comments, or seen without the commit messages or documentation which explain the rationale. So right away we can see how we can manage that kind of basic nuance decay risk: crucial information can be moved into the code, into the names or the shapes of its API, where you have to do extra work to remove it instead of extra work to keep it:
express "if you do this, that's an error" as an if statement that raises an error or as an assert;
express "doing this might do the wrong thing in ways this code can't or won't check for you" by having "unsafe" or "unportable" in the name;
and so on.
Here's a less obvious one: you write some code in a specific way to correctly handle some obscure edge-case - but you have no test to check that edge case. When someone looks at that code, if they don't think of that edge case, nuance decay has happened. This often does not matter until there's a need to change that code, but then it matters a lot. A test case stabilizes the nuance, at least within the environment of that project.
Similarly, much of "cargo culting" - copying patterns or practices without understanding how they work and why they are justified and in which contexts - can be understood as nuance decay. A good but rushed software developer sees an unfamiliar pattern in code, does their best to find or reverse-engineer a good explanation, gets to a plausible answer, and sees nothing to disprove that answer.
But I said it's everywhere, so let's go deeper - nuance decay risk almost always has one-to-one correlation with complexity, and in particular with code being badly coupled or complected together.
Any time you write some code which will do the wrong thing unless its caller or something it calls is written the right way, unless that's really obvious, that's introducing extremely "unstable" nuance, which will always decay unless we think about both the caller and called code at the same time:
A very common example is passing a reference to a mutable data object to a caller, and expecting them not to mutate it - or receiving a reference and expecting it not to be mutated concurrently. In C we fix this by having the called function make the pointed-to-object `const` in its signature (and hoping that const-correctness was not violated); in Python we can fix this by wrapping the object with a proxy that disallows mutation (and hoping that no one bypasses it with introspection or modules written in a language with no memory safety); if all else fails in most languages we can at least copy the object and hope that optimizations will eliminate the copy if it isn't needed. Notably this also reduces how complected the behavior of those two pieces of code is.
Another example is code which builds code strings - HTML, SQL, a shell command line, whatever. If you know that it will never process inputs that need escaping, you could justifiably ignore escaping. But this is also nuance - an assumption and a caveat that hovers over the code, and which is so vulnerable to decay that you have to keep actively reinforcing it in your head in order to not accidentally use the functions in an unsafe way.
Notice that these last kinds of nuances decay almost inherently can't be stabilized with comments or documentation - no amount of "this code will only work if you make sure to pass in only the right inputs!" warnings will free you from the work of remembering those warnings.
You must hold this extra complexity, these extra caveats, these extra wrinkles of nuance about how to use this code, in your head, every time you use it - or else your code might be broken or even dangerously hackable and you won't even know.
So:
Nuance decay gives you a pretty good way to answer "should I change the code shape? or change the names? or at least add a comment here?" - or in other words, "is this self-descriptive enough?" Just ask yourself - if someone doesn't know why I'm (not) doing this, and they had to figure it out from context, would they get the wrong idea?
Nuance decay is a very powerful idea for predicting readability and maintainability problems in your code, especially the ones caused by implicit assumptions and unnecessary complexity, because it centers "what information must come along with this code to use it correctly and keep it correct?"








