Merry Christmas! 🎅🏼
この記事では、2019年2月に Elm を始めた私が1年間の経験をもとに、Elmで初めて作ったアプリケーションをリファクタリングしていきます。当時の自分ができなかったことが、今の自分ならできるはず!この記録がElm入門者の壁を乗り越える助けになれば嬉しいですね。
できるだけ簡潔に書けるように頑張ります。「もっと説明がほしい」「詳しく知りたい!」というリクエストがあれば追記します。私はたくさんの記事を書く性格ではないので、少ない記事を大切に育てたい。
アプリケーションの説明
私はモータースポーツが好きです。自動車のレースです。ここ数年、日本人選手や日本チーム活躍も目立つので皆さんもニュースで見かけたことがあるかもしれません。「自動車を走らせるだけじゃん」と思われるかもしれませんが、いくつかの種目が世界各地で行われていて、選手もファンも大忙し!
そこで、レースの日程がひと目でわかるカレンダーを作りました。
MotorSportsCalendar 2019
https://y047aka.github.io/MotorSportsCalendar-2019/
改修の計画を立てよう
まず、今回の改修事項を書き出してみましょう。
改修前のスナップショット[^注釈]
[^注釈]:改修に際して開発環境を最新化しています。記事が長くなってしまうので今回は省略。
https://github.com/y047aka/MotorSportsCalendar-2019/pull/1
-
コードの見通しを良くする
→ view の整理など -
データのロード速度を改善する
→ 複数の JSON のロードをTask.sequense
で直列に実行しているので、Cmd.batch
に変更して改善する -
現在日付の取得タイミングを早くする
→subscription
ではなく、init
の際に取得する
では改修スタートです。
コードの見通しを良くする
以下の Pull Request にコミットをまとめました
https://github.com/y047aka/MotorSportsCalendar-2019/pull/2
モジュール分割に対する自分なりの基準ができた
-
The Elm Architecture
に影響しない箇所は、分割するほうが見やすいのであればモジュールに切り出していく
Elm の記法に目が慣れてきた
- 記法に慣れて一時変数が不要になったので
let ~ in
を削除する -
List.map a b
の書き方に慣れて、b |> List.map a
よりも明快だと思うようになった
データのロード速度を改善する
管理の都合でカレンダーの情報を複数の JSON で構成しています。これを全てロードして使用していたのですが、当時はまだ The Elm Architecture
を理解しないまま先に進んだため、Task.sequense
での実装になっています。全ての JSON をロードして表示するまでに数秒かかることがあったので、改善することにしました。
以下の Pull Request にコミットをまとめました
https://github.com/y047aka/MotorSportsCalendar-2019/pull/3
Cmd.batch に変更する
- 複数の
Cmd msg
を束ねるためにCmd.batch
を使用する - ただ使うだけであれば
Task
よりも簡単 - それぞれのロードが非同期に行われるので、完了した順番に
Model
へ追加される(どうしよう?)
ロードした JSON を任意の順番にソートする
-
List.sortWith
を使うと、任意の順番で比較できるようになります - 専用の
compare
関数を作成しました - Elm-jp の Discord で @arowM さんが挙げていた例を参考にしました
- カスタム型を活用したかったけど、実装が大きくなりそうなので見送り(さよなら〜)
import List.Extra as List -- List.dropWhile を使うために List.extra をインポートする
compare : Season -> Season -> Order
compare a b =
let
-- 定義した順番にソートされる
enumarate =
[ "F1"
, "Formula E"
, "WEC"
, "WEC"
, "ELMS"
, "IMSA WSCC"
, "IndyCar"
, "NASCAR"
, "SUPER FORMULA"
, "SUPER GT"
, "DTM"
, "Blancpain GT"
, "IGTC"
, "WTCR"
, "Super Taikyu"
, "WRC"
, "MotoGP"
, "Red Bull Air Race"
]
in
if a.seriesName == b.seriesName then
EQ
else
case List.dropWhile (\x -> x /= a.seriesName && x /= b.seriesName) enumarate of
x :: _ ->
if x == a.seriesName then
LT
else
GT
_ ->
LT
改善は成功しました!
現在日付の取得タイミングを早くする
以下の Pull Request にコミットをまとめました
https://github.com/y047aka/MotorSportsCalendar-2019/pull/4
アプリケーションの仕様上 Time.here
を使ってもあまり意味がなかったので、zone
は削除しました(バグっちゃったね)
https://github.com/y047aka/MotorSportsCalendar-2019/commit/e5e3278942448773c8c80909069fc850d8f7c927
-
削除しましたTask.perform AdjustTimeZone Time.here
をCmd.batch
に追加する -
Task.perform Tick Time.now
をCmd.batch
に追加して、subscriptions
を廃止する
まとめ
最新のコードはこちらからご覧ください
https://github.com/y047aka/MotorSportsCalendar-2019
大晦日に厳かな気持ちで MotorSportsCalendar 2020 を作りたいと思います。
2019年を振り返る
- 8月25日のイベント『Elm Meetup in Summer』で登壇しました
- 発表資料:私たちは絶対に絶対に
Ports を頼ったりしない - Elm のステッカーを作って配布した
- 発表資料:私たちは絶対に絶対に
- 12月7日 に Elm のイベント『ELMP1』を企画・実施しました
2020年に向けて
- 1月10日 に1966年のル・マン24時間レースを題材にした映画『フォードVSフェラーリ』が上映されます
- マット・デイモン と クリスチャン・ベイル のダブル主演です(豪華!)
- モータースポーツに詳しくなくても面白いので、ぜひ観てみてください(私は試写会で観た)
- デイトナ24時間レースまで、あと1ヶ月!
- 4月に Evan Czaplicki(Elm を作った人)が来日するイベント Elm Japan 2020 が計画されているので、一緒に盛り上げていきたい
- ELMP2 と ELMH(北海道 / 兵庫 / 広島)もやりたいね!
- モータースポーツのアプリケーションをいくつか作りたい
- 種子島でロケットの打ち上げを観たい