
An Opinionated Guide to Modern Java, Part 3: Web Development - dafnap
http://blog.paralleluniverse.co/2014/05/15/modern-java-pt3/
======
mark242
It's funny. An "Introduction to Modern Java Web Development" sounds like a
primer for the Play Framework, Scala, and Akka. Each of the examples looks
like the starter documentation for Play, in that you've got your json
manipulation, routing, connecting to a database, DI, actors, etc.

Java devs-- you seriously owe it to yourself to spend the time investigating
and ramping up onto Scala and Play. This is where the future of Java web app
development is being driven from, by Typesafe and the Play / Spray /Akka open
source developers. You do yourself a great disservice by sticking with Spring,
Hibernate, JBoss, and the old standbys.

~~~
zak_mc_kracken
First of all, your attitude is off putting and condescending. You don't
convince people by telling them "You guys are living in the past, look how I
do things, you should do the same".

Please enough of that, especially coming from the Scala community. Let's act
as professionals and judge tools on their merits instead of instigating flame
wars.

Second, I'm doing both (web Java at work, web Scala on my spare time) and in
my experience, there is really no clear winner. What's especially interesting
is that I can find about the same number of positive things to say about the
Scala tool stack (Scala/Typesafe platform/Akka/Play) as I can say negative
things about each of them. Every time I'm happy about something in the Scala
world, I find something I'm not happy with that counter balances it (tooling,
slowness of template recompilation, unprovedness of the actor model, Play's
arguable step backward in the v2 compared to v1, etc...).

Java is impossibly verbose and has a very limited type system compared to
Scala but man... do I develop things quickly with it. There is close to zero
friction to get from nothing to something workable, maintainable and fast. And
the tooling is top notch, the environment and compilers are super stable, and
Java 8 is numbing a lot of the pain I used to feel. In contrast, I feel that
I'm often fighting against the Scala compiler whenever I write Scala code. It
feels nice in the end to see how concise and neat the code looks compared to
Java, but I'm never really convinced the pain was worth it.

So, back to your original point: I've tried (and continue to experiment with)
all these "new" technologies that Scala is claiming to bring to the table, and
so far, I'm unconvinced that they are a clear improvement over what we
currently use in the Java world.

And given that Scala continues to be a marginal language on the JVM, I don't
think I'm the only one doubting that Scala represents the future.

~~~
jaxytee
I don't find mark242's comment off putting or condescending at all. He's just
telling is like it is.

Of course there are Java developers who can kick ass with Spring, Hibernate,
Servlet containers, and war deployments, but all of these tools are huge,
bloated, and starting to show their age. Modern frameworks like Play make
things simpler for those of us who don't have +7 year JEE experience with
Spring and Hibernate.

~~~
cpprototypes
The comment is off topic since the article is not about Spring or JBoss and it
recommends against using Hibernate. The article is about a modern lightweight
stack (JAX-RS, Jetty, Dagger, JDBI).

~~~
jaxytee
Not it's not, rebutting another poster who is commenting about Play (a modern
java web development framework) in a article that is about modern java web
development frameworks. Your comment is counter productive to this
conversation, and the purpose of Hackernews in general.

------
tristanperry
A very good article; well written and explained.

For Java web development, it is worth re-considering Spring Boot though *
([http://projects.spring.io/spring-boot/](http://projects.spring.io/spring-
boot/))

Spring MVC and Data (et al) powered entirely by annotations, and (e.g.)
Thymeleaf for templating, can lead to some fairly powerful yet concise apps.

We just started using this where I work, and it's a great step forward
compared to old style, XML driven Spring MVC and Hibernate.

Also Spring Boot does bring quite a lot of support for REST, via
RestTemplate/RestOperations, along with support for consuming and producing
JSON and/or XML at the controller levels.

* Edit: I say re-considering since the article only briefly mentions it.

~~~
smoyer
Full JavaEE development is pretty analogous - POJOs and annotations. I almost
gave up on enterprise Java when every EJB required multiple classes,
interfaces and often XML configuration too.

Modern JavaEE isn't nearly as heavy as the article seems to think ... but I
can't argue with the article's underlying pragmatism. Use the simplest set of
tools that accomplish the task!

------
hibikir
I am especially fond of his view on database layers. There's JDBC, which is
extremely verbose and needs scaffolding to make it usable, and then ORMS, that
will quickly fall apart the moment you actually need to do anything
interesting with the database.

