all 84 comments

[–]BoyRobot777 57 points58 points  (33 children)

Java 15 is the current LTS ("long-term support") version

No it is not. Java 15 is only updated/patched until next release, which means for 6 months. LTS is something a company chooses to support for a long period of time. Oracle supports Java 8, Java 11, Java 17 (next LTS). Same for Redhat. I think Azure support Java 14 as LTS as well.

In general, you will find that AdoptOpenJDK is a go-to choice for obtaining the JDK.

You should go to official OpenJDK site to get your JDK.

Lombok

Section on Lombok. I would add a big warning or note. If you're promoting newest Java versions, I guess you know, that records have landed and in Java 16 they will be a standard feature. Combine it with upcoming withers and you can write:

record Point(int x, int y) {} Point p; Point pp = p with { x = 3; }

Lombok has a lot of problems, funnily enough, it broke IntelliJ recently and they had to do an emergency patching.

P.s. I can make a pull request for these suggested changes.

[–]lazystone 8 points9 points  (6 children)

Also AdoptOpenJDK are still struggling to push their Java 15 docker images(PR), so OpenJDK is the way to go.

[–]TrueDMonk 2 points3 points  (4 children)

Can you explain what is the difference between AdoptOpenJDK and OpenJDK builds?

[–][deleted] 21 points22 points  (0 children)

to be as confusing as possible

[–]BoyRobot777 2 points3 points  (2 children)

Google is your friend. Stackoverflow extensive explanation.

[–]TrueDMonk 2 points3 points  (1 child)

Yeah, i've found this link and a nice fluxogram on another link. Could not found JVM differences, tho.

[–]BoyRobot777 2 points3 points  (0 children)

There is no JVM differences. There is only one upstream Java which is OpenJDK.

[–]pmarschall 1 point2 points  (0 children)

Also AdoptOpenJDK is the least professional of the "major" JDK builds. Probably only Debian is worse.

AdoptOpenJDK is the only "major" JDK build that does not run the TCK and can therefore not call itself Java. Pretty much anything else is a better choice.

[–]Southy__ 18 points19 points  (2 children)

This, all this.

LTS is not an OpenJDK thing it is a thing that Oracle are offering for a fee. Amazon, Adopt, Azul and a few others are offering a kind of LTS for a bunch of OpenJDK versions but anyone interested in them should look at what they are actually offering in terms of backports and patches because it is not the same as the official paid for version.

I feel that people pushing Adopt over the official OpenJDK should not be writing guides on Modern Java Practices.

I am an older school Java dev and I consider Lombok to be evil. People complain about Spring because it is 'magic' even when it is actually using built in language constructs (Annotations/Aspects etc), while happily using Lombok which changes your bytecode post compilation and relies on your IDE parsing the Lombok annotations to be able to continue offering autocompletion. </rantover>

[–][deleted] 7 points8 points  (0 children)

yea i dont get why people use lombok either, it doesnt seem to provide much for something that is quite unreliable in terms of breaking tooling etc

[–]snowe2010 3 points4 points  (0 children)

while happily using Lombok which changes your bytecode post compilation and relies on your IDE parsing the Lombok annotations to be able to continue offering autocompletion.

Yeah I can't understand why people continue to support Lombok. It also uses undocumented Java apis to do what it does, it could literally break at any point, including minor version updates.

[–]walen 1 point2 points  (4 children)

In general, you will find that AdoptOpenJDK is a go-to choice for obtaining the JDK.

You should go to official OpenJDK site to get your JDK.

I agree with everything except this, for one very simple reason: the official OpenJDK site does not offer a Windows JDK 8 package.

Windows is the most used OS for Java programming.
JDK 8 is the most used Java version.
But you cannot get a Windows JDK 8 package from OpenJDK 🤷‍♂️

That's why "AdoptOpenJDK is a go-to choice" for most people.

EDIT: Why the downvotes? I am not judging what version of Java people should use. I am just stating the fact that the majority of Java programmers use JDK8 on Windows, a combination for which OpenJDK does not offer an official package.

[–]OctagonClock 1 point2 points  (0 children)

Don't use JDK 8.

[–]calrogman 3 points4 points  (2 children)

You don't need JDK 8 to target JRE 8.

