解剖!シェアウィズPlayプロジェクトを構成するライブラリ

こんにちは。
@kuchitamaことシェアウィズエンジニアの国平です。

僭越ながら、Scalaアドベントカレンダー in Adventarのトップバッター! 1日目の記事を担当いたします。
Qiita版の1日目の記事はjwhacoさんのScala が解決できる Android アプリ開発の問題領域について – 非同期処理編です。

先日の本ブログの記事でシェアウィズではScala/PlayFrameworkを導入して新プロジェクトの開発を行っていることをご紹介しました。
シェアウィズの文化とScala
シェアウィズの文化とScala
今回の記事では、Scala/Play2の開発に利用したライブラリなどをご紹介しようと思います。
アドベントカレンダー初日なので、あまりハードルを上げすぎずに、これからScala/PlayをつかってWebサービスを開発しようという方に向けて、どういったライブラリが採用されているのかを軽くご紹介しようと思います。

また、調子に載ってアドベントカレンダーの火曜日を全予約してしまったので、今後のブログで個々のライブラリについても機会があれば触れていこうと思っています。

紹介するライブラリ

  • 認証ライブラリ: play2-auth
  • DBアクセスライブラリ: Slick3
  • Cacheライブラリ: scalacache
  • Jsonライブラリ: skinny-json
  • テンプレートエンジン: twirl
  • その他ライブラリ: Scalaz
  • デプロイツール: Capistrano3
  • プロビジョニングツール: Ansible

システムの全体像

まずは、今回開発しているプロジェクトの全体像です。
ざっくりとこのような構成になっています。

Overview
この構成は、とくに珍しいものではなく、Play2に限らず標準的なWebサービスの構成になっています。
更に、Playプロジェクト内は、このような構成となっています。(矢印はデータの流れです)

APIサーバ (1)

今回の記事では、上図のライブラリといくつかのツールを紹介します。

利用ライブラリ

それでは、PlayFrameworkで採用しているライブラリについていくつかご紹介していきます。
採用理由と実際に使ってみた雑感をそれぞれにご紹介していきます。

認証

今回のプロジェクトでは認証周りの実装に、 play2-authというライブラリを利用しました。

play2-authはScalaMatsuriでCFP投票最多得票数に輝いたがくぞさんによるPlayFramework2用の認証/認可モジュールです。

採用理由はPlay2のバージョンアップに充分追従していること、ドキュメントが日本語/英語両方共に充実していること、そしてがくぞ先生の作であること等です。

実際に使った感想ですが、ドキュメントがしっかりしているので導入にはそれほど困りませんでした。
ただ、今回のプロジェクトでは認可の機構は必要なく、認証だけで良かったのですが、設計に認証/認可の考え方が根付いているので、その辺りの理解が必要になるかもしれません。
それほど難しいことではないのですが、oauthについてのドキュメントを一読しておいて認証と認可の違いや使い分けをある程度把握しておいたほうがスムーズに導入できそうです。

DBアクセスライブラリ

データベースへのアクセスにはSlick3を採用しました。
採用理由としては、 ScalaやPlayFrameworkを開発しているTypesafe社製でPlay2向けのライブラリも提供されていることが挙げられます。また、非常に強く関数型プログラミングの思想が反映されているので、関数型のパラダイムを身につけるのにも良さそうだと感じて採用しました。また、Scala関西Summitではてなさんの発表を聞いて実用できる感触を得られていたということもあります。

使ってみた感想としては、 takezoeさんもブログ記事にされているのですが、トランザクションの制御が独特なので、設計レベルでトランザクション制御の設計を考える必要がありました。
かなり関数型プログラミングの思想が強いので、関数型プログラミングに対する知識がないと利用するのは難しいように感じました。
Scala関数型デザイン&プログラミング辺りを一通り読んでおくと良いのではないかと思いますが、シンプルにデータベースにアクセスしたいということであれば、ScalikeJDBCなど他のライブラリを採用してもいいと思います。

また、日付型を扱う際に、java.util.Dateはいろいろと扱いにくい場合が多いので、@tototoshiさんが公開されている slick-joda-mapperを利用しています。
もしSlickを使っていて日付型を多く扱う場合は、是非導入を検討してみてください。

Cacheライブラリ

Slick3には、キャッシュ機構が含まれていません。これは、関数型の思想が強く反映されているためで、キャッシュは副作用を引き起こすものとして、あえてSlick3の設計から排除されています。
しかし、サービスのパフォーマンスなどを考えると、マスタデータなどはキャッシュさせたい場合があります。

Play2自体も標準でEhcacheを利用することができるのですが、標準のキャッシュ機構を利用した場合、キャッシュキーの管理が必要になります。
キーを手動管理するのは面倒なので Chris Birchallさんのscalacacheを利用しました。

採用理由としては、前述のキャッシュキーの管理を自動化できる点と、以前にskinny-frameworkのissueで名前が挙がっていたという点があります。

