Postgres also had a long-held reputation for being slow and difficult, but it made incremental improvements for decades and now it's the default choice for databases.
I see Java in the exact same position, as the Postgres of languages.
Postgres also had a long-held reputation for being slow and difficult, but it made incremental improvements for decades and now it's the default choice for databases.
I see Java in the exact same position, as the Postgres of languages.
It feels like these frameworks are now just falling away, which is great. I'm not even hearing about Spring anymore, and if there is any reason to not use it, it would be this cringe "how do you do fellow kids?" blurb I just saw on their front page:
> Level up your Java™ code
> With Spring Boot in your app, just a few lines of code is all you need to start building services like a boss.
I personally would reach for Go by default, but I have no ill-will to Java.
Boot is something entirely different. You write very little code and get a ton done. The trade off is you are firmly now a "Boot" codebase, but once you learn how Boot works it's not a big deal.
Frameworks are frameworks, not libraries. You can't just start writing/understanding them - frameworks are different from libraries precisely because they call your code, not the reverse.
Some people hate to write the same basic things over and over. That's where a framework excels. Write only the glue/logic you need to make your app work.
The way you have described your experience with Spring Boot seems to imply you did not take the time to learn it at all, and therefore its' unsurprising to us you had a hard time of it.
How else would you architect with this in mind? Given that literally every other framework is quite similar (RoR, PHP's solutions, etc).
There is another niche, the HTTP server libraries, but they are much more low level.
You do this 18 times because you have 18 different apps with similar requirements but deal with different data/endpoints/whatever.
On your 19th app you decide to standardize how you cobble together all of these libraries so that you don't have to start at ground zero every single time.
Now you've invented a framework.
Hibernate eventually got entirely nuked, Spring we couldn't entirely unwind easily; it had caused a whole bunch of crappy architectural issues and was too much effort to rewrite from scratch.
Although the code looked simpler using the frameworks and annotations, it was actually a huge rotten mess that didn't work well at all, with workarounds for all kinds of weird things in it.
I agree with the sentiment, but I'd move up to a version with type inference at least. I have nothing against static types and in fact in a vacuum I prefer them, but the particular brand of OO and "weak" generics that Java and C# have feels like filling forms in triplicate. "var" alleviates that significantly.
.NET has true generics with full type information and struct type parameter monomorphization which works the same way generics do in Rust.
Edit: C# does have type inference for generics, just not the full HM one. It is also quite more capable for lambdas which is a bit frustrating because it does not resolve nested generics otherwise. I miss it - F# does it the way it always should have been.
There are many other differences small and big that arise from the way Java does generics and the fact that primitives can't participate - you will never see `IntStream` kind of workarounds in C#. Some libraries abuse and misuse generics for no profit (looking at you Azure SDK), but it's not as widespread. Shallow generic types are always inferred from arguments.
You may not see that in Java in the future either. Java will have value objects from the Valhalla project, and part of the plan is to replace Integer with a value object. Then there will be less of a reason to use raw int primitives, because the JVM can treat value objects much more efficiently than normal objects.
All APIs and collection types build on this foundation, with standard library leveraging generic monomorhpization for zero-cost abstractions. Code that would have needed C++ implementation in the past is naturally expressed in pure C#. Generics are fully integrated into the type system at IL level, avoiding special-cased types or bespoke compiler handling (besides monomorphization).
This enables numerous zero-cost features: tuples (unnamed/named), structs with controlled mutability and record structs, pattern matching, stack buffers that do not rely on escape analysis, structs with byref pointers for slice types (Span<T> and friends) which a good two thirds of the standard library accepts. Numeric and vector primitives are used in a simple way without setup requirements like Panama Vectors.
While project Valhalla will get Java's foot in the door in some domains, it will remain a less optimal choice than C#, C++, Rust, etc. Java's evolution primarily serves its ecosystem's needs, whereas C# benefits from being a newer language that learned from both Java and C++ and got influenced by F# and other research projects inside MS. This makes C# more idiomatic and terse. The historical drawbacks - platform lock-in, being closed-source, and having relatively weak compiler - have been resolved over the past ~9 years.
Conversely, in Java you often use the diamond operator like in:
List<String> items = new ArrayList<>();
(Half of which, again, is code completion in your IDE.)That doesn’t work with “var”. You’d have to write:
var items = new ArrayList<String>();
while losing the ability to constrain your variable to a narrower type.The loss of directly seeing the type information in statements of the form
var foo = bar(x, y);
should meet a very high bar, IMO.I've wrought my hands over this and eventually came to the conclusion that developers in every language that started with local type inference have embraced it. So I've mostly ignored my concerns and gone with "var for everything".
If you have trouble with a type then rename the function or variable (AKA your "foo" and "bar" example. The names are bad, fix them. Context matters, we have none here. No one has an editor that displays a single line of code at a time.). But in general we haven't had issues on our projects.
Beyond that, my IDE (Intellij) makes it easy to uncover the inferred type if I really need to be 100.00% sure what it is. In general I don't, because in general I don't care, and even before 'var' I was generally ignoring the type anyways.
Even in your example, narrowing the variable doesn't make much sense - you are in a local scope, you control everything. Narrowing is more meaningful in fields, where var won't work by design.
Locally a well-named variable is often significantly more important than some long, somewhat useless type signature, especially when the right hand side makes it clear.
Given, they are still quite reflection-heavy and full of POJOs and annotations, it supports compile-time resolution for many things now.
Also, you would be hard-pressed to find a more productive developer than a well-versed Spring boot guru for typical backend jobs. You might dislike the framework, but credit where it's due, it is a workhorse and the amount of time someone makes a POC, you can make it with spring properly, in a way that you can build your prod app on top. Like, it's easily as productive as RoR and similar.
Pretty much any modern computing problem you have, Boot has you covered[1].
So while you may not have ever used a Streaming library before, if you know Boot, then the Spring Boot Streaming library will already be familiar.
The eco system is a huge force multiplier, and is constantly evolving. Spring Boot simplifies that a lot by simplifying the setup to the point where you often only have to add a single dependency, and everything is configured with default configurations (which you can change if necessary of course)
Just look at all the different projects under the Spring banner: https://spring.io/projects
One example is the new Spring AI, where they have abstracted a lot of functionality and you can change providers (OpenAI, Mistral, AWS, Azure, Google) easily.
It would be hard to convince some people of this, because "everyone knows Spring is enterprise". Unfortunately many only have experience with legacy companies, bad code or through reading old blog articles, and base their opinions on that.
It's actually something you need to have experienced yourself to recognize the possibilities.
It may sound strange, but I enjoy going through the long list of projects in the Spring web site. I almost always find something cool and is surprised at how much they can simplify complex functionality
The learning threshold is also relatively low, because they tend to use common best practices in the framework.
I like Kotlin, but the lack of checked exceptions really kills it for me. Exception safety is a bigger thing for me than null safety.
I do agree that new ecosystems (js for instance) makes you miss some of the old big languages development feel. less churn