Hacker News new | ask | show | jobs
by jimbokun 3146 days ago
This is exactly the reason I despise Spring with a deep and abiding passion.

"Just add this dependency, and add these annotations to your class, and it will all Just Work."

"But...what do those annotations actually do?"

"Stop asking so many questions!"

I mean, I know the answers are out there, it's open source after all. But so much of it seems deliberately designed to obfuscate the flow of execution and make reasoning about the code as difficult as possible.

9 comments

This phenomenon came to a head with J2EE. The original spec was designed apparently by people who did not know the 8 fallacies of distributed computing. It also coevolved with XML, and I think the entire experience colors the configuration as code philosophy in a bad, or even sinister, light.

When I see people design systems where, when they break, the only way to diagnose the problem is to do a code review, (not read the logs, or fire up a debugger), I wonder how they got along in their education without understanding the importance of debuggers, or why they hate their fellow programmers so much.

Spring comes out of a book that tried to reject the arcane nature of J2EE. I wonder sometimes if Mr Johnson recognizes hay the Beast he created is just as bad as the one he slayed. And how well he sleeps at night.

It got so bad they made a mini version of Spring, and even that is very declarative, and nearly impossible to explore.

When I'm really disturbed by how something actually works, my approach is to try to implement something similar myself. Object oriented C (structs with function pointers) long ago gave me some insights including why Python has an explicit 'self' for everything. There's a similar exercise you can do in C to better understand the prototype chaining way of doing OOP. Have you tried to make a simple version of e.g. @Autowire that is still capable enough to let a Java app of many modules have one module only depend on an API module and not the implementation module with everything just working without explicit injection? Sounds interesting to me, I bet that would be more enlightening than a summary page, or at least make the summary page more understandable...
"without explicit injection?"

In many, many applications explicit injection works just fine and is exactly what you want. But once you say "I am going to write a Spring Boot application", you are pretty much stuck with a big part of your application logic stuck in annotations, even when there is very little benefit over explicit code.

That's exactly how I felt about Ruby on Rails.
It's also why I prefer more "straightforward" libraries such as Tornado or CherryPy.
Wait, that's contrasting to other Python libraries that use the Rails/Spring magic? Which ones?
Django for example has a lot of magic.

A lot of the development process consists of adding fields with particular names to classes that have a long inheritance chain of their own, and it's not trivial at all to understand what all of your options are and how they work behind the scenes.

Hm I figured Django may be guilty of that. FWIW I learned web apps on RoR but my first job was Django. Django (or at least, apps in practice) was definitely less magic than Rails, although I see what you mean about a lot of the config being less transparent than one might like. I always have to eg hit SO to figure out how to add something to the admin since the model for how it works is not transparent.

I’ll definitely check out Tornado and the others for how they compare.

Currently it's my feeling about Kubernetes. Yeah not coding, but the same feeling.
I agree with annotations like this making it harder to reason about control flow, but I don't really get the consternation about "what do these annotations do?" so much. You can go read their documentation or source yourself to answer that question. How is that different than anything else? Same thing with "rails magic": yes, it sucks that you can't grep for method definitions, but you can go peruse the has_many method implementation to see what it does!
This really isn't too difficult to do, but it is a time sink I'd rather not have to deal with. With Spring in particular there's a huge amount of complexity so it can take a bit of time to determine exactly what's going on. Whereas with something like Go, I generally have full control over my applications control flow and if I need to look at a libraries source it's typically very straightforward and to the point.
"I agree with annotations like this making it harder to reason about control flow"

That is precisely my consternation. Much, much easier to reason about abstractions in the core Java language, like methods and objects, then to discover what code is being injected by an annotation. Java has outstanding IDEs that excel at navigating, analyzing, and debugging Java code, but putting so much logic in annotations is almost like you are trying to deliberately keep much of the code secret from the IDE.

Yeah. In principle, IDEs could show you what an annotation is doing, but at least in my experience that aren't particularly good at this.
I generally agree, but it's not entirely Spring's fault. The underlying APIs they're using are awful. If I were doing anything Java EE based, I'd still prefer to be using Spring Boot even with it's warts. It might be a framework for a framework (Spring MVC) for another framework(Java EE)...but it's still less of a pain than dealing with the underlying frameworks directly.
This is exactly the reason I despise Spring with a deep and abiding passion.

It's interesting you took the time to post this. As the sibling to this comment indicate, there's a lot of 'magic' in many languages and frameworks. not just Spring. You don't off an example of a tech stack you do favor so one can only guess.

I will say that when I have encountered developers and teams who also disdain otherwise popular frameworks, they sometimes choose to roll their own instead of buckling down and learning said framework. Invariably they end up with a partial implementation of what they didn't understand, that is bug ridden, ill performing, and just plain bad.

There's a lot of good stuff in Spring (and EJB, and rails, and ...) the onus is on us, as professionals to learn it and use it where and when it's appropriate.

"You don't off an example of a tech stack you do favor so one can only guess."

I think annotations are used many times in Java where abstractions like first class functions would be used in other languages.

I also find Lisp macros easier to reason about. "This compile time source code expands to this run time source code, which executes like so."

Perhaps surprisingly, I even find Ruby magic easier to reason about. "This method causes these three other methods to be defined to do x, y, z." It can get confusing, and final behavior highly dependent on the order in which the code executes, but I still feel like I have a mental model of how everything executes.

With annotations, depends on the code processing the annotations. You could have different code doing different thing with the exact same annotations. Your IDE can take you to the annotation declaration, but not directly to the code the annotation causes to execute. In the debugger, you can see the code in the call stack that was generated, but no link back to what annotation caused it to be generated.

It all just feels more like memorizing spells at Hogwarts, and less like an engineering process.

Spring desperately needed some remote interfaces to the engine to let external debuggers attach & tell you what was what. It keeps track of all this data, & you can find out what's in the various object containers if you ask really nicely with a lot of code. If this had a GUI, I think it would be an enormously sophisticated & elegant way of dealing with systems. Alas now it's a fright.
That's exactly how I feel about express middleware...
I mean... Usually you could implement a simple dependency yourself pretty trivially, for the most common case. But will your implementation be as tested and cover your user base as well as the Generally Accepted dependency implementation that has a million monthly downloads?