Readit News logoReadit News
bluejekyll · 3 years ago
I agree so much with this article. Java EE practices bloat programs, waste memory, and make debugging harder. Let alone all the language constructs.

> Java allows null objects… that ship has sailed

Not necessarily, with project Valhalla, it should be possible to have generic Value Types in the language that would allow things like Optional to be defined on the stack where it would be non-null and then all it’s methods for checking if the Object it references would make sense, and actually work. This would be in contrast to today where the Optional type isn’t as useful as it seems since it can also be null.

Anyone know the status of this? https://en.m.wikipedia.org/wiki/Project_Valhalla_(Java_langu...

willsmith72 · 3 years ago
I've seen many other developers trash java because of the same reasons, often citing Go as a great alternative.

The problem is, for every org I've seen, saving memory is not the goal of the program. "Making debugging harder" is subjective, and most people I've heard use this argument are taking about "magic auto configuration". Maybe this isn't intuitive at first, but the knowledge comes quickly, and from my experience the java app with unit and integration tests is far easier to debug than the Go app with less testing and less readable syntax.

The memory argument is also way less applicable when using the author's framework, because your app is built into a native image.

I know you didn't mention Go, but that's where I always see this argument headed, and it always makes me wonder whether the writers have ever had to maintain or take over an app written in Go, or if they can happily write-and-forget.

bluejekyll · 3 years ago
I don’t think we even need to discuss Go though. Just compare the ease of using vanilla Java to the complexity and magic that have become popular (mostly to work around limitations in the language). Being able to follow code easily is an important aspect of debugging a program, Spring and etc, obfuscate implementations. Are they still worth it to use? At this point for many orgs unwinding that would take years.

That’s at least what I got out of the article, Java doesn’t necessarily need magic frameworks to have a good development environment, that resonates with my own experience.

geodel · 3 years ago
> The problem is, for every org I've seen, saving memory is not the goal of the program.

Thing is there are huge number of people, group, companies, projects and so on looking to save memory all the time. It is most of the time done by library, framework developers so generally app devs do not notice.

Oracle teams are spending ton of effort on GC efficiency, reducing object header size, or value types. If saving memory is not an issue they would not waste huge resources like this.

I have maintained Go apps and it turned out to be so simple because it is grand total of one Go file with 1.5K LOC of code. This was exactly opposite of Spring Boot apps which are used a lot here. They are perennially stuck due to some or other library upgrade required for security fixes.

jasonm23 · 3 years ago
If I'm in a Java shop, then the main thing(s) people are advocating for are, in order of volume.

- Kotlin

- Scala

- Clojure

Go may well compete on green fields, but if the culture is Java, they only have n lateral moves, and have a legacy that's generating value for the org. (on JVM)

Go is typically out of the picture.

Deleted Comment

democracy · 3 years ago
Java EE is not really a thing in the wild for long long time...
bluejekyll · 3 years ago
Spring and (and Quarkus apparently which I haven’t used) brought along a lot of the Java EE concepts. It lives on if not in name, in spirit. Thus the cultural problem this article discusses.
pjmlp · 3 years ago
Not only it is still around, Spring actually depends on many of the same standards.
Supermancho · 3 years ago
Forget the interface vs data structure (for which they provide little support), the final keyword is the horrific standout. Conspiring with the compiler to remove programmer agency, in the misguided effort to protect programmers from themselves, is ridiculous.
ilitirit · 3 years ago
Reading these comments, it's strange to see that the "Java" paradigm/context issue still exists after all these years.

I have never had significant problems with Java-the-language. But, like with many other programming languages out there, you can't really dissociate the language from the environment and everything that goes with it. The paradigms, VMs, IDEs, patterns and practices etc etc.

And for the record it's not just Java (it just seems to be more pronounced in the Java-development ecosystem). For every person who waxes lyrical about the joy of working with C# (for example), there are 3 more that will tell you anecdotes about "assembly hell". Or how Visual Studio is slow and a massive memory hog. Or that there is no proper Forms support on XYZ-os.

