This is the sixth post in my series: Coding Without the Jargon, where I show how I clean up and gradually improve real-world code.
Rule #6: never fail silently. Report any unexpected condition with a log message.
Never Fail Silently
Mistrust
My coding style is ‘defensive’: trust nothing, verify all is well all the time.
Mistrust the data being passed into the function. Mistrust the data you read from a file. Mistrust the result you’ve just calculated. Mistrust that there is enough memory for you to allocate. Mistrust that the directory actually exists…
Mistrust leads to more robust code which can sensibly handle most anything you can throw at it.
Be A Snitch
The other side of the coin is that my code has to be communicative. Each time my code sees anything even slightly odd, it will report the oddity in a log message.
A fictitious JavaScript example:
let v = x.attr;
The code accesses a property on an object.
Now, what happens when x
is undefined? The code will throw, possibly unrolling multiple levels of nested function calls, until the exception is caught or the script crashes.
More defensive coding might be something like this:
let v;
if ("undefined" != typeof x) {
v = x.attr;
}
which may or may not be sensible; it depends on the context.
Main thing: this code defends itself against an undefined x
, whether the variable itself is undefined or whether the variable contains undefined
as a value. The value of v
will remain undefined
in both those cases.
Unless an undefined x
is totally normal and expected, this code should also report the oddity to the developer, so the developer is alerted to the issue and can investigate.
let v;
if ("undefined" != typeof x) {
v = x.attr;
}
else {
LOG.warning(arguments, "x is unexpectedly undefined");
}
What To Report?
Much depends on the context.
If this odd condition for x
is an outright error, I’d use LOG.error()
or similar.
If this condition is strange, but not impossible I’d use LOG.warning()
or similar.
If the condition is rare, but not unexpected, I’d use LOG.note()
or similar.
And if the strange condition is not strange at all, and occurs all of the time in the normal code flow, I’d not add any logging.
Condition Ladders and Logging
I routinely use condition ladders in my code: a series of sanity checks. Nearly all functions climb down a ladder of tests and sanity checks before getting to the ‘meat’ of the function. I’ll elaborate further on condition ladders in a future post.
As my code descends down the rungs of the ladder, it might ‘fall off the ladder’ for expected or unexpected conditions.
For each unexpected condition, my code will emit a log message.
Sub importLicenseInfoFile(in_importFile as FolderItem)
logEntry CurrentMethodName
Do // While True: Non-loop for condition ladder
try
Dim appStorageDir as FolderItem
appStorageDir = getAppStorageDir()
// First rung of the condition ladder
if appStorageDir = nil then
// Report unexpected condition
logError CurrentMethodName, "appStorageDir inaccessible"
Exit // Fall off condition ladder
end if
Dim relativePathsToOmit as Dictionary
relativePathsToOmit = new Dictionary
relativePathsToOmit.Value(
DIR_NAME_APP_STORAGE + SEPARATOR_ZIP_INTERNAL_PATH + DIR_NAME_PREFS
) = true
Dim fileNamesToOmit as Dictionary
fileNamesToOmit = new Dictionary
fileNamesToOmit.Value(".DS_Store") = true
// Second rung of the condition ladder
if
not unzipUnwrappedFolder(
in_importFile,
appStorageDir,
relativePathsToOmit,
fileNamesToOmit)
then
// Report unexpected condition
logError CurrentMethodName, "import failed"
Exit // Fall off condition ladder
end if
// 'Meat' of the function after we've climbed down the ladder
// without 'falling off'.
CMachine.singleton().async_verify(false)
CCatalogEntry.scanCatalogEntryDir()
CLocalAccount.scanAccountsDir()
CProduct.scanProductsDir()
COrder.scanOrdersDir()
CGrant.scanGrantsDir(true)
call CCapabilityWrapperForCustomer.getAllCapabilities()
COrder.verifyAllCapabilities()
clearAndRebuildWindows()
// Log anything that might be of interest
logNote CurrentMethodName, "import completed"
catch e as RuntimeException
// Log any unexpected throw
logError CurrentMethodName, "throws " + e.Message
end try
Loop Until true // Non-loop for condition ladder
logExit CurrentMethodName
End Sub
Next
If you’re interested in automating part of a Creative Cloud-based workflow, please reach out to [email protected] . We create custom scripts, plugins and plug-ins, large and small, to speed up and take the dread out of repetitive tasks.
If you find this post to be helpful, make sure to give me a positive reaction on LinkedIn! I don’t use any other social media platforms. My LinkedIn account is here: