株式会社インタースペース 沖本様 登壇資料
TRANSCRIPT
2015/10/06 株式会社インタースペース
沖本 勇矢
元々はSIerにてJava、C#を中心に開発
Scala歴はまだ数カ月の駆け出し
酒が大好き酒飲みエンジニア
沖本 勇矢(Yuya Okimoto)
Playframeworkとは
なぜPlayを選んだのか
環境構築方法
初歩的な使い方
弊社導入事例
バージョン2.4へアップデート
まとめ
ScalaとJava言語で書かれたオープンソースのWebアプリケーションフレームワーク
Ruby on Railsをご存じの方は、まさにそれと似た感じのMVCデザインパターン
Typesafe社がサポート(scala言語の開発を主導している企業)
※参照 https://www.playframework.com/
とにかく構築がかんたん(内蔵webサーバ、インメモリDB利用可)
シンプルで軽量(リソース消費が最小限)
scalaのwebフレームワークとしては一番メジャー
弊社の現行システムで使用しているJava以外にも、 scalaという技術的資産を残したかった
準備するもの
jdk8(事前にPATHは通しておく)
Typesafe activatorのダウンロード
https://www.playframework.com/download (任意のフォルダに解凍しておく)
事前にダウンロードして解凍したフォルダから、activator new <プロジェクト名> play-scala
C:¥Users¥public¥workspace>C:¥activator-1.3.5¥activator new sample-project play-scala
※Windowsの場合のパス表記ですが、コマンドはOSに差異はありません
ステップ1で作成されたプロジェクトフォルダに移動し、activator run
C:¥Users¥public¥workspace¥sample-project¥activator run
※Windowsの場合のパス表記ですが、コマンドはOSに差異はありません
ブラウザでhttp://localhost:9000でアクセス出来れば、環境構築完了です
※ただし初回は関連モジュールのDLで時間かかります
app → アプリケーションのソースコード(ここにすべてのソースコード配置) └ controllers → アプリケーションのコントローラ └ models → アプリケーションのビジネスロジック層 └ views → テンプレート build.sbt → アプリケーションビルドスクリプト conf → 設定ファイル └ application.conf → メイン設定ファイル └ routes → ルート定義 public → 公開アセット(静的なコンテンツはここに配置) └ stylesheets → CSS ファイル └ javascripts → JavaScript ファイル └ images → 画像ファイル project → sbt 設定ファイル └ build.properties → sbt プロジェクトの基本ファイル └ plugins.sbt → Play 自身の定義を含む sbt プラグイン lib → 管理されないライブラリ依存性 logs → デフォルトのログ保存場所 └ application.log → デフォルトのログファイル target → Play により生成されたファイル test → 単体テストや機能テストのソースフォルダ
controllerを作成
ビジネスロジックを作成(model)
テンプレートを作成(view)
作成したcontrollerと、紐づけるURLを設定ファイル(routes)に記述
今回はメッセージを表示するだけのごく簡単な一例
Playへのリクエストの玄関口 i18n対応の為、MessageApiをDIし、I18nSupportをmixin ※messagesを外部化しない場合は不要
package controllers import play.api._ import play.api.mvc._ import play.api.i18n._ import javax.inject._ import models.SampleModel class Application @Inject() (val messagesApi: MessagesApi) extends Controller with I18nSupport { def now = Action { Ok(views.html.now(SampleModel.getDateTime)) } }
ビジネスロジックを記述 ServiceやDAOを配置して処理を行う ルール的に必ずしも分ける必要はないが、modelとして 切り離すのが一般的
package models import org.joda.time.DateTime object SampleModel { def getDateTime(): DateTime = { DateTime.now } }
プレゼンテーションレイヤー 暗黙パラメータとしてMessagesを受け取る ※Messagesを使用しない場合は不要
@import org.joda.time.DateTime @(datetime: DateTime)(implicit messages: Messages) <div>@Messages("message.now")</div> <div>@datetime</div>
ルーティング処理の設定 この設定ファイルでURLとcontrollerを紐づけることで リクエストの受け付けを行う ※リバースルーティングも可能
# Home page GET / controllers.Application.now # Map static resources from the /public folder to the /assets URL path GET /assets/*file controllers.Assets.versioned(path="/public", file: Asset)
開発体制
人員:2名(内、協力会社1名)
期間:約5カ月
規模:10k弱(画面数で約30画面)
開発内容
広告関連データをセグメント化して管理するに当たり、マスタ登録、レポート表示といった機能を提供
※それほど大規模ではないアプリケーション(akka等の並行処理は行っていない)
今回弊社としては初めてscalaとplayへの挑戦だった為、
いくつか問題点が浮かび上がる
scala関数型プログラミングに難航
Playの効果的な使い方がわからない(どういう構築&開発方法がマッチベターなのか)
元々がJava使いだったので、どうしても関数型には
大きな戸惑いがあったが、その中で特に以下を
意識して実装した
型を有効利用する
→Typeやclassなどで定義しておく(コンパイルエラーで拾える)
副作用を避ける
→式を意識して、メソッドを実装するとreturnなども不要で簡潔に
グッバイvar
→immutableな実装に努める為、極力val変数を使用
ある程度の使い方はわかるのだが、
どういう構築&開発方法がマッチベターなのか?
とにかく公式ドキュメントを読み込む
→まずは基本はドキュメントが推奨している手法をベースにする
勉強会やセミナーに参加
→他社事例を参考にし、別のアプローチがないか検討
今回弊社では、外部の経験豊富なエンジニアに
参画して頂き、先ほどからお話した問題も含め、
技術支援を頂きながら、すべての課題を解決し、
無事に開発&構築を行うこともできた
→独学でやることも大事だが、やはり有識者は必要
特にライブラリ周りなどの助言は非常に助かった
構築が簡単で、モジュールのデプロイも楽
シンプルを謳っているだけあって、動作的には軽さを感じた
ただしその一方でコンパイルの時間は少し長く感じた
またはIDEにEclipseを使用していたが、プラグインが
事前コンパイルエラーを正しく検知しないなど、ちょっと使いづらさはあった(IntelliJも試したい所)
scalikejdbc(データベースアクセス)
play-flyway(データベースマイグレーション)
play2-auth(認証ライブラリ)
scalatest(テスト支援ツール)
scoverage(カバレッジ取得ツール)
scalaliform(ソースコードフォーマッタ)
当初は2.3.7で構築
今セミナーで何かしらの情報共有が出来るようにと、早めにバージョンアップ作業をしてみた
しかし、いきなりコンパイルエラーが500件以上出るなど、少し難航・・・
対応した内容を簡単にご紹介します
build.sbtの変更
あとはひたすら置換
routesGenerator := InjectedRoutesGenerator
object Login extends Controller { ↓ class Login extends Controller {
Messagesのインタフェースが変更になり、コンパイルエラーの原因はこれが9割だった
こちらはMessageApiのDIと、I18nSupportをmixinし、テンプレートの引数をLangからMessagesに変更
import play.api.i18n._ import javax.inject._ class Login @Inject() (val messagesApi: MessagesApi) extends Controller with I18nSupport {
2.4から非推奨になったGlobalSettingsで使用していたCSRFFilterを、 HttpFiltersに移行
package global import play.api.http.HttpFilters import play.filters.csrf.CSRFFilter import javax.inject.Inject class Filters @Inject() (csrfFilter: CSRFFilter) extends HttpFilters { def filters = Seq(csrfFilter) }
play.http.filters = "global.Filters"
application.confには以下を追記
plugInが非推奨になり、使用していた外部ライブラリのmodule化に伴い、application.conf変更
2.4対応のために更新しているライブラリも多い為、使用しているライブラリは漏れなくチェック
play.modules.enabled += "scalikejdbc.PlayModule" play.modules.disabled += "play.api.db.DBModule"
logger.xml→ logback.xmlの置き換え
application.confの設定値名変更(play.crypto.secret、play.i18n.langsなど)
controllers.Assets.at→controllers.Assets.versioned
play.PlayImport.PlayKeys.routesImport→ play.sbt.routes.RoutesKeys.routesImport
弊社システムで行った変更以外にも、数多くの 変更点があります。詳しくはマイグレーションガイドを 参照してください
とにかく、まずはマイグレーションガイドを穴があくまで読みましょう
それでもわからないor私のように英語の読解が不得意の方は、playのソースを見ましょう
※経験上、その方が解決が早い場合もありました
GithubのURL https://github.com/playframework/playframework
Play構築かんたん、シンプルで使いやすい
知識ゼロベースで作る場合、ごくごくシンプルなシステムなら問題ないが、凝ったことをする際は、無理せず有識者に知見を求めましょう(gitter等のコミュニティもあります)
これから導入する方でplay2.4を使う場合、ネットの情報が古い場合があるので、必ずバージョンを確認