初めてSlackAppを作ってみた - 帰宅予定確認Bot

うちの家族チャットツールはSlackを使っています。家族連絡用にもっといろいろ上手いことやろうと、今回初めてSlackApp作ってみました。解説やドキュメントはしっかりあるものの実際の流れがよくわからなくて苦戦しましたので解説を交えて書いてみたいと思います。

開発の動機

以前はいわゆる「帰るコール」的なことをIFTTの位置情報と連携させてやっていました。ところが物理的に職場が変わったり、帰り始めたタイミングではなく、遅くなる場合にあらかじめいつぐらいになりそうか、を知りたいとのことでSlackAppを作ることにしました。

やりたいこと

  1. ある時間が来たら自分宛に帰宅時間がいつぐらいになりそうか尋ねる
  2. なんらかの答えを返して妻さんに伝わるようにする、その際の入力は楽なほうがいい

というのが最低要件です。要はリマインドして、文字入力ではない簡単な返信がしたい。ということですね。問題はこれをどうやって実装するか、なんですが、SlackAppのドキュメントや開発方法を調べてみるといろんな情報がでてきます。

開発前でのわからなかったことと

前述のとおり調べてみてなんだかよくわからなかったのは

  • SlackAppとBotってどう違うの?
  • 定時に尋ねる発言をするって、どうやってトリガーするの?
  • 対話的にやりとりするのってどうやるの?
  • そもそも開発と実装ってサーバー立ててやる必要があるの?

あたりがぼんやりとしていて、なにをどうしていいかわかりませんでした。

参考書とその所感

そう思っていたときにブログコミュニティや月イチ挑戦コミュニティでお世話になっているmottox2さんが技術書同人誌博覧会向けに『Slack App開発ガイド』が書かれていてPDF版でも頒布されてたのでこれ幸いと読んでみました。

内容的にはSlackAppをGoogle Cloud Functionを使って開発していくチュートリアル的な本です。Slack側の設定もGCF側の設定も記載されていますし、サンプルコードもあり、SlackAppの機能を一通り網羅してるので、これからSlackAppを開発しよう、という僕にはまさに渡りに船でした。

結論から言うとナナメ読みするより頭からいったん写経しながら全部やってみるのが結果的に近道な気がしました。あとになってふりかえってみると、僕は必要そうなところだけピックアップしてナナメ読みしてしまったことがかえって理解度が上がらず遠回りしてしまった感があります。ボリューム的にはライトなので最初から通しでやってみるのをオススメします。

疑問の解消

そんなこんなで最初のうちはなかなか理解度が上がらず、どう作っていいかの道筋ができませんでした。前述の疑問に答えると

SlackAppとBotってどう違うの?

基本同一と考えて良さそう。旧来、自動化されたものはBotと呼ばれてSlackもそう言われていました。そのBotを組み込む枠組みとしてSlackAppがあって、BotはAppとして扱われるアカウントのことをさすんだろうと思います。

また、Slackの開発ドキュメントではBotUserとして、App用のアカウントにメンションを飛ばすとトリガーされるイベントがあるので、これと前述の広義の意味のBotが混乱を招いていた原因でした。

定時に尋ねる発言をするって、どうやってトリガーするの?

これはSlack外の何かを起点として使います。chat.scheduleMessageというものがありますが、定期的にという用途には適しません。そもそもそれをスケジュールする何かをトリガーしなければいけないですね。

例えばCronのようなものと併用して、定時実行される関数を開発します。その中でSlackのIncomming WebhooksやWeb APIのメッセージを叩いてSlack内にメッセージを送信するのが良さそうです。

対話的にやりとりするのってどうやるの?

対話的な機能はSlackにはないです。ただし、Interactive Componentsなどを利用してユーザーがボタンを押したり、入力した項目に対してApp側で受けとれるように設定、実装をします。その返しとしてまたボタンや入力欄などを含めた返信をする、を交互にやりとりすれば事実上対話形式になります。

SlackのドキュメントにInteractive MessageInteractive Componentsという言葉がでてくるのが混乱ポイントです。ざっくり言えば前者はSlackのメッセージを表示するためのJSONをBlockやSectionをつかってボタンやフォームを表示させる方法。後者はそのボタンや入力を受けとるための設定と実装です。

そもそも開発と実装ってサーバー立ててやる必要があるの?

単純にリクエストを受けたらSlackに対してリクエストするものがあれば十分です。

例えばSlackAppだけを作りたい場合、『Slack App開発ガイド』にもあるようにFaaSでやるのがシンプルだと思います。すでに何かのサービスがあって、SlackAppとしてSlackと連携させたい、という場合ならサーバーでSlack用のリクエストをやりとりする実装をするのが良さそうです。

ちなみに僕はデータを永続化して管理したかったので、FirebaseでFirebase Cloud FunctionとFireStoreで開発、運用していますが今のところ問題なく動いています。また基本的にはJSONのやりとりだけなのでSlack用のフレームワークを使う必要性も感じませんでした。

帰宅確認Botイメージ

シーケンスを図にするとこんな感じ

SlackAppは、大きくわけて5種類のトリガーがあるイメージで
1. Incomming Webhooks
2. Interactive Components
3. Slach Command
4. Event Subscription
5. Bot Users

この中でIncomming Webhooksだけ少し特殊でSlack外からURLを叩いて指定したチャンネルにメッセージを飛ばせます。
それ以外はいずれもSlack内の特定の行動をトリガーとして、指定したURLにリクエストを投げる仕組みです。

ということで、指定時間に実行するケースはまずCronかなにかで指定した関数をキック。その中でIncomming Webhook, もしくはWeb API経由でSlackにボタンなどを含めたInteractive Messageのスタイルで発言します。

次にInteractive Componentsでその返答を購読して、指定の関数をキックします。その関数の中でまた次のSlackメッセージをリクエストする、というような感じです。

このピンポン的にやりとりする流れを最初に想像できなかったので苦戦しました。ちなみに今回の帰宅確認BotではSlashCommandやEvenSubscriptionは使ってません。

なお返答結果や今の状態に関してはFireStoreでデータを持ち、更新や確認をしています。そして再確認などは定期的にCronで走らせてその永続化したステータス状況を元に処理ををわけている感じです。
Cloud Functionだと定時実行しかありませんが、AWSならCloudWatchから動的に関数をキックする時刻が決めれそうでした。

できあがったもの

こんな感じのものができあがりました。

まとめ

今回、最初全然イメージが掴めなかったり、どう開発してどう実装して、どう使うのかがわからなかったです。しかし、実際に理解してみたらシンプルでした。SlackApp自体がいろんなことができるように幅を持たせてあること、いろんな独自の言葉が出てくることが混乱した要因かもしれません。

しかしもっとも悪手だったのは、ドキュメントをちゃんと読もうとしなかった事、必要そうなことだけ読んでなんとかしようとしたことが原因ですね。高機能なイメージから、全体像と仕組み、何ができて何ができないのかをきちんと理解できてなかったためです。

一足飛びにやろうとしてくことに何が必要かを探そうとしたのがかえって遠回りになってしまいました。前述したとおり、まずは一通り機能を試すためにも愚直にチュートリアル的なもの作ってしまったほうが早そうです。その上で何をつかえばどのような事ができるかを理解した後で、実現しようとしたことに何が必要かを考えるほうがスムースに行きそうです。

余談ですが、うちの家族チャットがLINEではなくSlackになったのは僕の希望でした。LINEは複数のPCから同時ログインができないことが凄く不便だったためです。

My ChangeLog[0.37.10] & Next OKRtextlintをてんこ盛りカスタマイズした