4. ‘Anyone who says
“and using this tool I can
remove the programmers”
just became the programmer’
!
Allan Kelly - @allankellynet
@PeterHilton • 4
5. Play Framework
Action-based MVC web framework
for applications in Java or Scala.
!
Full-stack framework with a simple,
flexible and powerful HTTP API and a
high-performance scalable architecture.
@PeterHilton • 5
6. package controllers
!
import play.api.mvc.{Action, Controller}
import models.Product
!
// Play web application controller.
object Products extends Controller {
!
// Action method -‐ show a list of products.
def list = Action {
val products = Product.findAll
Ok(views.html.products.list(products))
}
}
7. /** Formats a Product instance as JSON. */
implicit object ProductWrites extends Writes[Product] {
def writes(product: Product) = Json.obj(
"name" -‐> Json.toJson(product.name),
"description" -‐> Json.toJson(product.description))
}
!
/** Render a list of products in JSON format. */
def listJson = Action {
// Automatically sets Content-‐type: application/json
Ok(Json.toJson(Product.findAll))
}
8. # HTTP routes configuration.
!
GET /products controllers.Products.list
GET /products.json controllers.Products.listJson
HTTP
method
URL path controller action mapping
9. Play Framework
Designed by web developers
for web developers
!
High-productivity web development
!
Play is fun
@PeterHilton • 9
10. Template syntax starts with @
Template parameter declaration
@(products: List[Product])
!
!
@if(products.isEmpty) {
!
<h1>No products</h1>
!
}
No delimiter for the end of a
template syntax section
11. @(products: List[Product])
!
!
@if(products.isEmpty) {
!
<h1>No products</h1>
!
} else {
!
<h1>@products.size products</h1>
!
} Output the value of an expression
13. @(!
products: List[Product])
!
!
@if(!products.isEmpty) {
!
!
<table>
!
@for((product, index) <-‐ products.zipWithIndex) {
<tr class='@(if (index % 2 == 0) "even" else "odd" )'>
<td>@product.name</td>
<td>@product.price</td>
</tr>
}
</table>
}
XML inside an
HTML attribute
would be a mess
14. Code reloading
1. Change code (Java, Scala, HTML, etc)
2. ⌘R
!
Code reloading is essential for:
immediate feedback
fast development cycle
maintaining developer focus…
@PeterHilton • 13
15.
16.
17. Parse error: syntax error, unexpected T_VARIABLE
in /usr/local/www/htdocs/index.php on line 3
18.
19. Error messages
Error messages must be
immediate,
in the right place and
include context
@PeterHilton • 17
20. Developer Experience (DX)
Developers are people too
DX is UX for developers
Good DX = happy + productive developers
!
Code reloading and good error messages
are the most important factors for good DX
@PeterHilton • 18
21. More cool front-end features
Manage dependencies with web jars
LESS compilation
CoffeeScript compilation
JSHint JavaScript code checking
RequireJS integration
Built-in ETag, GZip and Cache-Control
@PeterHilton • 19
22. Summary
Code reloading during development
Useful error pages
Clean API for direct HTTP programming
(doesn’t break the web browser)
Modern front-end development
(plays with HTML5 instead of fighting it)
High-performance HTTP server
@PeterHilton • 20
24. ‘All problems in computer science can be
solved by another level of indirection,
except of course for the problem of too
many indirections.’
!
David Wheeler
@PeterHilton • 22
25. Direct HTTP programming
HTTP and the web matter
We don’t need to hide HTTP
!
We don’t need another abstraction layer
(or any other kind of indirection)
!
Play has a well-designed flatter HTTP API
(Play doesn’t use the Servlet API) @PeterHilton • 23
26.
27. Stateless architecture
No state in the application’s web tier
e.g. Java Servlet API’s ‘HTTP session’
State belongs in other tiers:
HTTP client, server cache or database
Web app behaviour defined by URLs
(except for identifying the logged-in user)
@PeterHilton • 25
28. Stateless architecture benefits
Simplified development and testing
(a URL is all you need for reproducibility)
Matches stateless web architecture
(HTTP is stateless by design)
Avoids synchronising state between layers
(‘sync’ should ring tech design alarm bells)
Cloud deployment & horizontal scalability
e.g. on Heroku or Cloudbees
@PeterHilton • 26
29. The web browser is your friend
!
Friends don’t let friends
break standard HTTP features
Don’t break the Back button
Keep your URLs clean
@PeterHilton • 27
30. h t t p : / / a p p . e x a m p l e . c o m / W a r R o o t
W e b D i r e c t o r y 1 / S e r v l e t s O n A P l a n e ?
s e s s i o n I d = x 8 1 n j 3 8 a v n g j L O L a n 4 w
q & a c t i o n = N e x t P a g e & H o n e y B a d g e r
C a r e s = f a l s e & e n t i t y I d = 1 2 9 9 1 2 7 4 3
& p r o c e s s I d = U n l a d e n S w a l l o w C a l c &
r o l e = p e o n & d a t e = 7 % 2 F 1 0 % 2 F 2 0 1 4
& f l a g S e t t i n g s = 0 1 0 1 0 1 1 1 0 0 1 0 1 1 &
r e d i r e c t = % 2 F v i d e o s % 2 F r i c k r o l l . a v i
31. URL-centric design
Clean URLs are stable URLs - your
application’s public API (and part of the UI)
http://example.com/products
http://example.com/product/42
Design the URL scheme before coding.
Configure application URLs in one file.
Read it, bookmark it, mail it, tweet it.
@PeterHilton • 29
32. # HTTP routes configuration file
!
GET / controllers.Application.index()
!
GET /products controllers.Products.list()
POST /products controllers.Products.add(p: Product)
GET /product/:id controllers.Products.details(id: Long)
DELETE /product/:id controllers.Products.delete(id: Long)
!
GET /products.json controllers.Products.listJSON()
GET /product/:id.json controllers.Products.detailsJSON(id:Long)
33. User-interface architecture
Think carefully about UI layer architecture
Embrace HTML5 technologies
Consider modern approaches:
CoffeeScript instead of JavaScript
LESS instead of CSS
Twitter Bootstrap for consistent HTML.
@PeterHilton • 31
39. Architecture summary
A stateful web tier is not a cool thing
Embrace HTTP-centric web architecture
Beware of lasagne architecture
Unlearn complexity and n-tier habits
Combine multiple design perspectives
UI-centric vs model-centric vs URL-centric
Use cloud-ready architecture
Leverage cloud tooling for running locally
@PeterHilton • 37
41. Optimising for time may cost you…
CPU time vs programmer vs maintainer efficiency
42. Writing Scala code
Don’t worry about Scala style to start with
(your code style will evolve anyway)
Start with the syntax
It takes a year to discover idiomatic style
@PeterHilton • 40
43. Writing code
Spend time on code review or
pair programming
Don’t to be clever
Aim for consistency
Optimise code for maintainability
@PeterHilton • 41
44. Scala coding rules of thumb
Immutability is your friend
Learn to use functional style in methods
… but don’t go overboard
Humans need more info than the compiler
… so add more variable names and types
Use the REPL to try things out
@PeterHilton • 42
45. Scala coding recommendations
Study the (immutable) collections API
(ignore mutable collections)
!
Put logic in pure functions and test those
def calculateRiskScore
(factors: List[Factor]): Int
@PeterHilton • 43
46. Scala coding recommendations
Split large classes into traits
!
Sometimes a Customer is just a
NamedOrganisation
!
Using more specific traits improves
maintainability and compilation speed
@PeterHilton • 44
47. Play application code
Keep controllers and templates lightweight
Single-use view case classes:
@PeterHilton • 45
!
case class ProductListView(
id: Int,
name: String,
available: Boolean)
48. Play application code
Learn how to write custom components
that work as if they were built-in:
template formatters
database column types
body parsers - custom request body types
writeables - custom HTTP response types
@PeterHilton • 46
49. // Code example: custom Play framework template formatters
!
package templates
!
object Formatters {
!
// e.g. @updated.format in a template outputs ‘2013-‐10-‐25’
implicit class RichLocalDate(date: org.joda.time.LocalDate) {
def format(): String = format("yyyy-‐MM-‐dd")
def format(pattern: String) = date.toString(pattern)
}
!
// e.g. @price.format in a tempate outputs ‘EUR 2.99’
implicit class RichMoney(m: org.joda.money.Money) {
import play.api.templates.Html
def format =
Html("${m.getCurrencyUnit.getCode} ${m.getAmount}")
}
50. Third-party libraries
There is no Father Christmas Hibernate.
Seriously.
ORM isn’t a Scala thing
Learn the alternatives
Slick is good but not particularly easy
NoSQL persistence may be easier to use
MongoDB, Neo4J, ElasticSearch, etc
@PeterHilton • 48
51. // Code example: Scala Slick database access
!
// Nice: select * from LICENSE where id=?
val query = Query(Licenses).filter(_.id === id)
52. // Code example: Scala Slick database access
!
// Nice: select * from LICENSE where id=?
val query = Query(Licenses).filter(_.id === id)
!
!
!
// Nasty: select b.NUMBER, b.DATE, p.NAME, o.NAME from BOOKING b
// inner join ACCOUNT a on (a.ID=b.FROM_ID)
// left outer join PERSON p on (p.ID=a.PERSON_ID)
// left outer join ORGANISATION o on (o.ID=a.ORGANISATION_ID)
val query = for {
entry ← BookingEntries
((fromAccount, fromPerson), fromOrganisation) ← Accounts leftJoin
People on (_.personId === _.id) leftJoin
Organisations on (_._1.organisationId === _.id)
if fromAccount.id === entry.fromId
} yield (
entry.bookingNumber, entry.bookingDate,
fromPerson.name.?, fromOrganisation.name.?)
54. Deployment infrastructure
Move on from application servers
Deploy to production before coding
Cloud deployment for test/prod is easy
Cloudbees, Heroku
Databases are commodity cloud resources
especially MySQL - Amazon RDS
@PeterHilton • 51
55. Development environment set-up
example
1. Install dependencies:
Java JDK 1.7, git, Play 2.1.3, MySQL 5.6
2. Clone GitHub repository
https://github.com/HappyMelly/teller
3. Create MySQL database and user
!
4. Start application
Play Evolutions SQL script initialises DB
@PeterHilton • 52
56. CloudBees deployment process
example
1. Source code in GitHub repository
2. Develop code in feature branches
3. Merge commits to master after review
4. Automatic test deploy on push to GitHub
5. Smoke test on test server with prod data
6. Use Jenkins to promote the build to prod
@PeterHilton • 53
57. Deployment - dev environment
Set-up your development environment as if
you were doing an open-source project:
Minimal steps to get started on a fresh
machine,
Idiot-proof instructions
@PeterHilton • 54
58. Deployment - prod environment
Set-up your production environment as if
you were deploying to the cloud:
Match the development environment,
Support continuous deployment,
Automate deployment from the version
control system
@PeterHilton • 55
62. Doing it the easy way
Become Scala experts:
Type system, compiler errors, OO vs FP
!
Become Play experts:
Try out most of Play’s features
Learn how Play works internally
Build ten experimental applications
@PeterHilton • 59
63. Doing it the hard way
The same as the easy way, but
without a year before the first real project
!
Many new things at the same time is hard:
uncertainty - especially unknown duration,
risk - rework and operational issues
@PeterHilton • 60
64. Starting a project
Enable high-productivity:
Have very fast laptops - SSD, lots of RAM
Match the team to the architecture:
Keep both simple - at least to start with,
Decide how to work with front-end devs,
Have a Scala expert available
Do experiments, or get help, to start faster
@PeterHilton • 61
65. M A N N I N G
Covers Play 2
Peter Hilton
Erik Bakker
Francisco Canedo
FOREWORD BY James Ward
Play for Scala
(Manning)
!
Peter Hilton
Erik Bakker
Francisco Canedo
!
http://bit.ly/playscala2p
66.
67. Reducing project risk - summary
Community events - talking to other teams
e.g. London Scala Users’ Group
Read the book - don’t learn the hard way
!
Attend the training course to learn faster
Hire an expert to reduce project risk
@PeterHilton • 64