4 jvm web frameworks
TRANSCRIPT
@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
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!