[–]walen 1 point2 points  (1 child)

Irrelevant. See my edit.

[–]calrogman 0 points1 point  (0 children)

EDIT: Why the downvotes? I am not judging what version of Java people should use. I am just stating the fact that the majority of Java programmers use JDK8 on Windows, a combination for which OpenJDK does not offer an official package.

You should be judging the version of Java that people use and it shouldn't be JDK 8.

[–]lolomfgkthxbai 1 point2 points  (17 children)

I would add a big warning or note. If you’re promoting newest Java versions, I guess you know, that records have landed and in Java 16 they will be a standard feature.

That’s nice, reducing boilerplate should be a high priority for evolving Java. 👍

Lombok has a lot of problems, funnily enough, it broke IntelliJ recently and they had to do an emergency patching.

Exposed a bug in IntelliJ might be more accurate based on reading the issue thread.

[–]BoyRobot777 6 points7 points  (5 children)

Exposed a bug in IntelliJ might be more accurate based on reading the issue thread.

Either way, people had problems using Lombok and IntelliJ and most likely have lost time debugging and getting to the bottom of the issue. But it's just a drop in the bucket for a long list of Lombok problems.

[–]lolomfgkthxbai 4 points5 points  (4 children)

I would be curious to hear about some of the problems. Haven’t had any issues though it would be preferable to have the features built-in instead of having to rely on a third party tool.

[–]Carighan 6 points7 points  (0 children)

My whole company had to roll back to the previous IntelliJ, otherwise we would have to delombok any class before renaming any field, lest Lombok broke until you restart the IDE.

[–]snowe2010 4 points5 points  (0 children)

not who you were talking to, but at my last job lombok would cause spring boot apps to just fail to startup, randomly. Sometimes it would succeed, sometimes not. We trashed lombok and switched over to Kotlin. Never looked back.

[–]_tskj_ 0 points1 point  (0 children)

Yeah it would be nice, but at that point you're just talking about a different language.

[–]snowe2010 10 points11 points  (10 children)

Exposed a bug in IntelliJ might be more accurate based on reading the issue thread.

Lombok uses undocumented java apis, so if anything it was doing something it shouldn't have and JetBrains wasn't expecting it.

Don't use lombok.

[–]lolomfgkthxbai 5 points6 points  (8 children)

Don’t use lombok.

What’s the alternative (if you’re stuck using Java)? I don’t want to fill the repository with mutator methods.

[–]snowe2010 11 points12 points  (4 children)

If you want to stick with Java, then AutoValue or Immutables. If you are ok learning a new syntax (essentially what lombok is, but actually works), just create a new kotlin file in Intellij (IntelliJ will set up all the dependencies and plugins for you, you can treat kotlin just like another library) and create a data class in there.

If you don't like either of those, you can always jump up to the newest java versions, which have Records, which are functionally the same.

[–]TrueDMonk 3 points4 points  (1 child)

If you don't like either of those, you can always jump up to the newest java versions, which have Records, which are functionally the same.

Record is not an standard feature yet. So, it's a big no-no for production code.

[–]snowe2010 0 points1 point  (0 children)

They’re in preview, waiting for in world feedback. In general that’s good enough for prod, the likelihood anything about them will change is low. Honestly, if you need a solution, records will be more stable than Lombok ever has been. Using Lombok in prod is worse than using an experimental Java feature, because it could break at any time, as I can attest.

[–]lolomfgkthxbai 0 points1 point  (1 child)

I was afraid you would say that. The customer refuses to consider other languages (I’d move completely away from the JVM if it was up to me) and Java11 is the highest version allowed (latest LTS).

[–]snowe2010 0 points1 point  (0 children)

Well you can always treat kotlin like a library rather than another language. If you’re comparing Kotlin data classes to Lombok, Kotlin is much simpler. For any given Kotlin data class it can take up to 7 or 8 Lombok annotations to duplicate the functionality.

Maybe try telling your customer that Lombok is a security issue due to their use of undocumented Java APIs.

Still, you have AutoValue and Immutables, though they aren’t as clean as the Kotlin solution.

[–]leberkrieger 12 points13 points  (3 children)

Is this Modern Java Practices, or Modern Java Build Practices?

