Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scala In Perl Company

Scala In Perl Company

10年あまりPerlを利用してきたはてなが、なぜ新たな開発言語としてScalaを選択したのかや、言語の変化が開発フローにどのような影響あたえたのかについて解説します。Scalaの言語自体にフォーカスするのではなく、Webアプリケーション開発にScalaを採用したメリットやデメリットを、Perlと比較しながら、Perlエンジニアの体験を通じて紹介します。

hakobe (Yohei Fushii)

August 29, 2014
Tweet

More Decks by hakobe (Yohei Fushii)

Other Decks in Technology

Transcript

  1. hakobe hakobe932.hatenablog.com twitter.com/hakobe github.com/hakobe - 2008 ͸ͯͳΠϯλʔϯ - 2008 ~

    ͸ͯͳΞϧόΠτ - 2010 ~ ͸ͯͳΤϯδχΞ … → Hatena::Bookmark → Portal
 → Hatena::Blog → Mackerel
  2. • ػೳ௥Ճ • ϦχϡʔΞϧ • όάϑΟοΫε • ηΩϡϦςΟ • ύϑΥʔϚϯεվળ

    • ֎෦มԽ΁ͷରԠ • ϦϑΝΫλϦϯά • ϥΠϒϥϦߋ৽ Ձ஋ΛੜΈग़͠ଓ͚Δʹ͸? ιϑτ΢ΣΞਐԽΛܧଓ͢Δ͜ͱ͕ॏཁ
  3. _人人人人人人人人人_ >�必須パラメータ忘れ�< ‾Y^Y^Y^Y^Y^Y^Y^Y‾ Use of uninitialized value in concatenation (.)

    or string at error.pl line 20. my $entry = Entry->new({ title => "hello, yapc", }); print("title: " . $entry->title); print("content:\n" . $entry->content); ΤϥʔͰ͸ͳ͍͕༧ظ͠ͳ͍ৼΔ෣͍
  4. Can't locate object method "scheme" via package
 "http://www.hatena.ne.jp"
 (perhaps you

    forgot to load "http://www.hatena.ne.jp"?)
 at error.pl line 13. sub check_url { my $url = shift; ! ... } check_url(“http://www.hatena.ne.jp") # ݩʑͷҙਤ check_url(URI->new(“http://www.hatena.ne.jp")) #ۮવಈ͘ sub check_url { my $url = shift; if ($url->schema eq 'https') { ... } Ҿ਺͸จࣈྻͷ͸͕ͣɺۮવ63*ΦϒδΣΫτͰ΋࢖͑ͨ _人人人人人人人人人人人_ >�$urlのメソッド呼び出し�< ‾Y^Y^Y^Y^Y^Y^Y^Y^Y‾ צҧ͍ͨ͠ਓ͕ʜ
  5. _人人人人人人人人人_ >�衝突に気づかずマージ�< ‾Y^Y^Y^Y^Y^Y^Y^Y‾ Can't locate object method "retrieve_by_id" via package

    "Entry" at error.pl line 21. Entry->retrieve_by_id(10); Entry->retrieve(id => 10); Entry->retrieve_by_id(20); Entry->retrieve_by_id(30); "͞Μ͕
 ϦϑΝΫλϦϯά #͞Μ͕
 ݺͼग़͠௥Ճ
  6. ‣ ྑ͍ - ඇৗʹߴػೳͳ੩తͳܕγεςϜ - ঢ়ଶ͕ͳ͍ϐϡΞͳੈք ‣ ͭΒ͍ - ࣾ಺ʹॻ͚Δਓ͕গͳ͍=νʔϜ࡞Εͳ͍

    ΑΖ͍͠ɺͳΒ͹Haskellͩ ϦʔυΤϯδχΞ͕)BTLFMMϑΝϯͳͷͰ
 ݁ߏՄೳੑ͸͋ͬͨ
  7. Scalaͷίʔυͷ༷ࢠ object Hello extends App { for( i <- 0

    to 100 ) { println(message(i)) } ! def message(n: Int): String = if ( n % 7 == 0) { "lucky!" } else { "Hello, world!" } }
  8. ୅਺తσʔλܕΛఆٛͰ͖Δ • ୅਺తૢ࡞ʹΑͬͯఆٛ͞ΕΔܕ • ௚࿨ܕ΍௚ੵܕͷ૊Έ߹Θͤ • Option/Either/Try/List/Map ! • ྫ:ଘࡏ͠ͳ͍͔΋͠Εͳ͍஋(Option)

    val opt1: Option[Int] = Some(100) val opt2: Option[Int] = None opt1 match { Some(value) => s"value is $value !!" None => "no value" } VOEFGνΣοΫΛܕͰڧ੍
  9. 100ΑΓখ͞ͳϑΟϘφον਺ - Perl my @nums = grep { $_ <

    100 } map { fib($_) } (0..30); ! sub fib { my $n = shift; return ($n == 0 || $n ==1) ? 1 : fib($n - 2) + fib($n - 1); }
  10. 100ΑΓখ͞ͳϑΟϘφον਺ - Scala val nums = (0 to 30) .map(

    fib(_) ) .filter( _ < 100) ! def fib(n: Int): Int = n match { case 1 | 0 => 1 case m => fib(m - 2) + fib(m - 1) } 1FSMͱൺֱͯ͠΋ಉ౳ʹγϯϓϧ
  11. ܕਪ࿦ʹཔΒͳ͍৔߹ val nums: Seq[Int] = (0 to 30) .map[Int, Seq[Int]]({

    n: Int => fib(n) }: Int => Int) .filter({ n :Int => n < 100}: Int => Boolean) ! def fib(n: Int): Int = n match { case 1 | 0 => 1 case m: Int => fib(m - 2) + fib(m - 1) } • ↑͋͑ͯͰ͖Δ͚ͩܕ஫ऍΛ௥Ճͯ͠Έͨ
  12. Scalaͳཧ༝(3) • Javaͷ࣮੷ͷ͋ΔϥΠϒϥϦ͕ॆ࣮ • ྫ:σʔλϕʔευϥΠό, ωοτϫʔΫ • Scala޲͚ͷϥΠϒϥϦ΋։ൃ͕ΞΫςΟϒ • PlayFramework/Scalatra/Skinny

    • Slick/ScalikeJDBC ! • ಋೖࣄྫͷ૿Ճ • Twitter/dwango/GREE/CyberAgent ๛෋ͳϥΠϒϥϦ Web։ൃͷ࣮੷
  13. • Play Framework 2 • MVC WebϑϨʔϜϫʔΫ • ܕ҆શ/εςʔτϨε •

    ϞδϡϥϦςΟ͕ߴ͍ • Model΍ViewΛ؆୯ʹ੾Γସ͑ΒΕΔ WebΞϓϦέʔγϣϯϑϨʔϜϫʔΫ IUUQXXXQMBZGSBNFXPSLDPN
  14. ίϯτϩʔϥͷྫ package controllers // Ұ෦ུ object Application extends Controller {

    def index = Action { val message = "Hello, Play framework!!!" val langs = Seq("Perl", "Scala", "Go") Ok(views.html.index(message, langs)) } } GET / controllers.Application.index GET /list controllers.Application.list POST /create controllers.Application.create SPVUFT "QQMJDBUJPOTDBMB
  15. • twirl - Play෇ଐͷςϯϓϨʔτΤϯδϯ ϏϡʔͷϨϯμϦϯά @(message: String, langs: Seq[String]) <!DOCTYPE

    html> <html> <body> <h1>@message</h1> <ul> @for( lang <- langs ) { <li>@lang</li> } </ul> </body> </html>
  16. ίϯτϩʔϥͷྫ: ϑΥʔϜΛॲཧ def create2 = DBAction { implicit rs =>

    val form = Form( tuple( "title" -> nonEmptyText, "content" -> nonEmptyText ) ) ! form.bindFromRequest().fold( formWithErrors => { BadRequest("has form error") }, values => { Entries.create(values._1, values._2) Redirect(controllers.routes.Application.list) } ) } } GPSNͷ஋ͷ ܕΛࢦఆ JNQMJDJUͳϦΫΤε τ͔Β஋ΛCJOE
  17. def create2 = DBAction { implicit rs => val form

    = Form( tuple( "title" -> nonEmptyText, "content" -> nonEmptyText ) ) ! form.bindFromRequest().fold( formWithErrors => { BadRequest("has form error") }, values => { Entries.create(values._1, values._2) Redirect(controllers.routes.Application.list) } ) } } ίϯτϩʔϥͷྫ: ϑΥʔϜΛॲཧ ஋͕औΓग़ͤΔ͔Ͳ͏ ͔ʹԠͨ͡ॲཧ ಘΒΕͨσʔλͰॲཧ ϦμΠϨΫτ શମͷฦ٫஋͸3FTVMUܕ
  18. • Slick • Functional Relational Mapping • ScalaͷίϨΫγϣϯૢ࡞ͷΑ͏ͳίʔυͰ
 SQLΛൃߦ (ܕ҆શੑΛߟྀ)

    • SQLΛ௚઀ॻ͘͜ͱ΋Ͱ͖Δ • ։ൃ͕ΞΫςΟϒ(TypeSafeࣾ) σʔλϕʔεΞΫηε IUUQTMJDLUZQFTBGFDPN
  19. Slick: ςʔϒϧͷఆٛ: SQL CREATE TABLE entries ( id bigint(20) NOT

    NULL AUTO_INCREMENT, title varchar(255) NOT NULL, content text NOT NULL, PRIMARY KEY (id) );
  20. Slick: ςʔϒϧͷఆٛ: Scala case class Entry( id: Option[Int],ɹtitle: String, content:

    String) ! object Tables { class Entries(tag: Tag) extends Table[Entry](tag, "entries") { def id = column[Int]("id", O.PrimaryKey, O.AutoInc) def title = column[String]("title") def content = column[String]("content") def * = (id.?, title, content) <> (Entry.tupled, Entry.unapply) } val entries = TableQuery[Entries] } 4DBMBͱ֎քͷ઀఺Ͱ͸ ͘Θ͘͠ܕΛॻ͘
  21. Slick: SQLͷൃߦ: SELECT val query = for ( entry <-

    Tables.entries ) yield entry query.sortBy(_.id.desc).take(10).list SELECT * FROM entries ORDER BY id DESC LIMIT 10 • Scala ͷ for จͷৼΔ෣͍͸flatMap/ map/filterϝιουͳͲͷ࣮૷ʹґଘ
  22. Slick: SQLͷൃߦ: UPDATE val query = for ( entry <-

    Tables.entries if entry.id === id ) yield (entry.title, entry.content) query.update(title, content) UPDATE entries SET title = ?, content = ? WHERE id = ?;
  23. Slick: SQLͷൃߦ: DELETE val query = for ( entry <-

    Tables.entries if entry.id === id ) yield entry query.delete DELETE FROM entries WHERE id = ?;
  24. • Play FrameworkͷϩʔΧϧ։ൃ
 αʔόػೳΛ׆༻ • ϑΝΠϧߋ৽Ͱαʔό࠶ಡΈࠐΈ • sbt: Scala Build

    Tool Ͱ࣮ߦ ϩʔΧϧͰͷ։ൃ $ sbt #ϏϧυπʔϧΛৗறىಈ > compile > test > run # localhostͰαʔό͕ىಈ
  25. ։ൃऀͷ؀ڥ 04 ΤσΟλ Ϗϧυͷ࣮ߦ IBLPCF .BD *OUFMMJ+  *EFB7JN TCU

    "͞Μ .BD *OUFMMJ+  *EFB7JN TCU #͞Μ .BD  -JOVY 7. &NBDT TCU $͞Μ 8JOEPXT  -JOVY 7. &NBDT TCU *%&ͷར༻͸ඞਢͰ͸ͳࣗ͘༝ʹ։ൃ
  26. • JenkinsΛར༻ • ςετͱϏϧυ • Ϗϧυ: ຊମ/ϥΠϒϥϦ/ىಈεΫϦϓτΛ
 ؚΜͩJARϑΝΠϧΛ࡞੒͢Δ • ฒྻ࣮ߦͯ͠ߴ଎Խ

    • Gitͱ࿈ܞͯࣗ͠ಈ࣮ߦ • feature branch: pushͰςετ • staging/master: 
 pushͰςετ&Ϗϧυ&։ൃαʔόʹσϓϩΠ ςετͱϏϧυ
  27. • σϓϩΠ • CapistranoʹखΛ͍Εͯར༻ • Jenkins͕࡞ͬͨϏϧυ(JARϑΝΠϧ)Λ scpͰσϓϩΠର৅ͷαʔό܈ʹίϐʔ • αʔόͰͷಈ࡞ •

    JARϑΝΠϧΛdaemontoolsͰ࣮ߦ • JVMͷىಈ͕஗͍ͨΊ
 Ұ౓ʹ࠶ىಈ͸ͤͣҰ୆ͣͭ σϓϩΠ
  28. • ίʔυͷมߋ΍͕҆৺ • มߋͨ͠ΒίϯύΠϧ͕௨Δ·Ͱमਖ਼ • ໊લ΍γάχνϟͷมߋ࿙Ε͕ͳ͍͜ͱ͕࣮֬ʹ Θ͔Δ • ϨϏϡʔ͕҆৺ •

    มߋ࿙Εͷ৺഑͕ͳ͍ͷͰػೳʹूத • ॊೈͰߴػೳͳจ๏ • ॻָ͍͍ͯͯ͠/TIMOTWTDIײ͕͋Δ • ؔ਺ܕϓϩάϥϛϯάٕज़Λ׆༻Ͱ͖Δ Scalaͷίί͕࠷ߴ
  29. • Mackerel: ϑϧίϯύΠϧ3෼ʙ • ීஈͷ։ൃ͸ࠩ෼ίϯύΠϧ • ϒϥϯνΛ੾Γସ͑Δͱ… • ։ൃͷϦζϜ͸มԽ •

    ίϯύΠϧதʹίʔυಡΉ/ϨϏϡʔ • ߴ଎Խͷ༨஍͸͋Δ • Ϟδϡʔϧ෼ׂ/ฒྻԽ • ଎͍ϚγϯΛങ͏ ίϯύΠϧ͕࣌ؒ௕͗͢Δ
  30. • ͔֬ΊΔର৅͕ҧ͏ • ςετ: ϓϩάϥϜͰॻ͚ΔൣғͳΜͰ΋ • ܕ : ܕͰදݱͰ͖Δൣғ !

    • ͔֬ΊΔࣄ࣮͕ҧ͏ • ςετ:ظ଴Ͳ͓ΓϓϩάϥϜ͕ಈ͘͜ͱ • ܕ :Τϥʔ͕ଘࡏ͠ͳ͍͜ͱ ςετ͕͋Ε͹ܕ͸ෆཁ?