Dec 07, 2014
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
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
What did we learn?
• Play is forgiving
• Learn it while being productive
• Adapt it to fit your needs
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)
[…]
Does it stay that simple?
Does it stay that simple?
Are you kidding me?
Serious production code (if you spot a bug, let us know :D )
SEO Authentication Caching DB Access I18n
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)))
}
}
}
}
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 Status Code, HTML/JSON/etc. Action: something that takes a request, and returns a response
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))
}
}
}
Birds-eye view Lots of libraries to integrate
Play Framework 2
Pitfalls
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
Mistake #2: HTTPS using Play 2
• Don‘t use Play/netty to handle SSL
• Now using nginx as reverse proxy
Mistake #3: Not managing Javascript
• First we hardcoded javascript routes
Eg. In Javascript: „$http.post(´/edit/guide/save`, ...)“
• Now:
• Javascript Routes
• Javascript Translations
• Javascript minification / compilation
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!)
// 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
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“
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 by Typesafe 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.