Hacker News new | ask | show | jobs
by geodel 1613 days ago
Indeed. I have a dozen or so microservices supported by team. Most are SpringBoot a couple of them I wrote myself with plain java and embedded tomcat. Needless to say Springboot stuff is rather complicated for such a simple business functionality. Errors are indecipherable being swamped by thousand line framework exception trace. But being an "enterprise standard" framework all projects must be move to this turd of a framework.
5 comments

And in 99% of cases that little microservice will suddenly need thread pooling, logging, some more advanced db management or God help some random messaging service and you are back to re-implementing the myriad features of spring in a shittier way.

It is not an accident that things like ruby on rails are popular. These are well-tested toolboxes with a solution for almost every conceivable problem. There are exceptions where it is not needed, but for business applications those are not numerous.

I don't think people have any issues with the fact that spring is batteries included. It seems to me (and this is my personal experience too) that the large amounts of abstraction and indirection through annotations makes the code very hard to parse. It makes it hard to create a mental graph of how it all works together
My experience is that it's not only the usage of annotations, but the way Spring handles/implements those annotations which is confusing.

As an example, Micronaut[1] also uses annotations a lot, but their implementation is a lot easier to reason about, because there is less indirection with proxy objects and other weird stuff that Spring uses.

Micronaut does not implement nearly as many annotations as Spring though, which basically means less functionality pre-built. I'm not sure that's a bad thing, but it could be.

[1] https://micronaut.io/

I found the real challenge to be that it's very difficult - if not impossible - to determine how spring functions simply by reading code and using it. In simpler libraries or frameworks, I normally just read the source to understand how I should be using it. With Spring, I've had to spend a lot of time reading and re-reaading docs to understand what's going on.

I think that this is sometimes a hard shift for developers who otherwise have spent their lives with an ability to puzzle out the constructs that they come across.

I absolutely understand it, but I think the correct, although bit inconvenient approach is the one you mentioned — properly learning the framework either through docs or other materials.

Way too many developers try to write spring (but also jpa and many other useful, but complex tool) by trial and error, which let’s be honest, not a good tactic even if one can easily inspect the source. (The recently posted microsoft blog post “even if the precondition doesn’t do anything, you still have to call it” comes to mind)

You're, of course, right that you just need to study and learn a complex framework. Basically the same way that you learn a new programming language- they're all different and have different behaviors and idioms (pass-by-copy vs. pass-by-reference, etc).

However, there's another dimension here, and while it's not totally unique to Java, it's definitely present in larger magnitude in Java, in my experience. There are two parts:

1. None of these frameworks are 100% consistent. I haven't used Spring{,Boot} in years, but I can tell you that JPA/JDBC are full of little "surprises" and rough edges, like handling nullable database columns. If you are not careful with your annotations, you'll get a `0` value for your `Int` object field instead of the `null` that was in the database. You can then go for quite a while before you figure out that's what happened. Similarly, JacksonXML has all kinds of little gotchas when it comes to date-time types and timezones, primitives and null-ness, etc.

2. Most projects have more than one of these complex frameworks. See above. I listed JacksonXML and JPA/JDBC. Odds are that you have AT LEAST these three frameworks (including Spring) in your Java project, which means you have to study all three and learn all of their intricacies before being confident in the code you write. That's on top of learning how to write half-decent Java, which is hard enough with its type-erased generics, bug-prone null-handling, and very verbose class definition syntax. If it were just one thing, I'd be sympathetic and tell people to just RTFM. But, unless you plan on only writing Java code for the next decade+, I have come to believe that it's probably not worth it.

I don’t think that it is any easier in other languages either — object serialization, conversion between language’s object/json/xml/etc, and database access with object relational mapping is just complex. You can make the trivial way trivial, but you have to expose the hard ways as well and that will not be pretty either way. For what it worth, java has a really high quality ecosystem for all these things - I would be really interested in what you think as an alternative. Sure, there are alternatives as well within the jvm ecosystem (though with much smaller userbases), but .NET is famous for having worse copies of java libs, node.js is in my opinion terrible for enterprise scale applications, there is erlang, ruby, php and whatnot, and sure enough you can make good web applications in any of them, but I really don’t buy that any of them would be easier.

Also, java is solid as a language. Sure, it is not the most modern one, but it is reasonably productive, has great tooling, is very performant and perhaps most importantly, it is observable in a very fine way.

Looks like an IDE / language server that unrolls the annotation generated code might be what's missing here. I like my abstractions to be hidden, but I like to be able to peek under the hood. That's one of the problems of C++ templates, sometimes I want to look at the expanded code.

