4 JVM Web Frameworks

Preview:

Citation preview

@codefinger#Devoxx #YourTagHere

4 JVMWeb Frameworks

in 40 minutes

@codefinger#Devoxx #YourTagHere

in 50 minutes

4 JVMWeb Frameworks4 JVMWeb Frameworks

with 10 minutes for questions

@codefinger#Devoxx #YourTagHere

in 50 minutes

4 JVMWeb Frameworks4 JVMWeb Frameworks

with 10 minutes for questions±5 minutes

@YourTwitterHandle#Devoxx #YourTag

Joe Kutner@codefinger

JVM Platform Owner

@YourTwitterHandle#Devoxx #YourTag

@YourTwitterHandle#Devoxx #YourTag

Alternative JVM languages

Scala Groovy

JRuby Clojure

What is a even a web framework??

2015

2000

Model

View

Controller

Model

View

Controller

2015

2000

MongoDB Redis Active

MQ

AJAX

WebSocket

CSS

Events AsyncIORESTSOAP

Auth

Logs

Mail

Full Stack (big circle)MRAAWC

EARSALM

MicroMRA

AWC

EARS

ALM (little circle)

NanoQ

(no circle)

Full Stack

Micro

Nano

Templating

Server

Docs

Stack

Tooling

Language Scala/Java

Play

Netty

A-

activator/sbt

Persistence Slick

Testing ScalaTest

Full

Groovy/Java

Groovy

Netty

B+

Gradle

Micro

JRuby

ERB

Torquebox

A+

Rake

ActiveRecord

Minitest

Full

Clojure

Hiccup

Immutant

B+

Lein

Yesql

clojure.test

Nano?

Full Stack Reactive Opinionated

Client Server Database

Block wait

Async IO

Client Server Database

Async wait

Async IO

Client Server PostgreSQL MongoDB

Async IO

Client Server PostgreSQL MongoDB

Client Server PostgreSQL MongoDB

Client Server PostgreSQL MongoDB

Async IO

Demo Time

Tooling

Templating

@(customer: Customer, orders: List[Order])

<h1>Welcome @customer.name!</h1>

<ul> @for(order <- orders) { <li>@order.title</li> } </ul>

val content = views.html.Hello.index(c, o)

HikariCP

Database

Database Functional Relational Mapping

coffees.filter(_.price < 10.0)

val crossJoin = for { (c, s) <- coffees join suppliers } yield (c.name, s.name)

Database

select x2."COF_NAME", x3."SUP_NAME" from "COFFEES" x2 inner join "SUPPLIERS" x3

compiles to…

Functional Relational Mapping

val fullOuterJoin = for { (c, s) <- coffees joinFull suppliers on (_.supID === _.id) } yield (c.map(_.name), s.map(_.name))

Database

select x2."COF_NAME", x3."SUP_NAME" from "COFFEES" x2 full outer join "SUPPLIERS" x3 on x2."SUP_ID" = x3."SUP_ID"

compiles to…

Functional Relational Mapping

Database Evolutions

conf/ ├─ evolutions │  └── default │   ├── 1.sql │   └── 2.sql

# --- !Ups

create table "people" ( "id" serial not null primary key, "name" varchar not null, "age" int not null );

# --- !Downs

drop table "people" if exists;

Streaming HTTP

def index = Action { val s = getDataStream val d: Enumerator[Array[Byte]] = Enumerator.fromStream(s) Ok.chunked(d) }

Websockets (with Actors)

class MyWebSocketActor(out: ActorRef) extends Actor { def receive = { case msg: String => out ! ("I received your message: " + msg) } }

WebSocket.acceptWithActor[String, String] { request => out => MyWebSocketActor.props(out) }

ScalaTest

class StackSpec extends PlaySpec {

"A Stack" must { "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() mustBe 2 stack.pop() mustBe 1 } "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[Int] a [NoSuchElementException] must be thrownBy { emptyStack.pop() } } } }

Testing

$ activator ~test

Pros

Great for…

• Traditional web apps with lots of IO• Getting something up and running fast• High Powered apps, which is often mutually exclusive

with getting started fast.

Cons

Not so great if…

• You don’t like heavy-handed tools• You like backward compatibility

Templating

Server

Docs

Stack

Tooling

Language Scala/Java

Play

Netty

A-

activator/sbt

Persistence Slick

Testing ScalaTest

Full

Groovy/Java

Groovy

Netty

B+

Gradle

Micro

JRuby

ERB

Torquebox

A+

Rake

ActiveRecord

Minitest

Full

Clojure

Hiccup

Immutant

B+

Lein

Yesql

clojure.test

Nano

Microframework Asynchronous Unopinionated

Async IO

Client Server Database

Async wait

Demo

Templating

Time

Database

?

Testing

?

Spring Hysterix

Integrations!

Pac4j

DropwizardRxJava

