😽

【GAS (Google Apps Script) 】コードを書く上で定めるべきポリシーについて|Offers Tech Blog

2022/08/25に公開

概要

こんにちは、Offers を運営している株式会社 overflow のバックエンドエンジニアの shun です。今回は、GAS(Google Apps Script)をチームで書く際に重要だなと思うポリシー(事前にチームへ共有した方がいいと思うこと)について、私の経験をもとにご紹介したいと思います。

Properties Service を使う

Properties Service とは、簡単にいうと 簡単なデータを格納できる箱 です。どんな情報を格納するかというのが重要になってきます。

この Properties Service で設定できる Property は 3 つあります。

Script Properties User Properties Document Properties
アクセス方法 getScriptProperties() getUserProperties() getDocumentProperties()
アクセス可能な人 エディタに入れる人全員 設定した人 エディタに入れる人全員

例えば、サードパーティの API を叩き、自社が管理するスプレッドシートにデータ出力したいとします。その時、サードパーティから発行された API キーなるものが必要になります。これを Google Apps Script にベタガキしていては、本来責任者が厳重に管理すべき書類を休憩室に置き忘れてしまったくらいに 危険 です。悪用まではいきませんが、「この API キー、練習で使いたいから私用 PC に入れて持ち帰ろう」ということを許容してしまっている状態が危険なわけです。(どこかに API キー落としてきた、なんてことがあったら社外の人にも利用可能にしてしまいます。)

そこで利用したいのが User Properties です。これは設定した本人しかアクセスができないようになっているため、外部に漏洩する可能性が圧倒的に下がります。

複数 Google アカウントがある方は、以下のように動作確認可能です。

Main.gs
/**
 * 自分だけがアクセスできるプロパティを設定
 * 実行後は記述ごと削除しないといけないので注意
 */ 
const setUserProperties = () => {
  const userProperties = PropertiesService.getUserProperties()
  userProperties.setProperty('XXXX_API_KEY', 'api_key')
}

/**
 * APIキー読み込みにトライ
 */ 
const tryAccessUserProperties = () => {
  const userProperties = PropertiesService.getUserProperties()

  if(userProperties.getProperties().XXXX_API_KEY) {
    console.log("アクセスできた!", userProperties.getProperties().XXXX_API_KEY)
  } else {
    console.log("アクセスできず")
  }
}

まず Google アカウント A にて setUserProperties を実行し、 tryAccessUserProperties を実行すると アクセスできた! api_key という分岐に入ることを確認できます。
続いて、Google アカウント B にて tryAccessUserProperties を実行するとどうなるでしょうか。
アクセスできず という分岐に入ることがわかります。

このように、スクリプトを書いた人のみ がアクセス可能なプロパティに重要な情報は格納すべきです。

念の為作業していい時間かを確認しておく

通常、アプリケーション開発時にはいわゆるチーム開発というものをしますので、複数人のエンジニアが自分の作業環境を用意して実装対応を行います。しかし、GAS エディタで作業するということは本番サーバー上で Vim 操作しコードをいじっているのと相違がないため、超重要な仕事を GAS に委ねている場合は、編集時間を見計らう必要があります。(個人的にはそこまで重要な機能なら GAS で行わずにアプリケーション側へ寄せるべきだと思っているので、あくまで GAS で行う作業は軽微なものにするのが良いと思われます。)

管理者アカウントでコードを書く

上記のプロパティの話で気になった方もいるかと思いますが、「一度作ったプログラムをその開発者以外メンテできない」というのは不健全です。仮にプログラムを書いた人が退職などしたらそのコードは迷宮入りしてしまう可能性があります。なので、実装するアカウントは共有アカウント上で行うのがポリシーとしては健全だと思います。しかし Googleサポート でも明記されているように共有アカウントの利用は非推奨です。が、禁止ではないので管理者アカウントでコードを書いていくと良いと思います。ただし、複数人が交代でメンテナンスをする必要のある重要な役割はアプリケーション側に寄せるべき、と個人的には思ってます。

管理者アカウントでトリガー設定を行う

これも上記と同様の理由ですが、GAS のトリガーは設定した人しか編集/停止ができず、設定者が退職した後に確認する身となった場合は厄介です。管理者アカウントを共有として少なからずメンテナンスができる状態にしておくことが重要だと思います。重ねてになりますが、Googleサポート では非推奨です。

