社員旅行の「旅のしおり」をアプリ化して社内オープンソース化した話

# まえがき
弊社の社員旅行のしおりアプリ（以下、しおりアプリ）を作成したというお話です。
長いので、読みたいところだけかいつまんでお読みいただけると幸いです。

アプリ作成の経緯から製造を経て実際の運用まで、採用したアーキテクチャ等に触れながら私の思いや思惑も書いています。

最初にことわっておきますが、アプリ作成時に度重なる危機や困難など、ドラマ性はありません。

# しおりアプリと開発経緯
しおりアプリとは社員旅行の「旅のしおり」をアプリ化したものです。
それまでは紙を冊子にして配布するという形態をとっていましたが、社員が増えてきたこともあり、冊子にする方法は次の2点を理由に難しくなってきました。

- 紙と印刷代のコストがかかる
- 紙資源を浪費する

いわゆるペーパーレスの流れがあるわけです。
しかし、ただペーパーレスを理由にするのであれば、アプリでなくPDFなどで配布すればいいわけです。
そこをあえてアプリにした理由は、弊社がシステム開発会社であること、それを営業トークに使いたいという思惑があったことなどがあったかもしれません。

実際はどれも建前で、本音はおもしろそうじゃね？　という好奇心から始まったものだと信じています。

# 3度目のアプリ化
そんなしおりアプリですが、今年で3度目のアプリ化となります。

1度目は私が2年目のとき、先輩社員が作成しました。
当時は何時にどこに行くのかという旅程を確認するというシンプルなものでした。

2度目はその翌年、機能が少しリッチになり、観光マップ機能などが追加されました。
これは先輩社員がiOS版、私の同僚がAndroid版の作成を担当しました。

さらにその翌年、つまり昨年、2度目のアプリ化ですったもんだがあった影響もあり、PDFで配布することになりました。

3度目、今年は満を持してAndroidアプリ開発をメインにする私がAndroidを担当、iOS版はiOSアプリ開発をメインにする後輩たちに依頼し開発を行いました。

# しおりアプリが抱える問題
それまでのアプリ化、しおりアプリは次の3点の問題を抱えていました。

- アプリ化する度にすべて作り直している
- しおりアプリの作成に膨大な時間を費やしていた
- データはアプリに埋め込みで、差し替えのためにアプリの修正が必要

本来、旅程を表示する機能は改修を必要としません。データを差し替えれば済むはずです。
（人によって旅行プランを選択でき、そのプランが多岐にわたるようになったため、単純にデータ差し替えで済まなくなったという事情はあります）
また、データを差し替えるためだけにアプリに手を入れる必要があるというのは極めてナンセンスです。
そして、毎年全機能を作り直すことは無駄と言わざるを得ません。

3度目のしおりアプリでは以上3点の問題を改善するべく、開発を行いました。

# 閑話：社員旅行委員会
弊社では社員旅行の計画立案、運営までを社員旅行委員会という組織が担います。
社員旅行委員会とは、社員から有志を募って組織される集団です。
社内ではSRIと呼ばれます。
（Shain Ryokou Iinkai、頭文字をとってSRIです。）
SRIはいくつかのチームから構成されます。
宴会、バスレク、しおりなどの複数チームで分担して作業を行います。
各チームの紹介は割愛しますが、しおりアプリはお察しのとおり、しおりチームが他チームに問い合わせた情報をもとにアプリ作成を手がけています。
私がSRIに参加したのは昨年、しおりをPDFで配布した年からになります。
このままではいかんでしょ？という思いから、本気でアプリ化してやろうと思い立ち上がった次第です。
しかしながら、その年はあまり仕事等で時間をとれなかったこともあり、アプリ化を断念し、2018年からアプリ化の流れに戻しました。

# しおりアプリに求めたもの
私がしおりアプリに求めたものは2点あります。

1点目は、仕事の成果物と同じ品質です。
ユーザ体験を含む、あらゆる面で可能な限り高い品質を追求したかったのです。
実際のところ、仕事が忙しくなるにつれてリッチな機能から削ぎ落とされていき、最低限の機能だけ残る形になってしまいました。
そこは残念なところですが、来年の課題としてコードを書く余地が残っているという点で、次の開発を楽しみにしています。

