Node.js vs Play Framework

Video: https://www.youtube.com/watch?v=b6yLwvNSDck Here's the showdown you've been

1/163 Documents & Tips - Sharing is our passion

Share This Page

  1. Yevgeniy Brikman
    Video: https://www.youtube.com/watch?v=b6yLwvNSDck

    Here's the showdown you've been
    Transcript Header:
    Node.js vs Play Framework
    Transcript Body:
    • 1. VS Node.js vs Play Framework
    • 2. Node.js: server-side JavaScript runtime environment; open source; single threaded; non-blocking I/O.
    • 3. express.js: the most popular web framework for Node.js.
    • 4. Play Framework: Java/Scala web framework; open source; multithreaded; non-blocking I/O.
    • 5. Yevgeniy Brikman Former Play Tech Lead at LinkedIn. Long time Node.js user.
    • 6. The framework scorecard Learn Develop Test Secure Build Deploy Debug Scale Maintain Share
    • 7. For each feature we discuss... 1 Much worse than most frameworks About the same as most frameworks Much better than most frameworks 5 10
    • 8. The framework scorecard Learn Develop Test Secure Build Deploy Debug Scale Maintain Share
    • 9. Node.js: 1-click installers for every OS
    • 10. var http = require('http'); http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hello Worldn'); }).listen(1337, '127.0.0.1'); console.log('Server running at http://127.0.0.1:1337/'); server.js The “Hello World” Node app: 1 file, 6 lines of code.
    • 11. var express = require('express'); var app = express(); app.get('/', function(req, res){ res.send('Hello World'); }); var server = app.listen(1337, function() { console.log('Listening on port %d', server.address().port); }); server.js The “Hello World” Express app: 1 file, 8 lines of code.
    • 12. Run using node . Starts instantly!
    • 13. Hit http://localhost:1337 to test
    • 14. nodeschool.io
    • 15. Node Beginner Book, Mastering Node.js, Node: Up and Running, Node.js in Action
    • 16. Node API Docs
    • 17. Express.js guide
    • 18. Express Web Application Development Express.js Guide
    • 19. Express.js API docs
    • 20. And much, much more Tons of resources; very gradual learning curve.
    • 21. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10
    • 22. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10
    • 23. Play: download from playframework.com, extract, add activator to your PATH
    • 24. Generate a new app using activator new
    • 25. The “Hello World” Play app: ~35 files and folders
    • 26. Run the app using activator run
    • 27. (Downloading all dependencies can take a while the first time around)
    • 28. Hit http://localhost:9000 to test
    • 29. Play Framework Documentation
    • 30. Activator Templates
    • 31. Play for Scala Learning Play Framework 2
    • 32. Ultimate Guide to Getting Started with Play. Not as many resources; steep learning curve.
    • 33. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7
    • 34. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7
    • 35. GET clients/:id Clients.show(id: Long) def show(id: Long) = Action { request => getClient(id).map { client => Ok(views.html.clients.show(client)) } } Routing app.get('clients/:id', function(req, res) { getClient(req.params.id, function(client) { res.render('show', client); }); }); RESTful routing. Extracts query & path params. RESTful routing. Extracts query & path params. Type safe. Actions are composable. Reverse routing.
    • 36. @(name: String, headline: String) @name Headline: @headline Templates {{name}} Headline: {{headline}} Many template options: handlebars, mustache, dust, jade, etc. Most support client-side rendering! Twirl templates are compiled into Scala functions: type safe and composable! Other template types via plugins.
    • 37. i18n Translations: i18next-node, i18n-node. Formatting: moment.js, numeral.js. Translations: Play i18n API. Formatting: Java formatting libraries. {{name}} {{t "headline.label" headline=headline}} @(name: String, headline: String) @name Messages("headline.label", headline)
    • 38. var regForm = forms.create({ name: fields.string({required: true}), age: fields.number({min: 18}) Forms, node-formidable, validator.js. Play form binding and validation API. Form binding and validation }); regForm.handle(req, { success: function(form) { ... }, error: function(form) { ... } }); val regForm = Form(mapping( "name" -> nonEmptyText, "age" -> number(min = 18) )(UserData.apply)(UserData.unapply)) regForm.bindFromRequest.fold( err => BadRequest("Validation error"), data => Ok(s"Hi $data.name!") )
    • 39. // Automatically parse application/json body app.use(bodyParser.json()); app.post('/clients', function (req, res, next) { var name = req.body.name; var age = req.body.age; res.send(name + " is " + age + " years old."); }); POST /clients Clients.create case class Person(name: String, age: Int) implicit val prsnFmt = Json.format[Person] def create = Action(parse.json) { request => val person = request.body.as[Person] Ok(s"$person.name is $person.age years old") } bodyParser, xml2js, node-formidable. Play JSON, XML, File Upload APIs. JSON, XML, File Upload
    • 40. Data Slick, Anorm, Ebean, JPA MySQL, MariaDB, PostgreSLQ, SQLite, Oracle, SQL Server, DB2, Derby, H2 Sequelize, Bookshelf.js, node-orm2 SQL MySQL, MariaDB, PostgreSQL, SQLite NoSQL mongojs/mongoose, cassandra-client, cradle/nano, node_redis, node-neo4j MongoDB, Cassandra, CouchDB, Redis, Neo4j ReactiveMongo, DataStax, sprouch, play-plugins- redis, Neo4j-play, JPA MongoDB, Cassandra, CouchDB, Redis, Neo4j node-memcached, connect-cache Caching memcached, in-memory (not recommended) play2-memcached, memcontinuationed, Play Cache, ehcache, Guava memcached, in-memory node-db-migrate, node-migrate Schemas Play database evolutions
    • 41. socket.io: server & client APIs; WebSockets, Flash Sockets, polling, etc. Play WebSockets, Comet, and EventSource APIs. Server-side only. Real-time web // server code io.on('connection', function (socket) { socket.emit('msg', 'Server says hi!'); socket.on('msg', function (msg) { … }); }); def chat = WebSocket.acceptWithActor { request => out => Props(new Chat(out)) } class Chat(out: ActorRef) extends Actor { def receive = { case m: String => out ! s"Got msg: $m" } } // client code socket.emit('msg', 'Client says hi!'); socket.on('msg', function (msg) { … });
    • 42. ● Express.js is a minimal framework ● Play is a full stack framework ● You need plugins for most tasks ● Finding good plugins takes time ● Gluing plugins together takes time ● There are defaults for most tasks ● Defaults are mostly high quality ● All defaults can be replaced
    • 43. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10
    • 44. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10
    • 45. Unit testing: Jasmine, Mocha, QUnit, nodeunit, Expresso or Vows
    • 46. var request = require('supertest') , app = require('express')(); app.get('/user', function(req, res){ res.send(200, { name: 'tobi' }); }); request(app) .get('/user') .expect('Content-Type', /json/) .expect(200); Functional testing: use supertest or call server.listen directly.
    • 47. UI testing: phantom.js or zombie.js
    • 48. Code coverage: Istanbul or Blanket.js
    • 49. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10
    • 50. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10
    • 51. Unit testing: junit, ScalaTest, specs2, or testng
    • 52. "respond to the index Action" in new App(FakeApplication()) { val Some(result) = route(FakeRequest(GET, "/Bob")) status(result) mustEqual OK contentType(result) mustEqual Some("text/html") charset(result) mustEqual Some("utf-8") contentAsString(result) must include ("Hello Bob") } Functional testing: use Play’s built-in functional test helpers.
    • 53. class ExampleSpec extends PlaySpec with OneServerPerSuite with OneBrowserPerSuite { "The OneBrowserPerTest trait" must { "provide a web driver" in { go to (s"http://localhost:$port/testing") pageTitle mustBe "Test Page" click on find(name("b")).value eventually { pageTitle mustBe "scalatest" } } } } UI testing: use Play’s built-in integration test helpers and built-in Selenium support.
    • 54. Code coverage: jacoco4sbt or scct
    • 55. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10
    • 56. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10
    • 57. (not enabled by default!) Connect CSRF Middleware CSRF (not enabled by default!) Depends on template engine XSS Twirl escapes correctly Vulnerabilities: eval, setTimeout, Injection Security CSRFFilter setInterval, new Function Few vulnerabilities of this sort Helmet middleware Headers SecurityHeadersFilter passport.js, everyauth Auth SecureSocial, deadbolt, play-authenticate Node Security Project Advisories Play Security Vulnerabilities
    • 58. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8
    • 59. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8
    • 75. { "dbConfig": { "host": "localhost", "port": 5984, "dbName": "customers" } } config/default.json var config = require('config'); var host = config.get('dbConfig.host'); server.js Configuration: node-config or nconf
    • 76. Use nginx, apache, or ATS to load balance, serve static content, terminate SSL Client Data Center Reverse proxy (e.g. nginx) DB Static server (e.g. nginx) Node instNaondcee instNaondcee instNaondcee instNaondcee instance Node instNaondcee instNaondcee instNaondcee instance Node instNaondcee instNaondcee instNaondcee instance
    • 77. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8
    • 78. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8
    • 79. A few Play-friendly hosting options: Heroku, playframework-cloud, CloudBees
    • 80. Monitoring: New Relic, metrics-play
    • 81. Use the SBT Native Packager to package the app as tgz, deb, RPM, etc.
    • 88. var winston = require("winston"); winston.info("CHILL WINSTON! ... I put it in the logs."); Use winston, log4js, or bunyan for logging
    • 89. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8 7 10
    • 90. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8 7 10
    • 91. Play runs on the JVM, so you can use your favorite IDE to debug: IntelliJ, Eclipse, NetBeans
    • 92. In dev, Play shows errors right in the browser
    • 93. Use YourKit, VisualVM, BTrace, and jmap to debug perf issues
    • 94. Use logback, slf4j, or log4j for logging
    • 95. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8 7 10 10
    • 96. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8 7 10 10
    • 97. Part 1: scaling for lots of traffic
    • 98. TechEmpower benchmarks. Warning: microbenchmarks are not a substitute for real world perf testing!
    • 99. JSON serialization
    • 100. Single query (Note: JDBC is blocking!)
    • 101. Multiple queries (Note: JDBC is blocking!)
    • 102. Internet Load Balancer Frontend Server Frontend Server Frontend Server Backend Server Backend Server Backend Server Backend Server Backend Server Data Store Data Store Data Store Data Store LinkedIn experience #1: Play and Node.js are very fast in a service oriented architecture with NIO.
    • 103. // BAD: write files synchronously fs.writeFileSync('message.txt', 'Hello Node'); console.log("It's saved, but you just blocked ALL requests!"); // Good: write files asynchronously fs.writeFile('message.txt', 'Hello Node', function (err) { console.log("It's saved and the server remains responsive!"); }); LinkedIn experience #2: Play is ok with blocking I/O & CPU/memory bound use cases. Node.js is not.
    • 104. Part 2: scaling for large teams and projects
    • 105. Node.js: best for small projects, short projects, small teams.
    • 106. Play: best for longer projects. Slower ramp up, but scales well with team and project size.
    • 107. For comparison: Spring MVC
    • 108. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8 7 10 10 10 10
    • 109. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7 8 7 10 10 10 10
    • 110. Maintenance: the good parts
    • 111. Functional programming: first class functions, closures, underscore.js
    • 112. JavaScript is ubiquitous...
    • 113. ...Which means you can share developers, practices, and even code: rendr, derby, meteor
    • 114. Node core is (mostly) stable and mature. Bugs, regressions, and backwards incompatibility are rare.
    • 115. Maintenance: the bad parts
    • 116. '' == '0' // false 0 == '' // true 0 == '0' // true false == 'false' // false false == '0' // true false == undefined // false false == null // false null == undefined // true ' trn ' == 0 // true Bad Parts
    View More

