JANOGerのみなさま、こんにちは。
PS・PC委員の齋藤です。
さて、JANOGのスタッフリストまで隅々確認されている熱心なJANOGerの方は、J57より新しく「Program Supporter」というポジションがあるのに気づかれたのではないでしょうか?
今回はこの、「PS委員」について裏話を書いてみたいと思います。
回を増すごとに倍率が高くなる”通常プログラム応募”
ありがたいことに、通常プログラム募集では非常に沢山の応募を頂戴します。
大体、毎回60件を超えるくらいの規模感です。
PC委員は、この大量の応募に目を通し最強のプログラムを作るために選考を重ねるわけですが、この過程にはたくさんの人力操作が発生していました。
まずは、PS委員が置かれる前のプログラム選考フローを見てみましょう。
- PC Chairがプログラム応募フォームを作成後、指定の期間でプログラム募集
- 応募されたプログラムは、Google Formの回答をコピー機能を用いて応募者に受理の旨を通知
- 同時にStaff Slackにも応募が通知されます
- 募集終了後、PC Chairは人力ないしGoogle Apps Script(GAS)等によってプログラム採点フォームを作成
- PC委員がプログラム採点後、PC Chairは人力ないしGAS等によって集計
- 採点結果に基づいてプログラムテーブルを各自作成、うち1つを最強のプログラムとして選出
- この時点でプログラム採否が確定します
- PC Chairは採否に基づいて、応募者のメールアドレス宛てへ採否通知するメールを人力ないしGAS等で作成。また通知を行う
- 採点結果及び採否をConfluenceへ転記
さて、ご覧いただくと項番3や5, 6は応募件数に比例してPC Chairのコストが高くなることがわかります。また、項番6に至っては採否の誤通知が発生しないようにしなければならないという注意点があります。
そこで、JANOG56ではこれらのコストが高い単純な処理は自動化しよう!という試みがなされたわけです。(Program Supporterの先駆けです。このときの自動化もJ57のPS委員が担当しました)
PS委員は、主にこういった自動化を担当する専門の委員ということです。
JANOG56での自動化 Ver.0
JANOG56ではPC Chairと自動化メンバ(現 PS委員)によって、以下のようなアーキテクチャを目指すこととなりました。

自動化後の流れを見てみましょう。差分は赤太文字で強調しています。
- PC Chairがプログラム応募フォームを作成後、指定の期間でプログラム募集
- 応募されたプログラムは、GASで作成した回答コピー機能を用いて応募者に受理の旨を通知
- 同時にStaff Slackにも応募が通知されます
- このとき、Slack上で採点を行うためのメニューが作成・通知されます
- このメニューが通知された時点で、PC委員は即時採点が可能になります。通知されたものからPC委員はSlack上で採点を行います
- 採点メニュー押下によって、予め連携されているGoogle Spreadsheetに対し採点結果が随時反映されます
- 複数登壇の場合に、応募者以外の登壇者にも応募通知を行うことが可能になりました
- 同時にStaff Slackにも応募が通知されます
- 採点結果に基づいてプログラムテーブルを各自作成、うち1つを最強のプログラムとして選出
- この時点でプログラム採否が確定します
- PC Chairは採否に基づいて、予めGASでプログラムされた採否通知を実行します
- 採点結果及び採否のConfluenceへの転記は人力
大きな特徴は、「応募→採点→通知」の一連のフローを自動化した点です。
この自動化によって、即時採点が可能になったことが応募者のみなさまへの最大のメリットではないでしょうか。採点の結果、もう少し具体的に把握したい点や確認したい点が出てきた際に応募期間内に応募者へ問い合わせ、また期間内に更新があった場合に限り応募を更新・再採点できるわけです。
しかし、この時点では応募の更新は人力です。メールでやり取りした内容を基に、Chairが応募一覧が格納されているマスターシートの更新やPC委員への周知を行います。
これらの自動化は、会期ごとに実行委員会が編成されることを踏まえ、サーバを構築しサービスをホスティングするような形ではなく、既存のサービスを活用して実現可能なソリューションを採用することとし、結果としてGASを全面的に活用しています。
これらの自動化にあたっては、GASでいくつかのモジュールを作成し、これらモジュールを組み合わせることで成り立っているわけですが、少しモジュールたちを覗いてみましょう。
Submission module
Google FormにはGASを用いたスクリプトセットが可能です。
この機能を用いて、みなさんが応募時に見るFormに埋めこまれたGASがSubmission moduleです。
このモジュールは次の役割があります。
- 登壇者全員への応募通知の送信
- Google Formは応募時に入力するメールアドレス1つに対してのみ、回答のコピーを送信できますが、この場合、複数登壇の場合にほか登壇者に通知がなされませんでした。このモジュールにより、Google Documentで作成されたテンプレート文面を基にGASでプレースホルダ置換の後、入力された登壇者全員へ通知を行っています。

