冥冥乃志

ソフトウェア開発会社でチームマネージャをしているエンジニアの雑記。アウトプットは少なめです。

follow us in feedly

Unfiltered + HerokuでTwitter ToDoサービスを作る(環境準備編)

一応連載になる予定です。
昨年、 id:kmizushima さんにコップ本第2版をいただいて以来、Scalaの言語そのものの勉強を続けてきていましたが、そろそろ次のステップとして何かWebサービスを作りたいと思い立ちました。その練習がてら、Twitter使ってこんなことができれば良いのになあ、と思っていたことを実現させてみようかと思います。
なにぶん、仕事でコードを書くことが圧倒的に少なくなっているのでExcel方眼紙爆発しろ!、進捗に関しては自信がありません。
今回は環境準備編です。なお、時系列に起こったことや試したことを書いているので、はまったところと試行錯誤も合わせて書いています。この記事を読んで試してみようと言う方は、最後まで読み切った上でお試しくださいませ。

作るWebサービスTwitter ToDo(サービス名:TwoDo[仮称])について

会社とか外出先にいるときに、帰ったら試したいこととかやっておきたいことやアイデアなんかを思いついたりすることはないですか?私はソウルジェムが濁ってくる*1と現実逃避したいせいなのか、よく思いつきます。
そういうときに、Twitterでつぶやいておけば、それを拾ってToDoとして集約できるとうれしいなあ、と思っていました。
今回は、それを作ってみることにします。超俺得です。
とりあえず、今のところ決定している仕様は以下の通りです。

  • 自分で自分に飛ばしたメンションのみ抽出*2
  • 抽出したTweetをToDoとしてタスク管理ができる
  • 管理するのはToDoとDoneの二つの状態のみ
  • Twitter IDによるログインが可能

以下については現在保留。

名前はTwoDo(仮称)とします。Twitter ToDoだからTwoDoです。ひねりがなくてすみません。

環境準備

ともあれ開発を開始するには準備が必要です。
TwoDoの実行環境はHeroku | Cloud Application Platformにしました。特に深い理由はありません*3
フレームワークにはUnfiltered(+テンプレートエンジンとしてScalate)、IDEにはIntelliJ IDEAを使います。
Unfilteredは天領倉敷Scalaの首謀者 id:razonScalaっぽくて面白いよ、と聴いたので。せっかくScala始めてアプリを作るので、フレームワークを使っている間でもScalaっぽさは常に感じておきたいところなのでUnfilteredを採用しました。
IntelliJ IDEAも同じく id:razon に教えてもらったもの。まだあんまり使い込んでいないのですが、使いやすそうな気はしています。

herokuの準備

メールアドレス持ってればアカとるだけですし、始めるためのドキュメントは全部Dev Center(英語だけど)にあるので省略。面倒臭がらず、そのくらいは自分で調べましょう。

sbtの準備

ビルドツールにはsbtを使います。Scalaのアプリケーションはsbtでビルドするのがデファクトスタンダードですし、後述するUnfilteredのテンプレートプロジェクトもsbtでビルドするように構成されています。
公式サイトHome · harrah/xsbt Wiki · GitHubを参考にインストールしましょう。
Unfilteredのテンプレートメソッドを使うだけなら、必要に応じてGetting Start Guideは後で読み込んでもかまわないと思います。

Unfilteredの準備

UnfilteredはScalaでHTTPのサービスを構築するためのツールキットです。公式のドキュメントはUnfiltered — Unfilteredを読んでください。
英語に不安があるので、 id:yuroyoro さんが翻訳してくれているUnfiltered/docs at master · yuroyoro/Unfiltered · GitHubも合わせて参考にしました*4
Unfilteredはgiter8でsbtの形式で空プロジェクトを配布していて、そのプロジェクトを使ってアプリケーションを書いていく感じです(本家のセットアップにはgiter8のインストールから記載しています)。
で、giter8のビルドでこける、と。
原因は単純で、パスが通っていたsbt-launchar.jarのバージョンが0.7系のシンボリックリンクだった訳なんですが、実は未だにシンボリックリンクが古いバージョンのものになってしまった理由はわかりません。まあ、リンクファイルを差し替えてビルドし直したら行けましたとも。

