SlackのInteractive Componentsの特徴と選び方(Message, Modal, Home tab)

SlackのInteractive Componentsは、UIをよりリッチかつ直感的にしてくれるので、単なるチャットツールとしてではなく業務のワークフローを効率的にする可能性を持っています。
ただ、後述しますがSlackでInteractive Componentsを使う方法は様々な種類があり、結局どういうユースケースで何を使えばいいか分からなくなってしまいました。
それぞれの特徴や使い方は公式にかなり詳細に書いてあるので、ちゃんと読めば分かりやすいのですが、どういう方法を使えばよいかを自分なりに調べた特徴などを踏まえて紹介します。(画像は公式ドキュメントから拝借しています)

# 呼び出し方

そもそもInteractive Componentsを呼び出す仕組みも様々なものがあります。

https://api.slack.com/interactivity

特にユーザからのアクションがきっかけとなって呼び出されるものには以下のようなものがあります。

## [Events API](https://api.slack.com/events-api)

何でもいいのですが、ユーザの何らかのアクションを元に発火する最も汎用的な仕組みです。
例えばbotにmentionを飛ばしてInteractive Componentsを始めたければ、 `app_mention` イベントを購読すると良いでしょう。
(もちろん発火できればなんでもいいので、bot呼び出しであれば [RTM API](https://slack.dev/node-slack-sdk/rtm-api)でも構いません)
他にも、 `app_home_opened` を購読すれば、ユーザがbot(app)のHome tabを開いたタイミングで始めることができます。

「Events API」としては最も汎用的で何でもできてしまうので、一概に特徴を言いづらいのですが、後述する仕組みが不適切なら、自ずとここから選択することになると思います。

## [Shortcuts](https://api.slack.com/interactivity/shortcuts)

![global_shortcuts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16458/866ebafd-0814-8318-fcfc-b5b37a73b50e.png)

特定のチャンネルに依存しない、新しい呼び出し方です。
上記リンクの通り、Global ShortcutsとMessage Shortcutsの2つが存在します。

特徴としては以下:


* Global Shortcuts
  * チャンネルに依存せずどこからでも呼び出すことができる
  * サーチバーなどから呼び出せるので、呼び出しが非常に早い
* Message Shortcuts
  * メッセージに紐付いて呼び出すことができる
  * チャンネルやメッセージに依存せずどこからでも呼び出すことができる
	(「その」メッセージには強く依存するが、どのメッセージからでもshortcutを呼び出すことができる)

基本的に特定のチャンネルやメッセージに関係なく呼び出すことができるので、自然とそれらに依存しない業務、あるいは全てで利用しうる業務で用いることになると思います。

## [Slash Commands](https://api.slack.com/interactivity/slash-commands)

![slash_commands.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16458/b61bd446-7929-403a-1055-58d5720aea7f.png)

手法としては割と前からある仕組みで、チャット画面上で `/some_command` と入力することで開始することができます。

特徴としては以下:
* 任意の引数を設定できる(例えば `/some_command arg1 arg2` )
* チャンネルに依存せずどこからでも呼び出すことができる

ただ、Slash Commandsという手法は確かにあるものの、Interactive Componentsとしてわざわざこれが適切なケースが…私には思い浮かびません。
例えば `/remind` のように、コマンド一発で操作が完結するものについては、わざわざポチポチ選ばなくてもチャット画面上で目的が達成できるのでいいのですが、Interactive ComponentsということはユーザとSlackがやりとりするのであって、わざわざ呼び出しにSlash Commandsを使うか？という気がします。
`/some_command arg1 arg2` で実現できてしまうなら、そもそもInteractivityいらなくない？と思ったり…。

(他にもスケジューリングや他のサービスからの連携での呼び出しなどが紹介されていますが省略します)

# UI

以下は一般的な特徴であり、作り込めばもちろんこれらの制限を回避することが出来ます。
ですので、UIはどれが一番目的に近いかをまずは考え、それによる制約の部分だけを作り込みで回避するのが良いでしょう。

## [message](https://api.slack.com/surfaces/messages)

![surfaces_messages.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16458/ab12bf4d-de5d-31a4-9c81-97eb48626e13.png)

### 特徴

会話上にComponentが表示される、最も一般的な方法です。
[ephemeral message](https://api.slack.com/methods/chat.postEphemeral)を使わない限り、基本的にはチャンネル上の誰でも入力を見ることができます。

注意すべき点として、[Block Kit Builder](https://api.slack.com/tools/block-kit-builder)を見れば分かりますが、ActionsとSectionしか使えず、Inputが使えません。
例えばセレクトボックスはActionにもSectionにもInputにもありますが、ActionとSectionだと「選択した瞬間」にhookが発動します。
逆に言うと、**他のボタンを押したタイミングではセレクトボックスの選択値を取得することができません**。

例えば、セレクトボックスで選択しておいて、実行ボタンを押す、みたいなUIにしたい場合には以下のようになってしまいます。

* セレクトボックスで選択した瞬間にhookが発動して選択値が通知される
* 実行ボタンを押した瞬間にhookが発動するが、セレクトボックスの選択値は通知されない(あくまで「実行ボタンが押された」という通知だけがされる)

この場合、実行ボタンを押したときにはセレクトボックスの選択値が分からないので、予め選択値をどこかに保存しておく、あるいはMessageを書き換えるといったトリックを行う必要があります。

もちろん上記のようなトリックを使えば作り込めばできるのはできるのですが、基本的に大変なので、1アクションで済むようなものが適しています。

### 使いどころ

* 業務がチャンネルに強く依存する
* 呼び出された(≠実行された)ということを他のチャンネルメンバーにも分からせたい
* チャンネル上の誰が呼び出しても問題ない
* 呼び出されたものについて、他の人がボタンを押しても問題ない
* 1つのアクション(例えば1つのボタンを押す、1つのセレクトボックスから選択する)で完結する

### あまり使うべきでないところ

* テキストボックスまたはテキストエリアを使いたい(そもそもMessageだと存在しない)
* セレクトボックス1でAを選び、セレクトボックス2でaを選んで「実行」、のような複合的な処理を行いたい

## [modal](https://api.slack.com/surfaces/modals)

![modal-abstract.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16458/df4cc099-7adb-d7dd-0ee5-f323aa69c314.png)

### 特徴

modalはその性質上、「自分に」modalが呼び出されます。他の人にmodalを送りつけることはできません。
ですので、自分が呼び出して自分が処理をさせたい場合に使います。

またmodalですので、入力が終わってsubmitしたら、明示的に残す処理を書かない限りは入力した痕跡は消えます。

modalは唯一inputというblockが利用できるのが特徴で、これによって複数の項目を入力や選択してから一気にsubmit、ということを実現できます。一方でactionなども利用できるので、他のmessageやHome tabのような使い方も可能です。というか、File以外の項目はすべてmodalが利用できます(Block Kit Builderを触ってみるとわかると思います)。

https://api.slack.com/reference/block-kit/blocks

`trigger_id` というキーを元にmodalの更新を行うため、 基本的に3秒以内にレスポンスを返す必要があります。
したがって、時間のかかるような処理は向きません…というか出来ません。
そもそもUX/UI的にもインタラクションに時間がかかる処理は望ましくはないのでしょう。

### 使いどころ

* その時点で処理さえされればよく、履歴の蓄積は不要
* 即時レスポンスできる
* 特定のチャンネルに依存しない

### あまり使うべきでないところ

* 3秒以上処理に時間がかかる(非同期にするという解決策もある)
* 他人にUIを強制したい(そもそも他人にmodalを使わせることはできない)
* 入力内容・結果を残しておく必要がある

## [Home tab](https://api.slack.com/surfaces/tabs)

![app_home_abstract.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16458/6a133bc2-5002-d7ca-15b3-1bfa334fc80a.png)

### 特徴

bot(app)のHome画面に通知させる方法です。いわばインタラクションのポータルみたいなもので、そのappのHomeに移動してから処理を依頼することになります。
modalと違って、こちらは他人に通知させることができます。

### 使いどころ

* チャンネルという形で依存せず、appに明確な役割を持たせたい
* 入力の履歴を持っておきたい
* 他の人にUIを強制させ、何らかの作業を依頼したい

appの向こう側にも人がいて、人同士でやり取りをするようなケース(例えば申請受付のような)に適しています。

### あまり使うべきでないところ

* 他人に入力内容・結果を公開したい
* チャンネルやユーザなど、appではない何らかのオブジェクトに依存している

# どの呼び出し、UIを利用するべきか

上記の通り、いずれの方法も、実現できることもあれば制約もあるので、何でも叶えていくれる唯一の方法があるわけではない、ということが分かるかと思います。
結局は利用したい目的によって選択するしかないのですが、とはいえそれぞれの特徴を理解しないと無駄に別の方法に飛びついてしまったりする(私がそうでした…)ので、この辺りの傾向を踏まえて手段が選択できると良いかなと思っています。