Google Apps Script 開発マイルール（設計編）

:::note info
この記事は、[LITALICO Engneers Advent Calender 2023](https://qiita.com/advent-calendar/2023/litalico) シリーズ２の21日目の記事です。
:::

# はじめに
本記事は２部構成の２記事目です。
あらかじめ１記事目をお読みいただけると幸いです。

https://qiita.com/gate9/items/deb63f5a8bef5fbf93b4

前の記事ではGASの開発環境を正しく整備して事故の起きないような環境を作りましょうというお話をしました。
この記事ではGASの設計における重要なルールをご説明しようと思います。

# 設計に関するマイルール
:::note info
**設計時にはGASの実行アカウントを意識すること**
:::
まずGAS特有の実行アカウントの仕組みをご説明した上で、実際に活用した事例を2件ご紹介します。

# GAS実行アカウントの仕組み
GASがどのアカウントで実行されるかを下記の表に示します。
| GASの種別 | 実行アカウント |
|:-|:-|
| 通常のGAS（ファンクション名呼び出し） | GASを呼び出したアカウント |
| WebアプリとしてデプロイしたGAS | GASのオーナー |
| シンプルトリガーで実行したGAS | GASを呼び出したアカウント |
| インストーラブルトリガーで実行したGAS | トリガーのオーナー（GASのオーナーとは別） |

この表のポイントは次の2点。
- 誰が呼び出しても同じアカウントとして処理したい場合は、Webアプリとして実装することを検討する。ただしWebアプリGASはURLコールで呼び出すため考慮が必要。
- トリガーを利用する場合は、種別によって実行アカウントが異なるので注意する。

> トリガーについて補足しておきます。
> <dl>
>   <dt>シンプルトリガー</dt>
>   <dd>
>     特別なファンクション名で実装することで設定できるトリガー。<br>
>     onOpen：ファイルを開いた時、<br>
>     onEdit：ファイルを編集した時、など
>   </dd>
>   <dt>インストーラブルトリガー</dt>
>   <dd>
>     GASエディターで明示的に設定したトリガー。<br>
>     ファイル操作駆動、cronのような時間駆動、Googleカレンダー駆動がある。<br>
>     スクリプトでトリガーを作成することも可能。
>   </dd>
> </dl>

# 事例１
## 要件
利用者が多数存在するシステムを構築する際、データへのアクセス権限を制御することはよくあると思います。
例えば下記要件があったとします。
- アクターは `利用者` と `管理者`
- システムに対して多くの `利用者` が入力を行う
- `利用者` が入力したデータは1つのスプレッドシートに集約される
- `管理者` は集約されたスプレッドシートを参照し分析などを行う
- `利用者` は他の利用者が入力したデータを参照できてはいけない

よくありがちな要件だと思います。
この設計を考えてみましょう。

## アンチパターン
まずはよく陥りがちなアンチパターンを説明します。
![2_1_アンチパターン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200478/c2efa5e9-96d2-5f5a-9c0a-829dbb687c2c.png)

- 利用者はデータ入力用スプレッドシートに入力して登録ボタンを押すと、データ登録GASが呼び出される
- データ登録GASはデータ格納用スプレッドシートに登録する
- 管理者はデータ格納用スプレッドシートを参照する

いたってシンプルな設計で、実装も簡単そうですね。
しかしこの設計には大きな問題点があります。
通常のGASで実装しているため、
　**データ登録GASの実行アカウント＝利用者のアカウント** 
になりますので、データ登録GASがスプレッドシートへ書き込むためには、
　**利用者全員に対してデータ格納用スプレッドシートの編集権限を付ける**
必要があります。

するとどうでしょう、 `利用者は他の利用者が入力したデータを参照できてはいけない` という要件を満たすことができなくなりました。

## 解決策
Webアプリを使うことで解決します。
![2_2_改善策.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200478/31b2b00d-fb4a-a89b-911e-c6a5a4fd6594.png)

データ登録GASをWebアプリとして実装することで、
　**データ登録GASの実行アカウント＝GASのオーナー**
になりますので、
　**GASのオーナーに対してのみデータ格納用スプレッドシートの編集権限を付与**
すればよく、 `利用者は他の利用者が入力したデータを参照できてはいけない` という要件を満たすことができました。（GASとは直接関係ないですが、管理者に対して参照権限を付与する必要もあります）

# 事例２
## 要件
弊社LITALICOは全国に教室を展開しており、教室に通う「教室利用者」とその利用者に対してサポートを行う「教室担当者」がいます。
そちらを前提として今回の要件をご覧ください。
- 教室利用者1人に対して1つのスプレッドシートを作成する
- スプレッドシートの作成は教室担当者いずれかが行う（誰でもよい）
- そのスプレッドシートは複数の教室担当者が更新する
- スプレッドシートを開いたときに別ファイルに保存されているデータをロードする

## アンチパターン
実際に私が目の当たりにした実装をアンチパターンとしてご紹介します。
![3_1_トリガー1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200478/eec87acd-caee-6864-ea59-66d9380c55b3.png)

この仕組みを使った業務の流れは次の通りです。
1. 教室利用者が増えると、教室担当者がGASを呼び出します。このGAS呼び出しは誰でも可能です。
1. GASは、教室利用者1人に対して1つのスプレッドシートを作成し、起動時トリガーをインストーラブルトリガーとして作成します。（インストーラブルトリガーはスクリプトで作成することが可能です）
1. 教室担当者は、作成されたスプレッドシートに教室利用者の情報を日々入力します。
登録された情報は別ファイルに保管されており、次回スプレッドシートを開いたときに起動時トリガーによりそのデータがロードされる仕組みになっています。

この仕組みをエンジニアではない方が作られたので、設計レベルの高さに当初は驚きました。
しかし程なくして大きな問題に気が付きました。

冒頭に記載したGAS実行アカウントの仕組みの表に記載したように、インストーラブルトリガーで実行したGASの実行アカウントはトリガーのオーナーになります。
今回のケースだとスプレッドシート生成GASを呼び出した **教室担当者Aさん** になります。
つまり、誰がスプレッドシートを開こうがその際に動く処理はAさんとして実行することになります。

**Aさんが退職したらどうなるんだろう？？？**

教室担当者Aさんのアカウントが退職等によって削除された場合、この起動時トリガーは動かなくなるのではと想像しています。（実際に検証していないので確かなことは言えませんが、少なからず悪い状況になるのは間違いないです）

しかもこの状況はGAS実行アカウントだけでなく、「インストーラブルトリガーはトリガーのオーナーのみ編集や削除が可能」という制約にも影響があります。Aさんしか編集や削除ができないのです。
実際にオーナー以外のアカウントで確認したところ編集ボタンや削除ボタンが表示されず、さらにオーナーの欄には「他のユーザー」としか表示されておらずAさんかどうかすら分からない状況でした。
この状況でこのシステムを運用保守していくのは困難を極めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200478/fc339550-80df-3e5a-9cf6-5eb114d9ae56.png)

