Earlier quoted context omitted.
Agreed. Stuff like this feels like magic for magic’s sake, and as someone who has had to operate services that use these DI frameworks, they are a big pain.
How about learning about the tools you use beforehand? You don’t sit into a car without any knowledge about it and blame it that it is magical.
Jodd – The Unbearable Lightness of Java
191–200 of 239 posts
Re: Jodd – The Unbearable Lightness of Java
#192Earlier quoted context omitted.
You know, you hear Java repeat things like that a lot, while Go programs just tend to stay simple and readable. It's either the culture or the language causing the problem. shrug
As mentioned, Go is not used for ENTERPRISE APP^TM — Java programs can really hold up under insane abstractions and complexity. Also, Go has really poor abstracting capability, which may be good for small code bases where having abstractions is a detriment, but abstractions are the only way to handle complexity. If you have the logic spread out over many different parts (or God save us, copied code!), a new programme…
Re: Jodd – The Unbearable Lightness of Java
#193Earlier quoted context omitted.
You're, of course, right that you just need to study and learn a complex framework. Basically the same way that you learn a new programming language- they're all different and have different behaviors and idioms (pass-by-copy vs. pass-by-reference, etc). However, there's another dimension here, and while it's not totally unique to Java, it's definitely present in larger magnitude in Java, in my experience. There are…
I don’t think that it is any easier in other languages either — object serialization, conversion between language’s object/json/xml/etc, and database access with object relational mapping is just complex. You can make the trivial way trivial, but you have to expose the hard ways as well and that will not be pretty either way. For what it worth, java has a really high quality ecosystem for all these things - I would b…
I agree that these things are just complex. But, what's interesting to me is that I fully agree with your second sentence and I see it as an indictment against the Java ecosystem around these operations. The common Java frameworks, IMO, serve to make the trivial stuff even more trivial, but then make the complex stuff even more complex. It's exactly the opposite of what I want.
Let's look at JacksonXML for serialization.
Here we have a framework that uses runtime reflection to more-or-less guess how to (de)serialize an object. Figuring it out at runtime is a tough engineering choice already, because it pretty much immediately means that you're going to have to figure out a caching system for what types you've already analyzed, so that performance isn't terrible. And we all know how hard cache is.
But, on top of that, Java uses type-erased generics, so you can't actually reliable use runtime reflection to figure it out! But the compiler certainly won't tell you it's a problem, because Jackson will try to (de)serialize anything you throw at it. You don't even need any annotations for most stuff. It "just works" (TM)... until it doesn't.
So, if you use generics or inheritance or any non-trivial mapping, you have to write a custom serializer. Okay, that's no big deal.
But then you realize that JacksonXML will IGNORE time zone information on an incoming serialized date field that is encoded as an ISO8601 string and just use the current JVM system time zone. Because why the fuck not, I guess?
So, in other words, Jackson makes already-trivial things a little less verbose, it makes non-trivial things a pain, and it even makes some things that should be trivial into a pain.
I can play the same game with JPA/JDBC. In particular, it also does really stupid things with time zones and date-time types. It also can't really handle complex types for similar reasons to JacksonXML.
> For what it worth, java has a really high quality ecosystem for all these things - I would be really interested in what you think as an alternative.
My favorite languages to work with at the moment are Rust, Swift, and Kotlin. All three have way better serialization stories than Java. Rust has serde, which is like JacksonXML, except it's compile-time and your types have to implement a Serialize "trait" (interface). I truly think I'm being honest when I say that I've NEVER had a runtime serialization (type) error in my Rust projects that have used Serde. If it compiles, it works. The same is almost true of Swift and Kotlin (with kotlinx.serialization), except I do think I've encountered some runtime issues in both of those (IIRC, there was a surprising limitation with Swift Dictionary keys needing to be Strings or something). Kotlin's approach is my least favorite of the three.
When it comes to ORM/SQL stuff, I've been using a query builder in Rust that's a delight to use. Basically, when you execute a query, you use the type system to indicate the type you expect the returned rows to be. As long as the type implements a `FromRow` trait, it will "just work" or return an error value or crash (you can choose to call a "safe", error-returning, function or a "crashy" version of the function that assumes success and crashes otherwise). Rust has ad-hoc tuple types, and the library implements its `FromRow` trait for all standard types as well as all tuples up to 13 or so elements, so often you can just write something like `let (id, name) = query.execute();` and it will just work. If the `id` column is `null`, then the call will FAIL instead of doing something insane like just making up data (like JDBC returning `0` instead of `null` for nullable int columns).
The Rust query library I'm using is the perfect example for the point you made earlier about making trivial things trivial. This library does require a little bit of boilerplate to implement `FromRow` for your custom object types. It's not really worse than JPA for the simple cases, but it's WAY ahead when it comes to dealing with the non-trivial cases.
> Also, java is solid as a language. Sure, it is not the most modern one, but it is reasonably productive, has great tooling, is very performant and perhaps most importantly, it is observable in a very fine way.
Credit where it's due: Java does have phenomenal tooling and it's very fast (except when you use the frameworks that we're discussing...). I think I'd lump in the observability with the phenomenal tooling.
But, no, I wouldn't call it a solid language. It's far too primitive and bug-prone for writing robust applications. The null issue doesn't really need to explained, the ease with which we can leak resources from Closeable things, the awkwardness of the type system (e.g., being unable to implement an interface for types you don't own, being extremely tedious to define "newtypes" like a `NonEmptyString`, etc), the incompatible-yet-ubiquitous use of runtime reflection and type-erased generics, etc.
I'm sure you're a Java expert, but I'd wonder how many years you think it took you to get to the point where you feel like you aren't bitten by all of the things I've described in this comment. If the answer is more than 1, then I'll go ahead and assert that Java is not a good programming tool for the domain in which you work. I've been working with JVM languages for about 5 years now, and I'll say that I'm now familiar enough to avoid these traps most of the time, but holy shit- it should not have taken nearly that long.
Re: Jodd – The Unbearable Lightness of Java
#194Earlier quoted context omitted.
If you have Java 11+ I presume you can't get any simpler than a standard library module: https://docs.oracle.com/en/java/javase/17/docs/api/jdk.https...
This comes from way before SE 11. I was using it in 7. The doc says it comes from 6. https://docs.oracle.com/javase/7/docs/jre/api/net/httpserver...
Re: Jodd – The Unbearable Lightness of Java
#195Earlier quoted context omitted.
I disagree here. Having GC, VM, streams, big stdlib, makes is quite highlevel. It's not very terse (like Ruby maybe), but modern Java is terse enough. To keep a language small is a good thing: less to remember, easier to join the team. Go, Elm, Reason/ReScript, LISPs all go that route. Java misses some things badly. Like being able to have a reference to a method (Jodd has a library fix for this). Or like sum types a…
Java has had method references for almost a decade. Pattern matching also was recently released.
So how can I pass a method to another method? (without using lambdas)
> Pattern matching also was recently released.
I know, great improvement (if it comes together with proper sum types). One less reaosn to switch to Kotlin.
Re: Jodd – The Unbearable Lightness of Java
#196Earlier quoted context omitted.
I disagree here. Having GC, VM, streams, big stdlib, makes is quite highlevel. It's not very terse (like Ruby maybe), but modern Java is terse enough. To keep a language small is a good thing: less to remember, easier to join the team. Go, Elm, Reason/ReScript, LISPs all go that route. Java misses some things badly. Like being able to have a reference to a method (Jodd has a library fix for this). Or like sum types a…
> I disagree here. Having GC, VM, streams, big stdlib, makes is quite highlevel. I used to think that, too. I probably wont't convince you otherwise, and it really doesn't matter how you or I categorize the language, but I think a solid argument can be made that Java's abstraction power is almost zero, especially if you consider versions older than two or three years (before records, switch expressions, sealed classe…
OTOH lets consider Rust. It is in my book a low-level lang, close to the metal (hence Rust?). It has a muuuuuuch better feature set compared to Java (IMHO). But it is geared at low-level, so no VM and certainly no GC out-of-the-box... In your def Rust'd be a high level lang: which is cool. I like your def :) But I still def'd high level slightly different: more in terms of the ability program close to the machine, or more in abstractions.
> Sum types and pattern matching are not OO.
Traditionally not often found in OO, but otherwise verrry much compatible with OO.
> In "true" OOP, you wouldn't have a sum type, because you'd have an object that would exhibit different behavior depending on the implementation.
I think this is more about tradition than "trueness". I cannot return an Either from Java. That sucks. Many have used Exceptions to fix it, but that suck even more. I'd say OO is compatible with sum types.
> But, I'd argue that the "problem" isn't Java's lack of sum types and pattern matching, but rather that we're trying to make Java into something it isn't.
This always happens. And some langs are better suited for that than others. I work on a Java codebase currently and welcome those features, and actively consider moving the whole show over to Kotlin. Kotlin to me is like a typed Ruby. And in Ruby many libs are in C (in Kotlin then many libs'd be in Java).
I think OO and FP bite eachother. You cannot have both. See Scala. It becomes way too big as a language, and lack idiomatic ways of doing things. But one can have a lot of FP in an otherwise OO lang (see Kotlin for instance).
Re: Jodd – The Unbearable Lightness of Java
#197Earlier quoted context omitted.
The point of the transaction in this context is that both the database(s) and the business logic/state stay in sync. I don’t think that naive attempts will be logically correct.
What do you consider naive? JDBC supports transactions, I’ve had success with that.
Re: Jodd – The Unbearable Lightness of Java
#198Earlier quoted context omitted.
As mentioned, Go is not used for ENTERPRISE APP^TM — Java programs can really hold up under insane abstractions and complexity. Also, Go has really poor abstracting capability, which may be good for small code bases where having abstractions is a detriment, but abstractions are the only way to handle complexity. If you have the logic spread out over many different parts (or God save us, copied code!), a new programme…
So, COBOL? That's an argument that works in a historical moment of Java legacy, until it doesn't. Monzo is an example of a bank writing everything in Go.
Java is in the unique position of excellent performance (state of the art GC, very good JIT compiler) and observability with no-overhead real time options. Due to the language having multiple implementations of a standard and it being one of the top 3 biggest ecosystem, it is nothing like Cobol. You can say it is legacy for 3 decades to come, but it will not die. Hell, it improves with a never-before seen speed.
Re: Jodd – The Unbearable Lightness of Java
#199Earlier quoted context omitted.
Java has had method references for almost a decade. Pattern matching also was recently released.
> Java has had method references for almost a decade. So how can I pass a method to another method? (without using lambdas) > Pattern matching also was recently released. I know, great improvement (if it comes together with proper sum types). One less reaosn to switch to Kotlin.
Re: Jodd – The Unbearable Lightness of Java
#200Earlier quoted context omitted.
What do you consider naive? JDBC supports transactions, I’ve had success with that.
As I mentioned, you will have to roll back not only the database, but the relevant application state as well. This is really error-prone if repeated enough times, or the flow of control is through many different methods, etc.
I recognize that what you’re advocating for makes of sense in some applications, I just wanted to point out that I haven’t felt the need for it in my eight years of software development.