使ってみた感想ですが、最初の導入は少しややこしい実装が必要になりました。
PlayFrameworkがEhcacheをラップしたAPIを提供しているのですが、scalacacheを利用するには、ラップされたEhcacheのインスタンスを取り出してscalacacheに渡す必要があり、PlayFraameworkのCacheAPIの実装を読みながら対応を行いました。
利用できるように組み込みさえしてしまえば、とても便利なのですが、組み込みのところがややこしいので、注意が必要だと思います。

Jsonライブラリ

Jsonの利用にはskinny-jsonを利用しました。
skinny-jsonはjson4sのラッパーなのですが、扱うのが簡単でシンプルなことをやるために、最小限のシンプルな実装で実現することが出来ます。
skinny-frameworkは、フルスタックのWebフレームワークですが、個々の機能がライブラリとして切り出されているので、必要な部分だけ使うことができるので非常に便利です。
PlayFrameworkを利用する人も、skinny-frameworkの機能は一通り抑えておくといいでしょう。

使ってみた感想としては、何も困らずシンプルにやりたいことを実現できたという、既に述べた通りの感想に尽きます。
複雑なJsonを扱う必要がないのであれば、ぜひご利用頂きたいライブラリとしておススメします。

テンプレートエンジン

HTMLを吐き出すテンプレートエンジンにはPlay標準となっているtwirlを利用しました。
採用理由は、特に目立ったものではなくPlay標準だから利用しています。

使ったメリットとしては、型安全にテンプレートエンジンがかけるところと、標準に含まれているだけあって、PlayのFormと相性がよく、使いやすいという点がありました。

その他

Scalaz

Scalazはscala上で、より関数型プログラミングを行いやすくするライブラリです。
非常に多くの機能が含まれていて私も本当に一部の機能しか利用できていませんが、非常に便利に利用できています。

Scalazを採用した理由としては、Slick3を利用していると、FutureとOption/Listが入れ子になってしまうことが多々あります。
その際に、なるべくFutureの処理をブロックせずに処理を繋げたいので、Scalazを導入しました。

具体的な使い方は@xuwei-kさんのScalaで、FutureやOptionやListがネストしてしまったときに、いい感じに変換する方法を参照してもらえると良いと思います。
ここで紹介されているsequenceを使い始めてから、scalazを手放すことができなくなりました。

APIドキュメンテーション

今回のプロジェクトでは、サーバサイドは一部を除いて基本的にはスマートフォンアプリのAPIサーバとして実装されています。
そのため、アプリエンジニアにAPI仕様をドキュメント化してコミュニケーションをする必要がありました。

今回は、SwaggerがPlayに対応していたのでSwaggerを使いました。
基本的にJavaアノテーションベースで仕様を書いていくことになるので、少しScalaっぽさが損なわれますが、充分な機能でアプリエンジニアとのコミュニケーションを手助けしてくれました。

ただ、問題点としてはPlay2.4の対応が Swagger公式リポジトリでは追いついておらず、フォークされたPlay2.4向けの実装を利用する必要がありました。
また、Swagger自体のバージョンは2.0が最新なのですが、Playモジュールではまだ2.0に対応しておらず、古いSwagger1系のバージョンでの利用となりました。

この辺りも別途記事に情報をまとめたいと思っています。

番外編:インフラ周りのツール

Scala/Playframeworkには直接関係ありませんが、開発に採用したツールを2つご紹介します。

デプロイツール

開発環境からサーバへのデプロイには、Capistrano3を利用しました。
Capistrano3を使ったScala製サービスのデプロイは、GREEさんやはてなさんでの採用実績があり、情報も充分手に入ったということから採用しました。

実際の利用には、GREEさんのこちらの記事が非常に参考になりました。

入門 Capistrano 3 ~ 全ての手作業を生まれる前に消し去りたい

こちらの記事は、CapistranoでRails以外をデプロイする情報をググると、だいたいどの記事からも参照されていて、バイブル的な存在になっているように思います。

プロビジョニングツール

サーバ環境のプロビジョニングにはAnsibleを利用しました。
シェアウィズの既存サービスではChefを使っているのですが、最近Chef-soloからChef-zeroへの移行の動きがあるなど、今後どのような形に落ち着くのかが不透明に感じたので、今回はAnsibleを利用することにしました。

昔は、yamlで設定を書いていくことが表現力が低いように感じていたのですが、今回本格的に利用してみると充分なモジュールがそろっていますし、AnsibleGalaxyを利用することで便利に利用できました。

まとめ

今回の記事では、標準的なPlay2のWebサービスを使った開発においてシェアウィズで利用したライブラリなどをご紹介しました。
開発言語にScalaを採用したメリットの一つとして豊富なライブラリを選択して利用できるという点があります。
Scalaで開発されたライブラリに限らず、Javaのライブラリも利用できるので、ライブラリの選定には非常に膨大な選択肢が存在することになります。

これからPlay2でWeb開発を始める人の何らかの手助けになれば幸いです。

さて、scalaアドベントカレンダーですが、2日目はQiitaもAdventarも空席となっているようです。
Scalaにご興味のある方は、ぜひ投稿してください。