Your SlideShare is downloading. ×
0
Skinny Framework
で始める Scala
瀬良 和弘
@seratch(_ja)
エムスリー株式会社
ソフトウェアエンジニア
日本 Skinny Framework ユーザ会
JJUG CCC 2014 Spring
2014/0...
私について
・本業は主に Web アプリ、バックエンド API 開発、社
内ツール諸々の運用整備の整備などに従事
・Scala は 2009 年に始めて触った(だけ)
・2011 年の正月休みから少しずつ使い始めた
・2011 - 2012 年...
今日は、JJUG の皆さんに
Scala を宣伝するために来ました。
Java から Scala へ!!(真顔)
!
Skinny Framework は
Java な現場、SI 業界の案件でも
十分使えるはずと思っています。
!
!
今日は私の話を聴いて
実際に使えそうか見極めてください。
!
!
- Scala について -
Scala のおさらい
・2003 年に生まれた比較的新しい言語
・オブジェクト指向と関数型プログラミングの融合
・スイス連邦工科大学教授 Martin Odersky
・2011 年に出資を受けて Typesafe 社を立ち上げ
・Types...
JJUG 的? Scala のメリット
・オブジェクト指向 + 関数型プログラミング
・静的型付け、型推論により記述の簡潔さを両立
・デフォルトが immutable な API
・並行処理、非同期プログラミングとの親和性
・JVM レベルの処...
JJUG 的? Scala のデメリット
・Java と比べてコンパイル時間が長い
・言語のバイナリ互換性などに対応する運用コスト
・Java エンジニアにとって意外にジャンプが大きい
・表現力の裏返しで OOP と関数型プログラミングが混在
...
Scala の互換性の件
・最新バージョンは 2.11.0
・2.10.0 ∼ 2.10.4 はバイナリ互換あり
・2.10.4 と 2.11.0 はバイナリ互換なし
・2.9 までは 2.9.x ごとに互換性がなかった(!)
・2.9(と 2...
- フレームワークの現状 -
Web フレームワーク事情
・長らく Lift ほぼ一択の時代(事例:4sq)
・2012 年春 Play Framework 2.0 が登場
・約 2 年経ち、現在は圧倒的に Play2 の人気が高い
・より軽量なフレームワークはいくつか現実...
DB ライブラリ事情
・あくまで目安として GitHub スター数で比較
・Slick (879)、Squeryl (358)、ScalikeJDBC
(254) がベスト 3、Slick は旧 ScalaQuery
・他には scala-ac...
テンプレートエンジン事情
・Scalate は長年メンテされており、SSP、Scaml、
Jade、Mustache と複数の文法が使える
・Play2 の Scala Template が最近独立(Twirl)
・Lift はタグを埋める独自...
- Skinny とは -
Skinny?
・響きもいいし、自然とこの名前を選びました、
一応 3 つの理由があります
!
・Application should be skinny
・Framework should be skinny
・ 好きに (su-ki-ni)
Skinny Framework
・2014/03/28 に 1.0.0 リリース(現在 1.0.14)
・Scala on Rails がキャッチコピー
・機能豊富なフルスタック Web フレームワーク
・MVC、ORM、DB マイグレーショ...
フルスタック?
・フルスタック Web フレームワークはもはや死語?
・定型な機能を提供するフレームワークが珍しくなくなり、
あえてアピールポイントとすることが少なくなった
・ライブラリを組み合わせること前提の開発は柔軟だが、
依存先が増えるリ...
Scala on Rails?
・それって Play2 のことではないの?(否)
・Play2 本体は HTTP 周り以外の機能をあまり持って
いない、今後も周辺を拡充するようには見えない
・Rails、Play1 のように HTML を返す ...
Skinny の構成
・極力自作を避け、実績があり、かつ Skinny の思想に
合うライブラリを土台とし、その上に作り込んでいる
・ルーティング、Servlet ラッパーのために Scalatra
・デフォルトテンプレートエンジンとして Sc...
- Skinny をはじめよう -
起動まで(1)
・必要なのは JDK(1.6 以上)のみ
・skinny-framework.org にある以下のダウンロー
ドボタンから約 80MB の zip ファイルをダウンロードし
てください
!
!
!
!
!
起動まで(2)
・zip ファイルを解凍して skinny run で起動
・ブラウザから localhost:8080 にアクセス
・Windows OS でも同じ手順です
!
!
!
!
!
!
起動まで(3)
・Skinny が推奨する sbt プロジェクトのひな形
・依存する jar がダウンロード済なので、初回起動時に
ダウンロード待ちをする必要がありません
・基本的な用途はデフォルトでカバーしているので最初か
ら sbt の設定...
- Skinny MVC -
・#set で request scope に設定した値は
controller/view から参照可能となります
・メソッドの戻り値が response body となります
!
!
!
!
!
!
最初の Controller(1)
// ...
・「Hello ${name}!」に「JJUG」が設定されました
!
!
!
!
!
!
!
!
最初の Controller(2)
! -# src/main/webapp/WEB-INF/views/root/index.html.ssp!...
・#set には様々な型の値を渡すことができます
・ここでは Scala のコレクションオブジェクトです
!
!
!
!
!
!
!
最初の Controller(3)
// src/main/scala/controller/RootCont...
・${numbers}」を使ったループと if 分岐の例です。
!
!
!
!
!
!
!
!
!
最初の Controller(4)
! -# src/main/webapp/WEB-INF/views/root/index.html.ssp...
・Scalatra が Servlet API の薄いラッパーとして簡
潔に記述できる DSL を提供しています
・例:status = 201, redirect(url), halt(400)
・どうしても必要になれば Servlet AP...
・Skinny の Routing は Scalatra の DSL を使いま
す(Routes という trait で少しだけ拡張)
・controller の実体は Filter/Servlet なので
ServletContext にひも...
・以下の場合 s.url(Controllers.root.indexUrl) で
実際の URL を取得できるので view template に
URL を直接書かずにすみます
!
!
!
!
!
!
最初の Routing(2)
! //...
・入力がある場合はバリデーション DSL を使います
・エラーの場合、エラーメッセージが request scope
に設定されるので入力フォームで表示するだけで OK
!
!
!
!
!
!
!
SkinnyValidator
! class...
・Scalate SSP(Scala Server Pages)の例は先ほ
どの Controller のところで少し触れました
・Scalate は SSP 以外に Scaml(≒Haml)、
Jade、Mustache もサポートしています...
・Scalate も Play2 の Twirl もテンプレートファイル
から Scala のソースコードを出力してコンパイルします
・メリットはコンパイラによるチェックがあること
・デメリットはコンパイル待ちが発生すること
・Skinny で...
・Skinny ORM を使って Rails ActiveRecord 的な
DB アクセスを行うモジュールの例を示します
・case class がエンティティで object が DAO です
!
!
!
!
!
!
最初の Model(1...
・Flyway を使った DB マイグレーションを使えばロー
カル開発用 DB を手軽に準備できます
!
!
!
!
!
!
!
最初の Model(2)
! ./skinny g migration createMember!
! // sr...
・これだけで各種 API をすぐに使えます
!
!
!
!
!
!
!
!
最初の Model(3)
! // Insert!
! val id: Long = Member.createWithAttributes('name -> “JJU...
・さらに country テーブルを追加して model を二つ
に増やして・・
!
!
!
!
!
!
!
最初の Model(4)
! case class Member(id: Long, name: Option[String])!
!...
・関連を持たせます
!
!
!
!
!
!
!
!
最初の Model(5)
! case class Member(!
! id: Long, !
! name: Option[String]!
! countryId: Option[Lon...
・#joins で設定した association を解決した query
を実行します
!
!
!
!
!
!
!
!
最初の Model(6)
! // Insert!
! val countryId: Long = Country.cre...
・#byDefault を指定すると #joins を呼ばなくても常
に join して取得します
!
!
!
!
!
!
!
!
最初の Model(7)
! case class Member(!
! id: Long, !
! name:...
・auto commit でよければ AutoSession ベースで
・トランザクションは ScalikeJDBC の機能を使うか 1
リクエスト 1 トランザクションでよければ、スレッドロー
カルに扱う TxPerRequestFilter...
・controller などからそのまま呼び出すだけ
・fat controller にならないように注意(controller
に一通り実装した後で service object としてまとめる、
model のインタフェースを先に決める)
...
・ここで示した例は最も規約に沿っているケースです
・ニッチなケースでは少し煩雑になる場合もあります
・最悪、泥臭く対応する場合 ScalikeJDBC を直接扱え
ば何でもできるので「詰む」ことはありません
・SkinnyModel の API...
FactoryGirl
・Ruby で人気の thoughtbot/factory_girl にイン
スパイアされたテスト用の DB データ生成ツール
・YAML ではなく typesafe-config の HOCON で
記述、Scala コ...
- Skinny その他の機能 -
最初の scaffold(1)
・CRUD 画面を生成するなら scaffold が便利です
・テストコードも生成されます
!
!
!
!
!
!
!
! ./skinny g scaffold members member name:Stri...
最初の scaffold(2)
! ./skinny db:migrate !
! ./skinnny run!
!
! ./skinny db:migrate test!
! ./skinny test
・バリデーションを含む入力フォームの自動生成
!
!
!
!
!
!
!
!
最初の scaffold(3)
・flash も動作する状態になっています
!
!
!
!
!
!
!
!
最初の scaffold(4)
・あらかじめ pagination も実装されています
!
!
!
!
!
!
!
!
最初の scaffold(5)
既存 DB から scaffold
・既存 DB から scaffold を生成します
・ID となる PK があることが前提です
!
!
!
!
!
!
!
! ./skinny g reverse-scaffold members memb...
・JavaMail をメソッドチェーンで簡潔に書けます
・Skinny 以外でも利用できます
!
!
!
!
!
!
!
!
SkinnyMailer
! val config = SkinnyMailerConfig.default.copy...
Assets(1)
・ローカル起動時に CoffeeScript、React JSX、
Scala.js、Sass、LESS を JS/CSS に変換
・Sass 以外は JVM だけでも動作するので Windows
マシンを使う開発プロジェク...
Assets(2)
・Scala.js、プロダクション利用可能な段階ではないで
すが、興味深いので触ってみてください
!
!
!
!
!
!
!
! ./skinny run!! ! ! // Terminal A!
! ./skinny sc...
デプロイ
・skinny package で war ファイルを生成
・package では全ての Scalate テンプレートをコンパ
イルするのでいつもアクセスしていないページのリンク切
れやエラーを検知できる場合もあります
・skinny...
- まとめと今後 -
Skinny の何が嬉しいか
・Play1/Rails 的なものが欲しいなら最適です
・全体的に Java での一般的なスタイルよりもほぼ本質
的なコードのみで簡潔に同じ機能を実装できます
・Skinny ORM + ScalikeJDBC は...
Reactive だけじゃない
・Scala 界隈では Akka のアクターモデルや非同期処理
が注目されることが多く、またそれが本流です
・一方で Ruby っぽいけど型検査のあるもの、Java と
の互換性があってより簡潔なものへの需要も相...
ロードマップ
・Skinny 1.1 - Scala 2.10/2.11 クロスビルドと各
種ライブラリメジャーバージョンアップ対応
・極力、基本的な機能の互換性を崩す予定はなく、開発者
が楽できるように細かい改善を続けていく予定です
・安定し...
Skinny コミュニティ
・日本 Skinny Framework ユーザ会
http://skinnyjp.doorkeeper.jp/
・Skinny Framework Meetup Tokyo というイベ
ントを先日初めて行い 25 ...
Skinny Framework
なかなかよさそうだと思った方?
!
メディアでの日本語のドキュメントなど
機会があればぜひやりたいです。
公式ドキュメントも協力者がいれば
日本語版をやれるかもしれません。
!
!
(時間があれば)質疑応答。
何でも聞いてください。
!
!
Upcoming SlideShare
Loading in...5
×

[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24

11,907

Published on

English version is here: http://www.slideshare.net/seratch/jjug-ccc-2014springeng

http://www.java-users.jp/?page_id=1048#R2-4

Published in: Technology
0 Comments
32 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
11,907
On Slideshare
0
From Embeds
0
Number of Embeds
18
Actions
Shares
0
Downloads
55
Comments
0
Likes
32
Embeds 0
No embeds

No notes for slide

Transcript of "[Japanese] Skinny Framework で始める Scala #jjug_ccc #ccc_r24"

  1. 1. Skinny Framework で始める Scala 瀬良 和弘 @seratch(_ja) エムスリー株式会社 ソフトウェアエンジニア 日本 Skinny Framework ユーザ会 JJUG CCC 2014 Spring 2014/05/18
  2. 2. 私について ・本業は主に Web アプリ、バックエンド API 開発、社 内ツール諸々の運用整備の整備などに従事 ・Scala は 2009 年に始めて触った(だけ) ・2011 年の正月休みから少しずつ使い始めた ・2011 - 2012 年、Akasaka.scala という勉強会 を隔週で主催していた(現在は休止中) ・社内外の Scala プロジェクトでメイン開発者として開 発している OSS を利用いただくようになってきた (ScalikeJDBC、Skinny Framework)
  3. 3. 今日は、JJUG の皆さんに Scala を宣伝するために来ました。 Java から Scala へ!!(真顔) !
  4. 4. Skinny Framework は Java な現場、SI 業界の案件でも 十分使えるはずと思っています。 ! !
  5. 5. 今日は私の話を聴いて 実際に使えそうか見極めてください。 ! !
  6. 6. - Scala について -
  7. 7. Scala のおさらい ・2003 年に生まれた比較的新しい言語 ・オブジェクト指向と関数型プログラミングの融合 ・スイス連邦工科大学教授 Martin Odersky ・2011 年に出資を受けて Typesafe 社を立ち上げ ・Typesafe 社は Scala の開発だけでなく sbt、 Akka、Play2、Slick、Spray 等のツール・ライブラ リのメンテナンス・商用サポートも提供 ・Rod Johnson 氏が Typesafe 社に参加し話題に
  8. 8. JJUG 的? Scala のメリット ・オブジェクト指向 + 関数型プログラミング ・静的型付け、型推論により記述の簡潔さを両立 ・デフォルトが immutable な API ・並行処理、非同期プログラミングとの親和性 ・JVM レベルの処理性能が期待できる ・Java で書かれた枯れた実装も流用できる ・大規模なプロダクション利用実績が多い ・GitHub 時代の言語、活気のあるコミュニティ
  9. 9. JJUG 的? Scala のデメリット ・Java と比べてコンパイル時間が長い ・言語のバイナリ互換性などに対応する運用コスト ・Java エンジニアにとって意外にジャンプが大きい ・表現力の裏返しで OOP と関数型プログラミングが混在 するなどスタイルが統一されない懸念がある ・Java と比べて、標準規格よりも動く OSS 実装がリー ドする世界なので、あまり受け身なスタンスだと難しい ・既に Scala を使いこなしているエンジニアの母数はま だまだ少なく、人材採用面での不安がある
  10. 10. Scala の互換性の件 ・最新バージョンは 2.11.0 ・2.10.0 ∼ 2.10.4 はバイナリ互換あり ・2.10.4 と 2.11.0 はバイナリ互換なし ・2.9 までは 2.9.x ごとに互換性がなかった(!) ・2.9(と 2.10 の一部)は Java8 で動作しない ・Maven でいう artifactId にバイナリバージョンが suffix としてつく(例:scalikejdbc_2.11) ・メンテされなくなったライブラリは新しいバイナリバー ジョンでビルドされなくなるので選定に注意が必要
  11. 11. - フレームワークの現状 -
  12. 12. Web フレームワーク事情 ・長らく Lift ほぼ一択の時代(事例:4sq) ・2012 年春 Play Framework 2.0 が登場 ・約 2 年経ち、現在は圧倒的に Play2 の人気が高い ・より軽量なフレームワークはいくつか現実的な選択肢が ある(Scalatra、Unfiltered、Spray など) ・Play2、Spray は現在 Typesafe 社のプロダクト ! ・2014 年春 Skinny Framework 1.0
  13. 13. DB ライブラリ事情 ・あくまで目安として GitHub スター数で比較 ・Slick (879)、Squeryl (358)、ScalikeJDBC (254) がベスト 3、Slick は旧 ScalaQuery ・他には scala-activerecord (164)、Activate (155)、SORM (124) など ! ・ScalikeJDBC は機能不足によって実務上困ることは ないが ORM よりもコード量は多くなりがち ・そこを埋めるのが Skinny ORM
  14. 14. テンプレートエンジン事情 ・Scalate は長年メンテされており、SSP、Scaml、 Jade、Mustache と複数の文法が使える ・Play2 の Scala Template が最近独立(Twirl) ・Lift はタグを埋める独自のやり方 ・Circumflex という Web フレームワークは FreeMarker の Scala 対応を実装(Skinny はこれ を fork して Scala 2.10 に対応させた) ! ・Skinny では Scalate を採用(理由は後ほど)
  15. 15. - Skinny とは -
  16. 16. Skinny? ・響きもいいし、自然とこの名前を選びました、 一応 3 つの理由があります ! ・Application should be skinny ・Framework should be skinny ・ 好きに (su-ki-ni)
  17. 17. Skinny Framework ・2014/03/28 に 1.0.0 リリース(現在 1.0.14) ・Scala on Rails がキャッチコピー ・機能豊富なフルスタック Web フレームワーク ・MVC、ORM、DB マイグレーション、メール送信 ・scaffold などの自動生成機能 ・Play2 と違い Servlet コンテナで動作 ・Java 1.6 以上、Servlet 3.0 以上 ・war、Jetty 埋め込み jar ファイル生成
  18. 18. フルスタック? ・フルスタック Web フレームワークはもはや死語? ・定型な機能を提供するフレームワークが珍しくなくなり、 あえてアピールポイントとすることが少なくなった ・ライブラリを組み合わせること前提の開発は柔軟だが、 依存先が増えるリスク、組み合わせの検証コストがある ・チーム開発の場合、ある程度やり方が決められている方 がありがたい場合も多い(もちろんチーム次第) ・よくある要件の実現に必要な時間は極力減らし、差別化 できる要件の開発にこそ時間を使いたい
  19. 19. Scala on Rails? ・それって Play2 のことではないの?(否) ・Play2 本体は HTTP 周り以外の機能をあまり持って いない、今後も周辺を拡充するようには見えない ・Rails、Play1 のように HTML を返す Web アプリ 開発の利便性に最適化しているわけではない ・Play2 は Rails 風味な記述で NIO ベースのサーバア プリを開発するためのフレームワーク ・JSON API サーバ、Akka の特長を活かしたアプリ ケーションなどに適している
  20. 20. Skinny の構成 ・極力自作を避け、実績があり、かつ Skinny の思想に 合うライブラリを土台とし、その上に作り込んでいる ・ルーティング、Servlet ラッパーのために Scalatra ・デフォルトテンプレートエンジンとして Scalate ・ORM の土台として ScalikeJDBC ・DB マイグレーションは Flyway ・JSON の処理に json4s ・入力バリデーション、メール送信はオリジナル ・後ほど、個別の機能を順次紹介します
  21. 21. - Skinny をはじめよう -
  22. 22. 起動まで(1) ・必要なのは JDK(1.6 以上)のみ ・skinny-framework.org にある以下のダウンロー ドボタンから約 80MB の zip ファイルをダウンロードし てください ! ! ! ! !
  23. 23. 起動まで(2) ・zip ファイルを解凍して skinny run で起動 ・ブラウザから localhost:8080 にアクセス ・Windows OS でも同じ手順です ! ! ! ! ! !
  24. 24. 起動まで(3) ・Skinny が推奨する sbt プロジェクトのひな形 ・依存する jar がダウンロード済なので、初回起動時に ダウンロード待ちをする必要がありません ・基本的な用途はデフォルトでカバーしているので最初か ら sbt の設定方法を学ぶ必要がありません ・skinny スクリプトだけで起動するので Jenkins で 動かす場合もセットアップは一切不要 ・2014 年時点で Scala は Eclipse ではなく IntelliJ IDEA 推奨(Community Edition で可)
  25. 25. - Skinny MVC -
  26. 26. ・#set で request scope に設定した値は controller/view から参照可能となります ・メソッドの戻り値が response body となります ! ! ! ! ! ! 最初の Controller(1) // src/main/scala/controller/RootController.scala! ! package controller! import skinny._! class RootController extends ApplicationController {! def index = {! set(“name”, “JJUG”)! render(“/root/index”)! }! }
  27. 27. ・「Hello ${name}!」に「JJUG」が設定されました ! ! ! ! ! ! ! ! 最初の Controller(2) ! -# src/main/webapp/WEB-INF/views/root/index.html.ssp! <%@val name: String %>! <h1>Hello, ${name}!</h1>
  28. 28. ・#set には様々な型の値を渡すことができます ・ここでは Scala のコレクションオブジェクトです ! ! ! ! ! ! ! 最初の Controller(3) // src/main/scala/controller/RootController.scala! ! package controller! import skinny._! class RootController extends ApplicationController {! def index = {! set(“numbers”, Seq(1,2,3,4,5))! render(“/root/index”)! }! }!
  29. 29. ・${numbers}」を使ったループと if 分岐の例です。 ! ! ! ! ! ! ! ! ! 最初の Controller(4) ! -# src/main/webapp/WEB-INF/views/root/index.html.ssp! ! <%@val numbers: Seq[Int] %>! #for (n <- numbers)! #if (n % 2 == 0)! ${n}! #end! #end!
  30. 30. ・Scalatra が Servlet API の薄いラッパーとして簡 潔に記述できる DSL を提供しています ・例:status = 201, redirect(url), halt(400) ・どうしても必要になれば Servlet API を直接使うこと も可能です(まずないとは思いますが) ・Servlet をある程度知っている人なら controller を 書く上でつまづくポイントは特にないはずです ! 最初の Controller(5)
  31. 31. ・Skinny の Routing は Scalatra の DSL を使いま す(Routes という trait で少しだけ拡張) ・controller の実体は Filter/Servlet なので ServletContext にひもづけるだけです ! ! ! ! ! 最初の Routing(1) ! // src/main/scala/controller/Controllers.scala! ! object Controllers {! ! object root extends RootController with Routes {! ! val indexUrl = get(“/“)(index).as(‘index)
 ! }! ! override def mount(ctx: ServletContext): Unit = {! ! root.mount(ctx)! ! }! ! }!
  32. 32. ・以下の場合 s.url(Controllers.root.indexUrl) で 実際の URL を取得できるので view template に URL を直接書かずにすみます ! ! ! ! ! ! 最初の Routing(2) ! // src/main/scala/controller/Controllers.scala! ! object Controllers {! ! object root extends RootController with Routes {! ! val indexUrl = get(“/“)(index).as(‘index)
 ! }! ! // 省略! ! }!
  33. 33. ・入力がある場合はバリデーション DSL を使います ・エラーの場合、エラーメッセージが request scope に設定されるので入力フォームで表示するだけで OK ! ! ! ! ! ! ! SkinnyValidator ! class MembersController extends ApplicationController {! ! protectFromForgery()! ! def createForm = validation(params,! ! paramKey(“name”) is required & maxLength(64),! ! paramKey(“email”) is email! ! )! ! def create = {! ! if (createForm.validate()) {! ! doCreate(params.permit(! ! “name” -> ParamType.String, “email” -> ParamType.String))
 ! } else {! ! render(“/members/input”)! ! }! ! }! ! }
  34. 34. ・Scalate SSP(Scala Server Pages)の例は先ほ どの Controller のところで少し触れました ・Scalate は SSP 以外に Scaml(≒Haml)、 Jade、Mustache もサポートしています ・SSP 以外を使う場合、拡張子を変えるだけで OK ・FreeMarker、Thymeleaf のサポートも拡張ライ ブラリとして提供していますが Scala の API に十分対 応できないケースがあります 最初の View(1)
  35. 35. ・Scalate も Play2 の Twirl もテンプレートファイル から Scala のソースコードを出力してコンパイルします ・メリットはコンパイラによるチェックがあること ・デメリットはコンパイル待ちが発生すること ・Skinny での Scalate は、ローカルデバッグでは precompile せずにこのデメリットを緩和し war 生成 時には precomile して、コンパイラチェックの恩恵を 受けるようにしています 最初の View(2)
  36. 36. ・Skinny ORM を使って Rails ActiveRecord 的な DB アクセスを行うモジュールの例を示します ・case class がエンティティで object が DAO です ! ! ! ! ! ! 最初の Model(1) ! sql”create table member (id serial, name varchar(64))”! ! ! .execute.apply()! ! ! ! // src/main/scala/model/Member.scala! ! case class Member(id: Long, name: Option[String])! ! ! object Member extends SkinnyCRUDMapper[Member] {! ! lazy val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member]) =! ! new Member(rs.get(m.id), rs.get(m.name))! ! }
  37. 37. ・Flyway を使った DB マイグレーションを使えばロー カル開発用 DB を手軽に準備できます ! ! ! ! ! ! ! 最初の Model(2) ! ./skinny g migration createMember! ! // src/main/resources/db/migration/V20140514141738__createMember.sql! ! // V20140514141738__createMember.sql に DDL を書く! ! ! // “development” ENV の DB! ! ./skinny db:migrate! ! ! // “test” ENV の DB! ! ./skinny db:migrate test
  38. 38. ・これだけで各種 API をすぐに使えます ! ! ! ! ! ! ! ! 最初の Model(3) ! // Insert! ! val id: Long = Member.createWithAttributes('name -> “JJUG")! ! // insert into member (name) values ('JJUG')! ! ! // Finder API! ! val ms: Seq[Member] = Member.findAll()! ! // select m.id as i_on_m, m.name as n_on_m from member m order by m.id;! ! ! // Querying API! ! val ms: Seq[Member] = Member.where(‘name -> “JJUG").apply()! ! // from member m where m.name = ‘JJUG'! ! ! // ScalikeJDBC QueryDSL! ! val m = Member.defaultAlias! ! val mopt: Option[Member] = Member.findBy(sqls.eq(m.name, "JJUG"))! ! // from member m where m.name = ‘JJUG'
  39. 39. ・さらに country テーブルを追加して model を二つ に増やして・・ ! ! ! ! ! ! ! 最初の Model(4) ! case class Member(id: Long, name: Option[String])! ! object Member extends SkinnyCRUDMapper[Member] {! ! lazy val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member] =! ! new Member(rs.get(m.id), rs.get(m.name))! ! }! ! ! // create table country(id serial, name varchar(128) not null);! ! object class Country(id: Long, name: String)! ! object Country extends SkinnyCRUDMapper[Country] {! ! lazy val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, c: ResultName[Country] =! ! new Country(rs.get(c.id), rs.get(c.name))! ! }
  40. 40. ・関連を持たせます ! ! ! ! ! ! ! ! 最初の Model(5) ! case class Member(! ! id: Long, ! ! name: Option[String]! ! countryId: Option[Long],! ! country: Option[Country] = None)! ! ! object Member extends SkinnyCRUDMapper[Member] {! ! val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member] =! ! new Member(rs.get(m.id), rs.get(m.name), rs.get(m.countryId))! ! ! val country = belongsTo[Country](Country, ! ! (member, country) => member.copy(country = country)! ! )! ! }
  41. 41. ・#joins で設定した association を解決した query を実行します ! ! ! ! ! ! ! ! 最初の Model(6) ! // Insert! ! val countryId: Long = Country.createWithAttributes('name -> “Japan”)! ! val id = Member.createWithAttributes(! ! ‘name -> “JJUG”, ‘countryId -> countryId)! ! ! // member だけ! ! val m = Member.findById(id)! ! // from member m where m.id = ?! ! ! // country も! ! Member.joins(Member.country).findById(id)! ! // from member m left join country c on m.country_id = c.id where m.id = ?!
  42. 42. ・#byDefault を指定すると #joins を呼ばなくても常 に join して取得します ! ! ! ! ! ! ! ! 最初の Model(7) ! case class Member(! ! id: Long, ! ! name: Option[String]! ! countryId: Option[Long],! ! country: Option[Country] = None)! ! ! object Member extends SkinnyCRUDMapper[Member] {! ! val defaultAlias = createAlias(“m”)! ! def extract(rs: WrappedResultSet, m: ResultName[Member] =! ! new Member(rs.get(m.id), rs.get(m.name), rs.get(m.countryId))! ! ! val country = belongsTo[Country](Country, ! ! (member, country) => member.copy(country = country)! ! ).byDefault! ! }
  43. 43. ・auto commit でよければ AutoSession ベースで ・トランザクションは ScalikeJDBC の機能を使うか 1 リクエスト 1 トランザクションでよければ、スレッドロー カルに扱う TxPerRequestFilter を使います ! ! ! ! ! ! 最初の Model(8) ! DB.localTx { implicit session =>! ! // このブロックから例外で抜けるときは全て自動 rollback される! ! Member.findById(id).map { member =>! ! member.copy(name = newName).save() // SkinnyRecord! ! MemberStatus.setAsActive(member)
 ! }.getOrElse {! ! val id = Member.createWithAttributes(‘name -> newName)! ! MemberStatus.addNewMemberAsActive(id)
 ! }! ! }
  44. 44. ・controller などからそのまま呼び出すだけ ・fat controller にならないように注意(controller に一通り実装した後で service object としてまとめる、 model のインタフェースを先に決める) ! ! ! ! ! ! 最初の Model(9) ! // src/main/scala/controller/MembersController.scala! ! ! import model.Member! ! class MembersController extends ApplicationController {! ! def showAll = {! ! set(“members”, Member.findAll())! ! render(“/members/showAll”)! ! }! ! }! !
  45. 45. ・ここで示した例は最も規約に沿っているケースです ・ニッチなケースでは少し煩雑になる場合もあります ・最悪、泥臭く対応する場合 ScalikeJDBC を直接扱え ば何でもできるので「詰む」ことはありません ・SkinnyModel の API を実装していれば Slick など 別の DB ライブラリによる実装でも scaffold の CRUD テンプレートに対応できます ・複数 DB 接続などよくあるケースは基本的に対応済です が、未対応のニーズがあれば気軽にリクエストをください 最初の Model(10)
  46. 46. FactoryGirl ・Ruby で人気の thoughtbot/factory_girl にイン スパイアされたテスト用の DB データ生成ツール ・YAML ではなく typesafe-config の HOCON で 記述、Scala コードも書ける ! ! ! ! ! ! member {! ! name=“JJUG”! ! luckyNumber="${scala.util.Random.nextInt(64)}"! ! } ! val member: Member = FactoryGirl(Member).create()! ! val member = FactoryGirl(Member).create(‘name -> “ScalaJP”)
  47. 47. - Skinny その他の機能 -
  48. 48. 最初の scaffold(1) ・CRUD 画面を生成するなら scaffold が便利です ・テストコードも生成されます ! ! ! ! ! ! ! ! ./skinny g scaffold members member name:String birthday:Option[LocalDate] active:Boolean! ! ! *** Skinny Generator Task ***! ! ! "src/main/scala/controller/ApplicationController.scala" skipped.! ! "src/main/scala/controller/MembersController.scala" created.! ! "src/main/scala/controller/Controllers.scala" modified.! ! "src/test/scala/controller/MembersControllerSpec.scala" created.! ! "src/test/scala/integrationtest/MembersController_IntegrationTestSpec.scala" created.! ! "src/test/resources/factories.conf" modified.! ! "src/main/scala/model/Member.scala" created.! ! "src/test/scala/model/MemberSpec.scala" created.! ! "src/main/webapp/WEB-INF/views/members/_form.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/new.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/edit.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/index.html.ssp" created.! ! "src/main/webapp/WEB-INF/views/members/show.html.ssp" created.! ! "src/main/resources/messages.conf" modified.! ! "src/main/resources/db/migration/V20140514173530__Create_members_table.sql" created.
  49. 49. 最初の scaffold(2) ! ./skinny db:migrate ! ! ./skinnny run! ! ! ./skinny db:migrate test! ! ./skinny test
  50. 50. ・バリデーションを含む入力フォームの自動生成 ! ! ! ! ! ! ! ! 最初の scaffold(3)
  51. 51. ・flash も動作する状態になっています ! ! ! ! ! ! ! ! 最初の scaffold(4)
  52. 52. ・あらかじめ pagination も実装されています ! ! ! ! ! ! ! ! 最初の scaffold(5)
  53. 53. 既存 DB から scaffold ・既存 DB から scaffold を生成します ・ID となる PK があることが前提です ! ! ! ! ! ! ! ! ./skinny g reverse-scaffold members members member! ! ! *** Skinny Reverse Engineering Task ***! ! ! Table : members! ! ID : id:Long! ! Resources : members! ! Resource : member! ! ! Columns:! ! - name:String:varchar(512)! ! - birthday:Option[LocalDate]! ! - createdAt:DateTime! ! - updatedAt:DateTime! ! ! *** Skinny Generator Task ***! ! ! "src/main/scala/controller/ApplicationController.scala" skipped.! ! "src/main/scala/controller/MembersController.scala" created.! ! "src/main/scala/controller/Controllers.scala" modified.
  54. 54. ・JavaMail をメソッドチェーンで簡潔に書けます ・Skinny 以外でも利用できます ! ! ! ! ! ! ! ! SkinnyMailer ! val config = SkinnyMailerConfig.default.copy(! ! // JavaMail, SMTP configuration ! ! )! ! val mailer = SkinnyMailer(config)! ! mailer! ! .to(“seratch@example.com”)! ! .cc(“users-ml@example.com”)! ! .subject(“JJUG CCC で登壇します!”)! ! .body {“””瀬良です。! ! |今度の日曜日に JJUG CCC 2014 Spring で Skinny について! ! |お話しさせていただくことになりました。! ! |”””.stripMargin}! ! .deliver()
  55. 55. Assets(1) ・ローカル起動時に CoffeeScript、React JSX、 Scala.js、Sass、LESS を JS/CSS に変換 ・Sass 以外は JVM だけでも動作するので Windows マシンを使う開発プロジェクトにも導入しやすいです ・Source Maps にも対応(要 native compiler) ・src/main/webapp/WEB-INF/assets/coffee の下の CoffeeScript は src/main/webapp/ assets/js にある JS としてアクセスできます ・本番では出力された JS/CSS ファイルを使います
  56. 56. Assets(2) ・Scala.js、プロダクション利用可能な段階ではないで すが、興味深いので触ってみてください ! ! ! ! ! ! ! ! ./skinny run!! ! ! // Terminal A! ! ./skinny scalajs:watch! // Terminal B! ! vim src/main/webapp/WEB-INF/assets/scala/Sample.scala! // Terminal C
  57. 57. デプロイ ・skinny package で war ファイルを生成 ・package では全ての Scalate テンプレートをコンパ イルするのでいつもアクセスしていないページのリンク切 れやエラーを検知できる場合もあります ・skinny package:standalone は java -jar で Web サーバとして起動可能な jar を生成します ・Heroku などの PaaS へのデプロイも可能です ! ! ! ./skinny package! ! ./skinny package:standalone
  58. 58. - まとめと今後 -
  59. 59. Skinny の何が嬉しいか ・Play1/Rails 的なものが欲しいなら最適です ・全体的に Java での一般的なスタイルよりもほぼ本質 的なコードのみで簡潔に同じ機能を実装できます ・Skinny ORM + ScalikeJDBC は Java では実装 できない利便性・柔軟性を提供しています ・Scala での開発のボトルネックはコンパイル時間、周 辺ツールや流儀の学習コストと考え、それらを解決・軽減 して現実解を提案したいと思っています(そして、ある程 度は示せたと思っています)
  60. 60. Reactive だけじゃない ・Scala 界隈では Akka のアクターモデルや非同期処理 が注目されることが多く、またそれが本流です ・一方で Ruby っぽいけど型検査のあるもの、Java と の互換性があってより簡潔なものへの需要も相当あると思っ ています(少なくとも私はそれも欲しい) ・Skinny(Scalatra)と Akka を組み合わせたり 非同期処理を実装することも問題なくできますが、フレー ムワークが提供する機能はいわゆる Better Java 的な 利便性を重視しています
  61. 61. ロードマップ ・Skinny 1.1 - Scala 2.10/2.11 クロスビルドと各 種ライブラリメジャーバージョンアップ対応 ・極力、基本的な機能の互換性を崩す予定はなく、開発者 が楽できるように細かい改善を続けていく予定です ・安定して使っていただけるようにプロジェクトをハンド ルしていきたいと思っています ・Scalatra 側で NIO なチャレンジも続けているような ので、こちらが実用段階になってきたら Skinny でも何 かできるかもしれません
  62. 62. Skinny コミュニティ ・日本 Skinny Framework ユーザ会 http://skinnyjp.doorkeeper.jp/ ・Skinny Framework Meetup Tokyo というイベ ントを先日初めて行い 25 名の方々にご参加いただきまし た、定期的に開催したいと思っています ・Tokyo 以外でも Meetup やりたいです ・Google Group に ML があります(英語) ・何かあればお気軽に Twitter で @seratch_ja や @skinny-framework(英語)まで
  63. 63. Skinny Framework なかなかよさそうだと思った方? !
  64. 64. メディアでの日本語のドキュメントなど 機会があればぜひやりたいです。 公式ドキュメントも協力者がいれば 日本語版をやれるかもしれません。 ! !
  65. 65. (時間があれば)質疑応答。 何でも聞いてください。 ! !
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×