1. Using Play Framework 2
in production
VSUG meetup 20.6.2013
Christian Papauschek
christian@miavia.in
3. Technology choice
• PHP, Java, C#, …
• Easy to find developers
• Big communities, lots of existing libraries
• Scala
• Hard to find developers
• More expressive, probably more productive
• A lot more fun
4. First steps with Play 2
on Startup Live (January 2013)
• IDE: IntelliJ IDEA
• Git Repo hosted on Dropbox
(yeah, I know…)
• Quickstart with Play 2 console
• Hotreload for development
• Packaged app and put it on EC2
5. What did we learn?
• Play is forgiving
• Learn it while being productive
• Adapt it to fit your needs
6. First production code
// Controller for landing pages
object Landing extends Controller {
// show main landing page
def showMain = Action {
implicit request =>
Ok(views.html.landing.main)
}
}
(conf/routes)
GET / controllers.Landing.showMain
(Landing.scala)
(main.scala.html)
[…]
9. Serious production code
(if you spot a bug, let us know :D )
SEOAuthentication Caching DB AccessI18n
object Landing extends Controller {
// show main landing page
def landing(language: String) = RichAction {
implicit request => Translate(language, otherLang => routes.Landing.landing(otherLang)) {
implicit lang => {
// fetch featured authors and guides
val (guides, authors) = Cache.getOrElse("landing.guides")(
DB.default withSession {
implicit session: Session => {
(GuideItems.getFiltered(GuideFilter()), RichUsers.getAuthorSample)
}
})
Ok(views.html.landing.landing(
Random.shuffle(guides),
Random.shuffle(authors)))
}
}
}
}
11. Play fundamentals
// Controller for landing pages
object Landing extends Controller {
// show main landing page
def showMain = Action {
implicit request =>
Ok(views.html.landing.main)
}
}
(Landing.scala)
Request: contains requested URL, parameters, Cookies, etc.
Response: HTTP Response containing StatusCode, HTML/JSON/etc.
Action: something that takes a request, and returns a response
12. Action Composition
(how we extend the Play framework for DRYness)
// represents an abstract request that may or may not be authenticated
abstract class RichRequest[A](private val request: Request[A])
extends WrappedRequest(request) {
def maybeUserSession: Option[UserSession]
}
// non-authenticated request
case class DefaultRequest[A](maybeUserSession: Option[UserSession],
private val request: Request[A])
extends RichRequest[A](request)
// represents an authenticated request
case class AuthRequest[A](userSession: UserSession,
private val request: Request[A])
extends RichRequest[A](request)
// run action with authenticated user data, or default request data
object RichAction {
def apply[A](f: RichRequest[A] => Result) =
Action { request =>
Auth.check(request) match {
case Some(authRequest) => f(authRequest)
case _ => f(DefaultRequest(None, None, request))
}
}
}
15. Mistake #1: CSS/less compilation
• Play uses Rhino, a library that runs JS in Java, to compile
less (it‘s very slow!)
• Switched to lessc compiler for production
• Switched to less.js during development
16. Mistake #2: HTTPS using Play 2
• Don‘t use Play/netty to handle SSL
• Now using nginx as reverse proxy
17. Mistake #3: Not managing Javascript
• First we hardcoded javascript routes
Eg. In Javascript: „$http.post(´/edit/guide/save`, ...)“
• Now:
• Javascript Routes
• JavascriptTranslations
• Javascript minification / compilation
18. Mistake #4: Configuring play for
synchronous code (Slick)
• Need to configure Play to have more threads
• Reuse of data access code
• Refactoring (where did I use this? Rename it!)
19. // filters guides which are visible on marketplace
def displayedGuides =
(for { g <- Guides if g.visible === 1 } yield g)
// return used category ids
def usedCategories(implicit session: Session) = (for {
g <- displayedGuides
cat <- GuideCategories if cat.guideId === g.id
} yield cat.categoryId).groupBy(id => id).map(g => g._1).list
• write Scala that’s compiled to SQL
• keeps your database queries DRY
20. Why Play 2?
Retrospective
• Readable codebase: Learn idiomatic Scala while being
productive!
• Has everything you need built in, but allows you to throw
everything out piece by piece as you have more advanced
requirements (less compilation, templates, etc.)
• DRY
• Play is (relatively) fast.
How fast? Google „TechEmpower Performance benchmarks“
21. Summary:Why Play 2?
• We know that code-bases eventually grow big. Scala helps.
• Took the good stuff from other successful frameworks such as Ruby on Rails.
„Embraces HTTP“
Adopted byTypesafe as de-facto standard web framework for Scala
• As a startup: attract people who want to learn and find better ways to
develop in the web.
• Scala as a new and powerful, but stable language
• Play 2 as a bleeding edge, but amazingly stable framework
• For other languages/frameworks you might find more developers, but
Scala acts as a good filter to find the good ones.