コードはモダンな書き方で書く

GAS といっても、中身はほぼ JavaScript です。GAS エディタを開いた際は function MyFunction というメソッドがデフォルトになっていますが、メインのアプリケーション開発ではモダンな記法(const やアロー関数など)を利用するため、そちらに合わせておいた方が、書いていて楽しいかつ後任の方も読みやすくなると思われます。

GASにもREADMEを書く

何かしら背景があって自動化プログラムを書くと思います。スプレッドシートに紐づくスクリプトの場合は、スプレッドシートの先頭に README という名前でシートを作成すると、とりあえず使い方や背景は知っておきたい実装者以外の方にも親切です。また、GAS に README.gs ファイルなどを作成して書くのも良いかと思います。「コードを見ないとやりたいことがわからない」というのは極力防いた方がいいと思います。

コード管理が必要ならする

スプレッドシート運用を長くしていると、気づいたら立派な 1 システムになっていることは多々あります。上記で提言したような内容は分かっていてもなかなかアプリケーション側に移行するにも大変です。立派なスプレッドシート + GAS でできたシステムを複数人でメンテナンスする必要性は結構な割合で発生するため、その際にはコード管理するのがいいと思います。
方法としては、大きく 2 つあると思います。
1 つ目に、GAS のコードをそのまま Push/Pull する Chrome 拡張機能の Google Apps Script GitHub アシスタント を用いる方法。履歴管理というよりも、どこかにコードを保存しておきたい時に便利です。
もう 1 つは、TypeScript や特定の Package などを利用しながら GAS の実装 -> デプロイまで可能な Google 製の clasp を使う方法。この場合は、通常のアプリケーション開発と同じようにコード管理 -> デプロイまで行えるため人気のようです。

ファイル構成の整理は意識する

利用する API が複数あるのであれば、Api/Slack.gs へ、定数管理は Constants.gs へと、まとめられるものは極力まとめた方が見栄え良くメンテナブルにできます。巨大な Main.gs に全ての処理が入ってたりすると読むのが億劫になります。
筆者の体感でですが、やりたいことベースでファイルを作成するといい感じです。
例えば、定期ジョブにて「毎日10:00にサービスXXXXのデータをエクスポートする」ということをしたい場合は、 Jobs/ExportXXXXData.gs などとファイル作成し、Api や Constants などのモジュールを組み合わせて構築していくとスッキリします。(GAS に限った話ではないが)

Jobs/ExportXXXXData.gs
/**
 * 外部サービス「xxxx」から毎日10:00にシート出力
 * @return {void}
 */ 
const main = () {
  const xxxxData = fetchXXXXData() // Api/XXXX.gs のメソッドを叩いてデータ取得
  const parsedData = JSON.parse(xxxxData)
  const appendableData = generateAppendableData(parsedData)

  // シート出力
  sheet.getRange(1, 1, appendableData.length, appendableData[0].length).setValues(appendableData)

  // シートへの出力が完了したらSlack通知
  const text = "XXXXのデータのシート出力完了したよ"
  postSlackMessage( // このメソッドはApi/Slack.gsのメソッドを呼び出す
    GENERAL_SLACK_CHANNEL, // Constants.gsから呼び出し
    text
  )
}

// mainメソッドをfatにしないためにメソッド分離
const generateAppendableData(rows) {
  ...
}

まとめ

今回は GAS(Google Apps Script)をチームで書く際に意識すべきポリシーについてご紹介しました。誰でも手軽に書けることも GAS の魅力ではありますが、「他の人も使う可能性がある」ということを考えて利用する方が安心安全だと考えております。
少々長くなりましたが、最後まで読んで頂き、ありがとうございました。「いいね」していただけると記事執筆の励みになりますので、参考になったと思った方は是非よろしくお願いします!

関連記事

https://zenn.dev/offers/articles/20220630-google-app-script-slack
https://zenn.dev/offers/articles/20220616-google-app-script-technique
https://zenn.dev/offers/articles/20220328-promote-communication-in-remote-team
https://zenn.dev/offers/articles/20220725-slack-app-introduction
https://zenn.dev/offers/articles/20220728-create-idea-post-slack-app

Offers Tech Blog

Discussion