The GNAT Ada compiler has an option to output a much-simplified code. Not compilable Ada, but very inspectable unrolled, expanded code. Makes for a great teaching tool. Aaaaaaah this generic mechanism does that!

Edit: link https://docs.adacore.com/gnat_ugn-docs/html/gnat_ugn/gnat_ug... look up -gnatG[=nn]... Good stuff.

> Looks like an IDE / language server that unrolls the annotation generated code might be what's missing here.

I think you're missing the point.

Lucky me, there were libraries available, for mail, JMS, Kafka, logging and so on. Also implementing things in shittier way than Spring is difficult feat to achieve for my modest skillset.

However there were some impossibly complex requirement like thread pool and with great effort I was able to found a solution in standard JDK like :

`ExecutorService exec = Executors.newFixedThreadPool(st.threads);`

Spring could have greatly simplified this code I guess.

> It is not an accident that things like ruby on rails are popular.

Now if we could have that without the magic (neither from annotations nor from open classes), and with strong type safety and proper sum types... That'd be great!

> I have a dozen or so microservices supported by team.

Why do you need a dozen of microservices? Why not to use role-based monoliths? Why not to keep your "microservices" as independent modules, pack them as one app and let such app to configure itself with proper set of services and dependencies according to the config or CLI parameters?..

Just a developer there. So not calling shots on overall architecture. And yes we do not need probably 80% of that crap but not in position to make them see reason.
I'm in an enterprise and have successfully lobbied people to use anything other than Spring. Such organizations and teams while rare do exist so don't give up hope! (or just move to a more progressive org)
> I'm in an enterprise and have successfully lobbied people to use anything other than Spring.