- 応募一覧を格納しているGoogle Spreadsheetへの応募記録
- 都度、データベース等を構築することはコストが高いためGoogle SpreadsheetをDBとして活用しています。Google Formには既存でこの機能が備わっていますが、あとのSlack採点のために独自様式で記録する必要があるため、この機能を実装しています。動作自体はGoogle Formの既存機能と大差ありません。
- なお、このシートのことをマスターシートと呼んでいます。
- Staff Slackへの応募通知及び採点メニュー生成
- 応募内容をSlack API(chat.postMessage)へ送信し、Staff Slackへ通知します。
- 予めWorkspaceにインストールした、独自のSlack appを使用します
- 投稿した通知に対し、TS値を用いて採点メニューをリプライします。
- このメニューにあるボタンを押下することで、Slack appのInteractivityに事前にセットされたRequest URLに対し、採点メニューの内容やどのボタンが押下されたかなどの情報がPOSTされます。
- 応募内容をSlack API(chat.postMessage)へ送信し、Staff Slackへ通知します。

Chair module
Google SpreadsheetにはGASを用いたスクリプトセットが可能です。
この機能を用いて、埋めこまれたGASがChair moduleです。
このモジュールは次の役割があります。
- 採否通知の送信
- 自動化前の中でコストが最も高いといっても過言ではない、採否通知を自動化するものです。
- 採用通知のテンプレートドキュメント、不採用通知のテンプレートドキュメントをそれぞれGoogle Documentで作成し、GASでこれらを基にプレースホルダー置換を行った後に応募者・登壇者の皆様へ採否をメール通知します。
- 採否通知には、応募者へのフィードバックも兼ねて採点結果もお知らせしています。

