Something I’ve recently wrapped my head around is the difference between development errors versus runtime errors.
For much of my career I’ve approached all errors as runtime because then you can fail gracefully.
But, that’s a mistaken approach and it adds unnecessary complexity. Let’s say, for example, your web app fails to instantiate a required class. In this case something, highly unlikely, has gone seriously wrong. The only way, after production release, that a class can fail to instantiate is if a file was deleted from production or, hopefully not, you’re using variable name classes. This is rare and serious, if it does happen there’s really no point failing gracefully because the user is not going to logout, log back in, and everything will magically work.
If a serious development type error occurs then the server administrator should be notified, the user should be advised something has gone seriously wrong, and the app/server should shut down. As I said, the only way this should happen is if the server is hacked and a file is deleted, renamed, or altered.
Now let’s take, for example, a failed login attempt. It’s entirely feasible the user simply forgot their password or had the caps lock on. Yes, an error log should be written so the admin can monitor the health of the app. But, ultimately the user should be given another opportunity to enter the correct password.
Failing gracefully takes a certain amount of code. You need to be able to write those log messages, format the log message, and send it to the user/client/browser. So how do you gracefully fail when the logging code or the error formatting code fails to instantiate? That’s a fatal development error and you shouldn’t need to worry about still failing gracefully.
For the longest time I worried about writing backup logs and hard coding various error conditions in case a fatal development error occurs. That was wasted time and effort, for those extreme edge cases we should simply use the built-in language/environment logging and error functions on the safe assumption that the error will be caught in dev, unit testing, integration testing, QA, or staging. If you’re production environment is facing this error as a result of something in your control then you’re making mistakes as a developer.
There’s plenty of terms for this; failing gracefully, race condition, fatal error, compile-time-error, runtime error, etc. The reason these terms exist is because people much smart than I have thought through this and developed the best solutions. Those solutions are often not communicated to junior devs or are assumed to be common sense.