2点目は、部署メンバーの教育につながるサンプルになることです。
私が所属する部署のメンバーがこの規模のアプリを難なく読み書きできるようになるためのサンプルにするため、ソースコードの品質には特に注意しました。
悪いお手本を参考にコードを書くより、良いお手本を参考にコードを書く方が上達が早いはずです。
私の書くコードが良いお手本とは言いませんが、少なくとも私が関わった今までの仕事の中でトップレベルの品質になったと自負しています。

後述するアーキテクチャやライブラリを社内に浸透させるためのサンプルにするためにも、しおりアプリは極めて重要な立ち位置にあります。
すでに社内ではソースを公開しており、弊社の社員であれば誰でも修正できる状態にしています。

# しおりアプリの基本要件
アプリ化当初からある要件は次の4点です。

- 社員旅行の行程を閲覧できること
- 社員によってプランが異なるため、個人別の行程を閲覧できること
- 社員全員の名前、所属を顔写真つきで確認できること
- 緊急時の医薬品、連絡先等を確認できること

そこに、今年は次の4点を加えました。

- 行程の予定時間が変更される場合、その通知を行えること
- 行程の更新を含めたアプリのデータを更新できること
- データの更新のためにアプリの更新を必要としないこと
- 従来のアプリよりもう少しまともなログイン機能を設けること

最終的に、以上の8点を要件として開発することになりました。
本当に最低限の機能です。

# アーキテクチャとライブラリ、それと言語
Android/iOSともに、MVVMとClean Architectureを組み合わせたアーキテクチャを採用しました。
その意図は、部署メンバーの教育に直結するアプリにするためです。
新卒を含め、社内の若手メンバーにアーキテクチャの重要性を認識してもらうことができれば、私がこれらを学習した時間より短い時間で習得してもらえると信じています。
なお、本記事ではアーキテクチャの解説は行いません。

ライブラリは以下のものを採用しました。
※ライブラリの説明は省きます。
※特に有名なライブラリはリンクも省きます。
※Android版のみです。
※バージョンの表記があったりなかったりという揺らぎはご容赦ください。

