Hacker News new | ask | show | jobs
by ragnese 538 days ago
It's fun to think through examples like this. But, of course, we need to exercise caution because so much is dependent on the specific contexts of each individual project.

First, I will say that I probably misspoke (mistyped...?) by using the word "unrecoverable". At the end of the day, it's not even really about whether or not something is recoverable, but it's really just about whether the caller might "want" to be aware of it and how much detail the caller needs.

For your example, you end up writing,

> It's also highly limiting because the caller now can't distinugish between programmer errors and possibly-transient environmental conditions like a service outage.

That's the giveaway that the caller needs to know about service outages, specifically. So, you need to handle your HTTP requests and/or database queries in such a way that you can incorporate some of the failures into your function's error type.

But, you SHOULD NOT just implement `From` for converting all of your database library's errors into your function's error type. You have to actually inspect the error returned from the database and return an appropriate error. Specifically, if you're using a SQL db library, it might return an error if your query generating invalid SQL statements--that should be a panic because that's not a "service outage", that's a programmer bug in the implementation of the function. Likewise, an auth error is not the same as an outage. If the db library specifically returns an error that it can't make a connection, then that's the one you'd want to wrap in your error type in this example.

But, again, it all depends on exactly what kind of project we're working on. Your example of doing HTTP, and filesystem, and database queries reminds me of Firefox. Firefox obviously does HTTP stuff, and it uses the filesystem and a SQLite database for settings or configs or something... So, if we were talking about your example function in the context of writing a web browser, then a failed HTTP request is 100% normal and expected because the user's device might connect and disconnect from the internet at any time. So, HTTP failures should be represented in the function's signature. However, since the SQLite database is basically part of the application, itself, any errors when trying to query it are probably panic-worthy. Phrased differently: it's a working assumption of the application that the database is always accessible, so there's no reason to describe failure modes that aren't supposed to ever happen. If the database ever became inaccessible, the top-level main function should catch all panics, log something about them (maybe send off telemetry data, etc), and warn the user that an unexpected error occurred and either tell them to restart the app or just kill ourselves, etc.

Have you ever written a function that returned a `String`? Or a `Vec`? Well, those require memory allocations and they may fail and panic. But, I've never worked in a context where it made sense to try to catch those panics and change those function signatures into `Result<String, OOM>`. My applications choose to assume that enough memory will be available, and I've made the decision to allow the apps to crash and burn if that assumption ends up violated rather than add the large burden of carefully handling that possibility in every line of code in these projects. And, so far, that has been the right call because none of my Rust projects have ever OOM'd yet (and some have literally been running in production for multiple years), and there's really nothing I would want to specifically do if they did-- I'd either figure out how to reduce the memory requirements or increase the server's memory.