On a more serious note than my other comment, Rust has shown me how much difference having good tooling can make. In Rust adding some new dependency or producing a performance flame graph or checking all dependencies for licenses you don't want is completely trivial where in other languages you would take multiple hours to get things working (I am looking at you, C and C++ in particular but not only those).
Rust
Welcome to the Rust community! This is a place to discuss about the Rust programming language.
Wormhole
Credits
- The icon is a modified version of the official rust logo (changing the colors to a gradient and black background)
As a sysadmin I always assumed having a log file that contains at least one backtrace in the last 60s was somehow required for the JVM to work. Certainly seems that way when running e.g. Jenkins or other "off-the-shelf" Java software.
Yes, Java lives by the credo "Backtrace or it didn't happen!"
The annoying part to me is usually that they often only print a backtrace but not the actually relevant information, e.g. if a file was not found at that point in the code it would usually be nice to know the filename or if some permission was denied, permission for who to do what (to which object(s)).
This is the reason you need to log the application state all of the time, to get context to the backtrace.
As someone who's written a lot of Java software over the years... this makes me sad to read.
It's pretty much in the description of the language, yet people somehow miss it and call it unexpected.
I'm kinda surprised by that, since Java is the one language that actually requires you to declare exceptions your code can throw. Shouldn't that be semantically be the same as a Result<T, E>
?
Well, but then any function may also throw random runtime exceptions, so even if a function declares that it throws IOException, it may also deep down throw an IllegalStateException. And if you then were naive enough to only catch IOException, then you are in trouble. I recently had that case, were I had forgot the top level catch (Throwable t) clause and the program just died with nothing in any log. Adding that top level catch and a log line, made me see where it threw and what. Then I just needed to add additional logging around that to see the application state to understand the why.
A runtime exception is the equivalent of a panic in Rust, with the same issues.
It should be, in the ideal world, just be thrown as a last resort... but in reality it isn't. I assume it is because when you find a nice IllegalStateException, you might feel that it really describes your condition quite well, so you use that without realizing that it is a surprise exception since that is not very clear. When you are using your IDE and need to throw an exception in an error case, it is not clear what is a runtime exception and not, and then you are not forced to use throws and here we are...
The equivalent in Rust would be to have a std::error::GenericError(String)
in rust, that looks like a normal error but secretly panics under the hood.
Not a RUST or Java user here, only C++ for micro controllers and Python, but always nice to hear such stories. Gives some insight what others did/do, thought and now think etc.