TypeScript で書いた Slack Slash Command を Firebase で動かしたらめちゃくちゃ簡単だった件について

こんにちは！[LOB のアドベントカレンダー](https://qiita.com/advent-calendar/2018/lob-inc) の10日目も僕だよ！

今回は PHP で書いていた Slack の Slack Command アプリをリプレイスしたお話でお送りします。

# はじめに
LOB では、もともと KPT や朝会などのエンジニアだけの MTG で「強いて言えばもうちょっと○○だったらもっと働きやすいのになぁ」を振り絞ってひねり出し、爆速で改善する文化がありました。
ただ、 ストレス的なものを感じてから　KPT や朝会でメンバーに共有するまでのタイムラグがあり、ついうっかり言いたいことを忘れちゃう問題というものが発生しがち。
とはいえ、なるべく非同期コミュニケーションであり続けたかったので、ひたすら bot に覚えさせ、 必要なときに一覧を取り出せる Slack の Slash Command 、 `tsurami` が開発されました。(しました

しかし次第に簡単に解決できそうな問題はすべて解消され、比較的ヘビィなものしか残らなくなった等々の経緯を経て `tsurami` は役目を終えました。

そして皆に忘れられて半年弱、会社規模が10数名から40人弱まで拡大した結果、エンジニアだけではなく全社員が「こういうの解決してほしい/こういう本ほしい/これどうしたらええのん？」みたいなことを気軽に経営チームに投げかけられる場所が必要とされ始めました。

弊社 CEO 竹林 に直接、気軽にお願いごとしていいんだよ空気感を生みつつ「お願いたけちゃんねる」という制度/チームが発足、


そして `tsurami` は `take-chan` に生まれ変わりました。 

今回のお話はそこからスタートする、コードのゼロベースでの書き直し、インフラの見直しのお話です。

# 動機
- PHP で書いたコードみんなホスティングしてくれない
    - もともと Go と TypeScript でプロダクトを作る会社ですしね！
    - 片手間でシュッと作りやすかっただけで Laravel が使われているだけで PHP であるべきこだわりもなかった
    - どうせならエンジニアチームだれでもメンテできる言語にしたい
- (諸般の事情で) Aws のアカウント解約することになり、少なくとも EC2 インスタンスを消すことになった
    - 察して

# 実際にやったこと
簡単に書いてしまうと以下の2点です。

- PHP to TypeScript
- EC2 to Cloud Functions for Firebase

今回やってみて Firebase の簡単さ & お手軽さが最高だったので、ここをお伝えできればと思います。

# Firebase で Slack の Slash Command を動かしてみるまで

## アプリケーションを用意
TypeScript にリプレイスした成果物がこちらです。今回の主体はコードをどう書くか云々ではなく、動かすことの簡単さですので、こちらを使って Slash Command を導入していきます。

- [hey admins](https://github.com/lob-inc/hey-admins)

こちらの動作はシンプルで、 Slash Command を経由でリクエストされた内容を config に set されている別の channel に incoming webhook 経由で POST し、完了後に ephemeral なメッセージを返却する、というものです。

細かいことはおいておいて、 `git clone` なり `ghq get` なりして一旦手元に落としてきてください。

## firebase cli の導入とログイン

導入はとても簡単です。以下のコマンドを打つだけ。

```sh
npm install -g firebase-tools
```

ログインはこちらで。

```sh
firebase login
```

ブラウザが立ち上がって Google のアカウントでログイン成功すると、ターミナル側でも成功した旨が表示されているかと。

## プロジェクトの作成と設定

[コンソール](https://console.firebase.google.com) からプロジェクトの新規作成をしてください。
完了後、課金プランが無料のままだと外部 API をコールできないらしいので Blaze に変更してきてください。

ここまで完了したら手元のリポジトリとプロジェクト ID を紐づけます。

```sh
firebase use --add [PROJECT_ID]
```

## 仮デプロイ
デプロイはめちゃくちゃ簡単です。 functions ディレクトリの下でいっぱつコマンド叩くだけです。

```sh
npm run deploy # もしくは yarn deploy
```

## Slack 側で Slash Command を設定する

[Slack Api の Start Builind](https://api.slack.com/apps)からアプリの新規作成を行います。
AppName を適当につけて、対象のワークスペース(チーム)を選択してください。
<img width="573" alt="スクリーンショット 2018-12-10 21.08.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/2e021217-e225-7639-6853-035e3d64a5a7.png">


あたかも Slash Command　をつくれそうなリンクがあるので踏みましょう。
<img width="1654" alt="スクリーンショット_2018-12-10_14_56_21.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/7ba83a0d-c7d1-0651-793f-86bc986752be.png">

まようことなく Create New Command ですね。
<img width="1654" alt="スクリーンショット_2018-12-10_14_56_31.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/47aa1f2f-72c5-c303-7a79-960eecf501df.png">

そしてこちらが Command の設定例です。 
<img width="573" alt="スクリーンショット_2018-12-10_14_57_44-2.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/1c913cb4-9ae0-189d-c6c7-4683e637b123.png">

そして左のメニューから Install App to WorkSpace で Slash Command 自体の設定は完了です。

<img width="1083" alt="スクリーンショット 2018-12-10 21.14.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/a40501eb-5a9d-0624-4335-db896bdc0a47.png">

最後に BasicInformation の中に書いてある Verification Token を控えておいてください。

## Incoming Webhook の設定
本アプリケーションは Slash Command に対してレスポンスを返してメッセージを送信するだけでなく、特定の channel に API 経由でメッセージを送信します。
というわけで Incoming Webhook ですね。
[こちらから](https://slack.com/apps/A0F7XDUAZ-incoming-webhooks) webhook URL を発行してきてください。

## 環境変数の設定
あとひといきです。

アプリケーションの URL と、ここまで集めてきた VerificationToken や Webhook URL を設定していきます。

```sh
firebase functions:config:set \
  app.endoint="[アプリケーションのURL]" \
  slack.verificationToken="[VerificationToken]" \
  slack.webhookUrl="[WebhookURL]" \
  slack.channel="[投稿先channel名(#つけて)]" \
  slack.username="[botの投稿時に使う名前]"
```
こちらを埋めていただいて実行してください。下2つは各環境/用途に応じて使い分けていただければ。

## デプロイ
成功すると deploy しなおせというメッセージが表示されるはずです。
再度デプロイです。

```sh
npm run deploy # もしくは yarn deploy
```

これで設定はすべて完了しました。動作確認してみましょう。

## 動作確認

手元でコマンドを実行すると ephemeral なメッセージが返ってきて
<img width="418" alt="スクリーンショット 2018-12-10 21.24.24.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/f528b7ca-f192-3792-406b-fab5b4e8f9de.png">

指定した channel にお便りがとどきます。
<img width="393" alt="スクリーンショット 2018-12-10 21.24.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/28612/9f35bac5-0714-070c-3673-b48d07ab8d1a.png">

うまくいったでしょうか？
(こちらの例ではここまでのフローに乗せていないアイコンの設定などしております


# まとめ

文章とスクショで解説してきたのでそれなりのボリュームになってしまいましたが、ここまでの流れを箇条書きにするとこんな感じです。

- (firebase-tools の導入とログイン)
- リポジトリの用意
- プロジェクトの作成
- プロジェクトのヒモ付
- 仮デプロイ
- Slack でのコマンド作成
- Incoming Webhook URL の取得
- firebase functions:config の設定
- デプロイ

firebase を使ったことがなくてもたった 9 ステップです。しかもメンテフリー。
ていうか Slack Slash Command ではなく小さな API を起きたいだけなら半分以下の手数で動作環境が作れてしまいますね。ほんと簡単。
ここまで簡単だとうっかりアホな bot を量産してしまいそうです。

_ちなみに今回しばらくリクエスト飛んでこないと sleep してしまう問題まで解消できていません…しばらく放置したあとにコマンド叩くとタイムアウトでこけるかも…近日中に修正版を push します…_



当初、「`社内 Slack bot を PHP から XXX で書き直した話 (を書く) (まだ書き直してない)`」という予定で本日分の記事をお送りする予定だったのですが、TypeScript に書き換えて Firebase で動かしてみたところ、 Firebase めちゃくちゃ簡単かつ最高だったので、記事の主体が大きく変わってしまいました。深くお詫び申し上げます。

株式会社 LOB は楽天のアセットを使って広告配信等などにチャレンジしているベンチャーです。
インフラでは GCP 、サーバーサイドでは Go 、フロントエンドには TypeScript + React を使っております。
もしこのへんのキーワードにピンときたら[ぜひご連絡ください](https://lob-inc.com)。