9 ms·
Oh, how often I wish that someone would have followed this advice. Working mostly on Java these days, Carmack's focus on efficiently doing the right thing soun
by fxtentacle 6y ago
Oh, how often I wish that someone would have followed this advice.
Working mostly on Java these days, Carmack's focus on efficiently doing the right thing sounds like fairy-tales of the promised land ;)
Just yesterday, I spent much longer than I believe is reasonable to fix a bug in a Java class whose sole purpose is to do an HTTP(S) call and determine if the URL is online (200 code) or declared offline (40x code).
The first thing that really slowed me down was that instead of having a clear location for the crash, a Java .war inside tomcat tends to vomit 40-50 lines of stack trace onto the console. The reported Exception was "java.io.IOException: Server returned HTTP response code: 400 for URL: ..." in HttpURLConnection.getResponseCode(). But debugging the issue, I noticed that getResponseCode exits just fine without any exception.
A bit of Googling around revealed that the root cause was this: https://stackoverflow.com/a/54837353/525608 https://stackoverflow.com/a/54837353/525608 Inside getResponseCode(), an exception is thrown, caught, and suppressed. And then later, it is retrieved out of HttpURLConnection.rememberedException and thrown around by a different HttpURLConnection function. But of course the Exception still had the old = wrong stack trace in it. So those 40+ lines of stack trace that Java garbled up? Completely useless.
I kid you not, Java source code with Exceptions is like your own private hell, especially because the control flow tends to be somewhere between "nested inside 30 functions" and "completely random". The latter usually happens when libraries do bytecode patching so that what is actually executed doesn't even match the source code anymore, and that's also the point where stack traces become almost completely useless.
I'd take a 2000+ lines monolithic function every day over this unholy mess that ["Enterprise Java" == stacking random libraries on top of each other] has become.
- scaladev 6y agoJust out of curiosity, are there any Java web frameworks with reasonable stack depths? After working on .NET Core codebases for several years (which rarely have more than 4-5 calls within the framework itself) I was shocked to see stack dumps from a Spring application I've been working on. Three to four nested exceptions, with up to 100 nested calls (and sometimes more) within each one. If you don't have a smart IDE folding the less interesting parts (and copious amounts of amphetamine), it's simply unreadable.
- modeless 6y agoSpring is the poster child for abstraction gone wild. Famously: https://docs.spring.io/spring-framework/docs/3.0.6.RELEASE_to_3.1.0.BUILD-SNAPSHOT/3.0.6.RELEASE/org/springframework/aop/framework/AbstractSingletonProxyFactoryBean.html https://docs.spring.io/spring-framework/docs/3.0.6.RELEASE_t...
- fxtentacle 6y agoHaha, I think the worst part of that unintended joke is that the class description starts with Convenient. I wonder if the author of that text noticed how weird the whole thing is? "Convenient proxy factory bean superclass for proxy factory beans that create only singletons."
- dustingetz 6y agoin poker, you are sometimes faced with a shitty decision on the river, but the mistake was made preflop
- willtim 6y agoIn some future decade, when Banks start trying to migrate their "Enterprise Java" systems, anyone that can make sense of that bizarre and rather absurd model of computation is going to get well compensated.
- justin66 6y agoHow many COBOL programmers do you know who drive Ferraris?
- willtim 6y agoNone, I guess they didn't make it complicated enough!
- mcv 6y agoKeep in mind that Spring was originally a reaction to the extreme complexity of Enterprise Java. I still remember a talk where they said everything would just be simple POJOs: plain old Java objects.
- rightbyte 6y agoI got a feeling "hardcoded" repeating code is underrated. I work in a code base right now that has alot of configs floating in from everywhere and functions taking function arguments with deep call tree. I just wish there was long crappy linear functions with inline configs so that I could search this mess and see line by line what it did without having to keep so much in my head. Maybe it was easier to write but it sure as hell is harder to read ...
- fxtentacle 6y agoAgree. In c++, I really like the JUCE editor exactly because of this. You have a GUI to configure things and it's stored as an xml config, but it'll also autogenerate a header for you with all the constant things hardcoded. In my opinion, that provides one huge advantage that Java currently lacks: you can use tools like ReSharper to statically analyze control flow, find uninitialized variables or unused branches, etc.
- bjarneh 6y ago> HttpURLConnection.rememberedException Something must be quite bad with the design if he ends up having to remember exceptions...
- kleiba 6y agoAgreed. This design deserves a moment of leaning back in your chair with your jaw dropped: as if exception handling wasn't awful enough to begin with, this construct completely undermines the whole purpose of it and on top of it adds another layer of complication. I feel for the poor guy who had to figure out the bug that was caused by this -- the waste of his time was completely predictable by this idiotic design.
- nitrogen 6y agoI feel like Java('s libraries) forces this kind of exception inception sometimes. But there's a useful way to do it at least: set the original exception as the cause of any new exception thrown, and make sure your exception logger walks the cause chain. You'll have an insanely long stack trace in your logs, but at least it'll be accurate.
- bjarneh 6y ago> set the original exception as the cause of any new exception thrown 100%, not only did this person make a pretty strange design, he has completely misunderstood how exceptions are to be used. even when he remembers exceptions, he fails to make them the root cause of the new exceptions he throws. truly a remarkable design, in all the wrong ways.
- bjarneh 6y ago> this construct completely undermines the whole purpose of it Absolutely, a bad design that says more about the designer of that piece of code, than the language (Java). Error handling can and should be discussed, but I hope people don't use this as an example to illustrate how bad Java checked exceptions are. This is just some nonsense that can be constructed when you misunderstand underlying concepts, which is possible in any language.
- MrBuddyCasino 6y agoExceptions are bad and languages using them should feel bad. Go and Rust got it right, it is a major reason why Rust code Just Works. Yet some Rust folks are moving towards exceptions, and I find it unsettling.
- matsemann 6y agoExceptions are nice and languages without them should feel bad. Your comment is a pretty useless blanket statement. At least invite some discussion by coming with a few arguments..
- evilsetg 6y agoWhat is bad about exceptions?
- brobinson 6y agoThey will be used for flow control in small, individually innocent ways until they've accumulated into the type of hell the OP of this thread is describing.
- phoe-krk 6y agoA solution is to use languages that make explicit control flow available, instead of pretending that exceptions are a good way of performing non-local jumps. Have you investigated Common Lisp, its use of BLOCK/RETURN-FROM and TAGBODY/GO, and how it is possible to close over these lexical constructs to achieve non-local jumps to predefined points on the stack ? All of Common Lisp's error handling system is based on this primitive mechanism (and therefore written in Lisp itself). (Disclosure: wrote a book on the topic.)
- kettro 6y agoExceptions form a secondary, unseen form of control flow. A program can exit via ‘return’ calls (as normal), or at any time by some internal function way down the stack throwing an exception for something that could have been an error code. Exceptions are not Structured Programming: they are worse than goto, because at least goto is scope-local. If, maybe, the language enforced that all throwable exceptions are declared by the prototype, then it’d be alright. But I don’t know of any that do. So, given a function call, will it error out? Can you know without inspecting the source, if you even have it?
- knorker 6y agoAfter coding some Java I understand why people hate exceptions. Suddenly the Golang authors ranting about exceptions seems somewhat rational. I mean they still added exceptions to Golang, but are so ashamed of it they named them something else. These people should have to code C++ for a while before being allowed to rant about exceptions. (real C++, not Google C++ which bans exceptions for historical reasons) But yeah, what the fuck are you doing, Java? I've yet to see a stack trace that was actually helpful.
- the_af 6y agoI've worked with Java for more than a decade and I've seen plenty of stack traces that were helpful. Stack traces aren't the problem; the problem is that programmers silently swallow exceptions without either handling them or passing them up. > Suddenly the Golang authors ranting about exceptions seems somewhat rational. Error handling in Golang is nothing to write home about, either.
- girvo 6y agoFrankly the only error handling that I haven’t actively disliked is in ML-derived languages with Either<L, R>, or Nim’s (and the latter really isn’t that far off from what we’re complaining about, but the community seems better at using it without the nested exception hell that Java and in my experience PHP can end up in)
- the_af 6y agoOh, I also like Either from Haskell. But it can get out of hand if misused by devs. Note I say "misused" -- but it happens. After all, if Java exceptions weren't misused, there wouldn't be any problem either.
- xorcist 6y agoIsn't swallowing (and passing) exceptions pretty much what they are for? Should you instead handle every error close to their source, exceptions would be an overly verbose way of doing it. But maybe it's just my specific kind of programming prejudice shining through here.
- girvo 6y agoExceptions for deeply nested control flow drive me mental in other languages for the same reasons you’ve mentioned. Explicit Either<L, R> or similar have meant slightly more code at times, but much clearer to understand where data is going and why, in my humble opinion.