OMM Japan 2016: Rails + React + Redux でアウトドアイベントの結果を表示するウェブアプリを書いている話

この記事は個人開発者 [Advent Calendar 2016 - Qiita](http://qiita.com/advent-calendar/2016/individual-developer) の22日目の記事です。今日は個人的に作成しているウェブアプリ [OMM Japan 2016](https://omm-japan-2016.herokuapp.com/) について、きっかけから振り返りまでを書きます。

<img src="https://qiita-image-store.s3.amazonaws.com/0/36122/84fd0d9d-d049-3017-c69d-1ed5961a61a9.png" width="100%" />

アプリは Heroku の [Free Dyno](https://www.heroku.com/pricing)（無料プラン）を利用しているため、だいたい初回アクセスが遅いのでご注意ください :bow:

また、Chrome で確認をしていますが、IE だと上手く動作しないことが分かっています :cry:

ソースコードは GitHub 上で公開しています。

- [kyoshidajp/omm\-japan\-2016](https://github.com/kyoshidajp/omm-japan-2016)

# きっかけ

今年の11月に長野県大町市で行われた、[OMM JAPAN2016](http://theomm.jp/?page_id=1063) というアウトドアイベントに参加してきました。

2人1組で1泊2日分の装備とコンパス、そして直前に配布される地図を持ち、山の中の決まったポイントをまわってスコアを競い合うスポーツです。行動時間は1日目は7時間、夜はテントでビバークして、2日目は6時間とハードなスケジュールでした:runner_tone1::runner:

自分たちはかなり真面目に走って、地図読みをして、ヤブを漕ぎながらゴールしたのですが、残念ながら順位は今ひとつでした。知り合いのチームは全く走らなかったのに、自分たちより良いスコアだったり:joy:

終了後すぐ大会のサイトにリザルトがアップされたので、他のチームがどのようなルートをとったのか分かりました。ただ、テキストだと位置関係が分かりづらいなと感じていました。

また、自分はフロントエンドについて「変化が早い、早くない」という議論の前に jQeury 時代で手が止まっていて、ちょっとマズイなという思いを感じていました。

そこで、フロントエンドのキャッチアップをかねて気になっていた React を使い、各チームのルートを地図にマッピングするウェブアプリを書いてみる事にしました。

# 目的と目標

## :v: 目的

- React を使ったウェブアプリを書いてフロントエンドのトレンドをキャッチアップ

## :raised_hand_tone2: 目標

- よくあるサンプルよりもう少し大きいアプリを作る
- React を中心に周辺のツール群を手になじませる
- （せっかくなので）見やすい、使いやすいアプリを作る

# できること

現在のところ次の機能があります。

- OMM Japan 2016 の各チームのリザルトを表示
 - レースカテゴリはスコアロングのみ（あらかじめルートが決まっているストレートと、時間の短いショートは含まない）
 - リザルトは番号、成績、スコア、氏名、ルート
 - ルートとポイントをページ内の地図に表示
 - チームの検索はナンバー（入力時サジェスト）か、氏名検索（部分一致）
 - 1日目、2日目をそれぞれ分けて表示
 - 表示したリザルトを地図から一時的に隠す
 - 表示したリザルトを強調して表示する（一覧でカーソルをあてる）

# 構成

構成はこんな感じです。

- サーバサイド
 - フレームワーク: Rails 5
 - DB: Postgre SQL（テスト時は SQLite 3)
- クライアントサイド
 - React + Redux + ES6 + babel + webpack

Rails はコントローラ（コース上にあるチェックポイント）やリザルト情報を JSON で返す API サーバで、React + Redux がアプリのメインになります。Rails 5 を使っていますが、機能的には Rails 4 ぐらいの使い方しかしていません。また、Rails については今回が初めてではありません。

Rails の採用を決めたあと、React の導入方法については次のエントリが参考になりました。

- [webpackを使った Rails上でのReact開発 \- クックパッド開発者ブログ](http://techlife.cookpad.com/entry/2016/07/27/101015)

この中では [react-rails](https://github.com/reactjs/react-rails) が手軽で良さそうに思えましたが、React 以外の npm による管理を考えて webpack を使う事にしました。

React の言語は TypeScript と CoffeeScript と ES6(ECMAScript 2015) を候補にして、最終的には ES6 にしました。React のサンプルとしてウェブの情報が多かったように思います。

TypeScript は個人規模のアプリでは学習コストに対する大きなメリットが感じられませんでした。CoffeeScript はチャットの bot スクリプトを書いた事があり、Ruby っぽくて好きなのですがここ最近は人気が落ちているような印象です。素の JavaScript はツラそうなのでナシで。

- [2016年9月現在だとReactアプリのTypeScript採用は時期尚早（※追記あり） \- Islands in the byte stream](http://gfx.hatenablog.com/entry/2016/09/12/162055)
- [CoffeeScriptは本当に駄目なのか？ \- Qiita](http://qiita.com/raccy/items/fae9fc5923d78112d935#%E3%81%A9%E3%81%86%E8%80%83%E3%81%88%E3%81%A6%E3%82%82-typescript-%E3%81%AE%E6%96%B9%E3%81%8C%E3%81%84%E3%81%84%E3%81%A0%E3%82%8D%E3%81%86)

ES6 については以前 ECMAScript3 実装の ActionScript 3.0 を使った事があったので、マインドセットを大きく変える必要はありませんでした。

また、多くの開発者が JSX で違和感を感じやすいのはロジックとデザインが同居しているところにある思うのですが、すでに [E4X](https://developer.mozilla.org/ja/docs/E4X) で似たような体験をしていたのでそれ程は感じませんでした。

# ワークフロー

コミットからデプロイまでの流れは次になります。

![work-flow.png](https://qiita-image-store.s3.amazonaws.com/0/36122/c6d2a45c-94ae-f35b-6b16-a44115a12b8c.png)

1. コミット
1. GitHub に push
1. Travis CI に hook
1. Travis CI でテスト実行
 - 失敗したらメールで通知
1. Heroku にデプロイ
 - 失敗したらメールで通知

push 以降は自動で実行されます。

コミット前にローカルマシンでサーバサイドは RuboCop による静的チェックと RSpec のテスト、クライアントサイドは ESLint による静的チェックと mocha + power-assert によるテストを実行しています。

静的チェックについては、当初エディタ（vim) でファイルを開いた時と保存した時に走らせていたのですが、マシンスペックが非力で毎回 6 秒ぐらいかかってしまうため、コミット前に手動で行うようにしました。たまに忘れるので [pre-commit](https://github.com/jish/pre-commit) などを使って自動的に実行されるようにしてもよさそうです。

また、Travis CI でもフロントエンドのテストとチェックをしたいのですが、`.travis.yml` の `before_script` に nvm インストールを指定しても、npm コマンドが見つからないというエラーになってしまうので実現できていません。

# React を使った感想

- MVC の View だけとあって、アプリを作るには他のライブラリをうまく取り入れる必要がある
 - 目的によって選択するライブラリが変わると思うが、オプションがありすぎてどれがいいのかよく分からない
- state を変更すると一気に DOM が作られるのが気持ちいい
- 当初 Redux は必要性が分からず使っていなかったが、実装を進める上でルールが欲しくなり採用した
 - Flux 実装としては今のところ Redux が覇権を取ったっぽい
- テストが書ける！（あまり書けていないけど）

# ハマったところ

- リザルトデータはオフィシャルサイトで公開されている PDF から簡単に取れたが、コントローラの位置は配布された地図とウェブサービスを目視チェックして入力した:sweat_smile:
 - [Googleマップで緯度・経度を求める](https://user.numazu-ct.ac.jp/~tsato/webmap/sphere/coordinates/advanced.html)
- [react-google-maps](https://github.com/tomchentw/react-google-maps) で `mapElement` の `div` 要素の `height` を `100%` に指定すると地図が表示されなくなる
 - モジュールの問題ではなさそうな気もするが [Issue](https://github.com/tomchentw/react-google-maps/issues/186) があった
 - とりあえず固定の `500px` にして回避
- 使っている npm モジュールが多すぎて細かいところを把握しきれない
- [Redux DevTools](https://github.com/gaearon/redux-devtools) がすごく便利で `console.log` デバッグしていた時間を返して欲しい :sob:
- ローカル環境では動作するのに Heorku にデプロイすると動かない事がある
 - [Multiple Buildpacks](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app) を使って Rails をインストールした後 `npm install` しているが、 `package.json` はプロジェクトのルートディレクトリにないと npm のパスが見つからずに失敗する
 - 当初フロントエンドのファイル群は client ディレクトリ以下にまとめていたが、`package.json` をプロジェクトルートに移動させた
 - buildpack を作れば解決できるかもしれないが断念
 - それ以外にも Heroku 独自のハマりポイントがある
 - 修正コミットが増えてしまうので rebase しまくり
- デザインの微調整
 - 今回の主目的ではないが、明らかにおかしいところは手を入れたい
 - が、ハマりやすい気がする

# KPT

ふりかえり重要。

## :ok_hand: Keep

今までできていなくて、今回出来たことです。

- 視覚的にチームのルートが分かるアプリができた :muscle:
- React でアプリが作れた :muscle:
- ES6 について概要をつかめた :muscle:
- Redux の必要性が分かった
- CI を実現する環境を作れた
- コミットのコメントを英語で書けた
- プログラミングとは違う趣味（アウトドアスポーツ）をプログラミングに応用する事ができた :relaxed:
- Heroku でアプリを動かせた

## :sweat_smile: Problem

問題点です。いくつか GitHub の [Issue](https://github.com/kyoshidajp/omm-japan-2016/issues) にしました。

- 他の人からフィードバックがもらえていない
- とりあえず作って動いているがきちんと理解できていない
- [Reducer が肥大化している](https://github.com/kyoshidajp/omm-japan-2016/issues/5)
- 見た目のデザインがイマイチ
- モバイルに対応できていない
- エディタの open/save 時に RuboCop/ESLint をかけると遅い
 - 外していると問題に気づくのが遅くなってしまう
- Heroku にアクセスした際、最初の読み込みが遅い
 - Free Dyno なので仕方がないかも
 - 定期的にアクセスするデーモンを動かす？
- [テストのカバレッジが感覚的に低い](https://github.com/kyoshidajp/omm-japan-2016/issues/4)
- [JavaScript の非 production コードが残っている](https://github.com/kyoshidajp/omm-japan-2016/issues/3)
 - 不要だし、console に warning が出る
 - webpack の設定で DefinePlugin で `process.env.NODE_ENV` に `production` をセットしているけど置換されていないっぽい
- [IE 11 で表示されない](https://github.com/kyoshidajp/omm-japan-2016/issues/2)
 - きちんと確認していないけど、それ以前のバージョンも IE はダメそう
 - 恐らく JavaScript 周りで、Rails の ActionCable や Promise がまずそう
 - 開発環境がないので修正できない
- ジョギングの時間が減った:scales:

## :rocket: Try

Keep と Problem をもとに今後やってみたい事です。

- 他の人に紹介してフィードバックをもらう（例えば Qiita に投稿する） :ear:
- 機能を追加する
 - 例えば
 - 制限時間を過ぎると減点されるが、減点がなかった場合の順位機能
 - 各コントローラのチェック率表示
 - もしこのコントローラをチェックしていればの順位スコア機能
- model 層を導入し、ビジネスロジックを Reducer から移動させる
- Android/iOS シミュレータによる確認を行う
- コミットまたは push のタイミングで RuboCop/ESLint をかけるようにする
- テストカバレッジを計測する

# まとめ

**キャッチアップの遅れは（あとからやれば）恥ではないし、（別の趣味の）役に立つ！**