GASウェブアプリでプランニングポーカーを作ってみた
利用してみたい方は、こちら
背景
チームでプランニングポーカーを実施していた時に、13〜21って範囲が少し広すぎるよ
とか気づいたら接続切れてて部屋作り直しになった
など、大した問題ではないが、少し使い勝手の悪さを感じていたので自作してみました。
利用技術
- Google Apps Script
- Vue.js
- Bulma
仕組み
- Clientで稼働するのは、Vue.js+Bulmaで構築される画面
- GoogleAppsScriptでは、Roomのデータ管理を実施
機能紹介
-
選択項目を誰でも好きなように変更可能
- プリセットされている選択項目は4つ
- 値は変更可能であり、制限も設けていないので自由な文字に変更可能
-
+ -
ボタンで自由に追加削除可能
-
作成した部屋にアクセスするID付きURLをクリップボードコピー
-
カード表示の各種機能
- アイコンにより、選択中/済みが判別可能
- 右上の
x
ボタンで退場する、させることが可能 - 全員の選択が完了すると自動オープン
-
選択結果の平均、最大、最小表示
-
Ghostモード参加機能
- ポーカーに参加しないが、見学する場合にカードを選択が制限されている状態で参加することが可能
実装
- 動作させる場合は、以下の手順で実施してください。
- GoogleAppsScriptを新規作成して、GitHubのプログラムを登録する。
- .html は、HTMLで登録、 .gs は、スクリプトで登録してください。
- デプロイ - 新しいデプロイでウェブアプリとしてデプロイする。
- トリガー - トリガーを追加 -
deleteProperty
を1時間おきで登録する。
- 発行されたURLにアクセスする。
POINT説明
データはGASのPropertiesService
を利用
const saveRoomData = (id, data) => PropertiesService.getScriptProperties().setProperty(id, JSON.stringify({
...data,
lastUpdated: (new Date()).toISOString()
}))
const getRoomData = (id) => {
const property = PropertiesService.getScriptProperties().getProperty(id)
return property ? JSON.parse(property) : false
}
よくある、GASといえばSpreadSheetでも良いのですが、比較的短時間の利用であること
と、データを保管し続けない(roomの利用が終了すると不要データになる)こと
から、PropertiesServiceを利用しています。
格納できるデータ上限もありますが、一時保存先なので十分であると判断しました。
また、定期的に不要になったデータを削除するトリガーを設定してクリーニングしています。
const deleteProperty = () => {
const properties = PropertiesService.getScriptProperties().getProperties()
const checkDate = new Date()
checkDate.setHours(checkDate.getHours() - 2)
Object.keys(properties)
.filter(key => JSON.parse(properties[key]).lastUpdated < checkDate.toISOString())
.forEach(key => PropertiesService.getScriptProperties().deleteProperty(key))
}
データ同期は、2秒おきのポーリング
polling: async function() {
if (this.isPolling) return
this.isPolling = true
while (this.isPolling) {
await new Promise(resolve => setTimeout(resolve, 2000))
google.script.run.withSuccessHandler((response) => {
const updateRoomData = response.roomData ? JSON.parse(response.roomData) : null
if (!updateRoomData || !updateRoomData.users[this.userId]) {
window.open(this.url, '_top')
return
}
this.roomData = updateRoomData
}).withFailureHandler((e) => {
console.log(e)
}).polling(this.roomId)
}
},
同時接続部屋を作るのが得意なWebSocketを利用する方法も考えたのですが、サーバーが必要になるので
今回は、ポーリングで実現しました。
感想
ここをベースに、チームにあった選択項目や、カード表示にカスタマイズしていくことで、楽しいプランニングポーカーが実施できるのではないかと感じました。
当初はGASで利用していたのですが、実際に運営してみると好評だったので
現在は、GASからFirebaseにリホストして、公開しています。
お試し利用していただけると嬉しいです。
データ同期もFirestoreになっているのでサクサク稼働するようにも改善されています、