play á la rails

36
à la Sebastian Nozzi

Upload: sebastian-nozzi

Post on 07-May-2015

764 views

Category:

Technology


1 download

DESCRIPTION

My attempts to make my experience developing Play 2 web-applications (in Scala) more Rails-like. I show 3 frameworks employed that draw nearer to the Ruby/Rails spirit than Play's default offerings.

TRANSCRIPT

Page 1: Play á la Rails

à la

Sebastian Nozzi

Page 2: Play á la Rails

Background

• Working with Java since 2001

• Flirting with Smalltalk all these years

• Involved with Rails since September 2012

• Hooked with Scala since January 2013

• Developing with Play since June 2013

Page 3: Play á la Rails

Ruby

Let’s talk about

Page 4: Play á la Rails
Page 5: Play á la Rails

“A dynamic, open source programming language with a focus on simplicity and productivity.

It has an elegant syntax that is natural to read and easy to write.”

Page 6: Play á la Rails

Let’s talk about

Page 7: Play á la Rails
Page 8: Play á la Rails

“Ruby on Rails is an open-source web framework that’s optimized for programmer happiness and sustainable productivity.

It lets you write beautiful code by favoring convention over configuration.”

Page 9: Play á la Rails

How Ruby is (self) perceived

Page 10: Play á la Rails

• Heavily inspired from Rails

• Fun. Productive. Save + Reload.

• Convention over Configuration.

• Routing. REST. MVC...

• ... but I missed some things ...

Page 11: Play á la Rails

ActiveRecord

db:migrate

Cucumber + Capybara

Anorm? Slick?

Evolutions?

Specs?

Rails’ vs. Play’s default offerings

Page 12: Play á la Rails

not “railsy” enough

Page 13: Play á la Rails

ActiveRecord

db:migrate

Cucumber + Capybara

ActiveRecord (for Scala)

Flyway

Cucumber-JVM + Fluentlenium

More “Rails-like” alternatives

Page 14: Play á la Rails
Page 15: Play á la Rails

case class User(var username: String) extends ActiveRecord { lazy val posts = hasMany[Post]}

case class Post(var text: String) extends ActiveRecord with Timestamps { var userId: Long = _ lazy val user = belongsTo[User]}

Declaring Entities

Page 16: Play á la Rails

object Tables extends ActiveRecordTables { val users = table[User]("users") val posts = table[Post]("posts")}

object User extends ActiveRecordCompanion[User]object Post extends ActiveRecordCompanion[Post]

Declaring the Schema

Page 17: Play á la Rails

val newUser = User(username=“Homer”).create()

val users: List[User] = User.toList

User.findBy(“username”, “Homer”).foreach { user => val posts = user.posts.orderBy(_.createdAt desc).toList ... ... user.posts << Post(“Ohhh donuts!”)}

Basic Operations

Page 18: Play á la Rails
Page 19: Play á la Rails

Play Integration

Page 20: Play á la Rails

object Global extends GlobalSettings { override def onStart(app: Application) {

if(!Play.isTest) { val flyway = new Flyway() // .. get values from Play’s config ... flyway.setDataSource(url, user, password) flyway.setInitOnMigrate(true) flyway.migrate() } Tables.initialize(...) // ActiveRecord }}

Triggering the Migrations

Page 21: Play á la Rails

object Global extends GlobalSettings { override def onStart(app: Application) {

if(!Play.isTest) { val flyway = new Flyway() // .. get values from Play’s config ... flyway.setDataSource(url, user, password) flyway.setInitOnMigrate(true) flyway.migrate() } Tables.initialize(...) // ActiveRecord }}

Initializing ActiveRecord

Page 22: Play á la Rails

SQL-based Migrations

Page 23: Play á la Rails

package db.migration

class V1_03__CreateSomePosts extends JdbcMigration {

override def migrate(ignoredConnection: Connection) { ... ... ... ... ... }

}

Code-based Migrations

Page 24: Play á la Rails

package db.migration

class V1_03__CreateSomePosts extends JdbcMigration {

override def migrate(ignoredConnection: Connection) { User.findBy("username", "Homer").foreach { homer => homer.posts << Post("I'm hungry") homer.posts << Post("I should go to Moe's") homer.posts << Post("Or order some Pizza") } }

}

Code-based Migrations

Page 25: Play á la Rails

+ Fluentlenium

Page 26: Play á la Rails

• Write in plain English

• Separation of specification / implementation

Page 27: Play á la Rails

Feature: Posting status updates

The goal of the system is keep co-workers informed by posting status updates. Background: Given that user "manager" exists And that user "manager" posted | first day at work | | meeting people | | working like crazy |

Scenario: Posts are ordered chronologically (newest on top) When I go to the posts page of user "manager" Then the post nr. 1 should contain "working" And the post nr. 2 should contain "meeting" And the post nr. 3 should contain "first"

Page 28: Play á la Rails

When("""^I type "([^"]*)" in the "([^"]*)" field$""") { (text: String, fieldName: String) => ... }

And("""^press "([^"]*)"$""") { (buttonLabel: String) => ... ... }

Then("""^I should be on the posts page of "([^"]*)"$""") { (username: String) => ... ... ...}

Step Declarations

Page 29: Play á la Rails

• Part of Play2

• DSL wrapping Selenium

• PhantomJS for headless testing

Fluentlenium

Page 30: Play á la Rails

When("""^I type "([^"]*)" in the "([^"]*)" field$""") { (text: String, fieldName: String) => ... }

And("""^press "([^"]*)"$""") { (buttonLabel: String) => ... ... }

Then("""^I should be on the posts page of "([^"]*)"$""") { (username: String) => ... ... ...}

Page 31: Play á la Rails

When("""^I type "([^"]*)" in the "([^"]*)" field$""") { (text: String, fieldName: String) => browser.fill("*", withName(fieldName)).`with`(text)}

And("""^press "([^"]*)"$""") { (buttonLabel: String) => val button = browser.find("button", withText(buttonLabel)) button.click()}

Then("""^I should be on the posts page of "([^"]*)"$""") { (username: String) => val user = User.findBy("username", username).get val expectedUrl = controllers.routes.UserActions.posts(user.id).url driver.getCurrentUrl() should endWith(expectedUrl)}

Step Implementations

Page 32: Play á la Rails

Conclusions

Page 33: Play á la Rails

Conclusions

• Satisfied with my choices (so far)

• Integration was doable

• Play flexible enough

• to replace some parts

• to let different libraries co-exist

• Reached a more Rails-like experience

Page 34: Play á la Rails

Some Thoughts

Page 35: Play á la Rails

Some Thoughts

• Programming can (and should!) be fun

• Scala embraces some of that “fun”

• ... but we can do more

• Go check Ruby / Rails

• Let’s steal get inspired from them ;-)

Page 36: Play á la Rails

Thank you