Hacker News new | ask | show | jobs
by jgrant27 1275 days ago
Plenty of rationalization of how java (the language) is "subjective for developers" in terms of productivity and happiness. From a non-engineer view though, let's be real : nobody ever got fired for picking java. This was just a decision made in favor of managers over the poor engineers that will have to deal with maintaining a large Java code base over time.
6 comments

As an engineer, Java would be one of the languages I would choose for maintaining a large codebase over time. It is far better for that than most other popular languages.
If that is because of static types then I might agree with you, however once Spring and other reflection-heavy frameworks are added to the mix then I'm not so sure. Java's biggest problem is not the boilerplate, but the culture of over-engineering.
Luckily, the culture of over-engineering has shifted significantly thanks to modern approaches for designing Java-based systems.

The "Triple Crown" of Java frameworks, namely Spring Boot, Quarkus, and Micronaut, but also with the influence of smaller contenders (Dropwizard, Javalin, SparkJava, and a few others) have helped developers focus on business code rather 'design patterns' because these frameworks have embedded a lot of the "over-engineered" concepts into their 'opinionated' approaches.

Developers are no longer thinking too much about layers, and just writing components by following the guidelines and best practices of these frameworks. The final result is pretty similar among all of them, especially for microservices.

I like the sounds of that but I would definitely note that this requires _significant_ technical leadership. If you try to hire Java developers, 95% of the resumes you're going to get are people who learned Spring the bad way and have very little experience shipping efficient or reliable code.
Can I ask what you mean by learning Spring the bad way? I'm new to the industry and starting a Java role in Jan.
The general problem I’ve seen is complexity and action at a distance - basically many things where anyone trying to figure out how it works or make changes has to understand a lot of code in multiple places.

A mundane version of this problem is dependency management: every Spring app I know is constantly patching CVEs, almost always in optional code for features they aren’t even using, and sometimes upgrades are not trivial because you have to push around a lot of framework code. Node is similar but at least the tools are better.

None of that is specific to Spring, and I’m sure someone will pop up to say that’s doing it wrong but it’s been 100% of the work I’ve seen from multiple contractor teams so perhaps the way to characterize it is that the community doesn’t have enough culture of pushing back against support burden or complexity.

In my long time java shop we're doing pretty much the opposite - using less frameworks and libraries to minimize time spent on constant upgrades to the frameworks and their myriad dependencies for exposed vulnerabilities.
These things are changing - Quarkus and Micronaut are gaining a lot of popularity, and both use compile-time DI, not reflection, and Quarkus in particular is designed to target GraalVM, and Graal does not like reflection at all.

Spring is the fucking devil though.

Agreed. Even if we buy into the argument that Java is just wordy and slow to work with, once we're doing with long-lived code that needs maintenance, that's less of a concern than code that's hard to decipher, so the trade-off seems like a good one.
Yep. The wordy nature of Java is just giving you more info to work with when you dive into code you haven't seen before. Java is also a lot less wordy than it used to be, and if you use the right tooling you don't need to actually type everything by hand anyway.

What matters most for maintaining large codebases that a lot of people work on is the type system and the tooling. A large ecosystem of good tooling exists for working with Java, and it is empowered by the static type system to do some very impressive things. Some of the .net stuff is probably close to that with Visual Studio and the ecosystem around it. Everything else is pretty far behind, including Python and Ruby and Go.

I know people who work on a massive Java codebase that is almost 20 years old and has over 1000 people currently working on it -- and thousands more have passed through that codebase in prior years. It's not a lot of fun. But if it was a Python codebase, it would actually be impossible.

The type system isn’t impressive. You can find usages and thereby get navigation and refactoring via excellent Java-centric IDEs. But it seems like that’s it(?). On the other hand you have to constantly exercise your code because of lurking NPEs. Although hopefully we can get good annotations through third-party tooling (Facebook’s looks good).
I do like Kotlin's nullable types for that reason alone. At least Java has far better NPE messages now.

https://www.baeldung.com/java-14-nullpointerexception

That's a lot on its own, and being able to understand the argument and return types solely by signature is a big productivity boost compared to environments where that isn't possible.
Java can be hard to decipher in its own way. Mostly because of a culture of favoring just-in-case indirections, a propensity towards making deep call stacks as the codebase evolves (maybe because IDEs make that navigation tolerable, although it never makes it easy to see the whole context), and pretty imperative constructs outside of streams and lambdas.

