Node.js vs Play Framework (with Japanese subtitles)

Software

yevgeniy-brikman
of 163
Description
Video: http://www.nicovideo.jp/watch/1410857293

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 version of the presentation has Japanese subtitles. For the English only version, see http://www.slideshare.net/brikis98/nodejs-vs-play-framework
Text
  • 1. VSNode.js vs Play Framework
  • 2. Node.js: server-side JavaScript runtime environment;open source; single threaded; non-blocking I/O.Node.js: サーバサイドJSランタイム、OSS、シングルスレッド、非同期I/O
  • 3. express.js: the most popular webframework for Node.js.express.js: Node.js で一番人気のWebフレームワーク
  • 4. Play Framework: Java/Scala web framework; opensource; multithreaded; non-blocking I/O.Play: Java/Scala Webフレームワーク、OSS、マルチスレッド、非同期I/O
  • 5. Yevgeniy BrikmanFormer Play Tech Lead at LinkedIn. Long time Node.js user.元LinkedIn社Play Tech Lead。ベテランNode.jsユーザ
  • 6. The framework scorecardLearnDevelopTestSecureBuildDeployDebugScaleMaintainShare
  • 7. For each feature we discuss...1Much worse than most frameworksAbout the same as most frameworksMuch better than most frameworks5101 = 酷い、5 = 平均的、10 = 優秀
  • 8. The framework scorecardLearnDevelopTestSecureBuildDeployDebugScaleMaintainShare
  • 9. Node.js: 1-click installers for every OSOSにかかわらずインストーラは万全
  • 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.jsThe “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.jsThe “Hello World” Express app: 1 file, 8 lines of code.
  • 12. Run using node <filename>. 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 moreTons of resources; very gradual learning curve.リソースが豊富、緩やかな学習曲線
  • 21. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10
  • 22. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10
  • 23. Play: download from playframework.com,extract, add activator to your PATHPlay:ダウンロードし、展開し、activator を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 awhile the first time around)初回はjarのダウンロードに時間がかかる
  • 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. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 7
  • 34. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 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))}}Routingapp.get('clients/:id', function(req, res) {getClient(req.params.id, function(client) {res.render('show', client);});});RESTful routing. Extracts query & pathparams.RESTful routing. Extracts query & pathparams. Type safe. Actions arecomposable. Reverse routing.
  • 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 supportclient-side rendering!Twirl templates are compiled into Scalafunctions: type safe and composable!Other template types via plugins.
  • 37. i18nTranslations: 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. 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 bodyapp.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.createcase 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. DataSlick, Anorm, Ebean, JPAMySQL, MariaDB, PostgreSLQ, SQLite, Oracle, SQL Server,DB2, Derby, H2Sequelize, Bookshelf.js, node-orm2 SQLMySQL, MariaDB, PostgreSQL, SQLiteNoSQLmongojs/mongoose, cassandra-client,cradle/nano, node_redis, node-neo4jMongoDB, Cassandra, CouchDB, Redis, Neo4jReactiveMongo, DataStax, sprouch, play-plugins-redis, Neo4j-play, JPAMongoDB, Cassandra, CouchDB, Redis, Neo4jnode-memcached, connect-cache Cachingmemcached, in-memory (not recommended)play2-memcached, memcontinuationed,Play Cache, ehcache, Guavamemcached, in-memorynode-db-migrate, node-migrate Schemas Play database evolutions
  • 41. socket.io: server & client APIs;WebSockets, Flash Sockets, polling, etc.Play WebSockets, Comet, andEventSource APIs. Server-side only.Real-time web// server codeio.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 codesocket.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 replacedExpress.js:ミニマル、プラグインを多く使う。Play:フルスタック
  • 43. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 10
  • 44. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 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 callserver.listen directly.
  • 47. UI testing: phantom.js or zombie.js
  • 48. Code coverage: Istanbul or Blanket.js
  • 49. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010
  • 50. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010
  • 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 OKcontentType(result) mustEqual Some("text/html")charset(result) mustEqual Some("utf-8")contentAsString(result) must include ("Hello Bob")}Functional testing: use Play’s built-infunctional 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")).valueeventually { pageTitle mustBe "scalatest" }}}}UI testing: use Play’s built-in integration testhelpers and built-in Selenium support.
  • 54. Code coverage: jacoco4sbt or scct
  • 55. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 10
  • 56. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 10
  • 57. (not enabled by default!) Connect CSRF Middleware CSRF(not enabled by default!)Depends on template engine XSS Twirl escapes correctlyVulnerabilities: eval, setTimeout, InjectionSecurityCSRFFiltersetInterval, new Function Few vulnerabilities of this sortHelmet middleware Headers SecurityHeadersFilterpassport.js, everyauth Auth SecureSocial, deadbolt, play-authenticateNode Security Project Advisories Play Security Vulnerabilities
  • 58. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 8
  • 59. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 8
  • 60. {"name": "Hello World App","version": "0.0.3","dependencies": {"express": "4.8.0","underscore": "1.6.0"},"scripts": {"test": "node tests/run.js"}}Node.js uses NPM to manage dependencies andbasic build commandsNode.jsは依存性管理や簡単なコマンド定義にNPMを使う
  • 61. Many options available for more complicatedbuilds: grunt.js, gulp.js, or broccoliより複雑なビルドの場合、grunt.js, gulp.js, broccoliのようなツールを使う
  • 62. Thousands of plugins for all common build tasksプラグインが何千もある
  • 63. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810
  • 64. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810
  • 65. Play uses SBT as the build system. SBT is aninteractive build system.Play は SBT という対話的ビルドツールを利用
  • 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.ビルドファイルをScalaで書く。でもビギナーには厳しい
  • 67. Dependencies are managed using Ivy:familiar, but slow.Ivyで依存性を管理する。使い慣れてるけど、実行性能は遅め
  • 68. Play uses sbt-web to build static content: fewplugins; depends on Rhino (slow) or node.js (!).Playは静的コンテンツのビルドにsbt-webを利用する。プラグインが少ない
  • 69. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 7
  • 70. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 7
  • 71. Many node-friendly hosting options: Heroku,Joyent, Azure, OpenShift, NodejitsuNode.jsをサポートするホスティング
  • 72. Monitoring: New Relic, Nodetime,AppDynamics, node-monitor
  • 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 CPUcluster を使ってコア毎にインスタンスを稼働
  • 74. Use forever, monit, or Domain to handle crashes.クラッシュ対処
  • 75. {"dbConfig": {"host": "localhost","port": 5984,"dbName": "customers"}}config/default.jsonvar config = require('config');var host = config.get('dbConfig.host');server.jsConfiguration: node-config or nconf
  • 76. Use nginx, apache, or ATS to load balance,serve static content, terminate SSLClientData CenterReverse proxy(e.g. nginx) DBStatic server(e.g. nginx)NodeinstNaondceeinstNaondceeinstNaondceeinstNaondceeinstanceNodeinstNaondceeinstNaondceeinstNaondceeinstanceNodeinstNaondceeinstNaondceeinstNaondceeinstanceロードバランサー、静的コンテンツ、SSL Termination
  • 77. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78
  • 78. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78
  • 79. A few Play-friendly hosting options: Heroku,playframework-cloud, CloudBeesPlayをサポートするホスティング
  • 80. Monitoring: New Relic, metrics-play
  • 81. Use the SBT Native Packager to package theapp as tgz, deb, RPM, etc.Appをネイティブパッケージとして包装できる
  • 82. dbConfig = {host: "localhost",port: 5984,dbName: "customers"}conf/application.confval host = Play.current.configuration.getString("dbConfig.host")app/controllers/Application.scalaConfiguration: Play comes with Typesafe Config
  • 83. Use nginx, apache, or ATS to load balance,serve static content, terminate SSLClientData CenterReverse proxy(e.g. nginx)Play appDBStatic server(e.g. nginx)Play appPlay app
  • 84. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7
  • 85. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7
  • 86. Node.js: use IntelliJ or node-inspector to debugNode.js:IntelliJでデバッグできる
  • 87. Use DTrace, TraceGL, node-stackviz, and node-profilerto debug perf issues性能問題のデバッグ
  • 88. var winston = require("winston");winston.info("CHILL WINSTON! ... I put it in the logs.");Use winston, log4js, or bunyan for logging
  • 89. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 710
  • 90. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 710
  • 91. Play runs on the JVM, so you can use yourfavorite IDE to debug: IntelliJ, Eclipse, NetBeansPlay:好きなIDEを使える
  • 92. In dev, Play shows errors right in the browser開発モードでエラーがブラウザで表示される
  • 93. Use YourKit, VisualVM, BTrace, and jmap todebug perf issues
  • 94. Use logback, slf4j, or log4j for logging
  • 95. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 710 10
  • 96. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 710 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 LoadBalancerFrontendServerFrontendServerFrontendServerBackendServerBackendServerBackendServerBackendServerBackendServerDataStoreDataStoreDataStoreDataStoreLinkedIn experience #1: Play and Node.js are veryfast in a service oriented architecture with NIO.LinkedInの感想:Node.jsもPlayもとても速い
  • 103. // BAD: write files synchronouslyfs.writeFileSync('message.txt', 'Hello Node');console.log("It's saved, but you just blocked ALL requests!");// Good: write files asynchronouslyfs.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.同期I/O、高メモリ使用率と高CPU使用率の場合、Node.jsの性能が落ちる
  • 104. Part 2: scaling for large teams and projects大きいチーム・プロジェクトのためのスケーリング
  • 105. Node.js: best for small projects, short projects, small teams.Node.js:小さいプロジェクト、短いプロジェクト、小さいチームにいい
  • 106. Play: best for longer projects. Slower ramp up, but scales well with team & project size.Play:より大きいプロジェクトにスケールできる
  • 107. For comparison: Spring MVC
  • 108. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 710101010
  • 109. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 710101010
  • 110. Maintenance: the good partsメンテナンス:「良いパーツ」
  • 111. Functional programming: first class functions,closures, underscore.js関数型プログラミング
  • 112. JavaScript is ubiquitous...JSは至る所にある
  • 113. ...Which means you can share developers,practices, and even code: rendr, derby, meteorそのため、デベロッパー、情報、コードは入手しやすい
  • 114. Node core is stable and mature. Bugs, regressions,and backwards incompatibility are rare.安定したコア。バグや後方互換性の問題は比較的少ない
  • 115. Maintenance: the bad partsメンテナンス:「悪いパーツ」
  • 116. '' == '0' // false0 == '' // true0 == '0' // truefalse == 'false' // falsefalse == '0' // truefalse == undefined // falsefalse == null // falsenull == undefined // true' trn ' == 0 // trueBad Parts
  • 117. // Default scope is globalvar foo = "I'm a global variable!"// Setting undeclared variables puts them in global scope toobar = "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. Wat
  • 119. this keyword
  • 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. Many NPM packages are NOT stable or mature.Incompatibility + bugs + dynamic typing = pain.NPMに不安定なパッケージが多い。非互換性 + バグ + 動的型付け = 苦痛
  • 122. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7101010103
  • 123. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7101010103
  • 124. Maintenance: the good parts
  • 125. def sort(a: List[Int]): List[Int] = {if (a.length < 2) aelse {val pivot = a(a.length / 2)sort(a.filter(_ < pivot)) :::a.filter(_ == pivot) :::sort(a.filter(_ > pivot))Functional programming}}
  • 126. Powerful type system
  • 127. val NameTagPattern = "Hello, my name is (.+) (.+)".rval ListPattern = "Last: (.+). First: (.+).".r// Case classes automatically generate immutable fields, equals, hashCode, constructorcase class Name(first: String, last: String)// Use Option to avoid returning null if there is no name founddef extractName(str: String): Option[Name] = {Option(str).collectFirst {// Pattern matching on regular expressionscase NameTagPattern(fname, lname) => Name(fname, lname)case ListPattern(lname, fname) => Name(fname, lname)}}Very expressive: case classes, pattern matching, lazy, option, implicits表現力が高い
  • 128. Runs on the JVM; interop with Java.
  • 129. Concurrency & streaming tools: Futures, Akka,STM, threads, Scala.rx, Async/Await, Iteratees
  • 130. def index = Action {// Make 3 sequential, async callsfor {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. Good IDE support
  • 132. Maintenance: the bad parts
  • 133. Slow compilerコンパイラ遅い
  • 134. Fortunately, Play/SBT support incrementalcompilation and hot reload!Play/sbt はインクリメンタルコンパイラと hot reloading があるから大丈夫!
  • 135. Complexity
  • 136. More complexity
  • 137. Play is stable, but not mature: backwardsincompatible API changes every release.Play は安定だがまだ成長期。APIはよく変わる
  • 138. Even worse: Scala is not binary compatiblebetween releases!Scala はリリース間でバイナリ互換性を持たない!
  • 139. Backwards incompatibility = pain.… Static typing makes it a little more manageable.バイナリ互換性が無いのは辛いけど、静的な型によって少しは緩和される
  • 140. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7101010103 8
  • 141. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7101010103 8
  • 142. 544 Contributors 3512,376 Watchers 57631,332 Stars 5,0776,970 Forks 1,8723,066 PR’s 2,201Github activity as of 08/10/14
  • 143. StackOverflow 10,69853,555 QuestionsGoogle Group14,199 Members 11,577Google Group~400 Posts/Month ~1,100StackOverflow, mailing list activity as of 08/12/14
  • 144. 4 langpop.com 1810 TIOBE 395 CodeEval 127 IEEE Spectrum 171 RedMonk 1312 Lang-Index 26Language Popularity as of 08/12/14人気ランキング
  • 145. 88,000 packages in NPM ~80 Play Modules
  • 146. 88,000 packages in NPM 83,000 artifacts in Maven
  • 147. Joyent offers commercialsupport for Node.jsTypesafe offers commercialsupport for Play有償サポート
  • 148. Node.js in production
  • 149. Play in production
  • 150. 1,172 LinkedIn 493,605 Indeed 179214 CareerBuilder 16Open jobs as of 08/13/14採用募集数
  • 151. 82,698 LinkedIn 9,0372,267 Indeed 206447 CareerBuilder 30Candidates as of 08/13/14採用候補者数
  • 152. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7101010103 810 7
  • 153. LearnDevelopTestSecureBuildThe framework scorecardDeployDebugScaleMaintainShare10 78 1010 106 810 78 7101010103 810 7
  • 154. Final score8584
  • 155. Final score8584
  • 156. 山田くん、これ全員の座布団全部持って行きなさい!
  • 157. Both frameworks are great. Decide based onstrengths/weakness, not my arbitrary score!結論:どちらもすごい!
  • 158. Use node.js if:1. You’re building small apps with small teams2. You already have a bunch of JavaScript ninjas3. Your app is mostly client-side JavaScript4. Your app is mostly real-time5. Your app is purely I/O bound向き: 小チーム小アプリ、JavaScript ニンジャ
  • 159. Don’t use node.js if:1. You don’t write lots of automated tests2. Your code base or team is going to get huge3. You do lots of CPU or memory intensive tasks不向き: 自動テスト書かない人、大チーム、高CPU か 高RAM
  • 160. Use Play if:1. You’re already using the JVM2. You like type safety and functional programming3. Your code base or team is going to get big4. You want a full stack framework5. You need flexibility: non-blocking I/O, blocking I/O,CPU intensive tasks, memory intensive tasks向き: JVM ユーザ、型安全性、関数型が好き、大チーム
  • 161. Don’t use Play if:1. You don’t have time to master Play, Scala, and SBT2. You hate functional programming or static typing不向き: Play/Scala/sbt を勉強してる時間が無い、型安全性、関数型が嫌い
  • 162. Questions?
  • Comments
    Top