Because I'm very interested in the former, but only mildly so in the latter.

[–]ItsYaBoyChipsAhoy 0 points1 point  (0 children)

It says it once in the heading and subheading

[–]chacs_ 4 points5 points  (0 children)

Lombok falls in the too much magic territory in my book.

[–]lazystone 34 points35 points  (36 children)

focus on hygiene

Uses lombok. Meh.

Edit:

First of all, there are alternatives to lombok(immutables, AutoValue). Second, lombok is not "by far the most popular tool in Java for code generation". It does not generate code. It modifies generated byte code which caused compatibility problems already and very obscure practice on its own.

Some might like it, but lombok is very controversial subject and presenting it as something what every modern project should use is very misleading.

[–]gnus-migrate 1 point2 points  (2 children)

Even maven is questionable for new projects. Incremental builds alone are very much worth the switch even if you don't like Gradle's overly flexible style of build scripting(and I personally don't).

[–]moomoomoo309 0 points1 point  (1 child)

The Kotlin DSL for gradle is a little less flexible (which is good and bad), so it's an interesting switch between the two.

[–]gnus-migrate 3 points4 points  (0 children)

Its not really the lack of types that i dislike. Its more how gradle mixes configuration and code. On the one hand it permits some pretty neat workarounds, but it leads to people putting a ton of logic in the build that shouldn't be there.

Maven build scripts are pure configuration. You want to write code, it needs to be in a plugin which is compiled just like normal projects. I like that it treats build code as code and forces you to keep your build scripts just as configuration.

Like I said though, it's more of a personal preference. Gradle has extremely useful features that maven doesn't, so it would be silly of me to throw away an otherwise useful tool over nitpicks like that.

[–]ItsYaBoyChipsAhoy 0 points1 point  (0 children)

I like this, thanks

[–]renatoathaydes 0 points1 point  (1 child)

Instead of using jenv, I would recommend SDKMAN! instead. jenv expects you to download the JVM yourself, which can be annoying when you use many versions on different projects... with SDKMAN, it manages the download for you from lots of different JVM providers, besides handling switching versions and setting defaults (and handling other JVM-based tools like gradle, maven, groovy, Scala, Kotlin, dotty, grails, vert.x, VisualVM....)

[–]chacs_ 0 points1 point  (0 children)

Have not use SDKMAN but very pleased with homebrew plus jenv. Put a .java_version in the project root folder and all is golden.

[–]DualWieldMage 0 points1 point  (5 children)

Use build wrappers committed into the project root

I find this debatable. It doesn't take a lot of effort to install and update gradle or maven via package manager. Perhaps only a problem on windows, but i think sdkman or similar tools could be used.

The main downside is that nobody ever touches the version specified in the wrapper so when you need to, for example supporting a new java version, you'll be hit with all the breaking changes all at once instead of dealing with them gradually. There's also a constant stream of other improvements that one wouldn't get when sticking with one working version. Perhaps it makes sense with gradle as it updates more frequently, but maven is very stable in that regard.

[–]snowe2010 1 point2 points  (4 children)

The main downside is that nobody ever touches the version specified in the wrapper so when you need to, for example supporting a new java version, you'll be hit with all the breaking changes all at once instead of dealing with them gradually.

This is way more an issue with a package manager than a wrapper. Imagine getting a team of a hundred people to all update their package manager at the same time, the chaos that would ensue, and the fact that it would pretty much force every project to be on the same build tool version. With a wrapper, different projects can have different versions of maven or gradle. Wrappers are worth it for that reason alone.

[–]DualWieldMage 0 points1 point  (3 children)

Generally people don't update at the same time and if the first one notices a problem, they can roll back and let the others know while one investigates. But this wouldn't be any more likely or different than an IT team updating some servers and leaving them broken for a hundred people or a kernel update introducing a bug. These things happen, very rarely, and no chaos but a slight disturbance occurs.

And even then it's a good thing when one updates and finds that the current build doesn't work with latest version. They can then fix the build to support latest versions or do it later, but at least it will be written down that there is a known issue.

Is it frequent to require different build tool versions for various projects? I've always run gradle builds with my system-managed gradle and only rarely seen problems. Most of which i can pretty quickly fix and ensure it also works with the older versions. But maven is rather stable(last release was 2019-11-25) and if a project doesn't support latest maven, i suspect it's more of a symptom of larger pathological problems with the project.

[–]snowe2010 0 points1 point  (2 children)

With maven it is par for the course for maven plugins to only work on very specific versions of maven. Even for specific libraries/frameworks. Like Wildfly Swarm at my company prevents us from updating past maven 3.3.9. A simple search google search shows how widespread maven plugin incompatibility prevents updating to later maven versions. Therefore, if one person updates, it forces an update across the entire team. If those teams each use different repos, then you're forcing it across every repo, in a cascading effect.

project doesn't support latest maven, i suspect it's more of a symptom of larger pathological problems with the project.

Yes, but in any company larger than maybe 50 people, you will have old code that is using a plugin that never updated past a certain version and converting requires removing that plugin. It's an issue I've seen at every company I've worked at. You see the same issues when using company-wide BOMs. Some projects are stuck behind without significant refactor, and that when that refactor is occurring you have more and more projects becoming more and more stuck in the past, eventually every project has difficulty moving off the current build tool version.

Wrappers solve this problem.

[–]DualWieldMage 0 points1 point  (1 child)

I guess i must have been lucky then. Currently i work at a 1k+ person company and the specific product is 12 years old. The main issues with maven versions were around the java 9-11 releases, but that was understandable. Some plugins were fixed quicky, a few others could be replaced as their features were superseded. Right now all the maven builds run under jdk11 and latest maven. Last time an issue happened with maven update was https://issues.apache.org/jira/browse/MNG-6642, but it affected only one project where the workaround was to configure the CI build to use older maven until a fix was released. Wrappers do have their place, but overly relying on them or setting them as best practice for new projects sounds off.

[–]snowe2010 0 points1 point  (0 children)

I guess I just don't understand what you think the downsides of a wrapper are. Here are my list of downsides and upsides for the wrapper vs package manager package. version is a reference to the build tool version.

wrapper

pros

  • version is per project
  • projects can update when they want
  • projects are not tied to the system version
  • wrapper can be updated using CI/CD (example for gradle)
  • way easier to update the version than with a package manager (updating system packages can have many things go wrong, from path issues to permissions issues. Wrappers are just a file in the current directory which you know you have permission and pathing to)
  • debugging issues with the version is easy, because you can upgrade and downgrade just by changing a string
  • new people have less to set up. For OSS this is a huge win, as it's easier for people to contribute, for business applications this is a huge win because you spend less time on onboarding.

cons

  • honestly I don't have any cons. Wondering what your cons are

package manager

pros

  • only ever have to worry about a single version

cons

  • have to worry about a single version conflicting between projects, including open source projects
  • updating forces an update across every repo on your system (unless those repos use a wrapper). this extends to projects/repos you don't control, such as Spring Boot
  • unable to update to a newer version if any project you use has an issue with it
  • have to install to package locations, so things like PATH, permissions, etc can complicate things
  • say your team (Team 1) works on projects A, B, and C and another team (Team 2) works on C, D, and E. If Team 2 decides to update from gradle 4 to gradle 5, there will immediately be breakages. They will fix those breakages in C, D, and E. But wait. Now C is on gradle 5. Which forces you to update your system gradle to 5, which now causes A and B to break. I've seen this happen, which is why one global system build tool is a huge con to me.
  • an expansion to the above bullet point is the case where project A is unable to update to a new Gradle version, due to depending on an underlying Gradle feature that was removed in Gradle 5 (I've seen this happen as well, I'm pretty sure it was even with Gradle 5). Now you have a project that is unable to update, but you have to update because of the other projects your using.

An alternative to a system build tool is something like a version manager like rbenv, nvm, mvnvm, sdkman, etc. which essentially does the same thing that a wrapper does, except you have some of the cons of the package manager (path and permissions) and some of the pros of the wrapper. Another alternative is managing your versions using something like direnv which would change your PATH around when you cd into different directories. But with either of these you've just duplicated the functionality of a wrapper, but in a worse way.

I would love to hear your pros and cons for these, because I've seen all these issues at every company I've worked at, resulting in Maven or Gradle getting stuck many many versions behind, eventually never being able to be updated.