Java is miserable to write. You don’t realize this until you work with other languages. It was literally built with guardrails to keep enterprise coders from getting too creative
Yes lets rewrite everything Ruby on Rails and CoffeScript, it is just so much more productive and creative! At least this was the opinion on HN a few years ago. Now of course other tools and languages are fashionable. And nothing against Ruby or CoffeScript per se, but the demands of an enterprise where software lives for decades is just different than for a startup which rewrite the whole stack every six months.
Creativity and cleverness is a double-edged sword, which is exactly what Dijkstra is talking about.
Compare writing Java professionally with writing Kotlin professionally. It's like night and day. Same projects, same VM, all that's different is the language.
Distaste for Java isn't elitism or arrogance, it's just that the language is so damn painful to write.
If you start your career with Java (as I did), dipping your toe into another[0] language for the first time feels like Neo being ejected from the matrix and waking up to reality.
You realize your eyes are finally open, you're awake, and you can see that all that pain was just what Java saddles you with, and wasn't "the way programming is done (TM)".
[0] depends on which language, of course. Java to C# isn't a big jump.
I started working in C++, moved to Java, used several other languages commercially (Python, JS, PHP, Groovy, Kotlin), and about dozen other languages for personal projects including the hip ones like Clojure, Prolog, Ruby.
My first programming languages were C64 BASIC and Turbo Pascal. I've written some Ada and SML.
I have worked in Java shops my entire career (Travelocity, Orbitz, Expedia, Southwest, Bank of America) and have lots of pain points. In these cases Java is used to prop up a web server and typically with Spring.
Pain points:
* Stack traces seem to run to 500+ lines and nobody reads them.
* The processes, release management, and integration of code in a Java environment is glacial slow and obtuse featuring very low automation and many large teams of dev ops. The very idea continuous deployment is absent. Code releases occur at regular intervals quarterly or monthly if you are super fast and it feels like moving a continent. All of that slowness and super man power also applies to everything else not written in Java like riding on the back of a retardant elephant.
* Java applications running enterprise web servers are monolith beasts like the Great Wall of China wrapping the Pacific. Refactoring in those applications feels like inventing a new language while sinking in quicksand. Writing a JavaScript application in a massive MVC framework feels like that too but Java is orders of magnitude worse.
* What I really don’t understand is that Java is such a fast language but large enterprise web server applications written in Java always feel so slow in user experience in production. It just feels like something from the late 90s. That slow becomes the baseline experience to internal development by which all user experience ultimately suffers. There is no reason pages from these servers should take 5-20 seconds to fully load in the browser even though the page is a light smattering of static text with sprinkles of CSS and JS. I have an application in TypeScript that emulates the front half of an operating system and it fully loads in the browser in 0.3-0.8 seconds (averaging around 0.65 seconds).
> What I really don’t understand is that Java is such a fast language but large enterprise web server applications written in Java always feel so slow in user experience in production. It just feels like something from the late 90s.
My personal suspicion is that the programming style used in Java (OOP and patterns) together with the fact that everything is a reference, and everything is implemented in Java itself way down, kills the cache locality, which is the thing that makes modern computers fast.
Yes, you can write fast Java programs, if you keep abstractions to a minimum, use arrays rather than objects when allocating, and take advantage of the JIT compiler. But these are more lab conditions (which are great for benchmarks) rather than the real world conditions. I think finally having a proper record type in Java will help to fix this.
Shitty, poorly-run corporate behemoths (a) are shitty and poorly-run and (b) use Java, because it's an industry standard. You are making the error of thinking that the latter consequence causes the former.
> Shitty, poorly-run corporate behemoths (a) are shitty and poorly-run and (b) use Java, because it's an industry standard. You are making the error of thinking that the latter consequence causes the former.
Other programming languages make it "more inconvenient" to apply such managament/programming practices.
> Stack traces seem to run to 500+ lines and nobody reads them
ok, you have a point here :) when you have libraries for filtering stacktraces you know something is wrong
> the processes, release management, and integration of code in a Java environment is glacial slow and obtuse featuring very low automation and many large teams of dev ops. The very idea continuous deployment is absent
that is the exact opposite of my experience - maven infrastructure beats anything C++ or Python have, and in every Java project I worked on we had CI (mostly BitBucket+Jenkins but I've also seen Apache Continuum and Team City and we had CI even back in svn/cvs era).
> large enterprise web server applications written in Java always feel so slow in user experience in production
Also not my experience, I've worked on an intranet app for warehouses that used jboss 4, jbpm 3 and plsql at the backend and a very small custom c# client running on remote Windows CE terminals. We had transactional and persistent business processes drawn as graphs invoking PL/SQL on the server, it was pretty nice. And the full roundtrip between pressing a key on a remote terminal and rendering the received response was under 150 ms. That's for all the layers:
- c# client -> intranet -> SOAP on jboss -> EJB3 -> jbpm -> hibernate -> JDBC -> PL/SQL and back
And it was around 2008 - in the age of spinning disks :) Certainly it was good enough for us and actually faster than previous simple code that we were replacing (remotes telnetted to a C++ text-only server that connected to the same business logic in PL/SQL). ORM cache wins covered all the performance loses caused by additional abstraction layers.
We didn't use html/js/front-end templating engines tho, at the time most people used JSF or similar and it sucked. We had a custom XML protocol that was rendered by the C# client and it was very fast.
Of course it wasn't that demanding - under 500 users all on the same local network. But without any thought spent on optimization (other than enabling 2nd level cache in hibernate) it was a pretty good result.
> There is no reason pages from these servers should take 5-20 seconds to fully load in the browser even though the page is a light smattering of static text with sprinkles of CSS and JS.
well yeah, something's wrong. I bet on data layer or passing each request through 20 microservices on different continents (this is the most recent fashion in server-side programming and it sucks).
Haven't upgraded Java since version 9, so take this with a cube of salt (my suspicion is that many hardcore Java haters were created by Java 5, 6 etc).. but my general issue is the readability. The idioms used to perform 'standard' things are verbose. The worst for me is that it's impossible to catch exceptions in lambdas. The absence of named or optional parameters.
Mind you, I'm only saying that after having spent 2 years in Kotlin. The Stockholm syndrom is real: you don't realize how much better things can be from the inside. Programming has become enjoyable again, my work 'feels' cleaner, more readable. Null safety makes reasoning about code that much easier. I can switch to functional programming when it's convenient. I keep all the tooling from Java, including the amazing IntelliJ IDE.
At the end of the day, choices are a matter of arbitration. Do I want the speed of C, the ecosystem and resource pool of Java, the locality / mathematical guarantees of functional languages, and the IntelliJ IDE? Sure. But they don't exist in one language.
So when I'm programming embedded, it's C. When I'm creating a complex data treatment pipeline for machine learning, it's Scala. And when I'm making a CRUD application that will have to support a team of 15 developers hacking on it for a decade, I'll go with Kotlin.
>The worst for me is that it's impossible to catch exceptions in lambdas.
I don't take issue with your comment overall, but this is not true. You can catch exceptions within lambdas, and you can define functional interfaces that declare that they throw checked exceptions.
You're right. It's been a while and I forgot the exact issue. I looked it up on StackOverflow, to refresh my memory [1]. It is indeed possible to thow exceptions within a lambda.
My issue is that for something as everyday as "throwing exceptions", you have to define a separate interface, or catch it inside the lambda. The first option being the Evil Verbosity everyone is on about, the second essentially rendering the exception useless as an instrument.
Java, in my experience of having to puzzle out a couple of large codebases in my career (that is, not having been a serious developer) is what happens when a couple of idioms run amok.
Inversion of control, interfaces, and OO make wandering a codebase feel like being lost in a bureaucracy.
Then we het to the issue of projects being coupled to IDEs. "Oh, this is an Eclipse project." "Oh, this is IntelliJ".
All of that chrome and tailfin leads to projects that take longer to boot than the OS.
The disdain for Java may be less about the language per se than the attendant mindset.
Maven and gradle projects can depend on each other, are producing the same kind of artifacts and deploying them to the same repositories. And both can be used in any IDE you like.
And ant is prehistory.
In C++ they don't even have Maven equivalent (only thousands build systems but no universal way of naming/deploying/running projects or specifying dependencies).
In Python there's several maven-like systems that are incompatible and don't have the concept of universal project identifier or repositories.
In JS and Rust they basically copied the Maven system and changed it a little.
Clojure uses Maven wrappers with lispy syntax for pom files.
I struggle to find a language where this is solved better than in Java.
All the problems here are solved till Java 15 in every iteration. A lot of opinion in Java is based on comparing old versions of Java with latest version of other languages
Bear in mind that I've written almost no Java since 8, so this may well be out-of-date.
With that in mind, though, the biggest gripe I have, by far, is its needless verbosity. It always feels like I need a huge amount of boilerplate and repeated keystrokes to get things done. My fingers literally get more sore writing Java than anything other language.
Lack of extension methods is probably my next complaint, because you end up fumbling about writing a lot of code to address what should be
Lack of null-safety would be the next one, too. I'd say around 90% of my runtime errors are due to improper null handling, so this would cut down a huge source of errors.
On par would be painful deployment (and to a degree, package management). For some reason Java always felt like it needed an industrial-size team to get anything actually up and running, and needed more hardware than any other language. That might not be fair, but I think it's definitely fair to say that deployment is not Java's strong point.
> With that in mind, though, the biggest gripe I have, by far, is its needless verbosity. It always feels like I need a huge amount of boilerplate and repeated keystrokes to get things done.
This is my biggest complaint about OOP development in general and languages like Java and C# that are heavily invested in OOP paradigms are miserable for me as a result.
It doesn't, in fact; but configuring a Java application to run well with minimal resources is a problem that isn't a programming problem, it requires a separate skillset. So you end up with build specialists, and deployment specialists, which in turn results in long deployment timetables.
I can’t speak to the actual act of Java development, but I can speak to Java applications from a sysadmin perspective (15 yr Sr. QA Engineer to a 3 yr Linux admin (don’t ask)) — I’ve got no real beef with Java from the development side, but maintaining some of those stacks in production is pure pain.
Huh? Java is probably the least demanding stack from the sysadmin side - no big chains of library dependencies, no docker, strong backwards compatibility that means you can fearlessly upgrade the language. All you have to do is keep an up-to-date JVM installed on your servers and deploy single-file fat JARs to them.
The keystore situation is indeed poor. For several years now, it has been possible to do more key management in-app, so you don't need to manage keystores (i have written programs which pull standard PEM-encoded keys from environment variables). But the practice of using a JKS keystore is so ingrained that it's very rare to make use of that.
No language is immune to slow or memory-hungry code. The JVM is probably the easiest runtime to monitor/instrument/profile (and it's not like having no runtime makes that any easier, quite the opposite), and has probably the most tuneable GC going.
I guess enabling your users to do that might be work for a sysadmin, but that's more a reflection of those users having higher expectations for Java than for other runtimes - providing your users with the same capability in other stacks is never easier than Java, and often significantly harder.
I know this is just flamebait, but I write a lot of Rust, Python, Java, C++, Ruby, Typescript, etc. Java is fantastic to write in. What guardrails are you talking about?
My guess? Lack of first class functions and macros. Maybe higher kinded types.
The first one is annoying, not really something a professional software developer would care about for more than 10 minutes while creating a new product.
Macros can be major footguns, they're something that can only be realistically used efficiently and safely in large code bases by actual senior engineers. So the jury's still out how much they really increase productivity for the averaged developer.
Higher kinded types seem great, but it seems that they're not easy to implement and they also slow compilation down a bunch (someone please correct me on this). These seems hard to bolt on to an existing language, so Java can't be faulted much.
Java itself may lack macros, but by the time you get in reflection and libraries with XML and compile-time magic to work around the lack of macros and the whole thing is a giant plate of spaghetti, maybe macros were no' so bad after all.
Those would've been my guesses too, but Java's had first class functions in the form of anonymous classes since 1.1, and as the other commenter mentioned reflection takes care of a lot of macro use cases.
Problem is not with programming languages. It is with lack of programming principles. For eg. Consistency, Readability, Maintainability. Software requirements keep changing with time & so if we do not do continuous refactoring, we see a decay. Also in enterprises team ownership keeps changing & we miss the accountability. This erodes software. People need to give a damn to maintain software.
That's like a mason or an engineer complaining that the bricks are too boring and predictable :)
There's a place for "artistic licence languages" like Ruby or Clojure and I like them for experimenting, but when you want to build a house you want the bricks to be boring.
I think those guardrails often help with the humility the article discusses - they reduce cognitive load, and let you focus on the problem at hand, at the expense of expressing total creativity. It's a tacit admission that we aren't all knowing, and often need help from our tools to save us from ourselves.
I find it's just the opposite - when working in a Java codebase you can't focus on the actual problem because you have to spend so much of your time reading past the needless verbosity - or, often, debugging the crazy reflection framework that your organization has introduced because that verbosity became intolerable.
I find that the language itself is quite good, simple to use and has some nice features and performance... but the issues you mention are also there, however they're part of the frameworks and individual codebases.
Did the Java community get over their love of code generation already? Last time I used it, I'd debug the crazy 1000's of computer generated lines that people changed here and there.
That's never been my experience in over 10 years of JVM work - people mainly use reflection or bytecode manipulation (aspectj) to do the kind of things you'd use code generation for. The only exception is thrift/protobuf and that's dumb serialization code that hopefully no-one's editing.
Oh, the last time I've made any extensive use of Java was more than 10 years ago. I've met an off the shelf code generation based platform on the meantime, but luckily it was deemed too expensive so I didn't need to even finish a technical evaluation (much less use the monstrosity).
Anyway, that is great news. That unexplainable love for code generation was one of the things holding the language back. It's always good to see things improve.