🦕

deno slack sdkで社内コミュニケーション活性化

に公開

こんにちは。株式会社Digeonでアルバイトとしてソフトウェアエンジニアをしているいつきです。
この記事では以下について話します。

  • deno slack sdkを利用したワークフローを作成するに至った経緯
  • 実装概要
  • 困ったこと
  • 社内に広めた結果

経緯

社内コミュニケーション活性化のためにゲーム大会を開催したい

ふと社内を徘徊していると、Linuxコマンドかるたなるものを見つけました。
見つけたというか、元々あることは知っていて遊んだこともあるんですが、ふと見かけたとき思ったのです。

「これ社内で大々的にやったら簡単な勉強にもなるし、社内コミュニケーションも活性化するのでは…?」
と。

社内のコミュニケーション活性化といっても、別に社内の空気が死んでいたとかそういうことではもちろんないし、時々オフィスに出社しているメンバーでご飯に行ったりもしていました。
ただ、どうしてもその交流の輪は同じプロジェクトのメンバーだったり、仲のいいメンバーだけで閉じてしまいがちでした。
自分自身もそういう傾向があり、もっと普段関わらない人とも関われる機会を作りたい!と考え、その日のうちに社内slackの雑談チャンネルで以下の発言をしました。
Linuxコマンドかるた大会がやりたいという投稿

反応としては悪くなかったので、トーナメント形式にして優勝者、準優勝者にはハーゲンダッツを贈呈というインセンティブを用意してLinuxコマンドかるた大会をその週のうちに開催することとなりました!
Linuxコマンドかるた大会開催決定のslack

結果として、当日は8人が集まりとても盛り上がりました!(私は優勝しました!)

(当日の様子)
当日の様子

ここでいい感触を得られたので、もっとやりたい!ということで元々あった
LinuxコマンドかるたHTTPステータスコード百人一首プログラム言語神経衰弱++
の他にも新しく以下も購入して、これらについて毎週大会を開こう!ということになりました。

もっと交流を活発化させるには?

ここからが本題なのですが、もっとみんなが自主的にこれらで交流するためにはどうすればいいだろうと考えました。
その結果、ゲームでよくあるようなレーティングシステムを構築し、実力が近いもの同士で競い合える環境を育てるのがよいのではないかと結論付けました。

まずはレーティングシステムを構築するとして必要な要素が以下です。

  • 試合結果を入力するフォーム
  • 試合結果を保持しておくデータベース
  • 試合結果を各プレイヤーのレーティングに反映させる処理
  • レーティングを何らかの形でメンバーに伝える仕組み

まず試合結果を入力するフォームとしては、UXの観点からアクセスは最短距離であるべきです。そのため、フォームとして普段使いのコミュニケーションツール(Slack)に付属しているSlackワークフローを用いることはひとまず決定としました。
これに伴ってレーティングを何らかの形でメンバーに伝える仕組みもSlackワークフローで構築することになりました。

試合結果を保持しておくデータベースですが、試合結果の入力にSlackワークフローを利用する関係上、Slackと連携できるサービスでなければなりません。
そして、試合結果を各プレイヤーのレーティングに反映させる処理も必要であるため、GASを利用し、データベースとしてGoogle スプレッドシートを用いればよいと考えました。

すなわち、以下のフローを実装することにしました。

ワークフローを起動

試合結果をフォームに入力

試合結果をスプシに書き込み

それをトリガーとしてGASの関数を実行

スプシ上でプレイヤーのレーティングを更新

その結果をSlackに送信

Slackワークフローの限界とDeno Slack SDKの発見

しかし、ここで少し問題が発生しました。
試合結果に最低限必要なフィールドとして、参加者とその全員についての得点があります。ただ、slackで用意されているステップではそのようなフォームを自然な形で構築できませんでした。
参加者の得点を入力するフォームを構築するので、参加者各自について「fooさんの得点」のようなフィールドを作りたかったが、他のフィールド(参加者)の入力を利用できなかったのです。

R.I.P. GAS

↓こんな感じにしか作れなかった(カンマ区切りで入力してもらう形になり、ダサい)
フォーム画面

そのようなステップを実装する方法について探した結果、最終的にはDeno Slack SDKでカスタムステップを実装できました。

ここで私が要求しているステップの要件をGUIが解決できないのなら後の候補はSDKとなるわけで、公式ドキュメントを探し回った結果Tools | Slack Developersを発見しました。
これを参照すると以下が候補として挙げられます。

The quickest way to build on the Slack platform is with our collection of Bolt framework.

まず、今回の要件としてカスタマイズ性は重視したいため、プラットフォーム化されているBoltではなくSDKに絞りこまれました。
そして、Slackオートメーションプラットフォームと呼ばれ、Slack が管理するアプリ・データのホスティング環境が提供されていることから、Deno Slack SDKを選択しました。(Slack有料プランで追加料金なしで利用可能)

Deno Slack SDKを利用してカスタムステップを実装するにあたっては、公式ドキュメントはもちろんですが、何よりKazuhiro SeraさんのSlack公式記事が大変参考になりました。ありがとうございます。