Those are all fair points, but more often than not, they have little-to-nothing to do with current discussion. IMO, I think it's usually far more productive to try to understand the discussion in context than to veer off into irrelevant semantic issues or tangential anecdotes.

Sohcahtoa82 · 3 years ago
> Reading these comments, it's strange to see that the "Java" paradigm/context issue still exists after all these years.

> I have never had significant problems with Java-the-language. But, like with many other programming languages out there, you can't really dissociate the language from the environment and everything that goes with it. The paradigms, VMs, IDEs, patterns and practices etc etc.

This is something I've been saying for years.

Java, as a language, is great. But Java paradigms are fucking awful, and I don't understand why people use them. However, I'll confess that I'm naive, as I've never had to build anything larger than about 1,000 lines.

Like...one of the patterns that I absolutely despise is the "Handler". So often, code is peppered with "MyHandler handler = new MyHandler(); handler.invoke(...);". If you have an object that consists of only a constructor and a single function, and is merely instantiated, called once, and then thrown away, why is this its own object?

I see Java developers complain about stack traces that are 50+ function calls deep with half the functions in the stack named ".invoke()" or ".run()", and all I can think is how those wounds are self-inflicted.

62951413 · 3 years ago
There have been at least two mostly disconnected "Java"s for the last 15+ years. The job descriptions used to be very clear about. There were "Core Java" positions and "Enterprise Java" ones. Very different communities, different libraries (remember the revelation that the LMAX Disruptor was for example?) etc. The developers spoilt by the experience with Scala/Kotlin probably count as a third group now.
jimbob45 · 3 years ago
You choose weird examples. I don’t know how VS can be considered slow when it only has one real competitor - JB Rider - and that competitor offers C# support. Also, I’d there a language that competes with C# that doesn’t also have some form of “assembly hell”?
pwdisswordfish0 · 3 years ago
> VS [...] has one real competitor - JB Rider

There is one other non-VS, non-Rider alternative: Visual Studio for Mac.

dvfjsdhgfv · 3 years ago
You conclude with:

> Those are all fair points, but more often than not, they have little-to-nothing to do with current discussion.

but earlier you noted that:

> you can't really dissociate the language from the environment

So it seems like a self-contradictory position.

ilitirit · 3 years ago
Why would it seem that way?

Why can't I say:

"I like how C# implements XYZ"

instead of

"I don't like the C# development environment, but I like how C# implements XYZ"?

What value is there in qualifying every aspect of a discussion given that you cannot fully dissociate <A> from <B>?

vbezhenar · 3 years ago
I really don't like Quarkus approach. It's full of magic. It's everything I'd love to get rid of. I'm using Spring which is kind of full of magic but I spent 15 years learning to deal with this magic, so it's bearable to me. But it does not mean that I like it.

I liked Helidon SE approach (not MP, MP is the same EE crap). It's 100% code, no magic. What I didn't like is reactive, I don't need reactive, so I don't use Helidon SE for my projects, I still endure Spring. But if someone enjoys reactive programming and wants zero-magic approach, I can recommend it.

Helidon Nima might be a saviour to me. I didn't research it yet.

grishka · 3 years ago
I can't stand any magic, it always inevitably feels like a massive liability to me and always bites me in the ass sooner or later.

I use http://sparkjava.com in my projects. It's as tiny as web frameworks get, it only handles routing and request/response, and you get to do everything else manually. Only thing I had to hack into it was response streaming. The one most internally convoluted and enterprise-y dependency I use is, surprisingly, the official MySQL driver. GraalVM complains about it as well.

