Remix.run Logo
Sohcahtoa82 3 days ago

> it's verbose and boring to use.

Python code that follows traditional Python paradigms is called "Pythonic".

Java code that follows Java paradigms is called "awful".

To be fully transparent, I've never written Java professionally, only for a couple small hobby projects 10 years ago, plus some while in school, so my opinion isn't worth the pixels you're reading it on, but I look at most Java code with abject horror.

Endless levels of abstraction. The apparent inability to write a simple function and instead creating a "ThingDoer" class with a single function called "doThing". Run-time introspection and reflection EVERYWHERE. Stack traces that are just an endless stack of calls to functions like ".invoke" and ".run".

I've been under the impression that all of that is a by-product of Java's strict type system, but someone please correct me. Why do Java paradigms seem so awful?

mike_hearn 2 days ago | parent | next [-]

Well, there are lots of people out there who view "Pythonic" as a euphemism for awful tbh. Throughout my career I've seen multiple large Python codebases be rewritten in Java after they turned into a mess, including - perhaps most embarrassingly - Google's internal code review tool Mondrian, which was written by Guido van Rossum himself.

One reason Java codebases feel more abstract is that they're attempting to solve problems that the scripting worlds tend to just punt on, or handle in ways that don't scale well. And because Java's type system is nominal, solutions to those problems require names.

For example, a lot of the abstraction in Java codebases is to make things deeply testable. That's what drives dependency injection, which is where a lot of BeanFactory stuff comes from. What's the Python solution to that problem? Often they just hardly have tests by the standard of Java developers! This is why Python is big in ML research where codebases are often small disposable experiments, and why after a brief era where Django was popular it sort of died off in the wider server / big data space.

Another source of complexity and abstraction is a focus on pluggable ecosystems. Databases are abstracted by JDBC, and then again by an ORM, which then might be abstracted again by Micronaut or Spring, and at each layer there are multiple competing implementations available which implement standard APIs. This kind of thing happens much less in the scripting world. The downside is that scripting codebases are far more locked-in to their choice of libraries. Porting a Java codebase from one database or ORM to another is hugely easier, because the core APIs are all standardized.

sorokod 3 days ago | parent | prev | next [-]

It's a culture, not language thing. Here is a JSON parser implementation (part of PlantUML) that lacks endless levels of abstraction.

https://github.com/plantuml/plantuml/blob/master/src/main/ja...

porridgeraisin 3 days ago | parent [-]

I'd argue culture solely defines the language.

Is there a full library ecosystem of stuff written like the json parser you shared, which is as complete as the enterprisey library ecosystem? Similarly, SO answers? LLM output? Tutorials? YouTube videos?

I think the answer is no.

It's the same problem with C#. Just adding alternate paradigms means nothing. The only thing that matters is how a majority of code in the ecosystem is structured. In java, that's enterprisey code. Most code is glue code, so you're forced into the majority pattern, lest you want to write endless wrappers...

On the other hand, while typescript supports a lot of the enterprisey nonsense similar to C#, the majority of the ecosystem is written with simple functions, callbacks and options objects. Not in an enterprisey way. I don't need to use decorators to use zod.

People that eschew enterprisey code and prefer simple code can't switch to java or c# until the whole culture changes, regardless of the kitchen sink of features either language adds.

zerkten 2 days ago | parent | next [-]

>> On the other hand, while typescript supports a lot of the enterprisey nonsense similar to C#, the majority of the ecosystem is written with simple functions, callbacks and options objects. Not in an enterprisey way.

Going back to culture, who makes up the Typescript community? While C# devs are attracted to it there are many multiples more devs coming from a JavaScript background. This has a big impact on how the culture developed.

Taking a step back. C# devs often need to do frontend work. They could go with what the industry has settled on, React, or go another way. The bulk go with react and some perhaps lament still have to switch their brain to another mode for that work. Frontend is obviously more fragmented, but the scale prevents C# devs from influencing patterns to the extent that they do on the backend.

I'd argue similar for Java devs when it comes to frontend. In the case of Blazor, I think C# patterns are a much smaller factor in decision-making. In fact, lots of C# adherents would default to React given it's the industry standard.

sorokod 3 days ago | parent | prev | next [-]

I agree with most of what you are saying except for the "solely defines" bit. The culture is a powerful force but individuals are free to make choices and the language allows for these choices.

troupo 2 days ago | parent | prev | next [-]

> It's the same problem with C#. Just adding alternate paradigms means nothing.

C# is still much better because it has a lot of useful DX improvements: from object initializers to IEnumerable everywhere. It keeps the tower of abstractions lower, and makes working with the tower a better experience.