But on the whole Java is not bad. I think it’s perfectly OK. I am more afraid of Java culture.

I disagree that it's a tradeoff, because those two are orthogonal. Java is often hard to decipher because there are many things that can happen dynamically outside the visible code path that affect execution logic, like annotation processing, classloading, dynamic bytecode manipulation, AOP, dynamic proxies, reflection, etc.
Most of those strategies are equally popular in Ruby but without the guardrails that at least make them cumbersome enough to make you think "is this really how I want to approach this?" The pitch for Ruby has always been productivity because it's terser so I'm trying to be charitable here and grant them their greenfield case.
In my experience (and our experience at TransFICC building middleware for financial trading systems, which is extremely throughput and latency sensitive), Java is the fastest language to work with simply because the tooling support is second to none.
> code that's hard to decipher

I've worked on a lot of codebases that appeared to be put together by developers who took that as a challenge - IME Java developers LOVE global variables (but they call them "public static" to make themselves forget they're using global variables).

I never understand java hate. The hate seems isomorphic to: "i hate types and i dont use a real ide"
Have you compared and contrasted Java and C# (especially with regards to let's say larger frameworks)?

Both of those put a strong emphasis on types, but only one of those (it's Java) is the sort of language that really attracts developers that love types like AbstractWidgetBoundaryFactoryWrapperFactory.

I can definitely understand the "Citizen Kane" effect of looking at a modern Java framework and going "yeah looks just like any other language, except with types and IDE support". Java didn't get there from nowhere. It got there after 20 years of being overly verbose and frustrating to work with.

Then haven’t seen some old .NET codebases. Both languages around the high of OOP-hype made similar monstrosities, but neither does it anymore.
My only real gripe with the language is JRE versioning and updating and that's the only legitimate complaint I've seen from others. It seems that you can sidestep that issue by baking in the JRE to your executable.

Honestly, I think the only reason C# is winning at all right now is because MS controls Windows and can silently keep .NET infrastructure up to date all the time. There must surely be a parallel universe where Oracle created their own OS where they enjoy the same benefits as MS.

Search for the memo where google employees were saying, "we the developers of google are losing to Youtube, as Youtube engineers use Python and we use Java. And iteration in Java is slower than Python." That's before google purchased youtube.

Edit : Python. The point remains the same.

Link : https://news.ycombinator.com/item?id=16674628

YouTube was based on Python from the very beginning. And since then has migrated more and more pieces to Golang. PHP was never a major component of their stack, if it was ever used at all.

Search for the memo where Twitter migrated to the JVM. That one actually did happen.

The link from your linked page states that Google were using C++, not Java. Which is correct. I was there. Writing web servers in C++ is a good idea if your web server is 1% HTML rendering/UI and 99% complex algorithms over large binary data structures i.e. a search engine. It's not so great if your web server is 95% UI.
Are you reading these links carefully enough? The first link you posted was talking about Google's use of C++, but you presented it as an argument against Java and in favour of PHP (which YouTube weren't using). This second source also doesn't say Java vs Python was the problem. They say:

"We're constrained on UI/Java development resources", "we have 1.5 engineers working on UI things and that is slowing us down" and "I think if we had one more good Java/UI engineer we'd be kicking butt vs YouTube".

So the problem was a lack of people ("resources") assigned to the UI side, i.e. too much of their headcount is being consumed by the C++ infrastructure leaving very little time for UI-centric work like social features. Google Video's problem is stated here to be too little Java development, not too much.

As someone who was there at the time and who read the internal post-mortem written by the Video team, Google Video vs YouTube wasn't primarily about implementation language. It was pretty much as the emails you cite say:

"They're cranking interesting features a lot faster than we are, but don't likely have a backend that will scale or a plan to make money. We, otoh, have these"

