Java ラブなヌーラボにおける Scala + Playframework 体験記

3e77f9dbec6a87756d1dbdddab283aee?s=47 Nulab Inc.
February 21, 2015

Java ラブなヌーラボにおける Scala + Playframework 体験記

3e77f9dbec6a87756d1dbdddab283aee?s=128

Nulab Inc.

February 21, 2015
Tweet

Transcript

  1. Scala + Playframework ମݧه Java ϥϒͳψʔϥϘʹ͓͚Δ

  2. None
  3. ࣗݾ঺հ • Tsuyoshi Yoshizawa (@ussy00) • גࣜձࣾψʔϥϘ • 2009 -

    2012 • डୗ։ൃ / Backlog / Cacoo • 2013 - • Typetalk (project leader)
  4. ψʔϥϘͷྺ࢙ 2004 2006 2010 2014 Nulab Backlog Cacoo Backlog API

    v2 Java Java / Seasar2 Java / Seasar2 Scala / Play2 Typetalk Nulab Account Java8 / Spring Nulab Status Go
  5. Seasar2 ͱͷܾผ • 2012 ೥ Typetalk ϓϩτλΠϓΛझຯͰ։࢝ • Seasar2 ϝϯςφϯεϞʔυ

    • RESTful/Web API/WebSocket ਐԽ͸ࢭ·Βͳ ͍ • ଞͷϑϨʔϜϫʔΫΛ୳͢͜ͱʹ
  6. ϑϨʔϜϫʔΫ୳ࡧ • Ruby on Rails • ੩తܕ෇͚ʹ׳Ε͖ͬͯ͠·͍ͬͯͨ • ࣗ෼Ͱϝϯς͠ଓ͚ΒΕΔࣗ৴͕ͳ͔ͬͨ •

    Spring Framework (Spring MVC / JAX-RS) • Seasar2 Λஔ͖׵͑Δʹ࠷దͰ͸͕͋ͬͨɺ෺଍Γ ͳ͕͋ͬͨ͞
  7. • Playframework 1 ͷ޷͖উख͞͸஌͍ͬͯͨ • Scala ΛϝΠϯͱͨ͠ Web ϑϨʔϜϫʔΫ •

    Playframework 2.0 ਖ਼ࣜϦϦʔε௚લ • ৽نϓϩδΣΫτͰࢼߦࡨޡ͠΍ܹࢗ͘͢త
  8. RESTful GET  /users/:id  controllers.UserController.find(id:  Long) object  UserController  extends  Controller  {

         def  find(id:  Long)  =  Action  {  implicit  request  =>          User.findById(id).map  {  user  =>              Ok(Json.obj(                  “id”  -­‐>  user.id,                  “name”  -­‐>  user.name              ))          }.getOrElse  {              NotFound(Json.obj(                  “message”  -­‐>  “User  not  found”              ))          }      }   } routes controller
  9. Hot Reloading • ։ൃ͕͠΍͍͢ • LL ͷੈքͰ͸౰ͨΓલ • dev ϞʔυͰແઃఆͰಈ࡞͢Δ

    • Seasar2 ಉ༷ ClassLoader Λࠩ͠ସ࣮͑ͯݱ • play.runsupport.Reloader (2.4.x)
  10. Type-safe View • HTML Λฦͯ͠ JSON Λऔಘ͢Δ࣌୅͚ͩΕͲ΋ • ܕͷߏ଄Λมߋͨ͠ΒΤϥʔʹͳΔ҆৺ײ •

    ϝʔϧςϯϓϨʔτʹ΋࢖༻Մ • HTML ίʔμʔʹͱͬͯ͸ਏ͍ @(account:  Account)   <span  class="name">@account.name</span>
  11. Type-safe Reverse Routing ϝιουͷγάωνϟ͕ มΘΕ͹ίϯύΠϧΤϥʔ GET  /users/:id  controllers.UserController.find(id:  Long) <a

     href=“@routes.UserController.find(user.id)”>@user.name</a> template routes val  url  =  routes.UserController.find(user.id) Scala
  12. Database Migration • ΞοϓάϨʔυ/μ΢ϯάϨʔυΛαϙʔτ • ίϚϯυΛೖྗ͢Δඞཁ͸ͳ͍ • ϖʔδΛϦϩʔυ͢Δ͚ͩ • ʮϚΠάϨʔγϣϯ࣮ߦ͍ͯͩ͘͠͞ʯ໰୊ճආ

  13. Database Migration

  14. Database Migration ϒϥϯνʹνΣοΫΞ΢τޙ ΞοϓάϨʔυ SQL ͕૸Δ ϒϥϯνΛ໭ͤ͹ μ΢ϯάϨʔυ SQL ͕૸Δ

  15. Database Migration • ϑΟʔνϟʔϒϥϯν։ൃͱ૬ੑ͕Α͍ • ϨϏϡʔΛؾܰʹߦ͑Δ • ϑΝΠϧ໊͸࿈൪Ͱ؅ཧ (n.sql) •

    Ϛʔδ͢Δͱ͖ʹίϯϑϦΫτΛىͤ͜Δ
  16. Playframework ໰୊఺

  17. ޓ׵ੑ໰୊ • มߋʹޙํޓ׵ੑ͕ͳ͘ͳΔ͜ͱ͕͋Δ • Ϧʔυίϛολʔ͕ James Roper ͞Μ (Typesafe) ʹ

    ͳͬͯྑ͍ํ޲ʹ޲͔͍ͬͯΔ • ৽͍͠όʔδϣϯ͕ग़ͨΒɺͱʹ͔͘௥ਵ • ࣗ෼ͨͪͰ޻਺Λ֬อͰ͖Δ͔Βɺ΍Γ΍͔ͬͨ͢
  18. Build front-end • Playframework 2.3 SBT Web • ඇެࣜ Plugin

    ͷΞοϓάϨʔυͷอোੑ • Grunt/Gulp ʹൺ΂Δͱຬ଍͍͔ͳ͔ͬͨ • ΤίγεςϜʹ৐Δ΂͘ Gulp ʹશ໘Ҡߦ
  19. Build front-end with SBT • PlayRunHook Λ࣮૷͢Δ͜ͱͰɺ SBT ͱ࿈ܞ͞ ͤͯɺىಈ࣌ʹ

    grunt/gulp Λ࣮ߦ • http://hakobe932.hatenablog.com/entry/ 2014/04/02/220457 • https://www.playframework.com/ documentation/2.4.x/SBTCookbook
  20. Scala Λ࢖ͬͯΈͯ

  21. Scala ΁ͷڵຯ Immutable Trait Pattern match Lazy evaluation Option Collection

    API JVM Future Lambda
  22. Option def  findLang(lang:  String):  Lang  =   supportLangs.find  {  l

     =>  l.code  ==  lang  }.getOrElse(english)   findLang(“ja-­‐JP”)   • NullPointerException ͷ࣮ߦ࣌ྫ֎͕ൃੜ͠ͳ͍ • Scala ͸ݩ͔Β Option ͕͋ΔઃܭͳͨΊɺ֤ϥ ΠϒϥϦ͕ Option Λฦͯ͘͠ΕΔ҆৺ײ
  23. case class case  class  User(id:  Long,  name:  String,  isAdmin:  Boolean)

      val  newUser  =  User(1L,  “yoshizawa”,  false)   val  updatedUser  =  newUser.copy(name  =  “tsuyoshizawa”) • σϑΥϧτͰಡΈऔΓઐ༻ϓϩύςΟ͕෇༩ • equals/hashCode/toString/copy … ϝιουΛੜ੒ • copy ͰݩͷΦϒδΣΫτΛഁյͤͣʹίϐʔ • pattern match ΁ద༻ՄೳʹͳΔ
  24. pattern match • Option ͷ matching Ͱ໢ཏ͞Εͯͳ͍৔߹͸ܯࠂ • ΦϒδΣΫτΛ෼ղͯ͠஋ΛऔΓग़͢͜ͱ͕Ͱ͖Δ findById(id)

     match  {      case  Some(user)  if  user.isAdmin  =>  “administrator”      case  Some(user)  =>  “normal  user”      //  case  _  =>  “guest  user”  warning!   }   val  r  =  “""(\d{4})-­‐(\d{2})-­‐(\d{2})""".r   “2015-­‐02-­‐22”  match  {      case  r(year,  month,  day)  =>  something(year,  month,  day)      case  _  =>  throw  new  Exception(“format  exception”)   }   if Ψʔυઅ͕͋Δ ৔߹͸ବ໨
  25. ࣮ߦ࣌ྫ֎͕ൃੜ͢Δέʔε • Java • ϓϩάϥϚʔ͕ྫ֎ͳ஋ (null) Λฦ͞ΕΔ͜ͱΛ ༧૝Ͱ͖ͳ͔ͬͨ • Scala

    • Option#get, List#head Λҙਤతʹݺͼग़͢ Scala Ͱهड़͢Δ͜ͱͰέΞϨεϛεΛݮΒͤΒΕΔ
  26. Self annotation • API ϑΝʔετͰ։ൃ • ॲཧ͸ڞ௨Խ͠ೝূΛ Web ͱ API

    Ͱ෼͚͍ͨ • ೝূॲཧΛ trait ʹ࣮૷͠ɺॊೈʹ૊ΈࠐΈ͕Ͱ͖ͨ trait  MessageController  extends  Controller  {      self:  Auth  =>      //  API  methods   }   object  MessageWebController  extends  MessageController  with  WebAuth   object  MessageApiController  extends  MessageController  with  APIAuth ೝূํࣜΛޙ͔Βܾఆ
  27. Scala ϥΠϒϥϦͷधཁ • Typetalk / Backlog API v2 API ެ։

    • ࣮૷࣌ʹ Scala ޲͚ͷ OAuth2 Provider ϥΠϒϥϦ ͕ͳ͔ͬͨ • Github ʹެ։ • https://github.com/nulab/scala-oauth2-provider
  28. OSS ʹͯ͠Έͯ • ӳޠͰެ։ͯ͠Α͔ͬͨ • ϑΟʔυόοΫΛ͘ΕΔਓ΋ඇӳޠݍ • ៉ྷͳӳޠͰ͋Δඞཁ͸ͳ͍ • ൓ڹʢϑΟʔυόοΫʣ͕͋Δͱخ͍͠

    • Awesome Scala ʹ΋ܝࡌͯ͠΋Β͑ͨ
  29. ӡ༻ • munin / Mackerel Λ࢖ͬͯ؂ࢹ • Java ͷӡ༻ࢿ࢈Λͦͷ··ར༻͢Δ͜ͱ͕Ͱ͖ͨ https://speakerdeck.com/nulabinc/

    java-8-falsehipumonitaringu Java 8 ͷώʔϓϞχλϦϯά
  30. Scala ໰୊఺

  31. όΠφϦޓ׵ੑ໰୊ • ϝδϟʔόʔδϣϯ͕มΘΔͱόΠφϦޓ׵ੑ͕ ͳ͘ͳΔ • ಛఆϥΠϒϥϦʹҾ͖ͣΒΕ Scala ͷϝδϟʔ όʔδϣϯΞοϓ͕؆୯Ͱͳ͍৔߹͕͋Δ (2.9

    - > 2.10 -> 2.11 ͱରԠ͖ͯͨ͠ʣ • ར༻͍ͯ͠ΔϥΠϒϥϦʹ PR Λग़͍ͯ͘͠ • Ұ࣌తʹΠϯϋ΢εϦϙδτϦʹ্͛ͨΓ΋
  32. ίϯύΠϧ଎౓໰୊ • ผϓϩδΣΫτɺαϒϓϩδΣΫτԽ • Α͍εϖοΫͷ PC Λߪೖ͠ʢͯ΋Β͍ʣ·͠ΐ͏ • ScalaDoc ͕͍Βͳ͍ϓϩδΣΫτͰ͋Ε͹

       sources  in  (Compile,  doc)  :=  Nil      publishArtifact  in  (Compile,  packageDoc)  :=  false build.sbt
  33. clean compile (౰ࣾൺ) 0 50 100 67s 90s MBA 11-inch

    Mid 2012 (2.0 GHz intel Core i7) MBP Retina 15-inch Early 2013 (2.7 GHz Intel Core i7) ։ൃ࣌͸ຖճΫϦʔϯίϯ ύΠϧ͢ΔΘ͚Ͱ͸ͳ͍ SBT ͕ࠩ෼ίϯύΠϧͯ͠ ͘ΕΔ
  34. Scala ͬͯ೉ͦ͠͏ • ࣮ϓϩδΣΫτൃ଍࣌ʹ Scala ະܦݧϝϯόʔ ͕ࢀՃ • better Java

    Ͱ։࢝ • Scala ͷΑ͍ػೳͱෳࡶ͞ͷόϥϯεΛऔΔ • ίʔυϨϏϡʔͰࢦఠ͢Δ • ྑॻΛखʹऔΔ
  35. ·ͱΊ • Playframework + Scala ʹΑͬͯҎલΑΓ΋Α͍։ൃ ؀ڥ͕खʹೖͬͨʢಛผͳઃఆͳ͠ʹʣ • Java ΑΓ΋ݎ࿚ͳϓϩάϥϛϯά͕Մೳ

    • Scala ʹܞΘͬͨ։ൃऀ͕ͭ͘Δ৽͍͠ΞϓϦ ʢπʔϧʣ͸ɺ Scala ͕બ͹ΕͯΔ • ։ൃνʔϜɺҊ݅ΛݟۃΊͯಋೖͰ͖Ε͹Α͍