Node.js vs Play Framework

131,842 views
135,571 views

Published on

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

Here's the showdown you've been waiting for: Node.js vs Play Framework. Both are popular open source web frameworks that are built for developer productivity, asynchronous I/O, and the real time web. But which one is easier to learn, test, deploy, debug, and scale? Should you pick Javascript or Scala? The Google v8 engine or the JVM? NPM or Ivy? Grunt or SBT? Two frameworks enter, one framework leaves.

This is the English version of the presentation. For the version with Japanese subtitles, see http://www.slideshare.net/brikis98/nodejs-vs-play-framework-with-japanese-subtitles

Published in: Software
7 Comments
378 Likes
Statistics
Notes
  • 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
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • For API purposes put Scalatra (instead of play framework) in the equation: http://www.scalatra.org/
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Great slides, thanks for sharing
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • @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.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • 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
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
131,842
On SlideShare
0
From Embeds
0
Number of Embeds
51,245
Actions
Shares
0
Downloads
1,168
Comments
7
Likes
378
Embeds 0
No embeds

No notes for slide

Node.js vs Play Framework

  1. 1. VS Node.js vs Play Framework
  2. 2. Node.js: server-side JavaScript runtime environment; open source; single threaded; non-blocking I/O.
  3. 3. express.js: the most popular web framework for Node.js.
  4. 4. Play Framework: Java/Scala web framework; open source; multithreaded; non-blocking I/O.
  5. 5. Yevgeniy Brikman Former Play Tech Lead at LinkedIn. Long time Node.js user.
  6. 6. The framework scorecard Learn Develop Test Secure Build Deploy Debug Scale Maintain Share
  7. 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. 8. The framework scorecard Learn Develop Test Secure Build Deploy Debug Scale Maintain Share
  9. 9. Node.js: 1-click installers for every OS
  10. 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. 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. 12. Run using node <filename>. Starts instantly!
  13. 13. Hit http://localhost:1337 to test
  14. 14. nodeschool.io
  15. 15. Node Beginner Book, Mastering Node.js, Node: Up and Running, Node.js in Action
  16. 16. Node API Docs
  17. 17. Express.js guide
  18. 18. Express Web Application Development Express.js Guide
  19. 19. Express.js API docs
  20. 20. And much, much more Tons of resources; very gradual learning curve.
  21. 21. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10
  22. 22. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10
  23. 23. Play: download from playframework.com, extract, add activator to your PATH
  24. 24. Generate a new app using activator new
  25. 25. The “Hello World” Play app: ~35 files and folders
  26. 26. Run the app using activator run
  27. 27. (Downloading all dependencies can take a while the first time around)
  28. 28. Hit http://localhost:9000 to test
  29. 29. Play Framework Documentation
  30. 30. Activator Templates
  31. 31. Play for Scala Learning Play Framework 2
  32. 32. Ultimate Guide to Getting Started with Play. Not as many resources; steep learning curve.
  33. 33. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7
  34. 34. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7
  35. 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. 36. @(name: String, headline: String) <div class="client"> <h1>@name</h1> <div class="headline"> Headline: @headline </div> </div> Templates <div class="client"> <h1>{{name}}</h1> <div class="headline"> Headline: {{headline}} </div> </div> 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. 37. i18n Translations: i18next-node, i18n-node. Formatting: moment.js, numeral.js. Translations: Play i18n API. Formatting: Java formatting libraries. <div class="client"> <h1>{{name}}</h1> <div class="headline"> {{t "headline.label" headline=headline}} </div> </div> @(name: String, headline: String) <div class="client"> <h1>@name</h1> <div class="headline"> Messages("headline.label", headline) </div> </div>
  38. 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. 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. 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. 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. 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. 43. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10
  44. 44. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10
  45. 45. Unit testing: Jasmine, Mocha, QUnit, nodeunit, Expresso or Vows
  46. 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. 47. UI testing: phantom.js or zombie.js
  48. 48. Code coverage: Istanbul or Blanket.js
  49. 49. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10
  50. 50. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10
  51. 51. Unit testing: junit, ScalaTest, specs2, or testng
  52. 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. 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. 54. Code coverage: jacoco4sbt or scct
  55. 55. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10
  56. 56. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10
  57. 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. 58. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8
  59. 59. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8
  60. 60. { "name": "Hello World App", "version": "0.0.3", "dependencies": { "express": "4.8.0", "underscore": "1.6.0" }, "scripts": { "test": "node tests/run.js", "lint": "jshint src" } } Node.js uses NPM to manage dependencies and basic build commands
  61. 61. Many options available for more complicated builds: grunt.js, gulp.js, or broccoli
  62. 62. Thousands of plugins for all common build tasks
  63. 63. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10
  64. 64. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10
  65. 65. Play uses SBT as the build system. SBT is an interactive build system.
  66. 66. object AppBuild extends Build { lazy val root = Project(id = "root", base = file(".")).settings( name := "test-play-app", version := version, libraryDependencies += Seq( "org.scala-tools" % "scala-stm_2.11.1" % "0.3", "org.apache.derby" % "derby" % "10.4.1.3" ) ) def version = Option(System.getProperty("version")).getOrElse("0.0.3") } In SBT, build definitions are written in Scala! … But the learning curve is very steep.
  67. 67. Dependencies are managed using Ivy: familiar, but slow.
  68. 68. Play uses sbt-web to build static content: few plugins; depends on Rhino (slow) or node.js (!).
  69. 69. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7
  70. 70. Learn Develop Test Secure Build The framework scorecard Deploy Debug Scale Maintain Share 10 7 8 10 10 10 6 8 10 7
  71. 71. Many node-friendly hosting options: Heroku, Joyent, Azure, OpenShift, Nodejitsu
  72. 72. Monitoring: New Relic, Nodetime, AppDynamics, node-monitor
  73. 73. if (cluster.isMaster) { for (var i = 0; i < numCPUs; i++) { cluster.fork(); // Fork workers } cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); }); } else { http.createServer(function(req, res) { // ... }).listen(8000); } Use cluster to run one node instance per CPU
  74. 74. Use forever, monit, or Domain to handle crashes.
  75. 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. 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. 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. 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. 79. A few Play-friendly hosting options: Heroku, playframework-cloud, CloudBees
  80. 80. Monitoring: New Relic, metrics-play
  81. 81. Use the SBT Native Packager to package the app as tgz, deb, RPM, etc.
  82. 82. dbConfig = { host: "localhost", port: 5984, dbName: "customers" } conf/application.conf val host = Play.current.configuration.getString("dbConfig.host") app/controllers/Application.scala Configuration: Play comes with Typesafe Config
  83. 83. Use nginx, apache, or ATS to load balance, serve static content, terminate SSL Client Data Center Reverse proxy (e.g. nginx) Play app DB Static server (e.g. nginx) Play app Play app
  84. 84. 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
  85. 85. 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
  86. 86. Node.js: use IntelliJ or node-inspector to debug
  87. 87. Use DTrace, TraceGL, node-stackviz, and node-profiler to debug perf issues
  88. 88. var winston = require("winston"); winston.info("CHILL WINSTON! ... I put it in the logs."); Use winston, log4js, or bunyan for logging
  89. 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. 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. 91. Play runs on the JVM, so you can use your favorite IDE to debug: IntelliJ, Eclipse, NetBeans
  92. 92. In dev, Play shows errors right in the browser
  93. 93. Use YourKit, VisualVM, BTrace, and jmap to debug perf issues
  94. 94. Use logback, slf4j, or log4j for logging
  95. 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. 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. 97. Part 1: scaling for lots of traffic
  98. 98. TechEmpower benchmarks. Warning: microbenchmarks are not a substitute for real world perf testing!
  99. 99. JSON serialization
  100. 100. Single query (Note: JDBC is blocking!)
  101. 101. Multiple queries (Note: JDBC is blocking!)
  102. 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. 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. 104. Part 2: scaling for large teams and projects
  105. 105. Node.js: best for small projects, short projects, small teams.
  106. 106. Play: best for longer projects. Slower ramp up, but scales well with team and project size.
  107. 107. For comparison: Spring MVC
  108. 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. 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. 110. Maintenance: the good parts
  111. 111. Functional programming: first class functions, closures, underscore.js
  112. 112. JavaScript is ubiquitous...
  113. 113. ...Which means you can share developers, practices, and even code: rendr, derby, meteor
  114. 114. Node core is (mostly) stable and mature. Bugs, regressions, and backwards incompatibility are rare.
  115. 115. Maintenance: the bad parts
  116. 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
  117. 117. // Default scope is global var foo = "I'm a global variable!" // Setting undeclared variables puts them in global scope too bar = "I'm also a global variable!"; if (foo) { // Look ma, no block scope! var baz = "Believe it or not, I'll also be a global variable!" } Awful Parts
  118. 118. Wat
  119. 119. this keyword
  120. 120. doSomethingAsync(req1, function(err1, res1) { doSomethingAsync(req2, function(err2, res2) { doSomethingAsync(req3, function(err3, res3) { doSomethingAsync(req4, function(err4, res4) { // ... }); }); }); }); Callback hell: control flow, error handling, and composition are all difficult
  121. 121. Many NPM packages are NOT stable or mature. Incompatibility + bugs + dynamic typing = pain.
  122. 122. 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 3
  123. 123. 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 3
  124. 124. Maintenance: the good parts
  125. 125. def sort(a: List[Int]): List[Int] = { if (a.length < 2) a else { val pivot = a(a.length / 2) sort(a.filter(_ < pivot)) ::: a.filter(_ == pivot) ::: sort(a.filter(_ > pivot)) Functional programming } }
  126. 126. Powerful type system
  127. 127. val NameTagPattern = "Hello, my name is (.+) (.+)".r val ListPattern = "Last: (.+). First: (.+).".r // Case classes automatically generate immutable fields, equals, hashCode, constructor case class Name(first: String, last: String) // Use Option to avoid returning null if there is no name found def extractName(str: String): Option[Name] = { Option(str).collectFirst { // Pattern matching on regular expressions case NameTagPattern(fname, lname) => Name(fname, lname) case ListPattern(lname, fname) => Name(fname, lname) } } Very expressive: case classes, pattern matching, lazy, option, implicits
  128. 128. Runs on the JVM; interop with Java.
  129. 129. Concurrency & streaming tools: Futures, Akka, STM, threads, Scala.rx, Async/Await, Iteratees
  130. 130. def index = Action { // Make 3 sequential, async calls for { foo <- WS.url(url1).get() bar <- WS.url(url2).get() baz <- WS.url(url3).get() } yield { // Build a result using foo, bar, and baz } } No callback hell!
  131. 131. Good IDE support
  132. 132. Maintenance: the bad parts
  133. 133. Slow compiler
  134. 134. Fortunately, Play/SBT support incremental compilation and hot reload!
  135. 135. Complexity
  136. 136. More complexity
  137. 137. Play is stable, but not mature: backwards incompatible API changes every release.
  138. 138. Even worse: Scala is not binary compatible between releases!
  139. 139. Backwards incompatibility = pain. … Static typing makes it a little more manageable.
  140. 140. 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 3 8
  141. 141. 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 3 8
  142. 142. 544 Contributors 351 2,376 Watchers 576 31,332 Stars 5,077 6,970 Forks 1,872 3,066 PR’s 2,201 Github activity as of 08/10/14
  143. 143. StackOverflow 10,698 53,555 Questions Google Group 14,199 Members 11,577 Google Group ~400 Posts/Month ~1,100 StackOverflow, mailing list activity as of 08/12/14
  144. 144. 4 langpop.com 18 10 TIOBE 39 5 CodeEval 12 7 IEEE Spectrum 17 1 RedMonk 13 12 Lang-Index 26 Language Popularity as of 08/12/14
  145. 145. 88,000 packages in NPM ~80 Play Modules
  146. 146. 88,000 packages in NPM 83,000 artifacts in Maven
  147. 147. Joyent offers commercial support for Node.js Typesafe offers commercial support for Play
  148. 148. Node.js in production
  149. 149. Play in production
  150. 150. 1,172 LinkedIn 49 3,605 Indeed 179 214 CareerBuilder 16 Open jobs as of 08/13/14
  151. 151. 82,698 LinkedIn 9,037 2,267 Indeed 206 447 CareerBuilder 30 Candidates as of 08/13/14
  152. 152. 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 3 8 10 7
  153. 153. 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 3 8 10 7
  154. 154. Final score 85 84
  155. 155. Final score 85 84
  156. 156. Both frameworks are great. Decide based on strengths/weakness, not my arbitrary score!
  157. 157. Use node.js if: 1. You’re building small apps with small teams 2. You already have a bunch of JavaScript ninjas 3. Your app is mostly client-side JavaScript 4. Your app is mostly real-time 5. Your app is purely I/O bound
  158. 158. Don’t use node.js if: 1. You don’t write lots of automated tests 2. Your code base or team is going to get huge 3. You do lots of CPU or memory intensive tasks
  159. 159. Use Play if: 1. You’re already using the JVM 2. You like type safety and functional programming 3. Your code base or team is going to get big 4. You want a full stack framework 5. You need flexibility: non-blocking I/O, blocking I/O, CPU intensive tasks, memory intensive tasks
  160. 160. Don’t use Play if: 1. You don’t have time to master Play, Scala, and SBT 2. You hate functional programming or static typing
  161. 161. Questions?

×