The YouTube guys did the now classic VC play of focusing on growth hacking without any idea of how to pay for it all beyond being acquired. At the time Google bought them the site was close to total collapse; the project to stop it running out of bandwidth was literally called BandAid. The Google Video team was also small but focused more on stable and scalable infrastructure, and product-wise they'd been chasing professional content as they couldn't see any obvious path to monetizing hobbyist produced video. In turn that pushed them away from the Flash plugin towards a more HD video oriented custom plugin, which hurt adoption. These were the wrong calls clearly, but, YouTube didn't really have a plan either. In the end both sides needed each other. One of the first things that was done after the acquisition was start moving core YT functions like video and thumbnail serving off Python and onto the Google C++/Java infrastructure. The web server UI on the other hand remained in Python for a long time so their (social) feature throughput wouldn't be disrupted. I think that codebase did eventually stop scaling and got rewritten, but my memory starts to fail there and I can't quite recall what the state was back when I left.

Rate of iteration changes with the size of the codebase, and not in PHP's favor...
And yet, YouTube rewrote their stack in C++.
The more common and recent hate I hear is that so much has been layered on top of it that it's difficult to manage or really understand what's happening in the code. Mentioned in other comments, but things like loads of annotations, Spring abstractions, and so on.
Recently coming from a Python/Flask codebase to a Java/Spring codebase, I would say that the amount of "magic" is not all that different.

It's just that with Spring, I can go to an extremely well-written user manual, or to StackOverflow and get my questions answered. With the Python/Flask codebase, I had to splunk my way through all the layers of random libraries the original developers slapped together, in an attempt to reproduce something resembling out-of-the-box Spring.

I suspect that those original developers had fun making all of those custom choices back in the beginning. I don't know for sure though, since of course they've all left the company since then. The company chose to migrate because it wasn't maintainable once that tribal knowledge left.

That sounds more like a microframework vs a kitchen sink opinionated framework issue though than a language issue. eg Flask is a DIY collection of libraries with your own architecture vs say Rails or Django where you have 95% of those decisions made for you and baked in.

I'm sure there are Flask style frameworks in Java land too. And there was a port of Spring for Python a while back too :)

Exactly this.

Had to stand-up a server in Java recently.

At some point I realized I was doing more programming via XML files and Spring decorators than via actual Java code. Mostly because Java itself isn't a great abstraction for a CRUD server.

If you did it recently, you should not have needed XML. Even a decade ago, XML-based configuration was on its way out. The transition from Spring to Spring Boot enabled us to use regular code to configure our injectors, for example.

I haven't touched XML for nearly a decade as a full-time Java developer.

I've only ever developed Java at places that had their own infrastructure for everything, so this question may sound uninformed, but isn't Maven still the de-facto package manager used for most Java applications and isn't Maven configured with XML?
Most of the pieces we were using allowed for configuration via XML or code.

Predictably, the team therefore used both.

XML is pretty rare in Java code written this side of 2010. Not that it doesn't exist, but the whole spring mess is not something you really have to touch to set something up in Java.

I usually enjoy Spark[1] for bootstrapping a simple REST-like interface. There are other options, but in general, you don't really need glue-languages at all if you stray away from old-fashioned EE-style frameworks.

[1] https://sparkjava.com/

Has those people have any understanding of what is their computer? It is layers upon layers of abstractions, plenty in hardware and even more in software. In fact, the only tool we have to actually solve complex problems is (good) abstractions. So those haters should probably find better arguments.
Large codebases in dynamic languages are the pits. Determining if some bit of code is used and how is a probabilistic exercise. Eventually you learn to give up or YOLO and see what happens.
Everyone always says that's fine if you have tests, but that's never actually true.
If I write the tests, maybe. Some tests make refactoring even harder. If I couldn't already refactor my own code we're also in pretty bad trouble. If I've written more than 10% of the tests overall, things have already gone badly.
And so we have a chicken and egg problem.

Thanks to verbosity, Java creates the very problem that it tries to help with.

Did you need to have that many programmers and that much code? Who knows. But once you have it, continuing with Java makes sense.

Verbosity is not a problem. The problem is being able to navigate and understand a large codebase. Terseness and dynamic typing are the enemy of that goal.
Attempts I've seen to quantify it have found that you hit a productivity peak in a team of 5-8 people. Then you need to add processes to avoid n^2 communication overhead. You don't get back to the same productivity until you have a team of 20-25 people.

If you've never worked on a small team, the productivity difference from staying small may not sink in. But they are real and large. And companies should not lightly cross that threshold.

I agree with you that, on a large team and in a large organization, terseness and dynamic typing are bad. But I don't agree that verbosity is not a problem. It absolutely is. It makes you have to go to large teams sooner.

Why is that verbosity never mentioned as a negative for Go, when in fact, Go is more verbose than Java?

