GASでやたらめったら長いアンケートを自動で作成し30分早く帰宅した #雑務Ops

こんにちは。大学生です。先日は個人開発の記事に大きく反響があり、ケーススタディの需要が高いことを学びました。今回は「Google Apps Scriptを使えば、**あなたにも業務改善ができる**」ということを実感していただけるような記事を書くことにしました。

https://qiita.com/kanta_yamaoka/items/7ecdd3c57206e4aff3f0

# Google Apps Script (GAS) について
Googleの提供する多くのサービスをJavaScriptで自動化できるサービスです。とりわけQiitaユーザの多くを占めるWEB系エンジニアは、**極めて低い学習コストで、反復作業を異次元に効率化**できます。また、Slack APIなどの外部APIと連携させることもでき、その多彩さは目を見張ります。

https://developers.google.com/apps-script

# アンケート作成ぴえん。。な件
私は「センシングとAIを用いて人間の学習を加速する」[^1]という研究を行うラボに所属しています。なんだか最先端な雰囲気のするテーマですが、当然、何らかの方法で被験者に介入したあとは、その結果を統計的に解析するために、心理学的なアンケートをGoogleフォームで作成&集計するという地味な作業も発生します。

この手のアンケートはやたらめったら質問数が多いことがあります。おそらく、質問数が多いほど、正確に被験者の何らかのスコアを図れることが期待されるからです。しかし、手動でGoogleフォームに作成するのは**ダルい**: 

* 時間がかかる
* 質問項目と選択肢がずれるとアンケートを再実施する必要がある
    * 人の貴重な時間と研究費が無駄になり、さらなる事務作業が発生

さあ、それでは私の場合の実例を見ていきましょう。

# フォーム自動作成で30分を節約した件

明日は被験者が来てしまうので、とあるフォームを作らないといけない。質問項目は50個程度。**今日は疲れたから早く帰りたい。**

このフォームは研究室の誰かが作ったものだけど、誰のアカウントに紐付いているのかすぐにはわからないので、Drive上でまるごと複製ができない。だから自分で同じものを作らないといけない。

とりあえず、質問内容と選択肢はコピーしてスプレッドシートにまとめた。けれども、これからまっさらなGoogleフォームに１つ１つコピペしていくと質問番号１つにつき1分かかりそう（最悪の想定:**50分**）だし、**ずれたら後でまじダルい。**

夕方5時。疲れがたまってイライラが高まり、もう帰りたい。ぴえん。。

「おちつくんだ！息の呼吸！ 弐ノ型 瞑想。」[^2]


自分を落ち着かせたあと、ついに私は伝家の宝刀**GAS**を抜き出したのです。

## 必要な構成要素からプロトタイピングしよう


やりたいこと

* ラジオボタンの質問及び2択の選択肢をフォームに自動入力する
* 回答は必須に設定する
* 項目のソースはスプレッドシートにまとめている

これらをもとに、公式ドキュメントを使ってスクリプトを書いてみよう。

これまでの経験から、GASは公式ドキュメントが神で、それ以外のサイトはあまり役に立たない。これは、**GAS自体が多彩すぎて、十人十色のユースケースのなかに、あなたのユースケースと一致することが稀**だからだ。

### ラジオボタンのフォームを作成してみる
とりあえず、50個のラジオボタンの質問を自動生成するスクリプトを作成してみる。

```js:

function createCrazyMultipleChoises(){
  // https://developers.google.com/apps-script/reference/forms/form-app
  const form = FormApp.create('質問がやたら多いフォーム')
  form.setDescription('これはやたら質問数が多いフォームです。我慢してお答えください。')

  // https://developers.google.com/apps-script/reference/forms/multiple-choice-item
  for(let i=0; i<50; i++){
    // 大量のラジオボタンを追加
    const item = form.addMultipleChoiceItem().setRequired(true) // 質問への回答を強制する
    item.setTitle(`${i+1}. ねえ、今どんな気持ち？`)
      .setChoices([
          item.createChoice('うあああああああああ質問が多い'),
          item.createChoice('あああああああああああああああ')
      ])
  }
}

```

スクリプトを実行すると、フォームがちゃんと作成されていた。


### スプレッドシートから回答選択肢を読み込んでみる

次は、Google Spreadsheet上の質問項目と、回答選択肢を読み込む部分を書いてみよう。

```js

const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("bar")

```

なお、今回のGASスクリプトは、スプレッドシートのコンテナバウンドになっている。GASにはコンテナバウンドとスタンドアロンの２つがある。このことについては以下の素晴らしい記事を参照。

https://qiita.com/sebisawa/items/4faa6d859f480e306f46


