SPAJAM2018 参加レポート、そしてその後の開発

この記事は、LINE Engineering Blog 「夏休みの自由研究 -Summer Homework-」 の13日目の記事です。


LINEメッセージングアプリの Android Client の開発を担当している玉木です。

この記事では、先月開催された「SPAJAM2018 本戦」に私が参加した際のレポートと、このときに作成したアプリをハッカソン後にどのようにリファクタリングしていくかという点について書かせていただきます。

SPAJAM2018 参加レポート

SPAJAMとは、温泉でハッカソン を合言葉に、ネクストクリエイターの育成を目的とする国内最高峰のスマフォアプリをハッカソン形式で作り競技を行う全国規模の大会です。

LINEはSPAJAM2018にてシルバースポンサーを務めさせていただき、福岡予選での会場提供などをさせていただきました。特段スポンサーだから参加したというものではなく、趣味の一環としてハッカソンへの参加を時々しています。

今回私は友人と一緒にチーム「まどや」として参加し、なんと本戦にて最優秀賞をいただくことができました。

SPAJAMがどんな会場で開かれるのか などSPAJAM2018オフィシャルフォトと共にイベントの様子をご紹介します。

会場

会場は COLONY箱根というコロプラさんの系列会社が運営する宿泊施設です。

この写真のようにとても開放感があり、過ごしやすい素敵な場所です。

アイデアソン

テーマが「モビリティ」と発表された後、即開発というわけではなく、所属チームを問わず一緒にアイデアソンを行いました。

オープニングパーティからアイデアソンまでの様子は毎年ニコ生で配信されているようで、コメントで斬新なアイデアを募集していたりしました。

http://live.nicovideo.jp/gate/lv314096391

開発風景

アイデアソンから24時間でプロダクトを作るルールですが、時間をどう使うかはチームごとに委ねられています。私達のチームはアイデアがなかなかまとまらずに12時間ほどアイデア決めに使ってしまいました。

そんなアイデア出し最中の風景をパシャリと写真に撮られていました。(右端のボケているのが私です)

アイデアが決まったあとに仮眠を取り、6:30頃から本格的な開発をはじめました。この時点で残り時間は10時間を切っていたので以下のことに集中して実装を進めました。

  1. はじめのうちは細部までこだわり過ぎずに一度見た目を用意する
  2. 必要な機能が小さなライブラリで代用可能ならササッと導入する
  3. キレイなコードが思いつかなければ愚直なコードで実装する

仕事ではもちろんハッカソン中でも時間があるときは上の3つに関しても妥協をせずに開発を行うようにしていますが、今回はいかんせん時間がないのでひたすらスピードを上げる工夫をしていました。

それでもプレゼンで見せられるレベルのものが完成したのが終了1時間前と非常にギリギリでしたので、こだわりすぎていたらプレゼンでデモの見栄えが悪くなるという事態になる一歩手前でした。

制作したアプリについて

「WheelFree!」という車椅子利用者の方が電車を利用する時の手助けをするアプリを開発しました。

車椅子利用者が、より鉄道を利用しやすくするための支援アプリ「WheelFree!」を開発。スマフォから入力した行き先情報や鉄道経路を、Twillioを利用し自動音声で駅員に伝える機能を実装した。必要最低限の入力情報と、鉄道・電話という旧来のインフラを簡単に接続することにより、利用者が、毎日出かけやすくなる仕組みを提供することが可能となった。モビリティというテーマ性への合致性、明日からでも使える利便性・実装力の高さ、明るさを意識したユニバーサルデザインが評価され、最優秀賞を獲得。

https://spajam.jp/final/result/ より引用

SPAJAMの感想

「モビリティ」というテーマは、身近なものに密に関わっているけど、じゃあ何か作れと言われたら難しいテーマでした。今回のアイデアは、モビリティが関わるものを利用するときにどういう問題が起きているのか、という事を考えたときにチームメンバーの友人の体験談からひらめいたものでした。

ハッカソン中は「なんでこんなに自分を追い詰めているんだ」という感情が生まれがちですが、SPAJAMはその中でも、終了後にそれを上回る心地の良い疲れを感じられるハッカソンでした。

ハッカソン終了後のリファクタリング

ここからは、SPAJAMにて開発したアプリを終了後にどのようにリファクタリングをしていくかということについて書いていきたいと思います。

1日〜数日で行われるハッカソンにおいて、コードがきれいなまま終わるということは少なく、スパゲッティコードになっていたり、その場しのぎの一時的なコードやプラットフォームで非推奨な手段を使用したりといった具合になっていると思います。これには、今後のメンテナンス性を考えて適切なクラス設計などの技術的負債を作らないための労力と、制限時間内にとにかく動作させるという目的とを天秤にかけたときに、今後メンテナンスをするかどうかわからないという点で後者が圧倒的に重要になってくるからであると思います。

現状の把握