Though I've only worked on microservices written in C# in .net core

Mawr 3 days ago | parent | prev [-]

Spot on. You can't separate a language from the speakers of it. You can't redo millions of hours of work put into an ecosystem.

johnyzee 3 days ago | parent | prev | next [-]

Those are not Java paradigms per se - they're just practices of mediocre enterprise developers, of which Java has many, owing to being such a mainstream platform.

As for the language itself, a lot of verbosity has been culled in later language versions, with diamond operators, lambda expressions, local variable type inference, etc.

In either case, code is read more than it is written, so if a bit of verbosity makes code easier to read, I'm okay with it.

cmrdporcupine 3 days ago | parent | prev | next [-]

As others are saying, it's a culture not the language. C++ and even some Python etc written in the late 90s, 00s era has the same pattern-itis. It comes from slavish adherence to the Gang Of Four patterns books and an obsession with OO generally. Also the languages themselves were weak on non-OO abstractions and ways of doing code re-use, so for example it took forever for Java to get lambda expressions ... so people used one-off helper classes with "invoke" methods, etc.

kbolino 3 days ago | parent | prev | next [-]

ThingDoer.doThing was often just functional programming squeezed into an object-oriented straightjacket. Java 8 added first-class functions and lambdas over a decade ago, eliminating a lot of the need to turn simple behavior into full-blown classes.

cryptos 3 days ago | parent | prev | next [-]

One reason for that Java style is that Java was not such a powerful language for a long time. For example lambda expressions were only introduced in Java 8 (2014) and before that developers need to work around this restriction. A common workaround were/are some annotations above of methods and some reflection magic on top. For example a life cycle callback method annotated with @PrePersist is basically the same a registering a _function_. The whole Lombok library is a massive hack to circumvent some inconveniences in Java (and in my opinion no longer needed).

robmccoll 3 days ago | parent | prev | next [-]

I think a lot of it is the people using it and certain parts of the culture. There are a lot of Enterprise TM programmers that seem to believe as many layers of abstraction and as much verbosity as possible with little tiny methods that do practically nothing leads to better solutions. It is totally possible to write concise and pragmatic code with Java. One thing that will be a thorn in your side though is null handling. The traditional approaches increase line count and branching. The newer(ish) Optional-based null handling is quite verbose but in width.

ifwinterco 3 days ago | parent [-]

In my opinion at this point null handling is the one remaining thing about Java that is genuinely bad technically

munksbeer 2 days ago | parent [-]

I haven't seen a NPE in the wild for years. We use NullAway in our build - works great.

lab14 3 days ago | parent | prev | next [-]

I think it doesn't have to be like that, but it's the way Java code has been written for ages, so those habits stuck. You can see it clearly when you bring a Java programmer to collaborate on a Ruby or Python codebase, if you let them, the will turn your codebase into an enterprise-ready mess with layers on top of layers of indirection in a blink.

never_inline 2 days ago | parent | prev | next [-]

> by-product of Java's strict type system

1. Lack of first class functions till Java 8 is one reason old APIs are horrible with inheritance and reflection everywhere. You had to extend class and override methods even for simplest of tasks.

After Java 11 the code is much more succinct and functional style. But old libraries remain.

There are places where the overextensibility these libraries provide is useful. But those are few.

2. the annotation processors were late to the game - so many libraries which need to inspect object structure (such as serialization) were written with heavy use of reflection.

I will give you an example of how frameworks designed for "modern" Java look like.

Micronaut has something called Micronaut data JDBC - in which you just declare methods with few annotations eg `List<Book> queryTop10BooksByYear(int year)` and it will auto generate the JDBC + SQL code and handle injecting it into your service. The returned object can be a POJO without all the Proxy object circus ORMs come with. I haven't seen something as easy in Python yet. And all this happens in compile time with an annotation processor.

microflash 3 days ago | parent | prev | next [-]

As someone who has seen awful code in pretty much every language I've worked with, I'd blame this more on inertia and reluctance to change habits. The bad patterns that have entrenched deep into the ecosystem are very hard to shed even when the language and platform is making progress at impressive speed.

lock1 3 days ago | parent | prev [-]

As other sibling comments have said, it's cultural. Fortunately, there's some push toward functional & ADT-style modelling in the Java community and they've decided to call it "data-oriented programming" for some reason.

Eh, I don't think Java type system is strict, nor is it the root cause of this cargo cult mess. It's probably due to many enterprise programmers who think design patterns are the building blocks of everything rather than an invisible, emergent structure.