6 ms·
Why Java Is Dying
- tobyhinloopen 6y agoI don’t know, is using micro services and a message bus “keeping it simple, stupid”? So far I’ve yet to see a micro services architecture that I don’t think is massively over-engineered. Also you can write your over engineered micro services perfectly fine in Java. There are even very nice tools for that specially designed for Java.
- jimbokun 6y agoMy company had a massive, over-engineered monolith that we broke down into more sensible microservices, and the architecture is now much cleaner and easier to maintain, scale, etc. I agree, though, that designing as microservices up front is generally premature optimization, as your initial guesses for where to put the boundaries between the services is likely to be wrong. Both the monolith and the microservices are written in Java with Spring Boot, but I agree with the author that Spring especially leads to runtime code that is extremely difficult for developers to really understand. I am curious whether writing future microservices in a language like Go might be more maintainable in the long run.
- koufatz 6y agoI would not agree that Go is a good replacement for Java Microservices. I would suggest looking into something like Quarkus (https://quarkus.io https://quarkus.io) and if Java is to verbose for someone, she/he can checkout Kotlin (https://kotlinlang.org https://kotlinlang.org) which is 100% interoperable with Java but clean, modern and pragmatic. With Quarkus you have a very powerful but simple framework that out of the box (GraalVM) can be compiled also to a single binary if you need very fast startup and very low memory consumption. Go evangelises simplicity but when someone has to use it in a bigger project the lang is very cumbersome. You don't have any functional programming features like filter, map, find to manipulate collections. The not null (nil) safety or the magic with interfaces{} does it make non safe especially compared to modern languages like Kotlin,Swift which have the notion of nullability build in the language itself. Dependency Injection support is very limited. I think Go is hyped because of the excellent single binary feature which you have nowadays via GraalVM also for Java, Kotlin as I described above.
- deleted 6y ago[deleted]
- kasperni 6y ago> My company had a massive, over-engineered monolith that we broke down into more sensible microservices, and the architecture is now much cleaner and easier to maintain, scale, 5 years from now you will go from a massive, over-engineered micro service architecture. To a well designed modular monolith that is much cleaner and easier to maintain, scale, etc.
- phendrenad2 6y agoThat's the thing though. If you have an overengineered or spaghetti-code monolith, often you can get management buy-in to rewrite it by saying "microservices"! Likewise, if you have an over-engineered or spaghetti-code set of microservices, often you can get management buy-in to rewrite by saying "microservices were a fad, we need tighter integration". The style you rewrote in didn't solve your problem, the act of rewriting did.
- throwaway189262 6y agoI'm a stereotypical Java dev even though I've used many other languages in the past. I think the author missed the point on what Java is designed for. It's supposed to be a friendlier, safer, more general purpose C++ for when you need good but not the absolute best performance. And in this I think its the best thing out there. The cruft in Java, and hacks like Lombok to reduce it exist in every statically typed language I've used. And if you've worked on a big enough project you'll start to see why dynamic languages like JS and Python are bad choices for enterprise apps. It's telling that every major dynamic language now has optional typings. Once you get to a certain size the ceremony around access modifier and statically typed objects makes sense. And the author falls into the common idiom of "the JVM is huge it uses too much ram". Then advocates for dynamically typed languages with even bigger run times that use multiple times more ram. Dynamic languages like Python and JS, as a generality, use 3-10X as much ram as VM languages like Java and C#. They're also equally slower. And the runtime argument makes zero sense. V8 is massive. CPython is massive. Any popular language over time develops a huge runtime. The author also complains about Spring. Spring isn't Java. There's a ton of Java web frameworks that aren't Spring. No matter how much you like Java you can always find common ground hating on Spring. Overall the article is a common set of complaints from developers that never used Java or only did a few Spring tutorials, got frustrated at the complexity of the language, and moved on to something else. Java is one of the fastest popular languages and uses way less ram than many alternatives. And the JVM is a great runtime, not a bloated one. Look at how massive V8 is and the JS standard library is still complete trash compared to Java's. The JVM is possibly the best runtime out there, and a big part of why Java is so popular. The JVM has great and fast FFI, profiling, metrics, multiple world class GC's, it's rock stable, it optimizes code to within spitting distance of C, it handled projects with hundreds of megs of code with no problem.
- deleted 6y ago[deleted]
- donmcronald 6y agoYeah. Java is pretty solid as a language / platform IMO. I gave up on it when Oracle fumbled the ball with JavaFX, but I agree a lot of the criticisms aren't really issues. The one that gets me is the microservices. I've never really understood it. I can build a Java project with a bunch of small, composable modules and things like refactoring across the entire codebase are trivial. There's no rule saying you can't put your (ex) auth API in a separate module and bundle it independently at build time, right? Or, if you want to use the same module in multiple projects, formalize the versioning and bundle it as a library. I think the thing that drives microservices adoption is that it's easy to start out without any planning or API design. You just yeet some code out, publish the REST "API" via Swagger, and call it a "service". There's no versioning, no clear rules, etc.. All of that becomes tomorrow's problem. Then, since you don't have proper API versioning or anything, you start to end up with things like mono-repos to ensure your "API" changes aren't going to break anyone relying on your "service". Seriously. Microservices in mono-repos. It's like a bad joke.
- jimbokun 6y agoAgree with everything he said about Spring especially, but was surprised he advocated Python as the alternative, not Go. Still getting up to speed on Go, but it seems a more straightforward replacement for Java in a microservice context. More performant than Python, trivial to deploy, and provides a good amount of static type checking.
- koufatz 6y agoI would not choose Go, the language is simply to simple and not modern at all. You will still have to check for nil values ( see Kotlin, Swift for alternative) or you have to use old for loops to manipulate cumbersome collections types like slices instead of having functional paradigms build into the language ( again Kotlin, Swift, Java Streams etc). A good alternative if already using JVM would be some of the newer generation frameworks like Quarkus (https://quarkus.io https://quarkus.io), Helidon etc
- doctor_eval 6y agoI’ve written a ton of microservices in Java and have recently started a new project using a very similar architecture, but with Go. I had a chance to reflec on what I like about Go, and what I miss from Java. To boil it all down: * I prefer the Java language over Go, for a bunch of reasons, although neither is perfect. * I very much prefer using binaries over bytecode objects, so Go is much better here. * The JVM is a very large runtime to associate with your code, and the startup time is still much longer than for Go (or it was a year ago). This makes Java CLI tools slow, and a great CLI can help make a great product. * I prefer Go’s approach to the standard library; easy to use production ready “for dummies” implementations, instead of abstract “reference” implementations. * I specifically don’t like Go’s use of capitalisation to mark fields and variables as public, since I find that collisions between type and variable names are really common. * Go’s “idiomatic” practices are much saner than Java. I’d already stopped using getters and setters in Java, along with dropping several other abstract “best practices” (factory factories!!?? “Fluent” APIs??), and Go really embraces a light approach here. So I guess I don’t really like idiomatic Java. I got the feeling I wasn’t alone, tho. * In general I like how Go feels like it’s a Unix tool, where Java always felt like they were trying to rewrite the world. This approach always felt odd to me, considering where Java came from. * I have really come to hate the “everything’s a framework” approach in Java and abandoned it a couple of years ago. Especially, Java EE, Wildfly, Spring, JPA etc. they all add enormous weight and complexity without realising any material benefit. It’s not that it has to be this way, and I think things were improving, but so many Java libraries were just massively complex and abstract, for no good reason. So for my use case, Go is clearly the right choice, but after 12 months working in Go there is plenty that I miss about the Java language. I had really high hopes for the Java AOT stuff but it seemed to stall (maybe I missed something).
- skanga 6y agoIf you don't like Spring then don't use Spring! If you don't like Annotations then don't use Annotations! Then you won't need to write inflammatory headlines ...
- sumanthvepa 6y agoYou will not have a choice in the matter. Most large existing projects already use Spring. Changing those to not using spring is a recipe for getting yourself fired.
- NovaX 6y agoI have not used Spring since 2009 (where I used it daily) and have been using Java full time throughout. In that time I have written a lot of code and worked with many excellent teams. I’ve not had any of your problems because we always chose tooling that, for us, struck better balances and gave clear, concise error messages. There are certainly projects which are badly designed, but that is the team’s failing in every one of your complaints. Perhaps you should look inwards and not lash out against a large, diverse community.
- skanga 6y agoEveryone is different! I've used Java ever since the first publicly released version from Sun. But, I've never used Spring.
- matsemann 6y agoYeah, at no point does this article deliver on its premise: that java is dying.
- trinix912 6y agoAh yes, it's one of those articles again... First of all, Spring is not the only framework out there (even tho I really dislike it). If the title were "What I hate about Spring", it'd be fine, but hating on an entire language because of one framework just misses the point. > Java’s focus still appears to be on silly rules that dictate what class names should be, what packages they should be in, and if variables should be private or protected. Seriously, who cares? This is the one thing that I like about Java. I can easily guess the names of classes/methods. Private variables are private so that they don't leak into the public API (ie. encapsulation). The "seriously, who cares?" at the end just discredits the entire article for me.
- sumanthvepa 6y agoI agree it's not the Java language per-se that is messed up, its the runaway use of annotations in frameworks and libraries that makes building an application a write-once never be able to debug problem. The real problems start when you start work on a existing codebase that you are not familiar with. Deep expertise with Spring is an absolute requirement for even minor work. That's what puts off management from investing in Java for new projects.
- gnusty_gnurc 6y agoIf there's something worth criticizing it's just how large and non-obvious it is to figure out what Spring(/Boot) does. And before you know it you're digging into some PostProcessBeanFactoryInitializerDooDad. I've come to appreciate some aspects, but it's not obviously good to me, like a lot of stuff it's just various tradeoffs. I like Java and the surrounding ecosystem/community because it's boring.
- cle 6y ago> The "seriously, who cares?" at the end just discredits the entire article for me. It doesn't for me. I can't keep track of all the times I've been frustrated by a "final" class or a private variable somewhere that, were it public, I could have trivially solved my urgent business problem in time, with full awareness of the tech debt being incurred. But I can't remember any time in the tens of thousands of lines of Python that I've written, where I had regretted consuming a variable somewhere. So at this point, based on my experience, it all just sounds like paranoia to me that doesn't actually add value in practice. I think many of these "best practices" in Java, especially those coming from "Effective Java", are over-paranoid for most developers, and just create more problems than they solve. Being paranoid about API contracts makes sense if you are writing a widely-consumed library like those that Josh Bloch worked on, where the cost of changing consumers is prohibitively high. But when you are working on a class that has a handful of consumers, it really doesn't matter--just go update the consumers if you really need to (which you probably don't).
- sumanthvepa 6y agoSpring is completely undebuggable. If you get your annotations wrong, you simply cannot debug the process. I'm desperately look for tools that can give insight into what objects were auto wired at runtime.
- ojhughes 6y agoThose tools are part of the Spring Boot actuators. It shows you which beans and auto configuration are active and what conditions activated them
- andor 6y agoIt's trivial to observe runtime behavior with a debugger. If you use constructor injection as it is recommended, just add a breakpoint in the constructor and start the app in the debugger. @Component public class Foo { public Foo(Bar bar) { // breakpoint here } } Edit: In most cases it should be obvious what is getting injected, e.g. in the example Bar is another component/bean that was manually created. If you have two beans of the same type, use a qualifier to specify which one you want. If you are having issues with unexpected things being injected, I'd recommend setting up a few tests that establish that your app is properly wired up.
- littlestymaar 6y ago“Better be dead like Java than alive like Rust” Joke aside, while I don't like typical Java frameworks' complexity and haven't done any Java in seven years for that reason, calling java dead because “everybody is using microservices” and “why bother with performance when you can just run more workers” is a bit ridiculous. First of all, in practice “everybody uses PHP” is still way closer to the reality. The microservices hype train is real, but it's far from ubiquitous in real life and the fashion will probably be dead long before Java (I'm not saying microservices are bad per se, but it's way overused, by companies who have zero scalability issues and adds a lot of engineering complexity). Then there's cost: deploying 3 times more machines because you use Python on a high traffic service is a good way to give some margin to the cost-killers in the next LBO.
- dmitriid 6y agoThe article isn't about Java dying. It's about the author's gripe with Spring. Undoubtedly, 10 to 15 years ago he'd write and article about how Java is dying because Struts. 20 years ago it would be an article about how it's dying because there's nothing to compete with the new kids on the block in the web space. Java isn't going anywhere. It will probably slowly lose its significance over a few years, but it will be a decade or so before it will actually start dying (if at all).
- fzingle 6y ago> Simpler code base from not having to worry about concurrency and multi-threading This kind of thing irks me when I read it. I don't understand why people think of microservices as an architecture pattern. To me they seem more like an implementation detail. When it comes to concurrency and multi-threading, microservices mean you have different problems to worry about, not that they go away. I try to get people on my projects to imagine microservices as network function calls. If you diagram out how your data flows, how your concurrency works, you tend to see that a microservice is roughly a thread in a monolith. You gain not worrying much about mutexes or shared memory, but you lose on performance. Languages like Rust let you get close to having your cake and eating it too. It is also a useful exercise for teams to consider "how big does my service need to get before microservices on Python scale better than a 64-core monolith in C/C++/Java/Rust?" Another good question, "if a monolith is stateless, does it scale as well as microservices?"
- coldtea 6y ago>This kind of thing irks me when I read it. I don't understand why people think of microservices as an architecture pattern. To me they seem more like an implementation detail. Implementation details and architectural patterns are orthogonal. Implementation detail means something that is-not/should-not be exposed at higher levels (e.g. API consumers and/or the end user). This includes architecture, but also all kinds of other things (e.g. choice of storage backend). Microservices is very much an architecture pattern (affecting the whole architecture/design/code-base of the app in the most fundamental way), and is/can-be an implementation detail, as far as API/UI users are concerned.
- TedShiller 6y agoBad title. It’s about Spring not Java. Spring sucks indeed. But Java Play Framework is great
- coldtea 6y agoMedium clickbait BS.
- sime2009 6y ago> Simpler code base from not having to worry about concurrency and multi-threading Microservice advocates are so naive it's painful. It is only simpler if you completely ignore the downsides of microservices. Taking a "monolith" application and turning it into a distributed application rarely makes it simpler. Now you have to deal with network failures, serialising and deserialising data for what was previously just a method call, API versioning all over the place, kubernetes/terraform/etc configs from hell, concurrency and race conditions still persist but now they're spread across services instead of between threads. You want data consistency and transactions? Forget about it!
- sto_hristo 6y agoBy mentioning data consistency and transactions - your microservice is supposed to be self-contained and self-sufficient, doing its own job only. True, it may rely on other service, but not in the way that the two services would do the exact same job together as if you're invoking a `private` method helpers. For ex., filling a shopping cart should be its own thing. Searching for stuff to fill that cart can be another service that is just a dumb catalog. No data consistency problems here.
- Volundr 6y agoSure there is. What do I do when a piece of information I need to fill the shopping cart is removed or renamed in the search service?
- sto_hristo 6y agoThere is always the single source of truth principle. It is expected that both the search service and cart reference the catalog service.
- Volundr 6y agoOK, so when the catalog service is updated I need to update the search service and the cart service and coordinate deployment of these various services, or provide multiple versions of the catalog api.
- fierarul 6y agoClickbait article. > My beef, in fact, is more with frameworks like Spring than Java itself. True. The whole article seems to be about Spring. How about I write an article about how the Python is crap because I can't do banking with the Zope libraries? It's ridiculous. I would hope these kind of article would die.
- Ziggy_Zaggy 6y agoLol at ppl who think Java is dying. You haven't lived until you've been serious with Java at some point imHo.
- cutler 6y agoMuch as I wish Java would just die sadly that's not the case as far as business goes. There is probably more money changing hands for Java worldwide than any other language and with new languge features appearing it doesn't look likely to change anytime soon.