
An Opinionated Guide to Modern Java, Part 2 - dafnap
http://blog.paralleluniverse.co/2014/05/08/modern-java-pt2/
======
cmicali
Nice article - Many of the suggestions (single-jar deployment, metrics, slf4j
logging, etc) are all wrapped up for you in Dropwizard
[http://dropwizard.io](http://dropwizard.io), which we use and love.

~~~
asdf1234
Do you just use it for producing a REST API or do you use it to render HTML,
handle session management etc.?

~~~
cmicali
We use dropwizard only for rest APIs currently. Our HTML and JS are served up
with an in-house framework that has plugins for less, minimization, svg
inlining, etc. We have open tasks to both publish it and make it hostable in
dropwizard directly.

------
badlogic
I'm glad someone took the time to write this, it's actually a very nice
resource to get new coworkers up to speed. Shouldn't be tought as dogma of
course (e.g. Gradle vs. Maven).

Also, thanks for mentioning Packr even though noone has used it in production
yet. It's only a week old.

Assuming OP is the original author: are you by any chance following JGO? I see
Quasar is actually using Matthias Mann's green thread lib which i don't think
was advertised anywhere outside JGO.

~~~
pron
Yep. JGO. And Quasar now uses a heavily modified fork of Matthias Mann's code.

------
benjaminpv
"Java application servers are dead" and since there's no alternative to Java
application servers here's a solution I cooked up myself.

Like I mentioned last time I appreciate an overview of modern Java practices
but boy howdy I can't discern if this is clever trolling or a cheap way to
make me read Part 3.

~~~
philbarr
I skimmed through Part 3 and it's basically saying that app servers are hard
to deploy, maintain and dev against and you should be using Spring Boot or
Dropwizard instead to create applications with the services you require.

~~~
Patient0
Where did you find part 3?

~~~
philbarr
Ah my apologies, it's not actually part 3 it's the link he referenced when he
talked about part 3: [http://www.slideshare.net/ewolff/java-application-
servers-ar...](http://www.slideshare.net/ewolff/java-application-servers-are-
dead)

------
pjmlp
I like the overview given to JVM tooling, many developers are fully unaware of
what JVMs (not only the official one from Oracle) offer in terms of
monitoring.

If you want to go really low level, a few of them even show the generated
assembly code by the JIT.

~~~
sehugg
You can do this from the JVM command line with "-XX:+UnlockDiagnosticVMOptions
-XX:+PrintAssembly". (it's kind of a mess, though)

~~~
pjmlp
Yes, it still requires the plugins which aren't delivered with the JDKs and
each JVM does it a bit differently, but is possible.

As complement of it, check JIT Watch

[https://skillsmatter.com/skillscasts/5243-chris-newland-
hots...](https://skillsmatter.com/skillscasts/5243-chris-newland-hotspot-
profiling-with-jit-watch)

~~~
pron
Oh, I forgot to mention JIT Watch! (I actually use it sometimes). I'll give it
a quick mention next time.

------
eeperson
As a Java developer, I thought this article had some interesting information
about logging and monitoring. However, the deployment section had my
scratching my head a little.

I've never totally understood why people want to make fat jars. It seems like
a process full of headaches since you can't have jars in jars. Wouldn't it be
much easier to create a regular zip file with a small script to set the
classpath and and run the project?

I'm not sure I understand the motivation for embedded instead of standalone
servlet container. The article linked to some slides but they mostly seemed be
demonstrating that you can function using an embedded container rather than
providing clear benefits. Maybe it would have made more sense with the
associated talk.

Can anyone provide more insight to these?

~~~
pron
Author here. A capsule is not necessarily a fat jar. It can point to Maven
dependencies that are downloaded on the first launch, and can later be shared
by other capsules. A zip with startup scripts is OK, but it requires
installation.

As to full blown app servers vs embedded servers, I think it's the other way
around. It's the big app servers that require justification, as they are a lot
more cumbersome to set up and deploy.

~~~
twic
_It can point to Maven dependencies that are downloaded on the first launch_

You wouldn't do this for a production deployment, right? Application starup
that may or may not require access to the artifact repository to complete
successfully. When that idea bounces around my developer neocortex, my
sysadmin hindbrain starts reaching forward to strangle it.

And if you're not going to do it in production, doing it in development means
having a gratuitous difference between development and production, which,
again, is something i have learned to fear.

 _A zip with startup scripts is OK, but it requires installation._

'gradle installApp' works out of the box, and 'installs' the jars and scripts
in your build directory, which is all you need to run locally. It's work of
minutes to write an fpm [1] invocation that packages the output of installApp
as an operating system package, which you can then send down the pipe towards
production. This is simple, easy, standard, and fully integrated with a world
of existing package management tools. Why would i use Capsule instead of doing
this?

[1] [https://github.com/jordansissel/fpm](https://github.com/jordansissel/fpm)

~~~
pron
Well, you can choose to embed the dependencies in the capsule, but I think the
best approach for production deployment is have an organizational Maven
repository (Artifactory/Nexus). This way you upload the libs, and the jars
containing the actual apps to your repo, and all you need to do is restart the
capsule (it can be configured to load and run the latest version).

~~~
twic
So you're downloading jars from the repository to the production server when
the app starts? I would feel very uneasy about that kind of coupling.

And i still don't see what _advantage_ this has over just pushing out normal
packages.

~~~
pron
I feel uneasy about deploying the wrong version. With capsule, at launch it
checks for a new version in the repo (if you configure it to use the newest
version rather than a specific one). The packages are only downloaded once:
not on every restart.

Alternatively, you can embed the dependencies, in which case it's just like a
"normal package", only it doesn't require installation, and is just as easy to
create (your build tool can create it). So it's a platform independent "normal
package", with added features.

~~~
twic
Interesting. I feel much more confident about deploying the right thing using
an operating system package than some other mechanism. Almost everything else
in the datacentre is deployed using operating system packages, so we get a lot
of practice at deploying the right versions of things. The few legacy
applications we have that are deployed via custom mechanisms are a headache -
they require completely different tooling and troubleshooting knowledge to
everything else.

But then, i have spent a fair amount of managing machines, shuffling packages
around apt repositories, writing Puppet code and so on. Perhaps for a
developer who has not served a sentence in operations, operating system
packages are a less comforting proposition.

You seem to be very keen on avoiding "installation". Could you tell us about
why that is?

And could you remind me what the added features of a capsule are? Putting
aside the differences in delivery mechanism, which as i've said, i'm afraid i
see as misfeatures, the only one i see is that it automatically finds the
right JRE.

(Sorry you're being downvoted, by the way. I think this is an interesting
discussion, and your gracious responses deserve upvotes, not downvotes.)

~~~
pron
The advantage Capsule gives you is statelessness. The user does not need to
put her system in a certain state. You get one file and you run it. It should
work regardless of anything else that's installed -- or not -- on your
machine, with the exception of an OS and a JRE.

There are other ways to achieve stateless deployment, and Capsule is not
always the right fit. For example, it's not the right fit if your app requires
an Oracle DB installed locally (it could be done, because Capsule supports an
installation script embedded in the JAR, but that probably wouldn't be a good
idea in this case). But when it is the right fit (e.g. microservices, grid
workers etc.), it's much more lightweight than any other solution.

------
eshvk
> While I personally prefer Gradle’s nice DSL and the ability to use
> imperative code for non-common build operations, I can understand the
> preference for the fully declarative Maven, even if it requires lots of
> plugins. The modern Java developer, then, might prefer Maven to Gradle.

I find Maven's abstractions surprisingly hard to understand. It is a major
part of my annoyance with Java as a dev setup. I miss Make/Ant. Not sure if
Gradle will be a good replacement or not but would be curious to try.

~~~
zmmmmm
I find all of them hard to work with, because they are all aiming for the
modern day "zero configuration" nirvana that Ruby on Rails achieved, and thus
enormous amounts of implicit knowledge is required to understand them.

Part of the problem is that the initial steps are so easy that you're actually
never forced to learn the mechanics of what is happening. Hence you get away
with a lot until you need to do something there isn't a magic command for.
This is also why you see blithe statements that you "don't need to know Groovy
to use Gradle", etc. However these are only said after the fact when you've
learned Gradle, understood enough Groovy to intuit what it's doing and then
retrospectively realised there is a theoretical path from ignorance to
enlightenment that didn't involve learning Groovy.

What you would probably like is Gant, which is Ant entirely converted to
Groovy. It's missing all the higher level project stuff from Maven / Gradle,
but it works a treat when you just want the simplest possible thing that could
work.

~~~
eshvk
> I find all of them hard to work with, because they are all aiming for the
> modern day "zero configuration" nirvana that Ruby on Rails achieved, and
> thus enormous amounts of implicit knowledge is required to understand them.

> ... realised there is a theoretical path from ignorance to enlightenment
> that didn't involve learning Groovy.

Yes! Learning is so non-linear that sure there are in theory fine lines that
minimize the amount of new stuff to learn. Yet, it never is that simple. Bad
design, indeed.

> What you would probably like is Gant, which is Ant entirely converted to
> Groovy. It's missing all the higher level project stuff from Maven / Gradle,
> but it works a treat when you just want the simplest possible thing that
> could work.

I will check it out; thank you!

------
vorg
> I personally prefer Gradle’s nice DSL [...] in order to use Gradle one does
> not need to know Groovy, even if one wishes to do some non-standard stuff
> [...] I just learned a few useful Groovy expressions that I found in Gradle
> examples online

The DSL is Groovy syntax from Groovy's antiquated Antlr 2.7 grammar, so simply
by using Gradle you're using Groovy along with all its warts. Underneath,
Gradle isn't so much a DSL as an API shipping with a programming language. You
could just as easily write the first Gradle example from the article in most
other JVM languages. If it was in Clojure...

    
    
      (require gradle :as g)
    
      (g/apply :plugin "java")
      (g/apply :plugin "application")
    
      (g/source-compatibility "1.8")
    
      (g/main-class-name "jmodern.Main")
    
      (g/repositories
        (g/maven-central))
    
      (g/configurations
        g/quasar)
    
      (g/dependencies
        (g/compile "co.paralleluniverse:quasar-core:0.5.0:jdk8")
        (g/compile "co.paralleluniverse:quasar-actors:0.5.0")
        (g/quasar "co.paralleluniverse:quasar-core:0.5.0:jdk8")
        (g/test-compile "junit:junit:4.11"))
    
      (g/run
        (g/jvm-args (str "-javaagent:" (-> (configurations.quasar.iterator) next))))

------
vidar
This feels like a different universe.

~~~
Terr_
... You mean the name of the blog?

------
lmm
Does anyone actually swap out their log backend? To me slf4j felt like an
overcomplicated, enterprisey step with no clear advantage over log4j.

~~~
paukiatwee
Think slf4j as API, and logj4 as implementation. slf4j has multiple
implementations, e.g. logj4, logback, apache common logging bridge, so you can
swap implementation easily without change your code(except configuration)

------
jebblue
I'm a fan of simplifying the server side, one I'd recommend for the latter
part of the slideshow he referenced:

[http://www.sparkjava.com/](http://www.sparkjava.com/)

~~~
danieldk
...or just use JAX-RS, which is simple, standardised, and has good
implementations (such as RESTEasy and Jersey).

~~~
jebblue
I suppose but SparkJava has as its core philosophy, build as a runnable jar
from the start which is in line with what the article was discussing in its
referential prohibition of conventional app server approaches.

edit: Further to the point of getting Java server technology to a simpler to
understand, design, debug and maintain place, SparkJava makes it insanely easy
to do REST services eliminating both Annotations and heavy configuration. I've
also speed tested my side projects on SparkJava and they are unreal fast.

------
anjanb
cool article. I wish if someone can give a Java update like this once every
year!

------
gsmethells
As far as packaging and deployment of a native executable goes, I thought it
odd to not mention Excelsior JET
([http://www.excelsiorjet.com](http://www.excelsiorjet.com)) as I believe
that's the only Java compiler that can handle all of the JDK (gcj isn't there
yet).

~~~
pron
Native executables are not always what you want. For example, they don't get
security patches.

~~~
Pacabel
That's total nonsense. Binaries (or shared libraries they depend on) can be
and are updated, on all sorts of systems. In many cases it's as simple as
overwriting the existing binary with the updated version.

Heck, the runtimes you're advocating are generally installed as binaries. If
they can get updated, then so can any other binary.

And if a user doesn't bother to update a given application's binary when a
critical flaw of some sort is found, then there's a very good chance they
wouldn't bother to update any runtimes that are installed, either. This is
true even when some sort of update notification and installation process is
offered. The end result is the same in either case: the update is not applied.

Runtimes shouldn't be portrayed as any better in this case, when they're
generally no different than any other binary.

~~~
pron
Anything can be done in many different ways. It all comes down to convenience.
When a library is found to have a security flaw, you can either upgrade all
binaries, or just upgrade one runtime. You could say that your OS is just a
binary, too, and that's true. But it's a binary that adds a lot of
convenience. A lot of people think runtimes add convenience, too. You
obviously don't agree, and that's fine: use whatever works best for you.

[http://xkcd.com/378/](http://xkcd.com/378/)

------
derengel
As someone not very familiar with Java can someone expand on what he means by
this: "Every library is usually packaged into its own JAR, and merging all
dependencies into a single JAR, might cause collisions, especially with
packaged resources (non-class files)."

~~~
saryant
A common example is with logging config files (e.g., logback.xml). Some
libraries ship with their own (or a library's dependency). It's not uncommon
in a large project to wind up with several logback.xml files littered around
from libraries that included their own. These are called "resources" because
they aren't code but they are included with the compiled distributable and are
placed on the classpath.

Of course, your project probably includes its own logback.xml in your
resources directory.

Libraries are typically distributed as JAR files, so when you include their
JAR on your classpath you're also including their logback.xml in that JAR.

Now, when you go to package up an uber-JAR for your project, whatever
packaging tool you use has to merge all those files into one classpath. So now
it's found collisions: there are multiple, different logback.xml files on your
classpath but you can only have one. How does the tool pick?

So now you have to specify a "merge strategy" to make sure that only your
logback.xml is merged in and the rest are discarded.

logback.xml is just one example. Typically Java classes themselves merge just
fine because the packaging tool can dedup by fully-qualified class name which
is almost never shared across projects. So even if two different dependencies
have a Utils class, the FQCN is different. com.foo.bar.Utils is not the same
as com.bar.baz.Utils, so there's no conflict.

Conflicts can also arise from libraries which include different versions of
the same transitive dependency. Generally the fix here is to exclude a
transitive dependency from one of your direct dependencies so as to only
include one version of that library. A common culprit is Apache Commons since
so many Java libraries rely on it.

~~~
pivo
Speaking of Java logging, that's one area that drives me batty. The lack of a
good standard Java logging library caused a multitude of logging libraries to
be written. Different libraries then of course use different logging
libraries, so each logging library generally has a way to wrap all the others,
and they all work in different ways. Getting consistent and controllable
logging (e.g. ability to turn on or off logging for a given thing) can
sometimes be almost impossible to understand.

~~~
twic
It's a sad story. The proliferation of logging libraries was the problem that
Commons Logging aimed to solve by providing a facade over all of them. But
because it screws up classloading (i forget the details, but it's serious),
eventually a critical mass of people needed to move off it. java.util.logging
tried to fix the problems and canonise a standard interface by putting in the
JDK, but it got so many things wrong that it wasn't widely adopted. SLF4J
finally came along as a very well-implemented facade that has gained wide
adoption. It would say it is a de facto standard.

Only then JBoss decided that all their stuff (including Hibernate) needed a
facade of its own, which manages to not quite properly interact with SLF4J!

It's almost enough to drive me to printlns.

------
dave3773
Very nice article. Capsule looks promising in regards to packaging. I'm going
to have give 'er a try. One could also use the fatjar[1] or application[2]
plugins (within the context of gradle).

[1] [https://github.com/musketyr/gradle-fatjar-
plugin](https://github.com/musketyr/gradle-fatjar-plugin) [2]
[http://www.gradle.org/docs/current/userguide/application_plu...](http://www.gradle.org/docs/current/userguide/application_plugin.html)

------
12345678123
This article does not mention OSGI or Jigsaw with one word but claims to guide
to modern Java development. Seems they never run any large scale EE projects
yet :)

~~~
twic
Ah, OSGI. OSGI is a bit of an enigma. People who use it think it's great, and,
by the sound of it, assume everyone else is using it. People who don't use it
think it's some weird thing from the turn of the century that nobody actually
uses.

I do think a well-rounded Java developer should know about OSGI (i have to
confess that i don't). But it would be mistaken to think that it's mainstream.

~~~
pswenson
I've found OSGi to be an absolute nightmare. Classloader hacks is not the way
to solve Java's dependency problem, it needs to be baked in the language IMO.

I think it's one of those ideas that sounds great in theory, but in reality it
all falls apart.

Even if it worked as advertised, fact is many 3rd party libraries have all
sorts of issues with OSGi. For example, my company is stuck on Jersey 1.x
because 2.x doesn't work properly with OSGi.

Testing is much slower and harder to write. Testing seems to be an
afterthought....

I think you can get most of the benefits of OSGi simply by using proper
dependency management (Gradle). Use the Single Responsibility Principle and
IoC and you'll get good modular code. These are much easer to do, have low
risk, and are easy to test.

JMO

------
kbcv
How does profiling Java applications work with JIT. Should you wait until the
code has been optimized before profiling, or these tools smart enough to
realize that the performance of code changes as the application runs?

~~~
thejdude
I think as soon as any method takes up a noticeable part of execution time, it
has been optimized all the way by the Hotspot or whatever your JVM uses.

After all, you want to profile your app's hot spots ;-)

------
skybrian
The article mentions a tool called Flight Recorder for profiling, but it
appears this is commercial and not available in the openjdk?

