ランチチーム分割（当たり付き）を作った話

2018.08.01に使う

- github.com/tsuyukimakoto/yoritomo

<img width="501" alt="スクリーンショット 2018-07-29 19.29.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/95506/a4f7096b-a6a8-bc9a-4045-cfe6b5debdac.png">


---

## モチベーション

- ランチに行く人を募り、お店に入りやすい人数にチーム分けしたい
- コミュニケーション促進のためという名目で会社から補助を得たい

---

## 要件

- 会社の基本コミュニケーションツールがSlackなので利用はSlackで完結したい
- httpsでアクセスできるサーバー
- 誰がサインアップしているかを保持しておくデータストア
- 指定した時刻にプログラムをキックできるスケジューラ

---

## SlackのInteractive Message

- 押せるボタンをメッセージに出せる
- 3秒以内にレスポンスがないとエラーに！
  - GAS+SpreadSheetで試していた時に3秒以内に戻ってこないことが多かった

---

## 浮気をしようとする

- GCEのずっと無料枠が拡大されたという記憶

---

## Google Compute Engineのずっと無料枠

- https://cloud.google.com/free/?hl=ja
- Google Cloud Datastoreが1GBまで無料ではないか

---

## Cloud Functions

- nodejsがv6.14.0でウッとなる

---

### つまり

- 何かの定期実行機能でSlackにMessage Butotnを送信
- Slackからの応答をGoogle Cloud Functionsで受ける
- Google Cloud Datastoreを参照してSlackに応答を返す

---

## あれ？AWSでいいんじゃね？

- API Gateway + Lambda
- Dynamodb

API Gatewayだけ料金が微妙にかかりそう

---

## Lambdaの定期実行

- https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/tutorial-scheduled-events-schedule-expressions.html
  - 間隔
  - cron式

nodejsもv8.10に対応している。Python3.6で何も気にせずに書いてしまえという誘惑も

---

## みやもとさん動いてんじゃん！

ということに気づいたというか、せっつかれたというか

---

## GASに戻ります

### 2018.07のイマドキ

clasp + Typescript で書くのが良いっぽい。

---

## clasp

`Command Line Apps Script Projects`

CLIからの認証、プロジェクトの作成、コードのプッシュやデプロイなんかができる。

以前は gapps ってツールを使ってたらしいのですが、Google製のclaspが出たのでディスコンらしい

---

## gas-clasp-starter

- https://github.com/howdy39/gas-clasp-starter
  - 雛形
  - PythonでいうCookie Cutterみたいなものか
    - 参考（django horizon/django lookup extensions）

package.jsonにgas-clasp-starterの名前とかバージョンが書いてあるので注意が必要

---

## Typescript

- @types/google-apps-script

補完効くので楽チン。
とはいえsublimetextだとビルドするまで気づかないエラーとかはある。

---

## yoritomoの構成

```
.
├── appsscript.json
├── config.service.ts ← 設定を扱う。ProeprtyServiceをここに閉じ込めている
├── constants.ts
├── index.ts  ← エントリーポイント
├── models.ts  ← 型定義。ここじゃない気がしている
├── storage.service.ts  ← データを扱う。SpreadSheetはここに閉じ込めている
└── utils.ts ← バグりがちなロジックを入れて、主にこのファイルをテストしている
```

---

## PropertyService

- スクリプトのプロパティを読み書きする
  - 簡易key/valueとして使える

<img width="701" alt="スクリーンショット 2018-07-30 1.06.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/95506/d099f2cd-0a88-9f1f-b8e8-9eff464a9aae.png">


---

## スプレッドシートに持たせられない
  - みやもとさんは設定用のシートがあるけれど
    - みやもとさんはデータが増えると遅くなった
      - 1週間でスプレッドシートを入れ替えるようにしたので、設定は別で持たないといけない

---

## DriveAppとSpreadSheetAPp

- G Driveの特徴
  - ファイルは複数のパスに置ける
  - 同じファイル名のファイルが同じパスにあっても問題ない

- SpreadSheetApp
  - 新しいファイルはrootにできる（マイドライブ）
    - 実行ユーザーのマイドライブにできるし、G Driveなどの権限も実行ユーザーでとっているので初期設定した人が辞めたらやり直しです

- フォルダもファイルもidをスクリプトプロパティに保存しておくと場所を変えられても問題ない
- フォルダをlsしてファイルを探すのも遅くなることが容易に想定できるのでid直打ちで開く

---

## ファイルを作って移動して決めうちでrootフォルダから消す

```Typescript
let root_folder = DriveApp.getRootFolder()
let spreadsheet_file = DriveApp.getFileById(spreadsheet.getId())
folder.addFile(spreadsheet_file)
root_folder.removeFile(spreadsheet_file)
```

---

## ログ出力

GASでログを出力って探すと `Logger.log` を使って ⌘+Enter でって書いてある。
これはScriptEditorから実行するときは手軽で便利。

タイマー実行とかWebアプリケーションとして実行された時にはLogger.logはたまらない。

- console.infoとかを使う
  - GOOGLE STACKDRIVERに記録される
    - Google Cloud Platform と AWS で実行されるアプリケーションをモニタリング、ロギング、診断
  - StackDriverの管理画面で見ると良い
    - 通知メールは12時間以上遅れて来たりするので注意
    - ScriptEditorから開くときはpopupブロックを解除しておかないと動かないように感じてしまう

---

## Webアプリケーションとして公開

- doGet/doPostという関数を用意しておくとWebアプリケーションとして公開できる
  - コードに変更を加えた場合には新しいバージョンで公開しないと反映されない
  - clasp deployだと新しいバージョンはできるけど公開されない
    - https://github.com/google/clasp/issues/43
  - バージョンを変えてもURLは変わらない

---

## SlackのInteractive Message

- Slack appを作る必要がある
  - ボタンを出せる
  - ボタンのレスポンスを受けるURLを指定できる
- Slack appはIncomming webhookも持てるのでIncomming webhookアプリでの管理ではなくてSlack appの管理で良い
- 3秒ルールがある（応答が3秒以内に返らないとエラーが表示される）