【LINE×GAS】Botを導入してシェアハウスの習慣化コミュニティをハックする

この投稿は、[身の回りの困りごとを楽しく解決！ by Works Human Intelligence Advent Calendar 2022](https://qiita.com/advent-calendar/2022/works-hi-1) の21日目の記事としても投稿しております。

https://qiita.com/advent-calendar/2022/works-hi-1

自分の記事は**カレンダー2**の方に登録されています。

# はじめに
## ご飯会のポイント管理Botを作成
自分は現在シェアハウスに住んでおり、ハウスでは**ご飯会**がちらほら開催されます。
開催にあたって特定の条件を満たすと**ご飯会ポイント**が付与され、ポイントでご飯会に使える器具（たこ焼き器やミキサーとか）に交換してもらえるという素敵な制度があります。

ただ、これのポイントの仕方がアナログで、ポイントを専用の用紙に手書きしなければいけませんでした。
これ面倒くさいな〜ってことで、過去にシェアハウスのLINEグループに自作のBotを追加してご飯会ポイントをある程度管理しやすい形にしたことがありました。

それに関する記事は過去に投稿しているので、詳しく知りたい方はよかったらご覧いただければと思います。

https://qiita.com/ta9yamakawa/items/4e5739b01fe23d222489

## シェアハウス運営陣からのお声がけ
ご飯会のポイント管理Botを導入したら、運営陣の代表の方に気に入っていただいたみたいで、
`「作成したBotを応用してぜひ習慣化コミュニティのイベントをやりたいんだけど...」`
とお声がけいただきました。

代表の方と相談をして、Botにやらせたいこと（要件）を箇条書きでまとめると以下のような感じになりました。
- 習慣化すると決めたことを報告してもらって、**報告した回数を管理する**
- **サボっている人を晒してもらって**、参加者に習慣化への適度な外圧を与えたい
- その日が**習慣化を始めて何日目かを教えてもらいたい**

イベントの期間は習慣として定着するまでの3週間（21日間）であり、その間は運営側はコミュニティを盛り上げ、Botは事務的な部分（=運営側の負担になる部分）を任せるといった内容でした。

ちなみに`21日間`という期間は、物事を続けてそれが習慣として定着すると言われている期間だそうですよ^^
みなさんも習慣化したいものがあれば21日間続けてみると良いかもしれません。

***

# できたもの
## 機能
### 応答系
**「名前→[任意の名前]」** で名前を登録します。
これをしないとスプレッドシート上にデータが登録されません。（後述する完了報告のカウントができない。）
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/77359751-9f7a-9b27-f4cb-5e5a3e10eee0.png' alt='名前登録' width=500px>
**「にっこり完了」** と言うとその日は習慣化に必要なアクションを行えたということで習慣くんにカウントしてもらいます。
習慣化アクションの完了報告ですね。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/60132f1c-8982-e6d3-d254-f47bbd70e4db.png' alt='完了報告' width=500px>

登録すると下記のイメージでスプレッドシートにデータが管理されるようになります。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/20891598-c5da-9737-22f7-bf695c346bd3.png' alt='スプレッドシート' width=500px>

### 定期配信
ユーザからの言葉に反応させることだけではなく、GAS側で定期的に実行させる機能も提供しています。

毎朝、習慣くんにより朝の挨拶が届きます。
日毎に内容が変わるので、毎日を楽しく始められますね。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/c3507587-c8d6-3de0-9374-8c8fdf5815e7.png' alt='朝の挨拶' width=450px>

習慣化のアクションができておらず、にっこり完了の報告がないおさぼりさんは習慣くんにより晒されます。
これにより適度にBotからお尻を叩かれます。

ちなみに4日報告がない人は、運営陣の手によってグループを退出させられます。
次回のチャレンジを待ってます的な感じですね笑
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/4e431a82-6ddc-758a-ae8a-f0694512cc5f.png' alt='おサボり確認' width=450px>

イベントの最終日には結果発表として、誰がどのくらいアクションできたかを発表して参加者を称え合います。
実際に21日間皆勤で報告した人は何人もいて、見ててすげぇ！！ってなってました。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/edee6ed6-4389-eaf1-ba38-900e2153151b.png' alt='結果発表' width=450px>

## 仕組み
ご飯会ポイントの管理Botと同じシステムで構成されています。
利用したサービスも同じです。
- LINE Messaging API
- GAS(Google Action Script)
- Google Sheets（スプレッドシート）

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/97379a68-f39e-33e9-607a-7b6c0ba5d742.jpeg' alt='システム' width=600px>

LINE上のユーザの発言をもとにGASでリプライの処理をさせます。
スプレッドシートで、参加者の報告回数等のデータを管理します。
また、今回はGASでトリガーの設定をして定期報告をするようにしています。

# できなかったこと
## ユーザへのメンション
おさぼりさんを晒す時に「@」でメンションをつけてあげられたら、忘れていた参加者も気づけると良いなぁと思っていました。

そこでBotの返すコメントの中にメンションの文字列を入れてみましたが、**実在するユーザ名・ユーザの送ったメッセージのデータの中にある`userId`** を利用してもメンションはつかずにただの文章になってしまいました。
公式のドキュメントやいろんな記事を見てみましたが、現時点ではメンションをつける術はなさそうです。

ちなみに`userId`は過去に書いた記事の検証方法で取得できます。

https://qiita.com/ta9yamakawa/items/deefa9792195836bb0d2#%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97id%E3%81%AE%E6%A4%9C%E8%A8%BC

いつの日か、メンションをつけられる日がくるのだろうか。。
期待せずに待ちたい。

## ユーザのグループ強制退出
4日間サボった人をグループから退出させるルールを決めたのは運営陣とはいえ、さすがに罪悪感があるみたいで笑、一応できるか調査してみました。
人がやるとどうしても恨みつらみが生まれる可能性はありますが、Botに退出させられるのであればまだマシかっていうマインドです笑

しかし、ユーザをグループから強制退出させるような操作は、**UXとして結構過激で攻撃的である**からか案の定調べても該当するドキュメントや記事は出てきませんでした。

これが仮にできたら、LINEグループの治安が悪くなりそうだし、Botの独裁政治感が出てしまってコミュニティの温度感に合わないので、逆にできなくてよかったかなとも思いました笑

***

# 改善と子離れ
21日間の習慣化コミュニティのイベントが終わった後は運営陣と毎回反省会をして作ったBotのフィードバックをもらっていました。

`「Botにもっとこういう機能があるとコミュニティが盛り上がるよね〜！」`

という声をもとに、実現できそうなものは次の21日間に機能を落とし込むように、イベントを重ねるにつれて機能のアップデートをしていきました。

## 完了報告を無機質にしない
どうしても `にっこり完了` の完全一致で完了報告をすると、グループがただの**完了報告部屋**になってしまってコミュニティとして一緒に頑張りあっている感が生まれませんでした。

そこで、`にっこり完了`をコメントに含めて、併せてその日に何をやったのかを報告できるようにする方針に決まりました。
正直完全一致の方が不正なカウントとかがなくなって良いかなと思いましたが、不正なことをしてまで報告してくる参加者がうちのコミュニティにはいないだろうということと、コミュニティを盛り上げることを優先して部分一致にしました。

ただ、
`あ、今日にっこり完了って言うの忘れた！`
にも反応させるのはさすがに参加者も困惑するだろうなとも思ったので、`にっこり完了`から始めてその後は好きにコメントしても良い形式にしました。

コードにするとこんなイメージです。

```javascript
// 完全一致のとき
if (message === 'にっこり完了') {
    return reportMessage(sheet, event);

// ↓↓↓

/// 前方一致のとき
if (message.indexOf('にっこり完了') === 0) {
    return reportMessage(sheet, event);
```

この改善を入れたイベント時には、参加者がその日にやったことを報告し合うようになったことで、以前よりも盛り上がりました。
特に、**感謝を習慣にするグループ**ではとても素敵なことをコメントしている参加者もいて、自分もエモくなりました。

<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/8758aefa-6514-288f-d366-a765dd60b4e4.png' alt='thanksreport' width=400px>


## Botのリアクションを柔軟に
毎日同じリアクションだと、報告することが作業になってしまい参加者のモチベを維持することを難しくしてしまう要因になりがちになってしまっていました。
おそらく最初はBotの機能に感動してもらえるけど、同じ内容だと慣れてしまって結局読まれなくなってしまうなと。。
それに自分が今どれくらい続けられているか、Botに把握してもらえると自分1人でやっている感じがしなくなって、ジムのインストラクターみたいな感じで伴走してくれている感じもして良いないうことで、ユーザの報告回数によってBotのリアクションを変えてみました。

より人間味が増して、21日達成した人の返答にはリアクションもついていて、喜んでもらえているようです笑

|1回目|4回目  |21回目（皆勤賞）  |
|---|---|---|
|<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/a423dee4-11ed-eb41-7cf4-8ed3a0528180.png' alt='1回目応答' width=400px>  |<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/8ee0c31d-60f2-5384-1619-db0619f1b75c.png' alt='2回目応答' width=400px>  |<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/6e1ef78d-77ac-10e8-a6f7-c46b476b9799.png' alt='3回目応答' width=400px>  |

同じ返答をしているバージョンの時にはコード上で返答文を定義しており、返答文に変更が必要だったり、今回のようにパターンをつける場合はいくつかのデメリットがありました。
- 返答文のパターンの数だけ**コード量が増える**
- 細かい返答文言を変えるだけでも**デプロイが必要になる**
- デプロイをイベント中に行うと、**不具合発生時のカウント漏れのリスクが生まれる**
- 運営陣が文章を変えたくても、自分の作業時間に依存するので変更に対する**属人性が高い**

該当箇所だけ抜粋すると下記になります。
この更新時のreturn部分が文言直書きなので、運用・保守のしやすい形に改善します。
```javascript:改善前
// 「にっこり完了」を受けた時の返答文を受ける
function reportMessage(sheet, event) {
  // 省略

  // すでに同日に更新がされている場合は更新を行わない
  if (shouldUpdate) {
    //スプレッドシートのデータを更新しておく
    // ※引数はそれよりも前の処理で生成した変数になるので、用途や設計に応じて増減するかもです。
    update(sheet, targetRow, formattedToday);

    return '完了報告ありがとう！😊\nまた明日も報告待ってるよ⭐️\n楽しく、無理なく、習慣化❗️';
  } else {
    return 'お！報告ありがとう！\n今日は何度も報告してくれるね😊\n\nでも僕の累計カウントは１日１回までしかできないよ！';  }
}
```

まずはスプレッドシートに「報告応答」のシートを作成します。
コメント列に任意の文字を打ち込みます。
<img src='https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/550560/997c313a-d463-7576-0fc5-a41ceaaac105.png' alt='システム' width=450px>

実装では直打ちしていた箇所を、報告回数にから返答するコメントをスプレッドシートから取得する処理に置き換えます。
今回はgetReportReplyメソッドという名前で作成しました。（今思うと結構急いで作ったからもっと綺麗に書けるかも...）
```javascript:改善後
// 「にっこり完了」を受けた時の返答文を受ける
function reportMessage(sheet, event) {
  // 省略

  if (shouldUpdate) {
    update(sheet, targetRow, formattedToday);

    // 返答文を受け取るメソッドを呼ぶ
    return getReportReply(sheet, targetRow);
  } else {
    return 'お！報告ありがとう！\n今日は何度も報告してくれるね😊\n\nでも僕の累計カウントは１日１回までしかできないよ！';  }
}

// 返答文を受ける
function getReportReply(sheet, targetRow) {
  const point = sheet.getRange(targetRow, 3).getValue();
  // スプレッドシートの「報告応答」シートのデータを取得
  const replySheet = spreadSheet.getSheetByName('報告応答');
  const rowSize = replySheet.getLastRow() + 1;
  const targetReplyRow = targetReplyRow(replySheet, rowSize, point);

  return replySheet.getRange(targetReplyRow, 2).getValue();
}

// 報告応答リプライ文言の行数を検索する
function targetReplyRow(sheet, rowSize, point){
  for(let i = 1; i < rowSize; i++) {
    const replyId = sheet.getRange(i, 1).getValue();
    if(replyId == point){
      return i;
    }
  }
  return 2;
}
```

これで、デプロイが不要になり、自分が本業やプライベートで手がつけられなくなっても運営陣の方で好きなタイミングで好きな返答文を返せるようになりました！

Botが一歩親元を離れた瞬間でした。
育てることの負担から解放された親みたいな気持ちになりましたね笑（子供おらんけど）


# 今後の展望
最近だと習慣化のイベントは定期開催になったので、運用の軌道に乗せられたなというところです。
とはいえ、結構走り書きで作成した機能とかもあるのでリファクタリングしたい部分がたくさんあります。

今後はトリガーで自分で手動設定している部分も、月初に必ず始まるイベントであるということが決まっているので、毎日動く関数を作ってその中で日時を設定してあげれば完全に自分が何もしなくても定期配信の処理は動き続けてくれるようになります。
おさぼりさんを晒す処理も、設定しなくても無事に動いてくれるのです笑

また、運営サイドではLINEではなくSlackに移行する？みたいな話も挙がっているようで、現状の仕組みから見直す機会もあるかもしれません。
Slackだとまたやれることも変わってくると思うので、リセットした状態で機能を見直していきたいです。
というかコード汚いので一から作り直したい気持ちもある笑

まだまだ改善の余地はあるので、引き続きユーザの声を拾いつつ良いBotを作っていきたいですね。

# おわりに
今回やったことは前回のご飯会のポイント管理から少し機能を拡張した程度で、そこまで難しいことはやっていません。
それでも、`すごい！`と感動して使ってくれる人たちがいることはとてもありがたいし、そこから改善をしていくことまで経験させてもらえているのは貴重だなと感じます。
回を重ねるごとに徐々に**人間味が増しているBot**に対しても楽しみにしてもらっているのも嬉しいし、生みの親としてリアクションがもらえるのは作ることのモチベになります。
なんでもかんでも、アウトプットは大事ですね。

好きで作っているものなのでお金はいただいていませんが、まるで副業のように顧客（運営陣）とやり取りをして進めるというのも楽しいです。

もっともっとBotを人間味溢れる奴に成長させて、もっともっと参加者を楽しませたいです。
そして、その過程を自分が一番楽しんで行こうと思います。