As someone who has watched many programming car crashes this century, none should have been more obvious than Go’s “error handling.”
When Go was announced, well over a decade ago, I did a simple test. I took the example from their home page — fmt.Println(“Hello, 世界”) — compiled it, then ran it while redirecting standard output to /dev/full.
No compile errors or warnings. No runtime error messages. Exit status code was 0 (success).
(I also don’t know what the Asian characters mean — clearly it’s a sign I’m too uncultured for Go and I should stick to the programming languages for plebs. I currently use C#, which as a plebeian, I very much enjoy.)
PS: Which languages have you used, that pass my “/dev/full” test by default?
The Shortest Solution Wins
Programmers like to use an inverse of the law of gravity. The shortest, smallest piece of code — by just a single character — has exponentially stronger force than a longer one.
The only force that counter balances the “shortest solution” is the ability to be readable and show programmer intent. For example, if you don’t know if the programmer was trying to create a new variable or assign to an existing one, you have lost readability and the programmer’s intent.
PS: The two programmers involved will often be the you from a few years ago, and the you today who has forgotten everything about that file. As programmers, we “evict our mental cache” all the time, and a language that lets us reload that cache from scratch quickly is fantastic and worth its weight in keystrokes.
Supporting Code > Primary Code
Many of you have probably written correctness tests, performance tests, IAC tooling, or preprocessing tools — like converting your game’s image or map assets from one tool’s format to another.
These ancillary programs can have a lot of code, but also a lot of *churn*, meaning they often need to change. For example, a small API change can cascade to a lot of test suites needing to be updated.
But errors from these programs are still precious. You don’t want to corrupt your game’s assets silently. You don’t want a performance test giving you bogus numbers because a function was actually failing. You don’t need the highest-performance errors, or the richest-context errors, but you must be signaled that some post-condition failed and do not continue.
Even a “primary program” has a ton of configuration loading and parsing, which can also involve talking to other remote services. Many users will happily sacrifice a tiny fraction of startup time for that extra knob they can configure. (If you haven’t worked on commercial software, trust me on this one.) And yet again, a typo in a config file must not pass silently, or users and support staff will be frustrated.
The bottom line: If a language isn’t optimized for the mundane supporting code, it’s not optimized for the common case.
Errors Must Not Pass Silently
Seeing a cryptic 500 error or stack trace is still better than thinking your form submission to Joe’s Tree Service website succeeded when it really didn’t.
The “set -e” feature of Unix shell is what all my scripts use. Unfortunately, it’s opt-in, when it should have been opt-out. Correctness always should be the default which comes for free. Makefiles are the best example; you have to opt-out of error checks. By doing *nothing*, you get what you wanted — talk about a good deal!
Imagine if a language had a #pragma I_will_manually_check_errors_here { }. Inside of that, you commit to either checking or ignoring all errors from println(), for example disk full, permission denied, read-only mount, etc. Maybe you do this because you want higher performance or richer context when a fault happens, or you want to do a few retries with a delay. Or maybe it’s the waiver you are signing that says ignoring errors is fine: #pragma yolo.
Of course, I ALREADY do a similar thing in C#, by making some of my methods take an optional “throwOnFailure=true” parameter which the caller can override to false to opt-in to manual error checks — exceptions are always the default. Or sometimes I return a Result. That’s my plebeian way, and why I’m not paid big bucks by Google.
Use a language that is flexible, because different modules you write will need different approaches to error handling. Sometimes the immediate caller wants to check and branch based off an error, sometimes you just want to bail out to a top-level handler. Good error handling requires thinking pragmatically.
You Have to Laugh
If I could give one piece of advice to younger programmers, you have to laugh at the stupidity and perverse incentives in this industry, and life in general. If you take it too seriously, you will get physically ill. Life is full of mobs, messiahs, and malarkey.
People will forget what a “scripting language” means, and build business critical software with one. Then they will be rug-pulled by the most expensive and disastrous migration ever, which nobody asked for (Python 2 to 3). Today, the “Zen of Python” is only good as satire.
People will forget why a “schema” is a good thing for important business databases. People will forget why “strong consistency” matters.
People will forget why requiring “let”, “var”, or “is” to signal programmer intent to a compiler matters. And to be clear that I’m unbiased, even C# had a fevered dream where it thought it was Perl and needed to use magic punctuation symbols, instead of searchable words — “!! for a null check”.
People will forget why exceptions were created and where they are useful. They will be pushing a boulder up a mountain a decade later. They are still too embarrassed to show “idiomatic” error checking on their home page example. (You have to be skeptical of software that seems more like religion than engineering.)
You cannot stop these things from happening. Large, too-big-to-fail organizations are full of hubris and NIH syndrome. All we can do is laugh or cry when that hubris is eventually punished. For every step forward, there are at least 0.9 steps back.
And thank God many programmers are paid to help people watch cat videos instead of building important physical structures.
PS I looked up what 世界 means: It’s an old, edo-period saying which means “I hope your disk isn’t full.”