The Spring solution to this problem was always my favorite part of their
stack: JDBC template removed most of the error prone boilerplate from JDBC,
adds a couple of features, and still lets you write SQL directly, which is
probably what you should be doing in almost all the cases where a relational
database becomes valuable.

I can't wait for shops to start to use Java 8. The removal of so much
boilerplate when trying to build functional interfaces should make the Java
toolsets move forward very quickly.

~~~
mahmud
Again, just use jOOQ. It's beautiful executed design, written by smart people.

[http://www.jooq.org/](http://www.jooq.org/)

I never cared for the library until I realized I'm spending a lot of time on
the developer's blog; he is prolific and very knowledgeable about everything
database and java. Was sold on it soon after.

------
arielweisberg
I think that thread scheduling is really not the high pole in the tent for
large numbers of threads. It's stacks. If you want to have a million stacks
and each is allocated to the highest watermark that thread ever reached you
will run out of memory.

I suspect that task size has to be smaller than the typical bit of web
processing code for context switching overhead to really dominate, or even be
expensive enough to matter. That says as much about how expensive common tools
and frameworks are as it does about the cost of context switching.

~~~
rdtsc
That is kind of the issue in Go at the moment. They have been oscillating
between default stack sizes and also switched from green threads to real OS
threads backing goroutines.

EDIT: scratch the last statement about Go using OS threads for goroutines. I
was thinking of something else.

Sometimes on Linux systems, even allocating a large stack size doesn't
actually consume that as physical memory. Malloc might give you the memory
block, but until you actually make function calls or allocate data on the
stack, it might not consume the memory.

~~~
jrochkind1
Someone should really compile a list of all the non-toy languages/environments
that started with green threads and switched to native threads, with
explanations of what they were trying to do and what happened and why they
switched. It seems to be a popular path. Before the next person thinks "oh,
this would be so simpler and more problem-free if I use green threads", that
person should really review the prior art, heh.

~~~
mwcampbell
On the one hand, I've observed that operating system implementers have
repeatedly tried and rejected green threads for their pthread implementations
(Solaris many-to-many threads and FreeBSD KSEs are both now historical
footnotes). In Linux around 2002, there was a new many-to-many pthread
implementation called NGPT that was backed by big players like IBM and Intel,
until a couple of Red Hat developers (Ulrich Drepper and Ingo Molnar)
obsoleted it with NPTL and some accompanying kernel optimizations. So at the
OS level, a 1-to-1 correspondence between kernel-level and user-level threads
seems to be what mature implementations settle on. Also, early JVM
implementations for Unix used green threads, but that's also now a historical
footnote.

On the other hand, Go does use green threads, and the main developers of Go
are by no means naive. So maybe green threads do have some benefit, but only
when implemented in something higher-level than libc and pthread.

~~~
jrochkind1
It seems like Go uses it's own threads but backed by OS threads, rather than
actually pure green threads. Yes?

But yeah, a whole lot of people seem to think "man, OS threads suck, surely we
can do better with green threads," only to find out why OS threads suck, and
that many developer-years of work have gone into making them not suck more.

~~~
pron
OS threads by no means suck, but they can't make certain assumptions that
lightweight threads can about thread behavior. They're great for a lot of
processing, but not so great when they have to constantly block and unblock.

------
haddr
I don't get the point of saying that application servers are dead and then...
embedding application server within the application. If applications should be
isolated they can be easily deployed on different application servers. The
result will be the same, with the difference that we get all advantages of
easy application deplyment using war files, and some nice tools supporting the
whole process.

~~~
jebblue
One of the problems with application servers is like well, port separation,
process isolation, when a change to the context is desired but it might affect
all the apps you have to be very careful. Having your web app be its _own_ app
is hugely advantageous.

~~~
twic
You can, and usually do, do exactly that with app servers.

It's true that app servers were originally conceived as a way of hosting
multiple apps in a single JVM, but it quickly became apparent that this was a
terrible idea, and nobody does it. You run one instance of the app server per
app. The app server is really just a great big bundle of useful libraries and
a web framework.

~~~
jshen
so why separate the two if there is always 1 app per app server?

~~~
twic
(I'm guessing that was "So why separate ...", and you've just had root canal)

They're separated in the sense that the app server is something you download
that exposes an API, and the app is something you write on top of the API.
It's much the same as the way the JVM and the class files are separated, or
the way the OS and the JVM are separated. It's a fairly straightforward,
pragmatic application of layering.

~~~
jshen
Maybe we mean different things by "separated". I want the app server bundled
into the app, not an assumed dependency that the app has on the target
environment.

Rack in the ruby world exposes an API that ruby web apps build on top of, but
you never install an app server then install your app into the server.

~~~
twic
Aha, yes, that makes sense. I don't think there's anything fundamentally wrong
with packaging the app server along with the app. It's just not traditional in
the Java world.

My preferred solution would be to package the app and the app server as
operating system packages, and have the app depend on the app server. That
makes the dependency explicit, but doesn't leave you with a gigantic
deployable.

~~~
jshen
Here is one reason I like the bundled approach. I've been using golang
recently which compiles into a machine executable. I was building a REST API
that many third parties would use. When they wanted to use the API for
development all I had to do was send them the bundle and tell them how to
start. There were no other dependencies at all. It didn't assume a particular
package manager, OS, or anything else. Take this file and execute it, that's
it.

------
DCKing
It's great to see how Java web development has progressed. I tried to make a
Spring MVC web app work like a decent, modern, readable and productive web
application two years ago and it just wasn't possible.

Anyone interested in modern JVM web development I would still advise to invest
time in learning Scala (or Clojure). They can work with your legacy code and
libraries, but my productivity and general joy in programming shot through the
roof when I started using Scala.

~~~
moondowner
You can actually make a good Spring MVC-based webapp (with Thymeleaf,
AngularJS and etc.); check out the JHipster Yeoman generator:
[https://jhipster.github.io/](https://jhipster.github.io/)

~~~
DCKing
Man, I wish that would have existed 2 years ago.

------
java-lang
As a modern java developer I was surprised to find no mention of Vert.X which
to me seems like one of the most modern and forward-thinking java web
frameworks. Not only does it support scaling your app out-of-the-box but also
provides a simple way to deal with concurrency.

~~~
eip
I've been stuck using Vert.x for a year and half. I recommend using something
else.

It's a questionable framework mashed together with a poorly though out
messaging system.

I would rather use Spring Integration, Quasar, or Akka.

~~~
zmmmmm
Would be interested in any more concrete description of the problems? I'm
considering using Vert.x in a project, mainly because of the polyglot features
(ability to be extended by many different people some of who only know Python,
others who only know Java and some who might only know Javascript, etc).

~~~
eip
Non-standard build/deploy/run.

Classloader per verticle type makes dependency injection painful. "I don't
know what a Spring "ApplicationContext" is" \-- Tim Fox

Uses multiple classloaders so you can "run multiple versions of the same
module at the same time". Not something I have ever done or would do.

Uses Hazelcast for clustering but uses tons of classloaders so using anything
other than simple types in Hazelcast is hard and inefficient.

Message bus is tightly coupled to application cluster through Hazelcast.

Messaging is missing the most useful features of AMQP like wildcard topics and
queues. Only possible to do very basic message routing. Many messages have to
be sent multiple times to mimic advanced routing.

Dividing everything into 'verticles' encourages use of callbacks for
everything. This increases code size and complexity which increases the need
for testing. 'Callback hell'

Encourages polyglot programming.

Writing Vertx apps with Groovy makes me feel like I could add a whole chapter
to 'How to Write Unmaintainable Code'.

[https://www.thc.org/root/phun/unmaintain.html](https://www.thc.org/root/phun/unmaintain.html)

~~~
zmmmmm
Wow - thanks for taking the time to put those down.

Some of those I consider advantages - polyglot is the whole reason I looked
into it, Groovy is the main language the app I'd be integrating it into is
written in, callbacks are the mainstay of many other frameworks (try writing
anything in Node.js without a callback!).

That the clustering is poorly designed is probably not an issue in itself
since in my case it's a web server embedded in another app, but it's a concern
that the framework isn't well thought out and I don't like that (it sounds
like) the whole thing is heavily entangled with Hazelcast (which I have no
need for, or interest in).

Thanks again for writing down your thoughts!

~~~
eip
You're most welcome.

> try writing anything in Node.js without a callback!

I wouldn't even try writing anything in Node. Server side javascript is not an
option I would consider.
[http://www.youtube.com/watch?v=bzkRVzciAZg](http://www.youtube.com/watch?v=bzkRVzciAZg)

Hazelcast on it's own is pretty useful if you need a distributed data grid in
Java although it's not without its quirks. Unfortunately it's much less useful
in Vertx because of the classloaders.

Callbacks as an antipattern is one of the main points of this HN post.

------
runT1ME
How does asynchronous futures end up being more complicated or in any way
worse than the blocking threaded approach?

    
    
        for { 
           user       <- asyncGetUser(1)
           company    <- asyncGeCompany(user.companyid)
           longresult <- asyncProcess(company.getSomething)
        } yield longresult

~~~
saryant
His issue seems to be the potential for modifying or referencing mutable state
where in the yield block (or map or flatMap or whatever).

It can be a problem. In Akka actors, referencing sender() from a future will
be unpredictable because sender() could've changed in the mean time.

I think there are three strong solutions which address this problem:

1) Immutable state. Solves this problem completely but accidental capture
remains an issue.

2) Hiding mutable state within actors. I hesitate to present this as a general
solution though since it really requires going all-in with actors (I don't
consider that to be a bad thing, necessarily).

3) Projects like Scala Spores [1] aim to tackle this at the compiler by
capturing mutable references and executing async closures in an immutable
environment and prohibiting accidental capturing. IOW, turning accidental
capture into a compiler error. I'm excited about this one.

[1] [https://speakerdeck.com/heathermiller/spores-
distributable-f...](https://speakerdeck.com/heathermiller/spores-
distributable-functions-in-scala)

~~~
runT1ME
You can (and should) use Futures independently of Akka actors. You're correct,
hidden mutable state with Actors can be a problem, as with mutable state in
general.

~~~
saryant
Absolutely, but people make mistakes.

It's also somewhat unavoidable when you're dealing IO, unless you stick to
.pipeTo(self)

------
phillmv
Man, am I ever fascinated with the complexity Java devs have to put up with.

Maybe it's just been a long time since I had to deal with Java-land, but you
need to know about _so many different things_ just to get off the ground.
Granted, this may be easier with newer frameworks, but still.

~~~
jrochkind1
> but you need to know about so many different things just to get off the
> ground.

I think that's probably true of just about any mature environment these days,
isn't it?

Nobody wants it to be true. You make something new, thinking, this time i'll
do it right, it'll be so simple, easy to get going with. And it is at first.
Then you add stuff to deal with all the things that turned out to be pain
points, all the edge cases and use cases that someone had that seemed
reasonable after all, before you know it, it's a monster again.

To get off the ground with Rails 3/4, you sure need to know a lot. That wasn't
neccesarily true in Rails 1/2 when some of us got started, and we were able to
learn the new stuff gradually as it was added in, but to get started from
scratch, let's say you don't even know ruby very well, oy, it's a lot now.

~~~
jksmith
It's certainly not true with Go so far in my experience. Download, grab some
packages that do specific things, put together a solution. Low noise.

~~~
Consultant32452
To be honest most of the java code I write is just gluing a bunch of libraries
together to accomplish the desired task.

------
zinxq
You had me until you said Asynchronous I/O is faster than Synchronous I/O in
Java.

[http://www.mailinator.com/tymaPaulMultithreaded.pdf](http://www.mailinator.com/tymaPaulMultithreaded.pdf)

~~~
pron
That's not what I said, or at least not what I meant. If you have blocking
operations (that take a long time), then thread-blocking (as opposed to fiber-
blocking or async) IO will require too many threads.

~~~
cpprototypes
I've heard of Quasar before and had a general idea of what it is, but didn't
look at the documentation carefully until now. My understanding is that I can
run arbitrary synchronous code in Fibers? For example, consider the MongoDB
client library:

    
    
      DBObject r = collection.find(query);
    

It blocks while getting the results of the query. If I do something like this:

    
    
      for (int x=0; x < 100000; x++) {
        new Thread(() -> DBObject r = collection.find(query))).start();
      }
    

it's going to start 100,000 threads and freeze my computer. However, with
Fibers I can do:

    
    
      for (int x=0; x < 100000; x++) {
        new Fiber(() -> DBObject r = collection.find(query))).start();
      }
    