## 解決策１
- スプレッドシート生成GASでインストーラブルトリガーの設定をやめる
- 起動時トリガーの処理を教室担当者のアクション（ファイルを開いたら必ず所定のボタンをクリックするルールとする、等）に委ねる

ユーザーに負担をかけますが、一番シンプルな考え方ではあります。

## 解決策２
- スプレッドシート生成GASをWebアプリとしてデプロイする

事例１と同様にWebアプリを採用する案です。
WebアプリGASを共用アカウントでデプロイすれば、誰がスプレッドシート生成を指示しても、インストーラブルトリガーのオーナーは共用アカウントになり、運用保守が可能になります。
![3_2_トリガー2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/200478/72b5cc24-86c8-bd8e-be3b-cee88e68cc2d.png)

スクリプトでトリガーを作成できるのは便利ではありますが、安易に使ってしまうと後々保守できないシステムを作りかねないので非常に注意が必要です。

# まとめ
２つの事例を通してGAS実行アカウントの重要性をご理解いただけたでしょうか。
正直なことを言うと、開発環境編の内容も含めて
**これほどの規模のシステムをGASで構築するのはいかがなものか**
というのが持論としてありますし、この記事をお読みいただき同じように思った方も少なくないと思います。
しかし、手軽にローコードで作れてしまうこの仕組みを使うことはもはや止めることはできないのが実情ですので、今回記事として書いた内容を意識しながら対応していくしかないと今では考えています。

もしこの記事が皆さんのGAS開発の一助になったら幸いです。
ありがとうございました。