switchbak · 3 years ago
The idea that someone would reuse the "Spark" name though? Not sure how that got past a cursory review, that must make googling endlessly difficult.
netvl · 3 years ago
The problem with SparkJava is that it is not maintained anymore :( according to GitHub, meaningful work on it last happened in 2020. It was indeed a great tool, but now I’d choose Javalin since it is maintained, or even better, Ktor if I’m using Kotlin.
BenoitP · 3 years ago
> What I didn't like is reactive

> Helidon Nima might be a saviour to me

Well, Helidon Nima is getting a Loom-based implementation; so you'll get to keep performance without the reactive headaches.

mwcampbell · 3 years ago
I agree with you about both magic and reactivity (meaning, IIUC, asynchronous rather than blocking APIs). Helidon Nima looks interesting.

But what I'd really like in Java is a non-magic, non-reactive server-side web framework that's designed to be used for full-stack, server-side web applications, including things like strongly-typed HTML templates, form validation and rendering, cookie-based authentication, and CSRF protection. Something we can use to develop a complete server-side web application, the kind that everyone used to write before the division into back-end API and front-end SPA became popular. Helidon Nima might be a good starting point for such a framework. Another starting point worth looking at is Javalin [1].

[1]: https://javalin.io/

hiram112 · 3 years ago
This is essentially the Java Servlet specification with JSPs (or if you don't like those, just bolt on Thymeleaf or one of the older templating languages).

Nearly all of these newer frameworks like Spring, Helidon, Quarkus, etc. just reuse the internal Sevrlet spec themselves. Otherwise, they're reinventing a TON of code that would be insane to do in order to deal with the general HTTP request / response cycle.

cutler · 3 years ago
Then you're going to need something like Turbo/Stimulus as in Rails. I don't know of any Java implementation.
rr888 · 3 years ago
I'm not sure the point of Quarkus. Its an easy way to get started with GraalVM development, but pre-compiled Java isn't any use for dev work. The autoreload classes is easy in most dev environments already too.
vbezhenar · 3 years ago
It seems to me that the point of Quarkus is to allow old EE applications to be ported to Graal Native. For example they did that with KeyCloak, it was Java EE application running on top of JBoss Application Server, now it uses Quarkus.
tofflos · 3 years ago
I like SmallRye Config and I feel it's designed this way because of the problems it tries to solve. The following is an excerpt from the MicroProfile Config standard which SmallRye Config is an implementation of:

> The majority of applications need to be configured based on a running environment. It must be possible to modify configuration data from outside an application so that the application itself does not need to be repackaged.

> The configuration data can come from different locations and in different formats (e.g. system properties, system environment variables, .properties, .xml, datasource). We call these config locations ConfigSources. If the same property is defined in multiple ConfigSources, we apply a policy to specify which one of the values will effectively be used.

> Under some circumstances, some data sources may change dynamically. The changed values should be fed into the client without the need for restarting the application. This requirement is particularly important for microservices running in a cloud environment. The MicroProfile Config approach allows to pick up configured values immediately after they got changed.

One reason we don't know whether SmallRye Config is reading from a file or querying a database at development time is because that choice has been deferred to the system administrator at deployment time.

Records are immutable. If we want to be able to reconfigure applications at runtime it might make sense to use a mutable data structure.

You can load configuration programmatically if don't want to use dependency injection and/or want something that is easier to test. See https://download.eclipse.org/microprofile/microprofile-confi....

le-mark · 3 years ago
What are you suggesting? That one should read the documentation? And have a level of understanding why things are the way they are? Blasphemy! Zero ignorant screeds would be written! Productivity would increase 10 fold!

Deleted Comment

ragnese · 3 years ago
I agree. Java has improved as a language quite a bit in recent years. And I don't even mean that in a "Java has followed the cargo cult of what's fashionable in programming languages"-sense. I mean that things like Records to define value types have "always" been desired in Java- at least in the 10 years that I've worked with people on Java code. If Java didn't automatically make everything equatable/hashable, it would be a different story.

Anyway, Java still has baggage that I doubt will go away any time soon. My biggest two complaints with Java are that null exists outside of the type system and that they mix runtime type reflection and non-reified generics. The latter features being actually incompatible with each other makes working with Java libraries/frameworks a minefield.

But, aside from those issues, the OP is totally right that so much of Java's bad reputation comes purely from library design and culture. Even when I preferred OOP architectures, I hated the fact that so many Java libraries and frameworks required a bunch of annotations for everything, even when it really wasn't necessary. I get that Java code can be verbose, but if you don't like it, use something else- don't just throw away compile time safety and information for a janky runtime-checked "DSL" where a bunch of the features don't even actually work together (I'm mostly looking at you, JacksonXML, but also Spring, et al).

Everyone praises the Java ecosystem as some kind of selling point, but I find that while the ecosystem is indeed broad, the actual quality and productivity of many of the popular libraries and frameworks is fairly low. And by "quality", I don't necessarily mean number of open bug reports, I mostly mean that the APIs are really difficult to understand and use correctly. In some sense the devs are "off the hook" when my app doesn't work correctly because "this is documented behavior", but that makes me think I should just start writing documentation for my apps' bugs and seeing what my boss thinks... ;)

titzer · 3 years ago
Not sure what you mean by null being "outside the type system"--it's just the bottom type, assignable to all references.

I loved Java circa 2002-2005 and was deeply interested in JVMs. However I wanted to develop the JVM itself, and it turns out that Java is bad systems language. So I really want a systems language because VMs are the itch I have.

What's weird to me are the choices that Java has made in its evolution. In Java 5, the VM and library powers-that-be basically killed reified generics, forcing type erasure. That was a huge language design mistake precipitated by not wanting to upset the apple cart of libraries and the .class format. But in versions 6 and 7 they updated the class format anyway, to add stackmaps and invokedynamic! I never understood why such a key language feature didn't get the requisite VM support it needs to be done right, but completely marginal features did get VM support. Poor choices IMHO.

Java is just a big ball of semi-typed mud at this point. There are no layers and hardly any separation between what features are in the VM and what features are in the class libraries that are wormholes into the VM.

ragnese · 3 years ago
It's outside of the type system for two-ish reasons. First, because of the point the sibling comment made: while you can assign the singleton value `null` to any reference type's binding (but not primitives, so it's not even the bottom value for all types), it's not actually a value of that type, bottom or not. E.g, I can assign `null` to a `String` binding, or pass it as a `String` parameter, but I can't actually get it to behave as a `String`, so any call to a `String` method results in a runtime error.

That leads to the second reason I say it's "outside the type system": you can't explicitly write down the `null` type in the language. The reason you get a runtime error when we pretend like the `null` value is a `String` is because it's not a `String`- rather, the binding actually has the type `String | null`, but the compiler allows (forces us) to pretend that the binding is a `String`. Since we can't describe nullability in the written Java language (express it in the type system's language), but it does exist at runtime, I say it's outside the type system.

BlackFly · 3 years ago
I would say it explicitly isn't the bottom type since it doesn't satisfy the Liskov substitution principle for any actual type due to null pointer exceptions unless you unreasonably axiomatize null checks into every single property any type may have.

Basically, you need to think of Java references as the tagged union of Void + the true type. But since nobody wants to discriminate and pattern match on every reference, most java code tries to either follow a convention of non-nullability + Optional, additional type annotations with static checks beside the compiler, or "trust me, I've done this a million times".

Lack of reified generics used to bother me. Than I started passing parameterized interfaces next to instances of that type parameter to access polymorphic "static" methods of the type. This allows for up stack dependency injection into the body of the method where you would want the reified generic type without being forced to extend the parameters of the method for every use case: that is, you get a much more flexible design this way.

nilsb · 3 years ago
Is it just me or is understanding those examples virtually impossible if you're not intimately familiar with that particular framework? Then again... I guess that's the author's point.
matsemann · 3 years ago
Why is that magic always hated when it comes to Java, but praised when Django or Ruby on Rails do it?
tartoran · 3 years ago
Maybe it’s different flavors of magic. One is intuitive, one is inpenetrable without being an expert or early on in the project lifecycle. Also java projects tend to grow way larger.
tcbasche · 3 years ago
I think most senior or experienced Python developers tend to steer clear of Django.

It's just that you don't hear about it because it's mostly junior / less experienced developers writing about Django online.

edit: having said that, I wish we would be more skeptical of magic frameworks like Django in the Python community at least. Things like 'get_object_or_404'[1] should be burned to the ground.

[1] https://docs.djangoproject.com/en/4.1/topics/http/shortcuts/...

ris58h · 3 years ago
Yeah. It's the issue with the framework not the language.
throw_m239339 · 3 years ago
The examples use CDI (dependency injection through annotations) and yes, these annotations become hardwired to the business objects... Java has some kind of traits now through interfaces so it's not much of a problem today.
mrkeen · 3 years ago
> Java has some kind of traits now through interfaces so it's not much of a problem today.

Well that's the article's premise, right? Opening sentence:

    Java is good by modern standards, from a technical perspective
Later on:

    Java’s culture eschews common sense approaches
> so it's not much of a problem today.

Every Java codebase I've worked on in my career has had plenty of this crap in it. The culture has settled on doing it this way.

strictfp · 3 years ago
This is why I left Java. Everything "looks nice" on the surface with annotations, but you loose the flexibility of code and a lot of the available tooling. Plus you need to be a real expert to debug issues and solve problems; understand framework architecture and read reflection code. You can't just put a breakpoint in there and start debugging. It's optimizing for the wrong thing.

The bad news is; this culture is permeating somewhat into Rust now that more Java devs are moving over.

This whole attitude is IBMs fault. They tried to get into the Java market by applying their big iron terminal thinking to create Java EE.

Java under Suns management was a lot more like golang today; pragmatism, fewer language features, and focus on writing code.

pjmlp · 3 years ago
Java EE was created by Sun themselves, it was reborn from a Objective-C framework for OpenSTEP called Distributed Objects Everywhere, better get your history straight.
strictfp · 3 years ago
Interesting. I can't find any sources for the IBM story, but I thought I read it here on HN. I found at least one similar comment; https://news.ycombinator.com/item?id=30538784 .

So you're saying it was just Sun and not IBM?

mike_hearn · 3 years ago
The article is talking about Quarkus, a framework that uses the same annotations but which generates Java code at build time. So there's no reflection and you can navigate with your IDE or debugger into the framework code to understand what it does.
moondowner · 3 years ago
The things you hate about working with Java, that you mention in the first paragraph, are the basic things that Java devs have to do, or actually any dev in any language.
strictfp · 3 years ago
In a sense this is about the fundamental difference between frameworks and libraries. So to a certain extent, you're right. But there's extra complexity in not knowing why some annotation was picked up. With any API call you know you're trying to register something and can debug into it. With an annotation project you're sometimes stuck at "nothing happens".

Which is also true for node projects I guess :D

And the metaprogramming comment stands IMO.

Chris2048 · 3 years ago
Any dev has to be a real expert and read reflection code to debug issues?
metaltyphoon · 3 years ago
It makes me laugh how people mention that C# or Java has "magic", which is just the lack of understanding a feature of the language, but in the same breath says that Rust doesn't have this problem. I rather be able to debug a C# attribute than a Rust one.
fomine3 · 3 years ago
Usually C# don't utilize AOP so much like Java, so language attributes are acceptable
democracy · 3 years ago
Seriously, the speech is from the 2000?
ncmncm · 3 years ago
"I enjoyed programming in Java, and being relieved of the responsibility for producing a quality product." — Mark Dominus

https://blog.plover.com/prog/Java.html

tempodox · 3 years ago
> In Java, you can forget about doing it in the cleanest or the best way, because that is impossible. Whatever you do, however hard you try, the code will come out mediocre, verbose, redundant, and bloated ...

+1, I love this article. Do language developments since 2014 invalidate any of his characterizations?

kaba0 · 3 years ago
No, language developments since 1995 invalidate them.
the_gipsy · 3 years ago
I've read this quote after working one year on a java project, and it just nails the sentiment. Both from devs like me that wouldn't pick java where you'd expect this kind of sentiment, but also from veteran java devs who also treat "quality" as something simply unobtainable.