【ヒーローズ・リーグ 駅すぱあと賞受賞】みんなの現在地から集合場所を決めてくれる機能、他。飲み会幹事おたすけ LINE BOT 「鯨飲くん」を作った

# はじめに
飲み会幹事の仕事って、なかなか大変ですよね。
みんな飲み会はやりたいけど、幹事はやりたくない。そんな幹事の負担を少しでも軽減してくれるサービスがあったら、もっと気軽に飲み会を開催できるようになって、みんなの繋がりをより広く、深くできるのではないか…
そんな思いを形にした LINE Bot「鯨飲くん」を作りました。

ProtoPedia はこちら。
>https://protopedia.net/node/1899

この作品はヒーローズ・リーグ 2019 のハッカソン予選で制作したものです。ありがたいことに、「駅すぱあと賞」を頂くことができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/d7067d29-5ff4-617b-35e2-4b8014c3db21.png)

2日間のハッカソンを通しての制作プロセスや、制作時にやってよかったこと、反省点などを後半でご紹介いたします。

# 作ったもの
LINE のグループチャットに参加させて利用する LINE Bot です。

1. みんなの現在地からだいたいの中間地点になる集合駅を提案
2. 集合駅付近の居酒屋をピックアップ、投票を募る
3. 一番票の多かった居酒屋に自動音声で電話して予約

以上をワンストップで行います。

## 1. みんなの現在地を教えてもらう
ユーザの「集合」のかけ声で鯨飲くんが起動します。
参加希望者は鯨飲くんに自分の位置情報を教えます。
鯨飲くんは位置情報を受け取るたび、最寄り駅を探して返答します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/6f8f6d78-3edb-2e1f-6cfb-54ee4077c624.png)


## 2. 集合駅を決める
ユーザの「集合場所」のかけ声で参加希望を締め切ります。
鯨飲くんは全員の最寄り駅からの移動時間の合計が最小になる駅を教えてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/c1907171-01af-fce6-1046-520d8e6c3d40.png)


## 3. 店を提案し、投票を募る
鯨飲くんは集合駅周辺の居酒屋をピックアップし、カルーセルで表示します。
参加者は「ここがいい！」を押して投票することができます。
![カルーセル.gif](https://i.gyazo.com/a395e262d5a1ad38622c98641999cbdf.gif)

## 4. 店を決める
投票の結果、一番票が多かった店に決定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/915dfb58-f2c6-f9ec-07e4-97fe1bce9788.png)

## 5. 店を予約する
ユーザが「予約しといて！」を押すと、鯨飲くんは予約する時間を尋ねます。
ユーザが時間を回答すると、時間を答えた人の名前で電話予約をはじめてくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/b334699d-2b71-c7cb-2c6c-1679362a19fd.png)

店にはこのような電話がかかってきます。
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">自動応答はコールセンターのためだけのものじゃない。<br>自動応答を使ってお店の予約をとってしまう「鯨飲くん」のデモ。 <a href="https://t.co/fg3w3PKySB">pic.twitter.com/fg3w3PKySB</a></p>&mdash; しーたけ🍄🎹 (@sh_tkn) <a href="https://twitter.com/sh_tkn/status/1209172168837197824?ref_src=twsrc%5Etfw">December 23, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 6. 予約完了を通知する
予約が完了すると、鯨飲くんが予約の成否を通知してくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/4370f22d-4dfd-87cd-f623-96883c85593f.png)

あとはみんなで集まって飲むだけですね！

# 仕組み
## 構成図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/89f2c8b4-8ca4-770e-bb17-4afe3b9a70cc.png)

## 使ったもの
* LINE Messaging API
    * いわゆる LINE Bot
    * UI 開発なしで、LINE の仕組みを利用してユーザとやりとりする仕組みを手早く構築可能
* Express.js
    * LINE Messaging API のバックエンド
    * SDK があるため開発が容易