I was in a team that used Spring Boot for a greenfield project. The documentation was great, there was tons of help of Stackoverflow (as it's Spring) and the consideration given to testing was first class. Deployment was also easy, as we just created a fat JAR. No application server necessary.

It was a great place to work.

I have also been in multiple organizations where Spring was used, including "modern" Spring Boot and greenfield projects, and people who knew every nook and cranny of Spring.

I don't agree with any of the things you bring up.

Spring documentation is and has always been poor and the sheer volume of outdated documentation (let alone ways to do the same thing) makes it needlessly difficult to find an answer to any given question.

Differences between the real app and real http requests to the app, and using the Spring test application context and Spring HTTP tests, result in tests misleadingly passing when things are actually broken. (or vice versa)

This is different to eg DropWizard where you actually boot the app (no different to how it does in a real env ie no "test application context") and make real http requests to it. (not some watered down fake Spring HTTP test requests)

Ability to deploy a standalone jar without the need for an application server is hardly unique to Spring.

Add in the horribly, horribly ingrained, unidiomatic ways people use Spring (eg sprinkling field autowiring all over the place instead of instead of using constructor injection) etc etc and every codebase is quickly completely ruined vs if it had been implemented in literally any other framework.

But! Fortunately for you, the Java community has made their choice, and it's not going to change - Spring is the default and correct option, and anyone who uses any other framework is just stubborn and wrong.

> Spring documentation is and has always been poor and the sheer volume of outdated documentation

Spring documentation is excellent. I had to learn Spring as a PHP developer, so I put the documentation onto a Kindle and read it. It's also versioned, so you don't need to read out of date versions:

https://docs.spring.io/spring-framework/docs/

> This is different to eg DropWizard where you actually boot the app (no different to how it does in a real env ie no "test application context") and make real http requests to it. (not some watered down fake Spring HTTP test requests)

Spring Boot allows you to write full application tests that will boot it up on a random port with the @SpringBootTest annotation, as is covered by the excellent documentation

https://spring.io/guides/gs/testing-web/

> Add in the horribly, horribly ingrained, unidiomatic ways people use Spring (eg sprinkling field autowiring all over the place instead of instead of using constructor injection)

You can use whichever.

> anyone who uses any other framework is just stubborn and wrong.

Not at all. Spring Boot is just a great solution, that's all. It's got strong support from a company, lots of documentation and first class support for testing. It also allows you to easily swap out different underlying technology, eg. you can switch from Jetty or Tomcat, Liquibase to Flyway.

It's a disservice to persuade businesses to use smaller projects that don't have a comparable level of support, or flexibility.

> It's a disservice to persuade businesses to use smaller projects that don't have a comparable level of support, or flexibility.

This is why we use Spring. We have confidence that it'll be supported long-term and will continue to have backing from a whole host of companies.

It's slightly different in a large enterprise environment where a service might be fairly straighforward - take in input, spit out output to some data store. But for the kind of work we do - end-to-end webapps - we'd be doing ourt clients a great disservice to sell them on a microframework with our homespun implementations of security, transactions etc. bolted on top.

> we'd be doing ourt clients a great disservice to sell them on a microframework with our homespun implementations of security, transactions etc.

One of the benefits of Spring Boot was that Pivotal test and ensure all the components work together, so you can upgrade safely. It made keeping things up-to-date much easier.

There's no business value in trying to knit it all together yourself, if you can pass the work onto somebody else who is paid to do it.

> @SpringBootTest

Oh what do you know, yet another annotation...

I'm literally looking at the docs for @SpringBootTest

``` @SpringBootTest public class SmokeTest {

    @Autowired
    private HomeController controller;

    @Test
    public void contextLoads() throws Exception {
        ...
    }
} ```

This is case in point of what I'm saying - I highly doubt this actually spins up a full fledged app.

+ where is the controller coming from? It's not instantiated anywhere. What about it's dependencies? If I add one, this test will still compile, when in reality, the tests will all fail. (or at least, you would imagine most would) This field autoinjection approach encourages adding arbitrary dependencies with zero thought to anything - who cares, everything will just compile anyway. Meanwhile, a sane framework would force you to send in dependencies, forcing you to be smart about how to structure things and not compiling if you add a dependency to a controller but not to its test.

Also, what does @SpringBootTest actually do? How does it work? What if I need to do <anything that doesn't align with the simplest use case that the Spring devs cater to>? Who knows! "Just add the annotation, it's easy!" (but not simple - it's extremely, and extremely needlessly, complex)

> You can use whichever

Yes, and that is wrong. Even Spring devs themselves are now trying to put the field injection cat into the bag in favor of the correct constructor injection approach. They're not succeeding.

> Not at all

You say it's not wrong not to use Spring and... go on to say it's wrong to use anything but Spring. Classic Spring dev mentality, and completely disingenuously portraying things as if other frameworks like eg DropWizard isn't constituted of well maintained, well documented components. In reality, unlike Spring, frameworks like DropWizard are a collection of some of the best tools for each job, and it's both simple and easy, whereas Spring is just Spring, Spring and more Spring, and while it's easy, it's not simple- there's a lot of magic.

Anyway, we're not going to agree, and as I said, very close to 100% of Java devs and Java shops are 100% committed to Spring, so you win.

I'm just glad throughout my career I've found a few orgs who have been through the Spring grinder and realized the emperor really does have no clothes and have been open minded enough to look outside of the Spring bubble and try something else.

> Also, what does @SpringBootTest actually do? How does it work? What if I need to do <anything that doesn't align with the simplest use case that the Spring devs cater to>? Who knows! "Just add the annotation, it's easy!" (but not simple - it's extremely, and extremely needlessly, complex)

You can read the documentation to find out what every annotation does.

https://docs.spring.io/spring-boot/docs/current/reference/ht...

There are several different annotations that you can use to test each particular "slice" of your application, ranging from a fully embedded server, to just testing the controller layer without the embedded server, to just testing the data layer without controllers or servers.

What do you recommend instead?
> Errors are indecipherable being swamped by thousand line framework exception trace

Don't you just look at the top lines?

If you're lucky and the exception happens in your code directly. If not you're gonna have about 30 lines of interceptors and generators and whatnot before you get to your class. If you call ClassA::foo from ClassB::bar you'll get about 5 lines of interceptors between foo and bar in your stack trace. Debugging is also a nightmare in IntelliJ as step-into and step-out will go through all those interceptors.
Debugging bothered me too. But in the end I have configured IntelliJ to skip all the interceptor classes while stepping into. Had to add a whole bunch of classes and packages for that though
I used Spring Boot and just set debug breakpoints, that way you don't have to step into and out-of, you just press "play" and it moves to the next breakpoint.
Another big difficulty is the handling of depedencies, as spring boot is bringing in gprc, jpa, jdbc and countless other libraries. One really needs a dedicated team to figure out all these issues!
Very true! But management is sold on "best practices" from VMWare suits. So any practical difficulty is just an excuse for not learning the latest, Next generation technologies.
It brings in whatever you use. Also, it has a goddamn webpage where you can click together what do you want to use and it will create an initial project for you with the chosen build tool and what not. It hardly gets easier than that.
This isn't true. Spring Boot by itself brings in very little, you can however _add_ GRPC, JPA and JDBC support by adding a library and Spring Boot will even autoconfigure it for you.