はい、これでもう大丈夫そうですね。
あとはスプレッドシートにまとめてある、質問と選択肢を今度は読み込んで、それらをもとにフォームを作成してみましょう。

### あとは最終形態を目指す


```js:GASで実行する関数
function getFormsDoneRealQuick() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("bar")
  const qObj = getItemsFromSheet(sheet)
  createForm(qObj)
}
```

```js:シートから項目を読み取り処理する部分

function getItemsFromSheet(sheet){
  // 範囲はインデックスでもいいけれど
  // 文字列としても渡せるのでありがたいです
  const raw_cols = sheet.getRange("A1:A132").getValues()
 
  // すんません、実際に使ったコードなのでいろいろハードコードしてます
  // A1-A132 (or index 0-131)
  let questions = []
  let items_a = []
  let items_b = []

  // シートには一列に質問、回答a、回答bの順で各質問が並べてあったのです
  for(let i = 0; i<= 131; i+=3){
    questions.push(raw_cols[i])
    items_a.push(raw_cols[i+1])
    items_b.push(raw_cols[i+2])
  }
  return {
    questions: questions, items_a: items_a, items_b: items_b
  }
}

```



```js:フォームを作成する部分

function createForm(qObj){
  // https://developers.google.com/apps-script/reference/forms/form-app
  const form = FormApp.create('自動生成フォームのタイトル')
  form.setDescription('概要はここ')

  // https://developers.google.com/apps-script/reference/forms/multiple-choice-item

  qObj.questions.forEach((question, idx)=>{
    // 大量のラジオボタンを追加
    const item = form.addMultipleChoiceItem().setRequired(true) // 質問への回答を強制する
   
    item.setTitle(question)
      .setChoices([
          item.createChoice(qObj.items_a[idx]),
          item.createChoice(qObj.items_b[idx])
      ])
  })
}

```





### シートから値の読み込みに関するコツ
GASでスプレッドシートの値を複数読み取るときは範囲指定して一括読取りを行おう。
これは、読み取りのオーバヘッドが大きく、１セル単位で多くのセルを読み取ると、そのオーバヘッドが累積してしまうからです。一括読み取りしたあとはその配列を一括操作しましょう。いわゆるバッチ処理をやりましょう。

# もたらされたメリット 30分の自由な時間

スクリプト作成にかけた10分で、目的のフォームを作成できました。
次の日の実験までに、無事Googleフォームが間に合い、好都合でした。

また、手動でシートとフォームを往復して、40-50分間コピペを繰り返すよりも早く帰ることができました。30分程の節約ですね。

たった30分かよ、と思うかもしれませんが、、

* カップラーメンを10個作る
* 家に帰る
* 3分の曲を10回きく

とかいろいろできます。

今回のフォーム作成作業を自力でやっていたら本当に**ぴえん**でしたね。

#あなたはパレートの法則に支配されている？

https://ja.wikipedia.org/wiki/%E3%83%91%E3%83%AC%E3%83%BC%E3%83%88%E3%81%AE%E6%B3%95%E5%89%87

いわゆる**２割８割**という値が常に成り立つか、という議論はおいておいて、「**多数のものが、少数の要因に大きく影響をされる**」という経験則的な考えは一考に値します

もしかしたら、あなたの労働時間の大半が、一部のどうでもいい作業に取られてる可能性もあります。とりわけ、その作業がコンピュータで行われていて、反復可能である場合は、Google Apps Scriptなどで大幅なコスト削減ができるかもしれません。


# 最後に
最近「週四時間だけ働く」という一見クレイジーな本を読みました。
この著者もパレートの法則に基づいて業務を改善することの重要性を説いています。

https://fourhourworkweek.com/

成果に結びつかないが、単調で時間がかかり、ストレスがたまる作業はありません？
それらを自動化すれば、捻出した時間で幸福度を高められます。

* 家族と過ごす
* 睡眠や運動する
* 恋愛をする


さあ、今日からあなたも、GASスタンド使いになりましょう！

# 関連項目

業務改善に有用な事柄に関してキーワードを述べておきます。

- Slack API
- Chrome拡張機能
- Pupeteer

実生活での業務改善に関しては他にも記事書いているので、もしよかったら見てみてください。

https://qiita.com/kanta_yamaoka/items/dd830cf23ff59353824d

https://qiita.com/kanta_yamaoka/items/14d8a8e9aab7ab7933cf


[^1]: うちの研究室にはアイトラッカーからOura RingやfNIRSや簡易な脳血流の測定装置などなんだかいろんなデバイスがあります
[^2]: マインドフルネスというやつです