* 駅すぱあと Web Service
    * ヒーローズ・リーグのパートナー企業であるヴァル研究所提供
    * [緯度経度からの周辺駅検索](http://docs.ekispert.com/v1/api/geo/station.html)
        * 位置情報から最寄り駅を検索するのに利用
    * [範囲探索](http://docs.ekispert.com/v1/api/search/multipleRange.html)
        * 各参加者の最寄り駅から集合駅を決定するのに利用
* Twilio
    * ヒーローズ・リーグのパートナー企業である KDDI 提供
    * 「電話をかける」「自動音声を流す」「番号入力を受け取る」などの様々なアクティビティから構成されるフローを GUI で構築可能
        * ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/9d09801f-5c34-7f52-47e1-7e3da0464fbe.png)
* ぐるなび Web Service
    * [レストラン検索 API](https://api.gnavi.co.jp/api/manual/restsearch/)
        * 集合駅の位置情報から周辺の居酒屋を検索するために利用

# 当日の開発の流れ
## アイデアソン
ヒーローズ・リーグの説明、パートナー企業提供サービスの紹介などが済んだあと、アイデアソンが行われました。
各参加者が個別にアイデアスケッチを出し、参加者同士で見せあって、自分のアイデアの実現に協力してくれるチームメンバーを集めます。
ありがたいことに私が出したアイデアに2人が協力を申し出てくれたため、3人でチームを組むことになりました。

* アイデアスケッチ（再現・当時のものを紛失したため）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/759c2c65-f1a4-514d-afc8-5a60474f25a8.png)

## 開発
あとはひたすら開発です。
以下のようにタスクを分解し、チームメンバーで分担して進めました。

* LINE Bot のバックエンド開発
* 各種 Web API を呼び出すモジュールの開発
* Twilio の電話応答フロー構築
* ブランディング (鯨飲くんというマスコットの考案)
* 発表資料の作成

開発を進め、動くものができあがっていく中で、こうするともっといいんじゃない？というアイデアはどんどん出てきます。
そうしたアイデアも時間が許す限り取り込んでいきました。
最初は集合駅を決めるというシンプルなアイデアだったものが、最終的には電話予約まで取ってくれるものに膨らんでいきました。

# 振り返って
## やってよかったこと
### デモに必要ないタスクは捨てる
ハッカソンは、デモで印象づけることが命です。
実際のプロダクト開発では、エラー系や異常系、セキュリティなどを考慮して開発を行います。
しかし、デモで見せるのは正常系だけです。限られた時間の中でユーザーにとって魅力的な機能を可能な限り多く実装することを最優先にしました。

具体的には以下のような割り切りをしました。

* エラー系、異常系は一切実装しない。ユーザーは常に正しい入力をする前提を置く
* 各種シークレットはソースコードにベタ書き。GitHub のプライベートリポジトリに直コミットして共有
* 駅すぱあと Web Service 側の制約で、6人以上が参加する場合は集合駅を出せない。でもデモは3人でやるから👉ヨシ！

### 各メンバーの開発成果物を npm モジュールとして分離する
複数人でソースコードを共有して開発すると、他のメンバーの開発がボトルネックになって開発が進まない、ということが往々にして起きます。
これを防止するために、メンバーごとの開発成果物を npm モジュールとして分離し、LINE Bot のバックエンドから `require()` して利用してもらいました。

具体的には以下のように開発を進めました。
私が、駅すぱあと Web Service を呼び出して位置情報から最寄り駅を取得する機能を開発していたときのケースです。

1. 駅すぱあと Web Service を呼び出す npm モジュールに `findNearestStation` という function を作成する
  * この function は、緯度経度を受け取って最寄り駅を返すものだが、実際に Web API を呼び出す処理の実装は後回しにし、常に「新宿駅」を返すよう実装した状態でコミットする
2. 他のメンバーには、常に「新宿駅」を返す実装のまま、この function を利用して開発を進めてもらう
3. 正しく最寄り駅を返すよう実装が終わったら再度コミットする
4. 他のメンバーは最新のコードを pull するだけで、自らのソースコードに一切変更を加えることなく正しい最寄り駅を受け取ることができる

また、モジュールの使い方を説明するときには、実際にモジュールを利用するサンプルコードを用意して渡すと非常にスムーズでした。
以下は実際に利用したサンプルコードです。
駅すぱあと Web Service を利用してメンバー3人の最寄り駅を取得し、集合駅を決めるところまでを実行しています。

```ekispertUsage.js
const ekispert = require("ekispertjs");

const nomikai = new ekispert.Nomikai();

const main = async () => {
    // 横浜
    const station1 = await ekispert.findNearestStation("35.450199", "139.627466");
    console.log(station1.name);
    nomikai.currentStations.push(station1.code);
    // 立川
    const station2 = await ekispert.findNearestStation("35.700230", "139.413544");
    console.log(station2.name);
    nomikai.currentStations.push(station2.code);
    // 大宮
    const station3 = await ekispert.findNearestStation("35.907608", "139.631058");
    console.log(station3.name);
    nomikai.currentStations.push(station3.code);

    // 集合場所を探す
    const meetPlace = await nomikai.findPlace();
    console.log(meetPlace.name);
    console.log(meetPlace.geoPoint);
    // 各自の所要時間を位置情報を送った順に並べたarray
    console.log(meetPlace.costs);

}

main();
```

### ブランディング
今回作ったものが「飲み会幹事お助けBot」という名前だったらどうでしょうか。
確かにわかりやすい名前ですが、印象に残らないし、きっとすぐに忘れられてしまいます。

「鯨飲くん」というマスコットを作成し、また特徴的な口調でキャラクター付けをすることで、一気にキャッチーさが増し、すぐに覚えてもらえるようになりました。
ハッカソンに限らず、実際のプロダクト開発でも非常に大切なことです。

このブランディング作業は、私が何も言っていないにも関わらず、メンバーが率先してやってくれました。
いいチームメンバーに恵まれたことに感謝しています。

## 反省点
### プレゼンの練習をする余裕がなかった
可能な限り多くのアイデアを詰め込むことに前のめりになった結果、成果発表プレゼンの練習をする時間が取れませんでした。結果、プレゼンが少々ぐだりました。
どんなプロダクトでも、プロダクト自体の品質と同じくらい、「どう見せるか」が重要になります。
プロダクトの技術力そのものが「すごい」と言えるほどではなくても、見せ方が非常にうまくて賞をかっさらっていく作品はハッカソンでは珍しくありません。
成果発表プレゼンは少なくとも1回以上練習しておくことをおすすめします。

### タッチ & トライの準備不足
デモでは、やはりハードウェアとして動く部分があるものが強いです。
今回のハッカソンでも、プロジェクションマッピングを利用した作品が最も多くの票を集めていました。

一方で、鯨飲くんはソフトウェアで完結しているため、デモのインパクトは弱いです。
しかし、実際にタッチ & トライで触ってもらえればその魅力は伝わります。実際に触った人たちからは口々に「これはすごいね」という評価を頂けました。

ところが、鯨飲くんにはタッチ & トライに至るまでの準備に時間がかかるという欠点があります。
鯨飲くんと友だちになってもらった上で、鯨飲くんのいるLINEグループに参加してもらう必要があるためです。
ここに手間取った結果、会場にいるうちの半分程度の人にしか試してもらうことができませんでした。

タッチ & トライに至るまでの時間で、参加者に声をかけて事前にグループに入ってもらえていたら、もっと多くの人に試してもらうことができたでしょう。
これは鯨飲くんに限った話ではなく、開発途中にでも作品を見てもらうよう周囲の人に積極的に声をかけることはとても効果的です。
早い段階でフィードバックを得て、ブラッシュアップをかけることができるからです。

# 感想
このハッカソンの中では、自分の中では満足の行くものができつつも、「反省点」に記したように見せ方に失敗し、総合賞に届くことができませんでした。

しかし、これはあくまでも「ハッカソン予選」です。ヒーローズ・リーグでは全国の至るところで予選が開催され、最終的にヒーローズ・リーグ全体での賞が決まります。
その全体賞として、パートナー企業のヴァル研究所様に評価頂き、「駅すぱあと賞」を受賞することができました。
見ていてくれる人はいるんだな、と、報われたような気持ちがして、非常に嬉しかったです。

今後も、「反省点」に記したことを胸に留めつつ、ハッカソンに挑戦していきたいです。
本当にいい経験になりました。

# 後日談
LINE Bot でお店探しや予約代行をしてくれる[ぺこったー](https://pecotter.jp/)というサービスがあるそうです。
鯨飲くんの後半の機能と被っている…どころか、こちらのほうが遥かに便利そうですね。
予約の電話ってやはり腰が重いタスクなので、多くの人にとって非常にありがたいサービスではないでしょうか。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154885/ee5863ee-9491-384e-e526-3eda2e71c7b2.png)

かわいいマスコットを作って、口調でキャラクター付けをしているあたり、まさにブランディングですね。

鯨飲くんでは自動音声での予約を行います。いつかそれが普通になる日が来るのかも知れないですが、現状それをやったらお店の人を驚かせてしまいますよね…。
鯨飲くんで集合駅を決めたあと、ぺこったーに予約をお願いできれば強そうです。
LINE Bot 同士の連携が難しいので、すぐに実装というわけには行きませんが。
LINE さんどうかよろしくお願いします。

# Special Thanks
* パートナー企業として駅すぱあと Web Service を提供してくださり、さらに駅すぱあと賞で鯨飲くんを救ってくれた、ヴァル研究所様
* パートナー企業として Twilio を提供してくださった、KDDI 様
* 私のアイデアを形にするために最善の協力をしてくれた、チームメンバーの2人
* ハッカソンの最中に利用していた[画像のぬいぐるみ](https://www.nitori-net.jp/ec/product/7980746s/)を販売している、ニトリ様
    * 勝手に使ってごめんなさい。宣伝しておきます！
* ポップでかわいい鯨のイラストを提供してくださった、いらすとや様