士気管理の運用をGASで自動化してみた。 

[mediba Advent Calendar 2020](https://qiita.com/advent-calendar/2020/mediba) の13日目を担当させて頂きます、2年目の@hiromasa-funです。

社畜2年目も折り返し地点に入り、時の流れは早いなぁと思う今日このごろです。
またコロナ情勢で、リモートワーク9ヶ月目に到達してました。
私はFtoFでお仕事したい派なので、昨今のリモートワーク縛りは少し寂しさを感じます...(共感求む)

前置きはこのくらいにして、今回は**「GASで自動化してみた話」**です。



# はじめに
私が所属しているチームでは、アジャイル思考を積極的に取り入れており、
今回触れている**士気管理の「ニコニコカレンダー」**もアジャイル思考の一つとして取り入れています。




# 士気管理「ニコニコカレンダー」
ニコニコカレンダーは、チームメンバーがどんな心境・面持ちで業務をしているかという気持ちを可視化し、
チーム全体の状況把握や個人単位での心理的安全性を担保できるようなツールです。

## 我チームの運用方法
私のチームでは、Googleスプレッドシートで管理しており、
午前/午後の2回で気持ちを表現しています。
気持ちの表現方法は、

* 🔵：Good!
* 🌕：Normal
* 🔴：Bad

の3種類で表現しています。

![nikoniko_calendar_sheet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185888/df0ca8b3-ea96-a15a-f6a4-8442620e0f60.jpeg)

### 運用フロー
自動化前の運用はこんな感じです。簡単なフローを図にまとめてみました。

①：チームメンバーは、Googleフォームに今日の気持ちを入力します。
②：Googleフォームに入力されたデータはGoogleスプレッドシートに反映。(連携してるのでここは自動)
③：メンバーは適宜スプレッドシートの表を見て、全体の士気がどのようになっているのか確認する。
※月ごとにシートを作成しており、運用作業として管理者が、月末くらいになったら来月用のシートを作る作業が発生する。

![スクリーンショット 2020-12-12 8.48.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185888/3039a3be-452a-2f2a-eaeb-c5fbeea1631e.png)

### 運用の課題
しかし、この運用を実施してみたところ課題が2点ほど浮き彫りに・・・

* **わざわざスプレッドシートに結果を見にいかなければならない**。
    * 結果を見なくなると入力している意味がないので、入力がお座なりになっていく傾向も見られました。
* **月に1回シートを作成する**というイベントが発生する。しかも月1というのが絶妙に忘れがち。




# 自動化したこと
ということで現在の課題を解決すべく、以下2つをGASで実装してみました。
(可読性はあまり気にせずスピード重視で書いたので、あしからず・・・)

**1. 【トリガー：月初の9~10時】先月の結果をSlackに投稿
2. 【トリガー：月初の0~1時】今月のシートを自動作成**

運用フローとしては、このように変化しました。
![スクリーンショット 2020-12-12 8.49.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185888/caff1f96-a319-028a-4419-df9b90f9d124.png)



## 先月の結果をSlackに投稿
* GASで`Webhook URL`にPOSTリクエストを送信してあげると簡単にWebhookさんがSlackに投稿してくれます。

```javascript:postSlack.gs
function postSlack() {
  let webhookUrl = "Webhookで生成されるURL";
  var description = "投稿文";
  var options =
  {
    "method" : "post",
    "contentType" : "application/json",
    "payload" : JSON.stringify(
      {
        "text" : description
      }
    )
  };
  UrlFetchApp.fetch(webhookUrl, options);
}
```

Googleスプレッドシートのデータを整形する処理やどんな結果を投稿するかは、
説明するときりがなくなるので、例として実際に投稿したものを載せておきます。
![スクリーンショット 2020-12-12 10.52.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185888/99a04efd-d6c7-1b91-3aeb-c5a60887f488.png)
この投稿は、**先月の集計分の結果と先々月分との比較結果を投稿**しています。
例えば、12月初めに投稿されたものであれば、11月分の結果を共有していて、11月分と10月分の結果を比較しています。
※最後の名言コーナーは遊び程度にいれてあります笑(ちょうど凄い名言だ・・・)




## 今月のシートを自動作成

コードはこんな感じ。

```javascript:createSheet.gs
/*
 * 今月のシートを自動作成
 */
function CreateSheet() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet()
  var sheetCopymoto = sheet.getSheetByName("先月分のシート名");
  
  // シートのコピー作成
  var nextSheet = sheetCopymoto.copyTo(sheet);
  nextSheet.setName("今月のシート名");

  // シートを一番左に移動
  sheet.setActiveSheet(nextSheet);
  sheet.moveActiveSheet(1);
  
  // 来月シートの中身整理
  NextSheetFixed(nextSheet);
}

```
※`先月のシート名`や`今月のシート名`の部分に関しては、Dateオブジェクトを使って年月表記で実装していますが、
今回は割愛させて頂きます。(例えば、2020年12月のシートであれば`202012`みたいな名前にしてます。)

処理の流れとしては、

**1. 先月のシートをコピー
2. コピーしたシートのシート名を変更
3. コピーしたシートを一番左に持ってくる
4. コピーしたシートの中身を今月仕様にする。**

です。
`4. コピーしたシートの中身を今月仕様にする`の処理は、以下の`NextSheetFixed`関数で行っています。

```javascript:createSheet.gs
/*
 * 来月シートの中身整理
 */
function NextSheetFixed(nextSheet) {
  // 年月変更
  nextSheet.getRange(1,3).setValue("年月");
  
  // 先月より日にちが増える場合
  if (getLastDateCount() > 0) {
    // 増えた分列を追加してコピー
    for(var i = 0; i < getLastDateCount(); i++) {
      nextSheet.insertColumnAfter(nextSheet.getLastColumn()-3);
      for(var j = 1; j < nextSheet.getLastRow(); j++) {
        nextSheet.getRange(j,nextSheet.getLastColumn()-4).copyTo(nextSheet.getRange(j,nextSheet.getLastColumn()-3));
      }
    }
  // 先月より日にちが減る場合
  } else if (getLastDateCount() < 0) {
    // 減った分列を削除
    nextSheet.deleteColumns(nextSheet.getLastColumn()-2 + getLastDateCount(), Math.abs(getLastDateCount()));
  }
}

/*
 * Date差分カウント
 */
function getLastDateCount() {
  var today = new Date();
  var thisMonthDate = new Date(today.getFullYear(), today.getMonth()+1, 0).getDate();
  var lastMonthDate = new Date(today.getFullYear(), today.getMonth(), 0).getDate();
  return thisMonthDate - lastMonthDate;
}
```

`getLastDateCount`関数は、`今月の日数` - `先月の日数`の値を返す関数になっています。
これを1つの指標としていくつ列を増減すれば良いのか、という処理を`NextSheetFixed`関数にて実行しています。
例えば、12月のシートを作成する時、1１月のシートをコピーして作られます。11月最終日は30日、12月最終日は31日なので、`getLastDateCount`の返り値は31-30=1になります。なので、12月のシート内の30日列の後に1列増やすことをする、というアルゴリズムになってます。(なんかもっと良いやり方ありそう笑。)

下記は`createSheet.gs`を実行して、12月のシートを自動作成している様子です。(見にくくてすみません。)
先程の例でも言ったとおり、12月は31日までなので、31日目の列がちょうど作られています。

<img width="1000" alt="Dec-12-2020 13-38-59.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185888/fe8a2052-f566-13e3-6599-2ab766eb0cd5.gif">

ということで、運用の課題は解消できました！(GAS様様:bow:)


# おわりに
**事務的/毎度同じ作業は自動化してしまって、別のことに時間を当てれるような環境づくり**も大切ですよね。

### GASに触れた感想
* GASでスプレッドシートを操作していると、コードと表が依存してしまいがちなのでコードは参考にならないかもです笑(丁寧に書けば別かも？)。しかし、やっぱりスクリプト言語は便利ってのと書いてて楽しい、参考ドキュメントもたくさんある、またトリガー(Batch的なやつ)も簡単に指定できるので軽いものであれば、どんどん使っていこうかなと思いました。

### ニコニコカレンダーの感想
* この士気管理「ニコニコカレンダー」は様々な用途で活用できると思っていて、今回の記事のようにみんなに見えるような形式でも良いし、マネージャー陣のみ結果を見れるようにする仕様でも、みんなに見られないという点では入力の内容が変化しそうですよね。自分のチームにとって、どのような活用の仕方が合うのかという判断は、難しいかも知れませんが、導入コストはそこまで高くないと思うので、チームの士気が見えない/あまり良くないと感じている方はぜひ試してみるのも良いと思います。

ps.我チームは、もともと言いたいことを言える方が多く、士気管理という面では、いらないという結論に至ったので**現在は使用していません草(どんでん返し)**。


# 参考文献
* au Webポータルチームにおけるチームビルディングの取り組み
    * https://ceblog.mediba.jp/post/628293655961157632/au-web%E3%83%9D%E3%83%BC%E3%82%BF%E3%83%AB%E3%83%81%E3%83%BC%E3%83%A0%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%81%E3%83%BC%E3%83%A0%E3%83%93%E3%83%AB%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%81%AE%E5%8F%96%E3%82%8A%E7%B5%84%E3%81%BF
* アジャイルなリモートコミュニケーションの極意
    * https://note.com/shift_tech/n/nd48c9345937c
* アジャイル開発での士気管理「ニコニコカレンダー」
    * https://www.fujitsu.com/jp/group/fst/about/resources/featurestories/about-agile-16.html#agile-01