Recent Reviews

  1. Bassem Zohdy
    Bassem Zohdy
    4/5,
    Version: 04/09/2014
    Thanks for sharing your experiance, but why I think you are biased against Spring, you just mentioned Spring MVC in productivity over time "which is not measurable" also it is orange/apple comparison you have to consider Spring Boot not MVC, and with considering learning curve of java developers
  2. George Pligoropoulos
    George Pligoropoulos
    4/5,
    Version: 04/09/2014
  3. Alessandro Zuniga
    Alessandro Zuniga
    5/5,
    Version: 04/09/2014
    Great slides, thanks for sharing
  4. Yevgeniy Brikman
    Yevgeniy Brikman
    5/5,
    Version: 04/09/2014
    @Tristan: wrapping a blocking JDBC call in a Future does not magically make it non-blocking. It's *still* blocking a thread until the response comes back from the database. Of course, you can make sure that the thread comes out of a separate thread pool and not the one Play uses for executing the rest of the controller logic (which is what the Play code does in the TechEmpower benchmarks), but you now have to tune that thread pool. If it has too few threads, they may all end up being blocked and all subsequent requests get queued, massively increasing latency; if it has too many threads, then you have to contend with lots of memory and context switching overhead. It's a tricky balance and Play's performance can suffer because of this compared to a purely non-blocking solution: this is likely why in the TechEmpower benchmarks Play is faster than Node.js for a single DB call per request, but slower for 20 DB calls per request.

    See http://engineering.linkedin.com/play/play-framework-async-io-without-thread-pool-and-callback-hell for more info.
  5. Tristan Lohman
    Tristan Lohman
    4/5,
    Version: 04/09/2014
    While JDBC is blocking, you can just wrap the database call in an async block and get a Future, and now you have non-blocking DB access. Also, many of the NoSQL drivers are non-blocking as well. Take a look at ReactiveMongo for non-blocking access to MongoDB
  6. Alexandre Galays
    Alexandre Galays
    5/5,
    Version: 04/09/2014
    10 for node scaling even though it just can't do CPU heavy tasks? It doesn't seem fair, even if you will always try to avoid doing blocking CPU work. Play just scales without limitations so I would expect something like 10 for Play and 7 or 8 for Node?
  7. Yevgeniy Brikman
    Yevgeniy Brikman
    4/5,
    Version: 04/09/2014
    @Alexandre: the video (which I'll post when it's available) has more details. The key idea is that both frameworks are fast enough for almost any real world case (which is why both get 10's), as long as you understand where each framework is strong or weak. For example, Node and Play both scale very well for purely I/O bound work, but since all stable/popular database libraries on the JVM (JDBC) are blocking and all stable/popular database libraries for Node are non-blocking, Node scales better for this (common) use case. On the other hand, Play can handle CPU/memory intensive work better than Node.js, so for more varied performance scenarios, Play will scale better. That said, everything I say here is a broad generalization: it's useful as a starting point to know that both of these frameworks are capable of good performance, but the most important thing is to benchmark your actual scenarios and not trust microbenchmarks or a random guy online :)