and it will work fine since these are lightweight threads (like Go
goroutines). I guess my main question is, can I use arbitrary unmodified
synchronous code like this to run in Fibers or would the library have to be
modified to support it? In this case, would someone have to update MongoDB
library to add support for Fibers?

~~~
eitany
Hi. You don't have to change the library in order to make it work through
fibers. You have to wrap it. In case it has efficient implementation of the
async-api you have to implement the fiber-synchronous using the asynchronous
api. If it hasn't you have to wrap it with threadpool. You can take a look in
the implementation of the JDBC wrapper here:
[https://github.com/puniverse/comsat/tree/master/comsat-
jdbc](https://github.com/puniverse/comsat/tree/master/comsat-jdbc)

------
rdtsc
Great work Ron.These should be a small (or maybe a full) book some day.

Java is not my main language, but I liked the Advanced Topic: Blocking vs Non-
blocking section and in general have been following Parallel Universe
technology stack.

If anyone is interested more in the async vs actors, there is a nice new
podcast with Ron Pressler, Fred Hebert (Learn You Some Erlang For Great Good
author), Kevin Hamond and Zachary Kessin

[http://mostlyerlang.com/2014/05/15/037-parellel-universe-
wit...](http://mostlyerlang.com/2014/05/15/037-parellel-universe-with-ron-
pressler/)

There is a discussion about concurrency, how Quasar works underneath (hint:
there is an interesting bytecode transform that takes place during loading),
shared state, Erlang, Clojure and Datomic. Anyway, highly recommend.

------
namelezz
Thank you for sharing the amazing work. I do not know if there is a part 4
coming or not but do you have a good pattern for validating users' input?

------
zinxq
I will say though, dismissing Rob Von Behren in the area of async vs. sync IO
with an anecdotal paragraph is a ballsy move. (i.e. "wrong approach")

~~~
pron
I've been misunderstood. I have not commented at all about whether sync or
async _IO_ is better. I meant that if you have a long operation that blocks
for a while, letting it consume a kernel thread is bad.

------
elchief
Do you really need to write a controller and all its actions for each resource
with Jersey?

~~~
logn
For static resources you can load them like this:

    
    
        public class WebAppConfig extends ResourceConfig {
          private final String[] mimeTypes;
        
          public WebAppConfig() throws IOException {
            //load static resource from htdocs dir
            Collection<File> files = FileUtils.listFiles(new File("./htdocs"), null, true);
            ArrayList<String> mimeTypeList = new ArrayList<String>();
            for (File file : files) {
              final byte[] contents = FileUtils.readFileToByteArray(file);
              Resource.Builder resourceBuilder = Resource.builder();
              resourceBuilder.path(file.getAbsolutePath().split("/htdocs/")[1]);
              final ResourceMethod.Builder methodBuilder = resourceBuilder.addMethod("GET");
              String mimeType = Files.probeContentType(Paths.get(file.toURI()));
              if (!mimeTypeList.contains(mimeType)) {
                mimeTypeList.add(mimeType);
              }
              methodBuilder.produces(mimeType)
                  .handledBy(new Inflector<ContainerRequestContext, byte[]>() {
                    @Override
                    public byte[] apply(ContainerRequestContext req) {
                      return contents;
                    }
                  });
              registerResources(resourceBuilder.build());
            }
             
            //load dynamic resources implementing interface Webpage
            register(MultiPartFeature.class);
            Reflections reflections = new Reflections(new ConfigurationBuilder()
                .setUrls(ClasspathHelper.forJavaClassPath())
                .filterInputsBy(new FilterBuilder().include(FilterBuilder.prefix("com.example.mycompany"))));
            Set<Class<? extends Webpage>> webpageClasses = reflections.getSubTypesOf(Webpage.class);
            for (Class<? extends Webpage> webpageClass : webpageClasses) {
              registerResources(Resource.builder(webpageClass).build());
            }
            mimeTypes = mimeTypeList.toArray(new String[0]);
          }
        
          public String[] mimeTypes() {
            return mimeTypes;
          }
        }
        ...
    
          public synchronized void start() throws Exception {
            WebAppConfig config = new WebAppConfig();
            HttpServer httpServer =
                GrizzlyHttpServerFactory.createHttpServer(URL, config, false);
            CompressionConfig compressionConfig =
                httpServer.getListener("grizzly").getCompressionConfig();
            compressionConfig.setCompressionMode(CompressionConfig.CompressionMode.ON);
            compressionConfig.setCompressionMinSize(1);
            compressionConfig.setCompressableMimeTypes(config.mimeTypes());
            httpServer.start();
            wait();
          }

~~~
elchief
Thanks, but I was referring to say a dynamic database-backed resource.

With SDR, you have an @Entity, and a @Repository for that entity, and SDR
handles the whole HTTP part, i.e. you don't need to write a @Controller to
expose the repository.

Just wondering if Jersey has anything similar.

------
rch
Is there a preferred way to submit typos other than in comments?

~~~
dafnap
of course, email us at info@paralleluniverse.co - thanks!

------
jaxytee
>Let me put this clearly: asynchronous APIs are always more complicated than
blocking APIs..

IMO I would rather use a single threaded server and manage synchronicity
explicitly with callbacks, composable promises, comprehensions, monads, and
"other functional shenanigans" vs having to sync shared state across threads
and manage thread pools.

~~~
simpsond
If you keep your data immutable you can have the best of both worlds.

