Hacker News new | ask | show | jobs
by mattmanser 4670 days ago
Nonsense.

Is the network up?

Is the connection to SQL up?

Did someone just turn off the SQL machine half way through the query?

Can we find the server?

Are there any rows?

Did the SQL compile?

Do I have rights on this table?

Have you just terminated me as a result of a deadlock?

Did you return a Null when I was expecting a value?

Did you return a float when I was expecting an int?

Did my value just overflow?

Did you just return 0 and I tried to use it in division?

Did I just try to access the session but some other idiot clear it?

Did I just try to call a method on an object that is in fact null?

And that's all possible in a three liner off the top of my head. I'm sure there's plenty more than that that are possible! I didn't even start on the file ones...

3 comments

I totally disagree. These are all the same:

    Is the network up? / Is the connection to SQL up? / Did someone just turn off the SQL machine half way through the query? / Can we find the server?
These are not errors, just normal business logic that has to be handled:

    Are there any rows? / Did you return a Null when I was expecting a value?
These are not runtime errors, they're just debugging during development (with possible exception of overflow, depending on context):

    Did the SQL compile? / Do I have rights on this table? / Did you return a float when I was expecting an int? / Did my value just overflow? / Did you just return 0 and I tried to use it in division?
And likewise, these all just have to do with the design of your program, which you either know you have to deal with or not:

    Have you just terminated me as a result of a deadlock? /  Did I just try to access the session but some other idiot clear it? / Did I just try to call a method on an object that is in fact null?
I already said that you may not have to worry about things like memory allocation errors, depending on your needs. Most of the stuff listed above is either redundant, or has more to do with the design of your program. I stand by my point that, in most programming (say, back-end web stuff), you're handling more like 5 errors per 20 lines, not 50 per 20.

And that, yes, those 5 (or however many) errors should be planned for from the start.

Functions should be scoped appropriately so that they only deal with one thing at a time. A function that checks for network connectivity isn't going to be checking for missing rows. Those are different problems, and should be handled by different functions.

Using your example, we have a function that queries a database. It will be given a valid database connection, and return the result of the query.

There is no "valid database connection" logic, since that is handled elsewhere. There is no result validation logic, since that is handled upstream. This function only cares about A) querying and B) returning a value (possibly null). The only exceptions that is handles is when something specific to it's domain goes wrong - for example, unauthorized access to a table. That is an error that is above networking (the connection worked fine) but clearly not a data validation problem (no data), so we handle the exception here.

If you find yourself throwing exceptions "across problem domains", that's a good indicator that your functions are doing too much.

You can't just assume that a valid database connection will remain valid the entire time you're using it. The network or server is free to go down at any time. In practice, this rarely happens, it's an exceptional condition. Exceptions are the best way to model these kind of errors.
Sure, but the query goes through the layer of functions that actually deals with the database connection. If an error occurs, that layer is responsible and the "higher" layers simply pass on the exception that is thrown.

Point is: the function that deals with database response should never be responsible for dealing with database connection errors.

The Haskell solution is to decompose the problem into the pure and impure parts while using types to eliminate a number of these. Then you end up with general classes of exceptions which can be handled using pure Maybe types, perhaps, in various locations as appropriate.

Resource availability (Is the network up? Is the connection to SQL up? Can we find the server? Did I just try to access the session but some other idiot clear it?)

Incomplete response (Did someone just turn off the SQL machine half way through the query? Have you just terminated me as a result of a deadlock?)

Result semantics and types (Are there any rows? Did you return a Null when I was expecting a value? Did you return a float when I was expecting an int? Did my value just overflow? Did you just return 0 and I tried to use it in division?)

Translation to intermediate language (Did the SQL compile?)

Assumptions about remote state (Do I have rights on this table? Did I just try to call a method on an object that is in fact null?)

Smart code handles these all separately. It's crazy to try to bundle them all into one function.