実装概要

今回作ったものは、Slack上で試合結果の入力からレーティングの更新・共有まで完結するワークフローです。Deno Slack SDKでカスタム関数を実装し、Slack側にホスティングしているので、別途サーバーやGASは不要になりました。

Slack CLI

また、Slack CLIを用いることで、slack create my-app によるプロジェクトの雛形の生成など、更なる効率化、自動化が可能になりました。

↓slack createコマンドの出力。様々なテンプレートが用意されている: https://docs.slack.dev/samples/
slack createコマンドの出力

↓Automation App Custom steps and workflows(Deno Slack SDK)を選択した結果。
あとはこの生成されたコードベースで構成に従って実装を進めるだけ。
Automation App Custom steps and workflowsを選択

その他にもslack runによるローカル実行、slack deployによるSlackホスティングへのデプロイなどが可能です。
slack runによるローカル実行に関しては、開発者用サンドボックスを組み合わせることで、より実際のSlackワークフローに近い形で動作確認が可能になります。
詳しくはKazuhiro SeraさんのSlack の CLI と無料サンドボックス環境でサクサク快適開発に詳しく書かれています。

ユーザーフロー(試合終了後)

  1. /match-result でワークフロー起動。種目、読み手、参加者を選択

ワークフロー起動後のモーダル

  1. 参加者ごとの得点を入力して送信

得点入力画面

  1. データストア上の最新レートを基に計算して更新

  2. 結果とレート変動をSlackに投稿して終了

結果投稿画面

ユーザーフロー(レーティング確認時)

  1. /ranking でワークフロー起動。種目を選択

ランキング確認モーダル

  1. 最新のランキングをSlackにエフェメラルメッセージで表示

ランキング表示画面

データストアのスキーマ

  • content_ratings: 各種目ごとのプレイヤーのレーティング情報を保存
    • id: UUID
    • player_id: プレイヤーのSlackユーザーID
    • content_id: 種目ID (例: linux_karuta)
    • rating: 現在のレーティング値
    • updated_at: 最終更新日時
  • contents: 種目情報を保存
    • id: 種目ID (例: linux_karuta)
    • name: 種目名 (例: Linuxコマンドかるた)
    • default_rating: 初期レーティング値
    • slope: レーティング計算の調整パラメータ
    • temperature: レーティング計算の調整パラメータ
    • created_at: 作成日時
    • updated_at: 最終更新日時
  • matches: 試合結果を保存
    • id: UUID
    • content: 種目名
    • reader_id: 読み手のSlackユーザーID
    • participant_info: 参加者の情報(JSON文字列)
      • participant_id: 参加者のSlackユーザーID
      • score: 参加者の得点
      • pre_rating: 試合前のレーティング
      • post_rating: 試合後のレーティング
      • ranking: 試合内での順位
    • played_at: 試合日時
  • players: プレイヤー情報を保存
    • id: プレイヤーのSlackユーザーID
    • name: プレイヤーの表示名
    • created_at: 作成日時
    • updated_at: 最終更新日時

レーティング計算の方針

  • ペア分解のEloライクな計算を採用し、初期値1500・K係数は固定値にして計算コストを抑制
  • スコアが同点の場合は期待値差のみを加味した微調整に留め、極端なレート変動を避ける
  • 計算ロジックは関数1つに閉じ込めているので、後からGlicko系に差し替えやすい

…らしいです。ChatGPT先生に以下のプロンプトで考えてもらいました。

多人数対戦型かつ全ての人の順位が決まるゲームで、点数によってレーティングの増減を調整できるような適切なレートの計算方法を考えてください。

困ったこと

APIの型ヒントが少ない

例えば今回のサービスではインタラクティブなモーダルを多く利用しました。
その際に利用するAPIはdeno-slack-apiclient.views.openclient.views.updateなどです。
しかし、これらのAPIの引数や戻り値の型ヒントが少なく、補完が効きませんでした。
これにより開発体験が悪く、typoなどに気づきにくいことも多くありました。
公式ドキュメントを確認すればおおよそのinterfaceはわかるのですが、やはりIDEの補完が効かないのは辛いです。

(deno-slack-apiの型定義)
deno-slack-apiの型定義

(上記のような型定義で下記のようなメッセージを構築する(泣))
メッセージ構築

まとめ

Deno Slack SDKを利用してSlackワークフローのカスタムステップを実装し、社内コミュニケーション活性化のためのレーティングシステム付きゲーム大会ワークフローを構築しました。
これにより、メンバー同士が自主的に交流する機会が増え、社内の雰囲気もより活発になったと感じています。
Deno Slack SDKはまだ発展途上の部分もありますが、Slackワークフローを拡張する強力なツールであり、今後も積極的に活用していきたいと考えています。

今回作成したワークフローのコードはこちらのリポジトリで公開しています。興味のある方はぜひご覧ください。
ありがとうございました。

株式会社Digeon

Discussion