Scoring module
Google DriveではGAS単体のファイルを作成することも可能です。
Slackの採点メニューから送信されたPOSTを基に、マスターシートへの採点結果の記録・更新またSlackの表示更新を担うのがScoring moduleです。
このモジュールは次の役割があります。
- POST受信時の採点反映処理
- 受け取った採点リクエストは、闇雲に処理するわけには行きません。たとえば、同じ項目内で複数の点数をつけれてはなりませんし、誤って採点してしまった内容を変更できないなどがあってはいけません。
- このモジュールは、次のような処理をたどり最終的に採点が反映されます。
- 受信したPOSTの内容は、採点ボタン押下時のSlackの表示内容(ビュー)及びどのようなボタンが押下されたか(アクション)といった内容です。これらをパースし、まずは現状の採点状況をビューデータから取得します。
- Slackの投稿内容を「当該のアクションは、すでに採点済みの項目に対するものであるか」、「当該のアクションは、未採点の項目に対するものであるか」に分類します。
- 前者については、採点済みの内容とアクションが同一の内容(つまり、自身がつけた点と同じ点数ボタンが押下された)場合は”採点取り消し”とみなし、ビューから当該人物・項目の採点表示を削除し、またマスターシートから当該点数を減じます。採点済みの内容とアクションが異なる場合(つまり、自身がつけた点と異なる点数ボタンが押下された)場合は”採点変更”とみなし、ビューからの情報削除・追加、差分の点数の反映をマスターシートに対して行います。
- 後者については、単純にビューに対しアクションの内容(点数)を記載(表示更新)し、マスターシートに当該点数を加算します。
- 上で加工されたビューデータをSlack API(chat.update)に対し送信し、表示を更新します。これにより、誰がどの項目に何点をつけたかが表示されます。また、マスターシートにも採点結果を反映します。
自動化してみて & Ver.1にむけて
上記のような自動化の取り組みにより、今まで人力で行っていた作業は大幅に削減され圧倒的な効率化がなされました。しかし、今回の取り組みで判明した新たな改善点やまだ人力で対処している作業も残っています。
Ver.0で判明した大きな改善点は3つあり、「Slack採点時に他人の採点状況が見えるため、引っ張られてしまう」、「Slackの採点が反映されないことがある」、「誰が採点していないかわからない」です。
「Slack採点時に他人の採点状況が見えるため、引っ張られてしまう」ですが、上記に記載の図を見ていただくと分かる通り、どの項目に誰が何点つけたかが視覚化されています。また、採点を行う時はそれを避けては通れません。そのため、採点者からは「採点が引っ張られてしまいそうになった。」といったコメントを頂きました。
そして、操作性をもっとも低下させる重大なバグが「Slackの採点が反映されないことがある」です。上記のScoring moduleの説明を更に細かくしてみます。POST受信時、GASはSlackのデータ(ビュー)を真として処理します。(ビューのパースと加工→加工後データをままマスターシートへ転記するという流れです。)
そう、あたかもマスターシートかのような処理をしているため、操作タイミングによってはマスターシートと点数がずれるといった問題が発生します。タイミングの例は次のようなものです。これは、実装次第で解決できるのかもしれませんね。
- 無採点状態から「有益性」の採点を実施
- この時、Slackの「無採点状態のビュー」と「有益性採点のアクション」が送信される
- 「有益性」の採点結果がSlack APIに届き、表示が更新される前に「新発見」の採点を実施
- この時、Slack側は無採点状態のビューを保持しているので「無採点状態のビュー」と「新発見採点のアクション」が送信される
- 1の結果および2の結果のうち、最も新しい応答が反映される。
- 結果として、有益性もしくは新発見の採点結果が破棄される。(Google Spreadsheet側も同様)
- Google Spreadsheetのデータ更新は、Slackからの採点クエリ送信時に行われる
- あるいは、APIに結果が届き表示更新される間での間に採点クエリが送信された場合、Google Spreadsheet側の採点結果とSlack側の採点結果にズレが出る。
- 結果として、有益性もしくは新発見の採点結果が破棄される。(Google Spreadsheet側も同様)
また、Google Spreadsheet APIの処理についても高速であるとは言えないため、Slack APIの3秒ルール(リクエスト後、3秒以内にレスポンスを返さなければならない)に間に合わないこともありました。
「誰が採点していないかわからない」というのも、Chairのコストを高めています。このバージョンでは、採点者の確認方法は採点メニューを目視確認する以外に方法がありません。また、上述の3秒ルールに間に合わなかったものは、本人はボタンを押したのに反映されていないのに気づかないという事例も多発しました。結果として、Chairが全採点メニューを目視確認することで対処しましたが、依然このコストも削減したいものです。
その他、操作性や改善など様々なコメントをもらい、このJANOG57におけるVer.1にたどり着くわけです。
JANOG57での自動化 Ver.1
前回のVer.0のフィードバックをもとに、Slack上で採点していたものを個々人用に作られた採点用のGoogle Spreadsheet上で採点するよう更新を加えたものがVer.1です。また、JANOG56における応募期間中の応募者へのフィードバック・応募内容更新(以下、シェパーディングという)についても自動化を行います。以下に、設計方針を記します。
下図におけるテンプレートシートは、採点のためだけに必要な情報をマスターシートからQUERY関数, IMPORTRANGE関数を用いて抽出・表示したものです。


個々人が入力した採点シートの内容は、以下の方針で設計することにします。


シェパーディングは、以下の方針で設計することにします。