|ジャンル|ライブラリ|
|---|---|
|View|[PDFView](https://github.com/barteksc/AndroidPdfViewer)|
|View|DataBinding V2|
|DI|Dagger2|
|Logger|Timber|
|DB|Room|
|JSON Parser|GSON|
|Image|Picasso|
|HTTP client|OkHttp3|
|HTTP client|Retrofit|
|Other|LeakCanary|
|Other|RxAndroid/RxKotlin|

ライブラリからもお分りいただけると思いますが、開発に使用した言語はKotlinです。

# 利用したサービス
毎年アプリに手を入れなくてもデータを差し替えるだけで運用できるようにしたいなどを理由に、ファイルを置いておくサーバやAPIなどが必要でした。
しかしながら、しおりアプリ開発自体に予算があるわけではないので、選択肢は基本的に無料で使えるものに限定されます。
また、自前でバックエンドのアプリケーションを作る余力もなかったため、バックエンドとして次のサービス（ツール？）を利用しました。

- Googleスプレッドシート
- [mobile backend][1]

Googleスプレッドシートは社員旅行の行程などテキストで管理できる情報を管理するために、[ニフクラのmobile backend][1] は画像ファイルの保管庫としてファイルストアを利用しました。
また、mobile backendはプッシュ通知も利用しました。

Googleスプレッドシートを選択した理由は、SRIメンバーの誰であってもデータの変更を行えるようにする必要があるためです。
日本にいてIT業界に身をおく人でExcelを触らない人はほぼいないと思うので、スプレッドシートなら分かるでしょという安直な発想です。

プッシュ通知はSRIからの連絡手段として利用します。
旅にはイレギュラーな出来事がつきものです。
例えば交通渋滞、宴会の準備が間に合わないなど、実に様々です。
そういうときは予定を変更せざるをえません。
その連絡手段としてプッシュ通知が必要なのです。
（実はプッシュ通知がなくてもよかったのですが、そこはしおりアプリ単体で完結させるためという言い訳をさせてください。）

# バックエンドそれはGAS
データをGoogleスプレッドシートで管理すると決めてから、それと連動するかたちでAPIを提供したいということもあり、もっとも手っ取り早いGoogle Apps Script（GAS）を選択しました。
基本的にはGASをAPIとして叩くことでJSONを取得できるようにし、アプリで使用するデータを更新するというという手段をとりました。

これはそのままスクリプトをガリガリ組んだわけですが、本来なら`POST`を使いたいところを全て`GET`で対応することになりました。
`POST`にするとリダイレクトされてしまい、期待通りの結果を得ることができませんでした。
期待通りの結果を得られるようにアプリを修正すればいいといえばそうなのですが、正直そこまでの労力をかけたくなかったというのが本音です。

# 閑話：JSONの渡し方
旅程情報や社員情報などのデータはそれぞれGoogleスプレッドシートの1セルにまとめて格納して、GASでそれを取得して渡すという方法をとっていましたが、データ量が多すぎたため、1セルに収まりきらないということが分かりました。
そのため、データを事前にJSONファイルに書き出し、それをGAS経由で渡すという手段に切り替えました。

## データの管理、取得方法
テキストとして渡すことのできるデータは全てスプレッドシートで管理しました。
シートをテーブル、行をレコードという扱いで、DBのように扱いました。
（繰り返しになりますが、SRIメンバーの誰でもデータの変更を行える必要があるためそのようにしました。）
スプレッドシートに入力したデータをGASでJSON形式のファイルに出力しました。
JSON形式のファイルをダウンロードすることで、アプリはデータの更新を行えます。
そのため、1シート1ファイルにし、できるだけ分割して必要なデータのみ更新できるようにしました。
この状態では、テーブルの1部を更新するために、多くのデータをダウンロードする必要があるという欠点があります。
しかし、諸般の事情を考慮した結果、この構造がもっとも都合のいいものでした。

APIのようにその都度データの一部だけ取得できるようにしなかった理由は次の2点です。

- オフラインでも動作するようにするため（他の諸般の事情による）
- GASの動作速度が遅いため
- スクリプトを動作させられる上限に達する恐れが高いため

しおりアプリを利用する社員数とGASのスクリプトを叩く回数を考えるとスクリプトを動かせる上限に達してしまう恐れが高いため、頻繁にアクセスしないようにする必要があります。
GASにアクセスする回数を抑えるために、ユーザに手動でダウンロードさせることでその問題を解決しました。

# 求めたのはアプリからのプッシュ通知
プッシュ通知をアプリから送りたかった。
[mobile backend][1] を選択した最大の理由はこれです。
多くのサービスではアプリからプッシュ通知を送るためにWebの管理画面あるいは別途APIを構築する必要があるように見えました。
それを作る余裕はなかったのです。

# 社内オープンソース化
有り体に言えば、ただ社内でソースコードを公開しただけです。
マージリクエストは大募集していますが、仕事でもないソースコードを見るなんて酔狂な人はそういません。
何を目指しているのかをまだまとめられていないので、機能追加が難しいというのもあると思っています。
なので、issueなどを作成して、マージリクエストを出しやすくするというのも検討中です。

# 今後の課題
さて、ここまでしおりアプリ開発のもろもろを書きました。
しかし、最終的にできあがったものは当初の計画のおおよそ半分程度の機能しか実装できていません。
そのため、次は当初の計画にあった機能も実装していくことを課題としています。

# あとがき
アプリの機能に関してはほとんど説明しませんでした。
「旅のしおり」にあるべき機能を最低限盛り込んだアプリであることを考えれば、説明するほどのものでもないでしょう。
プッシュ通知を送る処理など、個別のものについては公式でサンプルもありますが、どこかで記事を書くことがあるかもしれません。

今思えば、もっといい作りにできたのではないかというところが数多くあります。
Kotlinのバージョンが1.3になり、コルーチンが正式版になったということもあります。
来年はそのあたりをソースに反映することになるかもしれません。

しおりチームのメンバー構成についても時間があるときに追記したいと思います。

[1]: https://mbaas.nifcloud.com