SlideShare una empresa de Scribd logo
1 de 42
Descargar para leer sin conexión
Principles of the 

Play Framework
Bernhard Huemer
Why are we here?
Composition
Contextual vs. 

composable design
• Boundaryless extensions /

flexibility
• Steep learning curve
See also: http://nealford.com/memeagora/2013/01/22/why_everyone_eventually_hates_maven.html
• Anticipated extension points
• Easy to get into / quick wins
Referential transparency
• No reassignments of variables
• No setters, no mutations
• No exceptions (no throw new …)
• No console input / output
• No network communication
• ….
"An expression is said to be referentially transparent if it can be
replaced with its value without changing the behaviour of a
program."
Side-effects don’t compose
protected void renderBasket(HttpServletResponse response)
throws ServletException, IOException {
try (PrintWriter writer = response.getWriter()) {
writer.println(“HTML for our basket.”);
}
}
!
protected void renderProductList(HttpServletResponse response)
throws ServletException, IOException {
try (PrintWriter writer = response.getWriter()) {
writer.println(“HTML for our products list.”);
}
}
Best practice: 

Don’t assume any special context when calling these
methods, it will manage its resources itself.
Side-effects don’t compose
protected void renderAll(HttpServletResponse response)
throws ServletException, IOException {
renderBasket(response);
renderProductList(response);
}
• Composing code with side-effects always requires
additional “plumbing”
• in this case: close() method of the response
• Ignore the <head />, <body /> HTML issues ..
What’s wrong here?
import io.Source.fromFile
val it: Iterator[String] =
fromFile(“foo.txt").getLines

// or from the network
!
var result = 0
while (it.hasNext) {
val line = it.next
result += line.toInt
}
General idea: 

Some part of the application produces a stream of
something that we want to consume elsewhere.
What’s wrong here?
import io.Source.fromFile
val it: Iterator[String] =
fromFile(“foo.txt").getLines

// or from the network
!
var result = 0
while (it.hasNext) {
val line = it.next
result += line.toInt
}
val it: Iterator[String] =
fromFile("foo.txt").getLines
var result = 0
it foreach { line =>
result += line.toInt
}
val it: Iterator[String] =
fromFile("foo.txt").getLines
var result = 0
it foldLeft(0) { case (acc, line) =>
acc + line.toInt
}
Problems …
• Repetitive pattern (DRY principle)
• Manual pulling, possibly blocking I/O
• No error handling (sometimes we forget, right?)
• No communication with the producer (e.g. back pressure)
• Resource handling (how long do we need a resource and who
is responsible for opening/closing/recovering it?)
• Missing or rather difficult composability
• What if the input source was infinite? 
See: http://www.slideshare.net/afwlehmann/iteratees-intro
Architecture at LinkedIn
See: http://www.slideshare.net/brikis98/play-framework-async-io-with-java-and-scala
Latency spilled over to the
supposedly fast part
Clarification: 

Latency in one part of the network will slow down
anything that depends on it directly or indirectly, it
should, however, not have an impact on anything else!
Requests are functions
object Application extends Controller {
def greet(name: String) =
Action { request =>
Ok(s"<html>Hello $name!</html>")

.as("application/xhtml+xml")
}
}
GET /greet/:name controllers.Application.greet(name)
• Controller is not really required as base class
• Action { } is like a factory method that produces one of
these functions
Play in the command line
scala> controllers.App.greet(“ConFESS”)
res0: play.api.mvc.Action[play.api.mvc.AnyContent] =
Action(parser=BodyParser(anyContent))
!
scala> controllers.App.greet(“ConFESS”).apply(
play.api.test.FakeRequest()
)
res1: scala.concurrent.Future[play.api.mvc.Result] =
scala.concurrent.impl.Promise$KeptPromise@3ffe0466
Read-eval-print-loop (REPL): 

Scala, like most scripting languages, comes with an
interactive shell that you can use to test your
application. Play supports this tool as well.
Your application code never
uses the network directly
scala> val result =
Await.result(
controllers.App.greet(“ConFESS”).apply(
play.api.test.FakeRequest()
), atMost = 2.seconds
)
result: play.api.mvc.Result =
Result(200, Map(
Content-Type -> application/xhtml+xml; charset=utf-8)
)
• No HTTP server we needed to start
• Nothing we needed to mock *
* I will not count FakeRequest .. it’s infinitely simpler than mocking servlet requests
Side-effects are collected until
the very end of the request
scala> result.body.run(Iteratee.foreach({ bytes =>
println(new String(bytes))
}))
<html>Hello ConFESS!</html>
res8: scala.concurrent.Future[Unit] =
scala.concurrent.impl.Promise$DefaultPromise@3ee2e
• The framework takes care of “side-effectful” code
once you returned control to it
Minimises incorrect usage
“I was eventually persuaded of the need to design programming notations so as to 	

1. maximise the number of errors which cannot be made, or	

2. if made, can be reliably detected at compile time.“	

- Tony Hoare (ACM Turing Award Lecture)
• No IllegalStateExceptions in the API
• PrintWriters and OutputStreams
• Redirects after status codes / headers / etc..
• Headers after the response body was started
Composition of functions
def Logging[A](action: Action[A]): Action[A] =
Action.async(action.parser) { request =>
Logger.info("Calling action")
action(request)
}
def index = Logging { Action {
Ok("Hello World")
}}
No mental overhead: 

Simplistic example (think security, instead), but the
point is: No additional concepts you need to learn!
private def futureInt(): Future[Int] =
Future {
intensiveComputation()
}
!
def index = Action.async {
futureInt().map({i =>
Ok("Got result: " + i)
})
}
Small detour: 

Asynchronous HTTP programming
Futures: 

An object that acts as a proxy for a result that is
initially unknown, because the computation of its
value is not yet complete.
Sequential composition
def fetch(url: String): Future[Resource] = ???



def getThumbnail(url: String): Future[Resource] =
fetch(url) flatMap { page => 

fetch(page.imageLinks()(0)) 

}
trait Future[A] {
def map[B](f: A => B): Future[B]

def flatMap[B](f: A => Future[B]): Future[B]

...
}
Concurrent composition
object Future {
…
def collect[A](fs: Seq[Future[A]]): Future[Seq[A]]
def join(fs: Seq[Future[_]]): Future[Unit]
def select(fs: Seq[Future[A]]) : Future[(Try[A], Seq[Future[A]])]
}
“All non-trivial abstractions,
to some degree, are leaky.”

- Joel Spolsky
What about streaming?
Problem with our abstraction: 

With this simple abstraction we’d have to have both
fully in-memory: the request and the response body.
trait EssentialAction {
def apply(headers: RequestHeaders):
Iteratee[Array[Byte], Result]
}
The ♥ of the framework (1)
RequestHeader
Path, method (GET / POST),
headers, cookies, etc., but not the
request body itself!
Iteratee[A, B]
Repeatedly and asynchronously
consumes instances of A to
eventually produce an instance of
B
final class ResponseHeader(
val status: Int, headers: Map[String, String] = Map.empty)
case class Result(
header: ResponseHeader,
body: Enumerator[Array[Byte]],
connection: HttpConnection.Connection =
HttpConnection.KeepAlive) { /* ... */ }
The ♥ of the framework (2)
Iteratee[A, B]
Repeatedly and asynchronously consumes instances
of A to eventually produce an instance of B
Enumerator[A]
Repeatedly and asynchronously produces instances
of A
“Convenient proxy factory bean superclass for
proxy factory beans that create only singletons.	

!
Manages pre- and post-interceptors (references,
rather than interceptor names, as in
ProxyFactoryBean) and provides consistent
interface management.”
How many concepts can
you keep track of?
Iteratees and
Enumerators
Reactive Streams, RX, Conduits, Process, …
Enumerators
trait Enumerator[E] {

def run[A](it: Iteratee[E, A]): Iteratee[E, A]
}
!
sealed trait Input[+T]
case class El[T](x: T) extends Input[T]
case object Empty extends Input[Nothing]
case object EOF extends Input[Nothing]
• Stream producers that push input into consumers
Iteratees
sealed trait Iteratee[I, O]
!
case class Done[I, O](result: O, remainingInput: Input[I])
case class Cont[I, O](k: Input[I] => Iteratee[I, O])
case class Error[I, O](t: Throwable)
• Stream consumers, consume chunks at a time
State machine for iterations: 

If we were to draw a state machine for iterations, this
is what we would get.
Example: 

Counting characters
def charCounter(count: Int = 0): Iteratee[String, Int] = 

Cont[String, Int] {

case El(str) => charCounter(count + str.length)

case Empty => charCounter(count)

case EOF => Done(count)

}
def countChars(it: Iterator[String]): Int = {
var count = 0
while (it.hasNext) {
count = count + it.next.length
}
count
}
Why bother: 

Iteration can be paused / resumed at any moment
without losing the current state.
Example: 

Communication with the producer
def moreThanChunks[A](number: Int): Iteratee[A, Boolean] = 

Cont[A, Boolean] {

case input if number <= 0 => Done(true, input)

case EOF => Done(false, EOF)

case El(_) => moreThanChunks(number - 1)

case Empty => moreThanChunks(number)

}
def moreThan[A](number: Int, it: Iterator[A]): Boolean = {

var i = number

while (it.hasNext) {

it.next // not needed

if (i <= 0) {

return true

}

i -= 1

}

return false

}
Why bother: 

Done indicates to the producer that it can close the
resource (e.g. no need to wait until the last hasNext).
Example: Enumerator
def enumerate[E](elems: Iterator[E]): Enumerator[E] = new Enumerator[E] {

def run[E, A](it: Iteratee[E, A]): Iteratee[E, A] = it match {

case Cont(k) => {

val input = if (elems.hasNext) {

El(elems.next)

} else {

EOF

}

// recursively call this method again with the next Iteratee

run(k(input)) 

}

// here we could also do resource clean-up, if necessary

case _ => it

}

}
Complicated? 

Yes, I know, this isn’t particularly obvious stuff ..
Streams work just like collections
def charCounter(count: Int = 0): Iteratee[String, Int] = 

Cont[String, Int] {

case El(str) => charCounter(count + str.length)

case Empty => charCounter(count)

case EOF => Done(count)

}
def fold[A, B](acc: B)(f: (A, B) => B): Iteratee[A, B] = 

Cont[String, Int] {

case El(a) => fold(f(a, acc))(f)

case Empty => fold(acc)(f)

case EOF => Done(acc)

}
def charCounter: Iteratee[String, Int] = fold(0)({

case (str, count) => count + str.length

}
No mental overhead: 

They really behave in the same way, really nothing
new we’re learning here (I’m sorry ..)
Asynchronous streams
sealed trait Iteratee[I, O]
!
case class Done[I, O](result: O, remainingInput: Input[I])
case class Cont[I, O](k: Input[I] => Future[Iteratee[I, O]])
case class Error[I, O](t: Throwable)
def fold[A,B](acc: B)(f: (A, B) => B): Iteratee[A, B] = ...

def foldM[A,B](acc: B)(f: (A, B) => Future[B]): Iteratee[A, B] = ...
Composing concepts: 

The concept of Futures and Iteratees can be
combined rather easily to provide reactive streams.
Example: 

Using asynchronous combinators
def expensiveComputation(str: String): Future[Int] = ???

!
def processExpensive: Iteratee[String, Int] = foldM(0)({
case (str, acc) =>
expensiveComputation(str) map {

acc + _

}
})
Back-pressure for free (almost): 

Enumerators won’t push more elements into this
Iteratee than it can handle.
Composability for handling
streams of data
def isAroundLocation(tweet: Tweet, loc: Location): Boolean

def retweetsGreaterThan(tweet: Tweet, retweets: Int): Boolean

def userForTweet(tweet: Tweet): Future[User]



val tweets: Enumerator[Tweet] = // …

!
tweets

.through(Enumeratee.filter({ tweet =>

isAroundLocation(tweet, Location.Vienna)

})

.through(Enumeratee.filter({ tweet =>

retweetsGreaterThan(tweet, 50)

})

.through(Enumeratee.mapM({ tweet =>

userForTweet(tweet)

})

.run(Iteratee.foreach({ user =>

println(s“User $user tweeted something popular in Vienna.”)

})
void onWritePossible(){

while (isReady()){
out.write("<H1>Hello</H1>");
}
}
Async Servlets
• Iterative processing while stream is available
• Callbacks otherwise
What’s the problem here?
void onWritePossible(){

while (isReady()){
out.write(“<H1>Hello</H1>");

out.write(“<H1>World</H1>”);
}
}
Async I/O is hard: 

Side-effects in the API are kind of necessary, but they
make it very hard to use.
boolean flag = true;

!
void onWritePossible(){

while (isReady()){

if (flag) {

out.write(“<H1>Hello</H1>");

} else {

out.write(“<H1>World</H1>");

}

flag = !flag;
}
}
Async I/O is hard …
Enumerator.interleave(

Enumerator.repeat(“Hello”),
Enumerator.repeat(“World”)

)
.. it doesn’t need to
be though, if you 

make your API
composable.
See: https://blogs.oracle.com/theaquarium/entry/javaone_replay_into_the_wild
Conclusion
• Build your APIs like Lego blocks
• Stay away from side effects as much as possible
• Deferred execution / interpretation allows you to do
that
Book recommendation
Q & A
Bernhard Huemer
@bhuemer

Más contenido relacionado

La actualidad más candente

Advanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesAdvanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesGanesh Samarthyam
 
An Introduction to Property Based Testing
An Introduction to Property Based TestingAn Introduction to Property Based Testing
An Introduction to Property Based TestingC4Media
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtleScott Wlaschin
 
Reading and writting v2
Reading and writting v2Reading and writting v2
Reading and writting v2ASU Online
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterScott Wlaschin
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeScott Wlaschin
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to javaciklum_ods
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioLuis Atencio
 
Using FakeIteasy
Using FakeIteasyUsing FakeIteasy
Using FakeIteasyDror Helper
 
Learning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a NeckbeardLearning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a NeckbeardKelsey Gilmore-Innis
 
How To Use IO Monads in Scala?
 How To Use IO Monads in Scala? How To Use IO Monads in Scala?
How To Use IO Monads in Scala?Knoldus Inc.
 
Lambda functions in java 8
Lambda functions in java 8Lambda functions in java 8
Lambda functions in java 8James Brown
 
5 Tips for Better JavaScript
5 Tips for Better JavaScript5 Tips for Better JavaScript
5 Tips for Better JavaScriptTodd Anglin
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming iiPrashant Kalkar
 
Swift internals
Swift internalsSwift internals
Swift internalsJung Kim
 

La actualidad más candente (20)

Java Concurrency by Example
Java Concurrency by ExampleJava Concurrency by Example
Java Concurrency by Example
 
Advanced Debugging Using Java Bytecodes
Advanced Debugging Using Java BytecodesAdvanced Debugging Using Java Bytecodes
Advanced Debugging Using Java Bytecodes
 
An Introduction to Property Based Testing
An Introduction to Property Based TestingAn Introduction to Property Based Testing
An Introduction to Property Based Testing
 
Thirteen ways of looking at a turtle
Thirteen ways of looking at a turtleThirteen ways of looking at a turtle
Thirteen ways of looking at a turtle
 
Reading and writting v2
Reading and writting v2Reading and writting v2
Reading and writting v2
 
Dr Frankenfunctor and the Monadster
Dr Frankenfunctor and the MonadsterDr Frankenfunctor and the Monadster
Dr Frankenfunctor and the Monadster
 
Enterprise Tic-Tac-Toe
Enterprise Tic-Tac-ToeEnterprise Tic-Tac-Toe
Enterprise Tic-Tac-Toe
 
Completable future
Completable futureCompletable future
Completable future
 
Java Class Design
Java Class DesignJava Class Design
Java Class Design
 
Bring the fun back to java
Bring the fun back to javaBring the fun back to java
Bring the fun back to java
 
Java Annotations and Pre-processing
Java  Annotations and Pre-processingJava  Annotations and Pre-processing
Java Annotations and Pre-processing
 
Functional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis AtencioFunctional Programming in JavaScript by Luis Atencio
Functional Programming in JavaScript by Luis Atencio
 
Using FakeIteasy
Using FakeIteasyUsing FakeIteasy
Using FakeIteasy
 
Java Generics - by Example
Java Generics - by ExampleJava Generics - by Example
Java Generics - by Example
 
Learning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a NeckbeardLearning Functional Programming Without Growing a Neckbeard
Learning Functional Programming Without Growing a Neckbeard
 
How To Use IO Monads in Scala?
 How To Use IO Monads in Scala? How To Use IO Monads in Scala?
How To Use IO Monads in Scala?
 
Lambda functions in java 8
Lambda functions in java 8Lambda functions in java 8
Lambda functions in java 8
 
5 Tips for Better JavaScript
5 Tips for Better JavaScript5 Tips for Better JavaScript
5 Tips for Better JavaScript
 
Functional programming ii
Functional programming iiFunctional programming ii
Functional programming ii
 
Swift internals
Swift internalsSwift internals
Swift internals
 

Similar a Principles of the Play framework

Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)tarcieri
 
A Survey of Concurrency Constructs
A Survey of Concurrency ConstructsA Survey of Concurrency Constructs
A Survey of Concurrency ConstructsTed Leung
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojureAbbas Raza
 
Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0Oscar Renalias
 
Clojure concurrency
Clojure concurrencyClojure concurrency
Clojure concurrencyAlex Navis
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVMVaclav Pech
 
History of asynchronous in .NET
History of asynchronous in .NETHistory of asynchronous in .NET
History of asynchronous in .NETMarcin Tyborowski
 
A Brief Conceptual Introduction to Functional Java 8 and its API
A Brief Conceptual Introduction to Functional Java 8 and its APIA Brief Conceptual Introduction to Functional Java 8 and its API
A Brief Conceptual Introduction to Functional Java 8 and its APIJörn Guy Süß JGS
 
Software Transactioneel Geheugen
Software Transactioneel GeheugenSoftware Transactioneel Geheugen
Software Transactioneel GeheugenDevnology
 
Writing Asynchronous Programs with Scala & Akka
Writing Asynchronous Programs with Scala & AkkaWriting Asynchronous Programs with Scala & Akka
Writing Asynchronous Programs with Scala & AkkaYardena Meymann
 
Concurrency Constructs Overview
Concurrency Constructs OverviewConcurrency Constructs Overview
Concurrency Constructs Overviewstasimus
 

Similar a Principles of the Play framework (20)

Java tut1
Java tut1Java tut1
Java tut1
 
Tutorial java
Tutorial javaTutorial java
Tutorial java
 
Java Tut1
Java Tut1Java Tut1
Java Tut1
 
Java Tutorial
Java TutorialJava Tutorial
Java Tutorial
 
Async fun
Async funAsync fun
Async fun
 
Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)Concurrent programming with Celluloid (MWRC 2012)
Concurrent programming with Celluloid (MWRC 2012)
 
A Survey of Concurrency Constructs
A Survey of Concurrency ConstructsA Survey of Concurrency Constructs
A Survey of Concurrency Constructs
 
Introduction to clojure
Introduction to clojureIntroduction to clojure
Introduction to clojure
 
Java Concurrency
Java ConcurrencyJava Concurrency
Java Concurrency
 
Java tutorial PPT
Java tutorial PPTJava tutorial PPT
Java tutorial PPT
 
Java tutorial PPT
Java tutorial  PPTJava tutorial  PPT
Java tutorial PPT
 
Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0Asynchronous web apps with the Play Framework 2.0
Asynchronous web apps with the Play Framework 2.0
 
Clojure concurrency
Clojure concurrencyClojure concurrency
Clojure concurrency
 
Java Tutorial
Java Tutorial Java Tutorial
Java Tutorial
 
Concurrency on the JVM
Concurrency on the JVMConcurrency on the JVM
Concurrency on the JVM
 
History of asynchronous in .NET
History of asynchronous in .NETHistory of asynchronous in .NET
History of asynchronous in .NET
 
A Brief Conceptual Introduction to Functional Java 8 and its API
A Brief Conceptual Introduction to Functional Java 8 and its APIA Brief Conceptual Introduction to Functional Java 8 and its API
A Brief Conceptual Introduction to Functional Java 8 and its API
 
Software Transactioneel Geheugen
Software Transactioneel GeheugenSoftware Transactioneel Geheugen
Software Transactioneel Geheugen
 
Writing Asynchronous Programs with Scala & Akka
Writing Asynchronous Programs with Scala & AkkaWriting Asynchronous Programs with Scala & Akka
Writing Asynchronous Programs with Scala & Akka
 
Concurrency Constructs Overview
Concurrency Constructs OverviewConcurrency Constructs Overview
Concurrency Constructs Overview
 

Último

Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfDrew Moseley
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsAhmed Mohamed
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Natan Silnitsky
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprisepreethippts
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作qr0udbr0
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odishasmiwainfosol
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commercemanigoyal112
 
Patterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencePatterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencessuser9e7c64
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLionel Briand
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identityteam-WIBU
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxRTS corp
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxAndreas Kunz
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsSafe Software
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...OnePlan Solutions
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 

Último (20)

Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Comparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdfComparing Linux OS Image Update Models - EOSS 2024.pdf
Comparing Linux OS Image Update Models - EOSS 2024.pdf
 
Unveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML DiagramsUnveiling Design Patterns: A Visual Guide with UML Diagrams
Unveiling Design Patterns: A Visual Guide with UML Diagrams
 
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
Taming Distributed Systems: Key Insights from Wix's Large-Scale Experience - ...
 
Odoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 EnterpriseOdoo 14 - eLearning Module In Odoo 14 Enterprise
Odoo 14 - eLearning Module In Odoo 14 Enterprise
 
英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作英国UN学位证,北安普顿大学毕业证书1:1制作
英国UN学位证,北安普顿大学毕业证书1:1制作
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company OdishaBalasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
Balasore Best It Company|| Top 10 IT Company || Balasore Software company Odisha
 
Cyber security and its impact on E commerce
Cyber security and its impact on E commerceCyber security and its impact on E commerce
Cyber security and its impact on E commerce
 
Patterns for automating API delivery. API conference
Patterns for automating API delivery. API conferencePatterns for automating API delivery. API conference
Patterns for automating API delivery. API conference
 
Large Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and RepairLarge Language Models for Test Case Evolution and Repair
Large Language Models for Test Case Evolution and Repair
 
Post Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on IdentityPost Quantum Cryptography – The Impact on Identity
Post Quantum Cryptography – The Impact on Identity
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
 
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptxUI5ers live - Custom Controls wrapping 3rd-party libs.pptx
UI5ers live - Custom Controls wrapping 3rd-party libs.pptx
 
Powering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data StreamsPowering Real-Time Decisions with Continuous Data Streams
Powering Real-Time Decisions with Continuous Data Streams
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
Tech Tuesday - Mastering Time Management Unlock the Power of OnePlan's Timesh...
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 

Principles of the Play framework

  • 1. Principles of the 
 Play Framework Bernhard Huemer
  • 2. Why are we here?
  • 4. Contextual vs. 
 composable design • Boundaryless extensions /
 flexibility • Steep learning curve See also: http://nealford.com/memeagora/2013/01/22/why_everyone_eventually_hates_maven.html • Anticipated extension points • Easy to get into / quick wins
  • 5. Referential transparency • No reassignments of variables • No setters, no mutations • No exceptions (no throw new …) • No console input / output • No network communication • …. "An expression is said to be referentially transparent if it can be replaced with its value without changing the behaviour of a program."
  • 6. Side-effects don’t compose protected void renderBasket(HttpServletResponse response) throws ServletException, IOException { try (PrintWriter writer = response.getWriter()) { writer.println(“HTML for our basket.”); } } ! protected void renderProductList(HttpServletResponse response) throws ServletException, IOException { try (PrintWriter writer = response.getWriter()) { writer.println(“HTML for our products list.”); } } Best practice: 
 Don’t assume any special context when calling these methods, it will manage its resources itself.
  • 7. Side-effects don’t compose protected void renderAll(HttpServletResponse response) throws ServletException, IOException { renderBasket(response); renderProductList(response); } • Composing code with side-effects always requires additional “plumbing” • in this case: close() method of the response • Ignore the <head />, <body /> HTML issues ..
  • 8. What’s wrong here? import io.Source.fromFile val it: Iterator[String] = fromFile(“foo.txt").getLines
 // or from the network ! var result = 0 while (it.hasNext) { val line = it.next result += line.toInt } General idea: 
 Some part of the application produces a stream of something that we want to consume elsewhere.
  • 9. What’s wrong here? import io.Source.fromFile val it: Iterator[String] = fromFile(“foo.txt").getLines
 // or from the network ! var result = 0 while (it.hasNext) { val line = it.next result += line.toInt } val it: Iterator[String] = fromFile("foo.txt").getLines var result = 0 it foreach { line => result += line.toInt } val it: Iterator[String] = fromFile("foo.txt").getLines var result = 0 it foldLeft(0) { case (acc, line) => acc + line.toInt }
  • 10. Problems … • Repetitive pattern (DRY principle) • Manual pulling, possibly blocking I/O • No error handling (sometimes we forget, right?) • No communication with the producer (e.g. back pressure) • Resource handling (how long do we need a resource and who is responsible for opening/closing/recovering it?) • Missing or rather difficult composability • What if the input source was infinite?  See: http://www.slideshare.net/afwlehmann/iteratees-intro
  • 11. Architecture at LinkedIn See: http://www.slideshare.net/brikis98/play-framework-async-io-with-java-and-scala
  • 12. Latency spilled over to the supposedly fast part Clarification: 
 Latency in one part of the network will slow down anything that depends on it directly or indirectly, it should, however, not have an impact on anything else!
  • 13. Requests are functions object Application extends Controller { def greet(name: String) = Action { request => Ok(s"<html>Hello $name!</html>")
 .as("application/xhtml+xml") } } GET /greet/:name controllers.Application.greet(name) • Controller is not really required as base class • Action { } is like a factory method that produces one of these functions
  • 14. Play in the command line scala> controllers.App.greet(“ConFESS”) res0: play.api.mvc.Action[play.api.mvc.AnyContent] = Action(parser=BodyParser(anyContent)) ! scala> controllers.App.greet(“ConFESS”).apply( play.api.test.FakeRequest() ) res1: scala.concurrent.Future[play.api.mvc.Result] = scala.concurrent.impl.Promise$KeptPromise@3ffe0466 Read-eval-print-loop (REPL): 
 Scala, like most scripting languages, comes with an interactive shell that you can use to test your application. Play supports this tool as well.
  • 15. Your application code never uses the network directly scala> val result = Await.result( controllers.App.greet(“ConFESS”).apply( play.api.test.FakeRequest() ), atMost = 2.seconds ) result: play.api.mvc.Result = Result(200, Map( Content-Type -> application/xhtml+xml; charset=utf-8) ) • No HTTP server we needed to start • Nothing we needed to mock * * I will not count FakeRequest .. it’s infinitely simpler than mocking servlet requests
  • 16. Side-effects are collected until the very end of the request scala> result.body.run(Iteratee.foreach({ bytes => println(new String(bytes)) })) <html>Hello ConFESS!</html> res8: scala.concurrent.Future[Unit] = scala.concurrent.impl.Promise$DefaultPromise@3ee2e • The framework takes care of “side-effectful” code once you returned control to it
  • 17. Minimises incorrect usage “I was eventually persuaded of the need to design programming notations so as to 1. maximise the number of errors which cannot be made, or 2. if made, can be reliably detected at compile time.“ - Tony Hoare (ACM Turing Award Lecture) • No IllegalStateExceptions in the API • PrintWriters and OutputStreams • Redirects after status codes / headers / etc.. • Headers after the response body was started
  • 18. Composition of functions def Logging[A](action: Action[A]): Action[A] = Action.async(action.parser) { request => Logger.info("Calling action") action(request) } def index = Logging { Action { Ok("Hello World") }} No mental overhead: 
 Simplistic example (think security, instead), but the point is: No additional concepts you need to learn!
  • 19. private def futureInt(): Future[Int] = Future { intensiveComputation() } ! def index = Action.async { futureInt().map({i => Ok("Got result: " + i) }) } Small detour: 
 Asynchronous HTTP programming Futures: 
 An object that acts as a proxy for a result that is initially unknown, because the computation of its value is not yet complete.
  • 20. Sequential composition def fetch(url: String): Future[Resource] = ???
 
 def getThumbnail(url: String): Future[Resource] = fetch(url) flatMap { page => 
 fetch(page.imageLinks()(0)) 
 } trait Future[A] { def map[B](f: A => B): Future[B]
 def flatMap[B](f: A => Future[B]): Future[B]
 ... }
  • 21. Concurrent composition object Future { … def collect[A](fs: Seq[Future[A]]): Future[Seq[A]] def join(fs: Seq[Future[_]]): Future[Unit] def select(fs: Seq[Future[A]]) : Future[(Try[A], Seq[Future[A]])] }
  • 22. “All non-trivial abstractions, to some degree, are leaky.”
 - Joel Spolsky
  • 23. What about streaming? Problem with our abstraction: 
 With this simple abstraction we’d have to have both fully in-memory: the request and the response body.
  • 24. trait EssentialAction { def apply(headers: RequestHeaders): Iteratee[Array[Byte], Result] } The ♥ of the framework (1) RequestHeader Path, method (GET / POST), headers, cookies, etc., but not the request body itself! Iteratee[A, B] Repeatedly and asynchronously consumes instances of A to eventually produce an instance of B
  • 25. final class ResponseHeader( val status: Int, headers: Map[String, String] = Map.empty) case class Result( header: ResponseHeader, body: Enumerator[Array[Byte]], connection: HttpConnection.Connection = HttpConnection.KeepAlive) { /* ... */ } The ♥ of the framework (2) Iteratee[A, B] Repeatedly and asynchronously consumes instances of A to eventually produce an instance of B Enumerator[A] Repeatedly and asynchronously produces instances of A
  • 26. “Convenient proxy factory bean superclass for proxy factory beans that create only singletons. ! Manages pre- and post-interceptors (references, rather than interceptor names, as in ProxyFactoryBean) and provides consistent interface management.” How many concepts can you keep track of?
  • 27. Iteratees and Enumerators Reactive Streams, RX, Conduits, Process, …
  • 28. Enumerators trait Enumerator[E] {
 def run[A](it: Iteratee[E, A]): Iteratee[E, A] } ! sealed trait Input[+T] case class El[T](x: T) extends Input[T] case object Empty extends Input[Nothing] case object EOF extends Input[Nothing] • Stream producers that push input into consumers
  • 29. Iteratees sealed trait Iteratee[I, O] ! case class Done[I, O](result: O, remainingInput: Input[I]) case class Cont[I, O](k: Input[I] => Iteratee[I, O]) case class Error[I, O](t: Throwable) • Stream consumers, consume chunks at a time State machine for iterations: 
 If we were to draw a state machine for iterations, this is what we would get.
  • 30. Example: 
 Counting characters def charCounter(count: Int = 0): Iteratee[String, Int] = 
 Cont[String, Int] {
 case El(str) => charCounter(count + str.length)
 case Empty => charCounter(count)
 case EOF => Done(count)
 } def countChars(it: Iterator[String]): Int = { var count = 0 while (it.hasNext) { count = count + it.next.length } count } Why bother: 
 Iteration can be paused / resumed at any moment without losing the current state.
  • 31. Example: 
 Communication with the producer def moreThanChunks[A](number: Int): Iteratee[A, Boolean] = 
 Cont[A, Boolean] {
 case input if number <= 0 => Done(true, input)
 case EOF => Done(false, EOF)
 case El(_) => moreThanChunks(number - 1)
 case Empty => moreThanChunks(number)
 } def moreThan[A](number: Int, it: Iterator[A]): Boolean = {
 var i = number
 while (it.hasNext) {
 it.next // not needed
 if (i <= 0) {
 return true
 }
 i -= 1
 }
 return false
 } Why bother: 
 Done indicates to the producer that it can close the resource (e.g. no need to wait until the last hasNext).
  • 32. Example: Enumerator def enumerate[E](elems: Iterator[E]): Enumerator[E] = new Enumerator[E] {
 def run[E, A](it: Iteratee[E, A]): Iteratee[E, A] = it match {
 case Cont(k) => {
 val input = if (elems.hasNext) {
 El(elems.next)
 } else {
 EOF
 }
 // recursively call this method again with the next Iteratee
 run(k(input)) 
 }
 // here we could also do resource clean-up, if necessary
 case _ => it
 }
 } Complicated? 
 Yes, I know, this isn’t particularly obvious stuff ..
  • 33. Streams work just like collections def charCounter(count: Int = 0): Iteratee[String, Int] = 
 Cont[String, Int] {
 case El(str) => charCounter(count + str.length)
 case Empty => charCounter(count)
 case EOF => Done(count)
 } def fold[A, B](acc: B)(f: (A, B) => B): Iteratee[A, B] = 
 Cont[String, Int] {
 case El(a) => fold(f(a, acc))(f)
 case Empty => fold(acc)(f)
 case EOF => Done(acc)
 } def charCounter: Iteratee[String, Int] = fold(0)({
 case (str, count) => count + str.length
 } No mental overhead: 
 They really behave in the same way, really nothing new we’re learning here (I’m sorry ..)
  • 34. Asynchronous streams sealed trait Iteratee[I, O] ! case class Done[I, O](result: O, remainingInput: Input[I]) case class Cont[I, O](k: Input[I] => Future[Iteratee[I, O]]) case class Error[I, O](t: Throwable) def fold[A,B](acc: B)(f: (A, B) => B): Iteratee[A, B] = ...
 def foldM[A,B](acc: B)(f: (A, B) => Future[B]): Iteratee[A, B] = ... Composing concepts: 
 The concept of Futures and Iteratees can be combined rather easily to provide reactive streams.
  • 35. Example: 
 Using asynchronous combinators def expensiveComputation(str: String): Future[Int] = ???
 ! def processExpensive: Iteratee[String, Int] = foldM(0)({ case (str, acc) => expensiveComputation(str) map {
 acc + _
 } }) Back-pressure for free (almost): 
 Enumerators won’t push more elements into this Iteratee than it can handle.
  • 36. Composability for handling streams of data def isAroundLocation(tweet: Tweet, loc: Location): Boolean
 def retweetsGreaterThan(tweet: Tweet, retweets: Int): Boolean
 def userForTweet(tweet: Tweet): Future[User]
 
 val tweets: Enumerator[Tweet] = // …
 ! tweets
 .through(Enumeratee.filter({ tweet =>
 isAroundLocation(tweet, Location.Vienna)
 })
 .through(Enumeratee.filter({ tweet =>
 retweetsGreaterThan(tweet, 50)
 })
 .through(Enumeratee.mapM({ tweet =>
 userForTweet(tweet)
 })
 .run(Iteratee.foreach({ user =>
 println(s“User $user tweeted something popular in Vienna.”)
 })
  • 37. void onWritePossible(){
 while (isReady()){ out.write("<H1>Hello</H1>"); } } Async Servlets • Iterative processing while stream is available • Callbacks otherwise
  • 38. What’s the problem here? void onWritePossible(){
 while (isReady()){ out.write(“<H1>Hello</H1>");
 out.write(“<H1>World</H1>”); } } Async I/O is hard: 
 Side-effects in the API are kind of necessary, but they make it very hard to use.
  • 39. boolean flag = true;
 ! void onWritePossible(){
 while (isReady()){
 if (flag) {
 out.write(“<H1>Hello</H1>");
 } else {
 out.write(“<H1>World</H1>");
 }
 flag = !flag; } } Async I/O is hard … Enumerator.interleave(
 Enumerator.repeat(“Hello”), Enumerator.repeat(“World”)
 ) .. it doesn’t need to be though, if you 
 make your API composable. See: https://blogs.oracle.com/theaquarium/entry/javaone_replay_into_the_wild
  • 40. Conclusion • Build your APIs like Lego blocks • Stay away from side effects as much as possible • Deferred execution / interpretation allows you to do that
  • 42. Q & A Bernhard Huemer @bhuemer