以上を基に設計したモジュール群について見てみましょう。全機能を列挙すると長くなってしまうので、ここではVer.0との差分だけ示すことにします。(Scoring moduleはSlack採点の廃止&Google Spreadsheet移行に伴い廃止となります。)
Submission module
Staff Slackへの応募通知時の、採点メニュー生成は不要となるため機能削除を行います。
Chair module
採否通知の機能に加え、個々人の採点シートを集計し、マスターシートに反映する機能を実装します。
集計機能では、指定したディレクトリ内に存在するGoogle Spreadsheetを順にOPENし、先頭行から読み込みを行います。読み込んだ行について、整理番号をインデックスとしてマスターシート内における該当行を探した後、集計結果を反映します。また、GASのトリガー機能を用いて、毎日一定時間ごとに集計するようセットしています。また未採点の場合は、そのファイル名(つまり、PC委員のニックネーム)を未採点者列に記載し採点済みか否かを管理できるようにしています。
また、後述のシェパーディングフォームの内容(どの応募を更新するかを選択するリストの更新)を行う機能も実装します。こちらも、トリガーを用いて一定時間ごとにすべての応募をGoogle Formのリストに適用する機能となっています。
Updater module
シェパーディングの自動化に向けて新規に作成したモジュールです。Google Formにセットしています。
PC委員は更新内容をシェパーディングフォームに入力します。入力された内容はGASによって、「Slackへの更新通知」、「Confluenceの表示更新」、「マスターシートの更新」を行います。これによって、J56における手動更新を撤廃することが可能となります。
ロジックとしては単純で、指定した応募について該当行をマスターシートから抽出し、更新された内容のデータを上書きするというスタイルです。

テンプレートシート, 採点シートの準備
上記のモジュール構築に加え、PS委員はテンプレートシートを作成した後、それをPC委員数分コピーして採点シートを準備します。
テンプレートシートでは、誤った編集をできないようにPC委員が編集すべき場所のみを編集可能にし、その他はロックするなどの操作性向上を行っています。

自動化してみて
さて、これによって従来問題となっていた、「Slack採点時に他人の採点状況が見えるため、引っ張られてしまう」、「Slackの採点が反映されないことがある」、「誰が採点していないかわからない」を全て解決することができました。
しかし、新たな問題も発生しました。それはGAS自体のタイムアウト(6分/30分ルール)です。
Ver.0にも記載した通り、Google Spreadsheet APIは高速とは言えません。そのため、複数シートの処理&複数行の処理となるとかなりの処理時間を要します。JANOG57では65件の応募 × 15名のPC委員 = 975件の処理が必要です。これを行単位でAPIを呼び出していては、到底タイムリミット内に処理を終えることができません。そこで、GAS高速化の取り組みとして「Google Spreadsheetを丸ごと読み込んだ後、それをキーマップに変換しそれに対し処理を加える」という動作にすることとしました。Read, Writeを行単位で処理するのはしんどいため、以下の流れで処理することにより高速化を実現しました。しかし、タイムアウトしづらくなったものの事象自体は解決できませんでした。
- マスターシート全体を読み込み、見出し行をもとにキーマップを構成します。
- 個々人の採点シートを順に読み込み、都度キーマップを構成します。
- マスターシートのキーマップと採点シートのキーマップを用いて、API呼び出しすることなく採点を処理します。
- 採点を完了したマスターシートのキーマップは、最終的に一括でマスターシートに書き込みます。
PC委員からは採点引っ張られがなくなったという点含め、使いやすくなったというコメントも頂戴した一方、GASの限界が見えてきたバージョンでもありました。
今後の自動化
さて、様々な改善を加えてきた自動化の取り組みですが、より高い操作性を得るためにGASはもはや限界を迎えてきたという認識です。
Google Formをお使いになれない企業がいらっしゃることも認識しており、より高い操作性やPC委員また登壇者自身の双方が自動化によって、円滑な登壇準備をすることを可能にするためにはサーバを設置してのアプリケーション開発・ホスティング・継続的なメンテナンスというフェーズに達するのではと感じています。GASの活用を含めた、さらなる自動化の推進のためにも多くの知見が溜まってきましたので、これらを活用していきたいところです。
さて、非常に分量のある記事となりましたがこの記事がなんらかのお役に立てれば幸いです。