ratpack { bindings { module DropwizardMetricsModule }

handlers { all { MetricsRegistry -> mr mr.counter(“request-count”).inc() next() } get { // ... } } }

Metrics Dropwizard

ratpack { bindings { modules HystrixModule }

handlers { get(“users”) { new HysterixObservableCommand<User>(... //... } } }

}

Fault Tolerance Hystrix

Hystrix is a latency and fault tolerance library designed to isolate points of access to remote systems, services and 3rd party libraries, stop cascading failure and enable resilience in complex distributed systems where failure is inevitable.

ratpack {

handlers { get { httpClient.get(“http://host”.toURI()) { s -> s .headers { h -> h.set(HttpHeaderNames.ACCEPT, “application/json”) } }.then { resp -> render(resp) } } }

}

Non-blocking HTTP Client

Templating

Server

Docs

Stack

Tooling

Language Scala/Java

Play

Netty

A-

activator/sbt

Persistence Slick

Testing ScalaTest

Full

Groovy/Java

Groovy

Netty

B+

Gradle

Micro

JRuby

ERB

Torquebox

A+

Rake

ActiveRecord

Minitest

Full

Clojure

Hiccup

Immutant

B+

Lein

Yesql

clojure.test

Nano

vs.

StrengthsNetty Netty

Full-Stack Microservices

Traditional Web-app API, Circuit Breaker

Weaknesses

Monolith New(ish)

Async IO Async IO

Backward Compatibility Docs

Demo

@codefinger#Devoxx #LameSlideTemplate

@codefinger#Devoxx #YourTagHere

in 50 minutes

4 JVMWeb Frameworks4 JVMWeb Frameworks

with 10 minutes for questions±5 minutes

with a few minutes for intermission

why java?

Full Stack Convention Opinionated

Full Stack

Synchronous IO

Client Server Database

Block wait

Demo Time

Tooling

$ rails new

$ rails generate

$ rails asset:precompile

$ rails server

$ rake routes

Templating ERB

<% @books.each do |book| %> <tr> <td><%= book.title %></td> <td><%= book.content %></td> <td><%= link_to "Show", book %></td> <td><%= link_to "Edit", edit_book_path(book) %></td> </tr><% end %>

Database ActiveRecord

class Person < ActiveRecord::Baseend

class CreatePerson < ActiveRecord::Migration def change create_table :persons do |t| t.string :name t.references :bodyguard t.integer :age t.timestamps null: false end endend

Torquebox

Torquebox

Templating

Server

Docs

Stack

Tooling

Language Scala/Java

Play

Netty

A-

activator/sbt

Persistence Slick

Testing ScalaTest

Full

Groovy/Java

Groovy

Netty

B+

Gradle

Micro

JRuby

ERB

Torquebox

A+

Rake

ActiveRecord

Minitest

Full

Clojure

Hiccup

Immutant

B+

Lein

Yesql

clojure.test

Nano

vs.

StrengthsNetty Torquebox

Full-Stack Full-Stack

Traditional Web App Traditional Web App

Weaknesses

Complex (Scala) Opinionated

Async IO

Flexible

Mature

Approachable (Ruby)

Async IO

Nano Modular (Un)opinionated

Libraries

F****work is a dirty word

Fordevelopers…

Demo Time

REPL Driven Development

Templating

Hiccup Selmer

(html [:ul (for [x (range 1 4)] [:li x])])

<ul>{% for item in items %}<li> {{item}} </li>{% endfor %}</ul>

ClojureScript

var zero = 0; if (zero) { console.log("Nope!");} else { console.log("Zero is false!");}

(def zero 0) (if zero (println "Zero is not false!"))

Javascript ClojureScript

Database

(with-transaction [t-conn conn] (create-user! {:id "foo" :first_name "Sam" :last_name "Smith"}) (get-user {:id "foo"}))

Yesql

--name: create-user!-- creates a new user recordINSERT INTO users(id, first_name, last_name)VALUES (:id, :first_name, :last_name)

Server

Immutant

caching

messaging

scheduling

transactions

logging

websockets

Websockets

(defn reverser "An example WebSocket app" [request] (async/as-channel request {:on-open (fn [channel] (async/send! channel "Ready to reverse!")) :on-message (fn [channel m] (async/send! channel (apply str (reverse m)))) :on-close (fn [channel {:keys [code reason]}] (println "close code:" code "reason:" reason))}))

Templating

Server

Docs

Stack

Tooling

Language Scala/Java

Play

Netty

A-

activator/sbt

Persistence Slick

Testing ScalaTest

Full

Groovy/Java

Groovy

Netty

B+

Gradle

Micro

JRuby

ERB

Torquebox

A+

Rake

ActiveRecord

Minitest

Full

Clojure

Hiccup

Immutant

B+

Lein

Yesql

clojure.test

Nano

vs.

StrengthsNetty Immutant

Microservices Client-Side Web App

API, Circuit Breaker Traditional Web App

Weaknesses

Async IO

Async IO

ModularModular

Functional

Functional

There is one thing all of these frameworks

have in common

NO WAR FILES

modern JVM web development uses alternative languages

pick one

Scala Groovy

JRuby Clojure

$ lazybones create ratpack my-app

$ activator new my-app

$ rails new my-app

$ lein new luminous my-app

@codefinger#Devoxx #YourTagHere

Joe Kutner@codefinger

JVM Platform Owner

thank you!

Recommended