今回はherokuで動くアプリケーションを作ります。herokuはScalaにも対応していて、Getting Started with Scala on Heroku | Heroku Dev Centerにheroku上でScalaのアプリケーションを動かすためのガイドがあります。で、ご覧いただくとわかるんですが、まあ、ちょこちょこと定型的っぽい設定がある訳です。herokuを使うのが今回だけであれば良いけれど、これを毎回やるのはちょっとなあ、スクリプトでも書かなきゃ行けないかなあと思ってたんですが、インターネットって便利ですね、heroku用のプロジェクトを公開してくださっている方がいたので、それを使わせていただくことにします。unfiltered on Heroku のgiter8テンプレートを作ってみた - sassuntの日記

> ~/bin/g8 sassunt/unfiltered-heroku

ただし、このテンプレートプロジェクトはUnfilteredのバージョンが最新ではないので、build.sbtのlibraryDependenciesのunfilteredのバージョンを以下のように変更します。

libraryDependencies ++= Seq(
   "net.databinder" %% "unfiltered-filter" % "0.5.3",
   "net.databinder" %% "unfiltered-jetty" % "0.5.3"
)

これで、Unfilteredを使う準備は整いました。

Unfiltered-scalateの準備

TwoDoでは、ブラウザからアクセスできるサービスにする予定です。というわけで、TwoDoはリクエストに対してHTMLのレスポンスを返す必要があります。
昔のServletじゃないんだし、コードの中にHTMLをジェネレートする部分をごりごり書くのは格好悪いですね。というわけでテンプレートエンジンを使います。
UnfilteredからScalateを使うための外部ライブラリが公開されているので(https://github.com/unfiltered/unfiltered-scalate)、それを使います*5。Unfiltered本家のサイトに、unfiltered-scalateをビルドに取り込むためのソース(build.scala)があったので、まんま取り込めば終了です。ビルドもローカルではちゃんと通ります。が、これが後々herokuへのデプロイ時のはまり要素となってしまうので、試す人は注意してください。

IntelliJ IDEAプロジェクトとして取り込む

皆さん、テキストエディタは何派ですか?私は Emacs vs Vim宗教戦争を横目に見ているIDE派です。IDEマンセー
Scala型推論が強力な言語で、コードの上では型をかなり省略することができます。ライブラリによる補完機能などを十分に活かすのであれば、Scalaのコードを書くのなら私にはIDEが心地よいのです。まあ、使いやすいと思うツールを使い込んでいけばいいんじゃないでしょうか。
インターネットは便利ですね。私と同じことを考えている人はいるようで、sbtのプロジェクトからIntelliJ IDEAのプロジェクト関連ファイルを吐いてくれるsbtプラグインを作った人がいます。やり方はほとんどsbtプロジェクトをIntelliJに取り込む - CLOVERに書いております。前述の記事に従い、gen-ideaコマンドをsbt上で実行すると、.ideaと.idea_moduleという隠しディレクトリにIDEA用のプロジェクトファイルが出力されます。
これらのプロジェクトファイルはherokuにデプロイする必要もないですし、特に変更管理をする必要もないので、gitの管理対象から外すために.gitignoreに以下を追加します*6

/.idea
/.idea_modules

後はIDEAを立ち上げて、IDEAのプロジェクトとして取り込むだけです。元記事の中では、JREのバージョンがマッチしないということも書いてありましたが、私の環境では特に問題はありませんでした。
ここまでくれば後はIDEの恩恵を存分に享受するだけです。プラグインにお願いしてsbtのコマンドを叩いたり、ローカルリポジトリの差分を判断して指定のフィアルだけgit commitしてもらったり思う存分IDEに働いてもらいましょう。

herokuへのデプロイ

基本的にはherokuが公開しているGetting Started with Scala on Heroku | Heroku Dev Centerに従えば問題ありません。
が、私の場合ここが一番はまりました。正確に言うと、herokuへのデプロイそのものにはまった訳ではなく、githubに公開されているexternal libraryを利用する場合のデプロイにはまった訳ですが。

今までの流れで作ったものをデプロイしようとするとエラーになります。以下はgit push heroku master実行時のログです。

          • > Heroku receiving push
          • > Scala app detected
          • > Building app with sbt v0.11.0
          • > Running: sbt clean compile stage
Getting net.java.dev.jna jna 3.2.3 ... 〜以下、Scalaコンパイラダウンロードとかコンパイルとか〜 :: retrieving :: org.scala-tools.sbt#boot-app confs: [default] 38 artifacts copied, 0 already retrieved (6960kB/42ms) [info] Loading global plugins from /tmp/build_69k01ct8nrg9/.sbt_home/.sbt/plugins 〜省略〜 Initialized empty Git repository in /tmp/build_69k01ct8nrg9/.sbt_home/.sbt/staging/77acba64d34653fb29fa/.git/ fatal: Not a git repository: '.' [error] Nonzero exit code (128): git checkout -q 0.5.3 [error] Use 'last' for the full log. Project loading failed: (r)etry, (q)uit, (l)ast, or (i)gnore? ! Failed to build app with SBT 0.11.0 ! Heroku push rejected, failed to compile Scala app

ええ、filed to compileとか出やがってます。どうやら、何かがgitのリポジトリとして認識されていないようですよ。ちなみにこの後色々試して、unfiltered-scalateのソース依存用のbuild.scalaを削除するとデプロイが上手く行くことがわかりました。というわけで、原因はunfiltered-scalateというところまでは確定することができたのですが、さてどうして良いのやらは全く以てわかりませんorz
で、結局はunfiltered-scalateを個別にビルドしてアンマネージド依存でビルドすることにしました。
まずは、ライブラリ用のディレクトリをアプリケーションのホームディレクトリ直下にlibという名前で作成します。次にunfiltered-scalateのビルドです。https://github.com/unfiltered/unfiltered-scalateからソースをダウンロードしてきてjarにパッケージしてビルドするまでは普通の流れなので省略。ビルドが通ると、プロジェクトのディレクトリ直下にjarファイルができるので、それをアプリケーションのlibディレクトリにコピーしてください。
これでコンパイルしても通らないんですね、まだ。jarの中身はunfilteredの外部ライブラリとしてのScalateクラスのみです。このクラスからはscalateを使っているので、こいつらをビルド依存性に追加してあげる必要があります。大丈夫かなあ、と不安になりつつbuild.sbtのlibraryDependenciesを以下のように変更します。

libraryDependencies ++= Seq(
   "net.databinder" %% "unfiltered-filter" % "0.5.3",
   "net.databinder" %% "unfiltered-jetty" % "0.5.3",
   "org.fusesource.scalate" % "scalate-core" % "1.5.3",
   "org.fusesource.scalate" % "scalate-util" % "1.5.3" % "test"
)

これで、herokuへのデプロイが上手く行きます*7
ちなみに、上記のような手順でbuild.sbtを触ってビルドの構成を変更したりしても、IDEAのプロジェクトファイルが更新される訳ではないので、そのままでは追加したライブラリのクラスがコード補完の対象にされなかったりします。そういうときはgen-ideaをもう一度やり直してプロジェクトファイルをもう一度作り直してください。

長文エントリですが、まだ環境構築のみです。次からはアプリケーションの本体を書いていきます。とりあえずはherokuのAdd-onを使ってTwitter APIを叩いてみるところあたりから始めてみましょうか。

*1:使っておきながらあまり意味はわかっていないww

*2:そうしとかないと瀬戸内変態クラスタにToDoを荒らされそう^^;

*3:強いて言うなら独自のSDKがなかったこと。できれば最初はフレームワークの生の状態で使いたかったというのは少しありました。

*4:幾つか本家の方には追加されている記載があったので、最新のバージョンの翻訳ではないようです

*5:元はコアなモジュールと合わせて公開されていたようなのですが、いつの間にか外部ライブラリ扱いになっていたようです

*6:プロジェクトテンプレートに.gitignoreは含まれています

*7:HerokuでScalaやろうとしたら、すごくはまったけど、とりあえずHello worldできたっていう話 - scalaとか・・・を読むと、ソース依存性が必ずしも上手く行かない訳ではないようです。