SPAJAMに臨むにあたり、MVPアーキテクチャにRxJavaとDagger2を用いたテンプレートを準備しました。テンプレートのベースとなる部分を以下で公開しています。

https://github.com/r-ralph/mvp-template/

事前に用意したテンプレートのおかげで「フルスクラッチで書き直さないと厳しい」ほどまで汚い状態にはなりませんでしたが、それでも以下のような状態でした。

  • Model-Viewしか使わず、 Presenterが息をしていない状態だった
    • Viewにネットワークアクセスが記述される
  • Activity間、Fragment間連携が綱渡り状態
    • 画面遷移のIntentへの受け渡しデータのKeyを様々な場所に記述する
  • デザイナーから依頼されたデザインを中途半端な状態で実装してしまった
    • MaterialDesign Componentsの導入を行わず、見た目だけを再現した

しかし、テンプレートによって、ネットワークアクセスしたいときはRetrofitのインスタンスをDagger2でインジェクトするといった部分の共通認識をチーム内で持てていたため、自前でURLConnectionを用意してしまうといったことや、RxJavaによって非同期処理周りが複雑になってしまうことを防ぐことができました。

責務ごとに役割を分離させる(MVPアーキテクチャの適用)

今回のケースでは、Model部分はあまりハッカソン中に実装されるものがなかったので、主にViewにへばりついてしまったPresenter要素を剥がすという作業が主になりました。

- editText.addTextChangedListener(object : TextWatcher {
-     override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-     }
-     override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-     }
-     override fun afterTextChanged(s: Editable) {
-         query(s.toString())
-     }
- })
+ editText.afterTextChangeEvents()
+     .bindToLifecycle(fragment)
+     .map { it.editable().toString() }
+     .subscribe(presenter::onTextInput)

上のコードは、入力によってインクリメンタルサーチのように検索結果を絞り込んでいく部分の実装です。ハッカソン中のコードでは、EditTextのリスナーで直接検索を行うためのqueryメソッドを呼んでおり、そのqueryメソッドの実装もView(Fragment)に存在します。これを下側のコードではPresenterの方に入力された文字を送り、その中で検索を行うようにしています。また、リファクタリングに合わせてRxBindingを使用したコードへの変更も行いました。

これにより、View側としては今まで「入力されたら検索を行う」という部分まで知っていたのを「入力されたらそのことをPresenterに教えて後は任せる」といった動作に変わりました。

テストを行うときを考えると、今までのコードだと「EditTextに対して文字が入力されたら検索が行われ、その結果が〜」という一連の処理が行われるかというテストを書くことしかできませんでした。しかし、この変更により以下のようにテストを分離して記述することができるようになります。

  • Viewのテスト
    • 「EditTextに文字を入力するとPresenterのonTextInputが呼ばれるか」というテストを記述できる
  • Presenterのテスト
    • 「onTextInputが呼ばれたときに、ネットワークなどへアクセスして、結果をViewに反映させようとするか」というテストを記述できる

それぞれが必要とするオブジェクトはモックオブジェクトに入れ替えることができるので、純粋にロジックだけのテストとして記述することができます。

デザイン面での妥協の修正

今回のアプリでは、Material DesignにおけるFilled text fieldを使用してほしいというのがデザイナーからの要望でした。

https://material.io/design/components/text-fields.html

Googleが公式で出しているAndroid Material Componentを使うことで非常に簡単にMaterial Designに準拠した見た目のViewを使用できるのですが、導入に際してAndroidXへのマイグレーション、targetSdkをAndroidPにしなければいけないなど、テンプレートに組み込んでいないものが多く必要でした。

AndroidXへのマイグレーションに伴うAndroid SDKなどの更新のダウンロードにかかる時間や、マイグレーションがすんなり終わるかが未知数だったため当日は見送ってしまい、見た目だけ再現するという手段に移しました。

ハッカソンが終わり改めてAndroidXへの移行を行ってみましたが、想像以上に簡単に終わったのでこれならハッカソン中にやった方が最終的なコストが低かったなぁという印象です。

AndroidXへのマイグレーションでは主に3つの作業を行いました。

  1. AndroidXへのコンバーターの実行
  2. AndroidXへの対応が必要なライブラリの洗い出しと更新
  3. 発生していたコンパイルエラーの修正

今回のマイグレーションでは、1ではエラーは発生せず、2の部分で更新が必要なのは画像ローダーライブラリのGlideだけであり、3の部分のエラーもNullableの問題が1つだけと非常に簡単に終わりました。

このような感じで現在も修正の作業を続けています。

まとめ

エンジニアの自由研究ということで私個人が業務以外で参加しているハッカソンについて書かせていただきました。
SPAJAMはとても楽しいハッカソンですので、興味ある方は、ぜひ次回参加してみてください。


明日は Kohei Ohara さんによる Visual Explain でインデックスの挙動を確認する です。お楽しみに!

Related Post