Also, I really have a hard time believing that java would be significantly longer than any other mainstream language, it is at most longer by a small constant amount.

Modern Java isn't remotely as verbose at scale. The language is very different and the API+3rd party support is so vast you can usually build huge things with very little code.
20 years ago, the rule was that Java took an average of 10x as much code to say the same thing as a scripting language did.

In all the time since I keep hearing "modern Java this" and "modern Java that". But every time I venture into some Java, well, my limited experiences haven't fit what I was told about "modern Java".

Maybe I just haven't encountered modern Java?

As for the API+3rd party support argument, the productivity of third party libraries has been used as an argument for ages. I remember when it was being made about Perl with CPAN. My experience of it has always been that libraries make a great start to the extent you have a common problem. Which is wonderful for demos. But once you're in the weeds, you still have to write lots of code. Maybe there isn't a library for your unique needs. Maybe the standard library has bugs. Maybe you wrote code because there wasn't a library but now there is.

No matter how it comes about, you wind up writing code.

20x was always an exaggeration. It counted class boilerplate and compared stuff like hello world which was always "decorated". As scale that overhead gets minimized. Java will always be a bit more verbose than some other languages. It's strict. By definition that's more verbose. It also forces declarations (e.g. public). Again, a choice to keep things clear.

But that's not the code that takes time to write or read. In that department Java isn't more verbose in a significant amount. If you're the type of person that gets upset that every line ends with a semicolon or that we need to repeat the word public for many methods. Then sure. Java is verbose.

Looking at the body of a Java method I don't see something I can significantly cut down with TypeScript or Python.

> Maybe I just haven't encountered modern Java?

even modern Java 18 codebases with exclusive use of records instead of classes, and with enabled enhanced support for instance pattern-matching instead of old-school conditional blocks and switches, are still significantly more verbose than Scala codebases, especially if the latter use `cats` or `scalaz` for all traversal/mapping/folding logic. Java developers would just manually encode all these patterns into series of nested loops by hand by default every time, because the required tooling as well as the compiler help to aid that tooling is not available in the language.

Mapping/folding is possible with plain old java streams. So while scala can be smaller, the difference is not too significant in my opinion.
refactor tools for Java is just so much better than what you can do in a plain text editor or if the language does not have type annotations.
It's the (static) types, not the type annotations that matters in IDEs these days. Even in Java there are (very limited) situations where you can omit the type and the compiler infers it. And the ide handles it just fine. And in, say, Scala, which has more inference, the ide works fine (albeit not as well as Java but that's more down to maturity).
>This was just a decision made in favor of managers over the poor engineers that will have to deal with maintaining a large Java code base over time.

What's wrong with maintaining large Java code bases? Say what you want, but the language is built for that.

The worst code-bases I've seen tend to come from dynamic languages. Try to maintain hundreds of thousands of lines of python or ruby code over several years, and see how fun that is.

>From a non-engineer view though, let's be real : nobody ever got fired for picking java.

No. That's not a correct framing. Java is one of the few languages that able to strike a great balance between performance, development productivity, 'debuggability", cross-platform support (i.e. works just as well under Windows as Linux), language safety, and library and framework ecosystem. Honestly, it's hard to come up with a use-case where Java isn't a natural right answer.

I disagree. The alternative is some rockstar developer saying "let's pick Elm!" or "let's pick Elixir!" and then leaving the company after a few months. I'd take Java (or C#) over several other languages in a heartbeat. I'll leave the more esoteric stuff for the weekend, thanks.
I picked Elm once and I managed to convince my boss to let me got rid of it 6 months+ before I left. Turned out it's a good move! (well.. a not that bad move)
Most of the flak that java gets is from people who have never used/maintained java codebase. I moved from java to python and I actually miss java. It’s much easier to navigate and refactor java code. Yeah, you can write code faster in loosely typed languages like python, but maintaining it is a different story.
At my workplace I would pick Java 8/10 times. I would only pick something else when Java is really not an option (e.g. Scala/Python for Apache Spark, Typescript for CDK).

Maintaining a larga Java code base is very easy (I think much easier than e.g. Python). The tooling is awesome, there are countless libraries, last but not least Java is the easiest to hire for.

I think nobody fires developers who pick a language the boss or whoever in power doesn't like. And the boss would just say: NO.