🥰

Google Apps Script は、もはやエンジニアが書かない方がいいまである

2023/10/25に公開2

ラブグラフでエンジニアをしています横江 ( @yokoe24 ) です。

ラブグラフでは、エンジニア以外で Google Apps Script (GAS) を書く方も多く
Slack通知の自動化など、業務の効率化がおこなわれています。
マジですごいと思います!

GASをエンジニア以外が書く問題点

一方で、コードを見るとプログラマーからするとムズムズするところもあります。

  • 変数名に snake_case が混ざっている
  • インデントが揃っていない
  • for文の中で getValue() を回している
    • Google Apps Script の getValue() メソッドはコストが高く、何度も実行するとタイムアウトの可能性が高まる
  • == で比較している
  • double quotes " と single quotes ' が混ざっている

こういうコードを見ると直したくてウズウズしてしまいます。
とはいえ、プログラマーが書く時間もなかなか割けないのが実情です。

そこでChatGPT!

Google Apps Script を書いてもらうため、
ChatGPT にこう聞いてみました。

Google フォームの回答が連携されるスプレッドシートの回答を、質問と回答の関係が見やすいように Slack 通知する Google Apps Script を書いてください。
なお、Slack への通知が済んだらスプレッドシート側にマークを付けて、同じ回答が再び通知されないようにしてください。
let や const を使う ES2015 らしい書き方で、trailing comma, single quotes を使うようお願いします。定数名は大文字とアンダーバーで表現してください。関数には必ず JSDOC の形式で日本語のコメントを、他もなるべく日本語のコメントをつけてください。

(あとで説明しますが、この3行目のところがけっこう大事です)

すると ChatGPT はこう返してくれました。


以下は、Google フォームからの回答を Slack に通知し、通知済みのものにマークをつける Google Apps Script です。

/**
 * Google スプレッドシートと Slack 連携用の Google Apps Script
 * @fileoverview Google フォームの回答を Slack に通知し、通知済みはスプレッドシートにマークを付ける
 */

// Slack への Webhook URL と、通知済みマークを設定する列のインデックス
const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/XXXXXXXXX/YYYYYYYYY/ZZZZZZZZZZ';
const NOTIFIED_COLUMN_INDEX = 10;  // 10列目に通知済みマークをつけるとする

/**
 * スプレッドシートの新しい回答を Slack に通知する関数
 */
function notifyNewResponsesToSlack() {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const rows = sheet.getDataRange().getValues();
  
  // ヘッダー行(質問)を取得
  const headers = rows[0];

  for (let i = 1; i < rows.length; i++) {
    const row = rows[i];

    // すでに通知済みの場合はスキップ
    if (row[NOTIFIED_COLUMN_INDEX - 1] === '通知済み') continue;

    let message = '*新しい回答があります:* \n';
    for (let j = 0; j < headers.length; j++) {
      message += `>${headers[j]}: ${row[j]}\n`;
    }
    
    // Slack にメッセージを送信
    sendToSlack(message);
    
    // 通知済みとしてマークを付ける
    sheet.getRange(i + 1, NOTIFIED_COLUMN_INDEX).setValue('通知済み');
  }
}

/**
 * Slack へのメッセージ送信を行う関数
 * @param {string} message - Slack に送信するメッセージ
 */
function sendToSlack(message) {
  const payload = {
    text: message,
  };

  const options = {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify(payload),
  };
  
  // Slack へのリクエストを行う
  UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);
}

注意事項:

  1. 上記のスクリプトは仮想のものであり、動作保証はありません。利用の際は適切にテストしてください。
  2. `SLACK_WEBHOOK_URL` を実際の Slack Incoming Webhook URL に置き換えてください。
  3. `NOTIFIED_COLUMN_INDEX` は通知済みマークを付ける列のインデックスを指定します。10列目に通知済みマークをつけるとしていますが、実際のシートの列の配置に応じて適宜変更してください。

このスクリプトは、スプレッドシートに新しい回答があるたびに手動で実行するか、トリガーを設定して自動実行することを想定しています。


注意事項まで記載してくれているのがいいですよね。

ちなみに、Googleフォームの回答時のトリガーはたまに適切に動かないことがあるそうなので、
回答を記録するスプレッドシートに対して1時間ごとに実行するトリガーを設定することを想定しています。

すごいぞChatGPT!

上のコードは、質問してから 30秒程度で 書き上げてくれます!
仮に私が書いたら、1時間以上はかかっていることでしょう。

そして 私が書くよりもきれいなコードです。
コメントはややエンジニアからすると冗長かもしれませんが、
関数に対しての説明コメントがわかりやすいですし、
「通知済み」と記載される列を定数にするなど、メンテナンスしやすいコードで書かれています。

getValues() で最初に全ての値をとってから
その二次元配列を回す構成は、Google Apps Script を書くことに熟練している人のものです。

ChatGPT に Google Apps Script を書くのを任せると、
速い上にメンテナンス性の高いコードを書いてくれるのです!

たまに動かないコードを書くことがあるので、その場合はエンジニアに確認してもらうといいですが、
もはや Google Apps Script は、人間の手で1から書き上げるものではなくなっています!

質問のポイント

質問をする際は、こういうふうにするといいです。

〜〜〜〜〜〜〜する Google Apps Script を書いてください。
let や const を使う ES2015 らしい書き方で、trailing comma, single quotes を使うようお願いします。定数名は大文字とアンダーバーで表現してください。関数には必ず JSDOC の形式で日本語のコメントを、他もなるべく日本語のコメントをつけてください。

  • 必ず 『Google Apps Script を書いてください。』 という言葉を含ませます。これがないと、Google Apps Script では動かないタイプの JavaScript コードを出力してしまいます
  • 最後の行に 『let や const を使う ES2015 らしい書き方で、trailing comma, single quotes を使うようお願いします。定数名は大文字とアンダーバーで表現してください。関数には必ず JSDOC の形式で日本語のコメントを、他もなるべく日本語のコメントをつけてください。』 と書いてください。エンジニアでない方は、おまじないくらいに思っておいてくださって大丈夫です。これで、メンテナンス性の高いコードを書いてくれます。

エンジニア向けのさらなる説明

  • let や const を使う ES2015 らしい書き方: これを言わないと全部 var で書いてきます。また、 `a: ${a}` のような文字列内の変数展開も使うようになってくれます
  • trailing comma, single quotes を使う: trailing comma は通称「ケツカンマ」と呼ばれるものです。あとで項目を足すときにこれがあると便利です。そして、single quotes を使うことを言っておかないと、double quotes と single quotes の混ざったコードを出力してくることがあるので明言しています
  • 定数名は大文字とアンダーバーで表現: これを言わないと定数名を camelCase で付けてくることがあります
  • 関数には必ず JSDOC の形式で日本語のコメントを、他もなるべく日本語のコメントを: これはそのままですね。特に言わなくてもコメントを付けてくれることは多いのですが、関数に対してのコメントがない場合が多いので、これで強要しています

注意点

『ChatGPT Enterprise』を使っていない限りは、社内の機密情報を書かないようにしましょう。
学習に利用されるためなんらかの事故につながる危険性があります。

社内で扱う商品名など具体的な情報を書かずに、なるべく抽象的な言い回しにして質問するようにしてください。

おわりに

生成AIは時代を変えてくれましたね!

なお、同じ質問を Bing Chat にもしてみたのですが、
そちらは以下のような onFormSubmit を使うやり方で出力してきました。

トリガーをどう設定するかこちら側が言及していないせいではあるのですが、
メソッドとしてコードを切り分けてくれたりはせず、
ChatGPT のほうが、コードを書くことに関して上手いことチューニングされているように感じました!

/**
 * Google フォームの回答を Slack に通知する
 *
 * @param {Object} e - フォームの回答情報
 */
function onFormSubmit(e) {
  const SLACK_WEBHOOK_URL = 'https://hooks.slack.com/services/...'; // ここに Slack の Webhook URL を設定してください
  const SPREADSHEET = SpreadsheetApp.getActiveSpreadsheet();
  const SHEET = SPREADSHEET.getSheets()[0]; // 最初のシートを取得
  const ROW = SHEET.getActiveRange().getRow(); // 現在の行を取得

  let message = '';
  e.namedValues.forEach((value, key) => {
    message += `${key}: ${value}\n`; // 質問と回答をメッセージに追加
  });

  // Slack への通知
  UrlFetchApp.fetch(SLACK_WEBHOOK_URL, {
    method: 'post',
    payload: JSON.stringify({ text: message }),
  });

  // スプレッドシートにマークを付ける
  SHEET.getRange(ROW, SHEET.getLastColumn() + 1).setValue('通知済み');
}
ラブグラフのエンジニアブログ

Discussion

Shohei TaiShohei Tai

GASとChatGPTの相性は良いと感じていました!
GASはシンプルに書けるのでChatGPTでも精度高めに実現してくれるのが良いですね。

僭越ながら私が使用しているpromptを上げていたのでご参考までに・・
https://github.com/tai-sho/chatgpt-prompts/blob/main/prompts/google_apps_script.md?plain=1

横江@ラブグラフ横江@ラブグラフ

ありがとうございます!
ChatGPTのプロンプト例を GitHub に上げているの、めっちゃいいですね! おもしろいです!!

コーディングルールが別項としてまとまっているの、わかりやすくていいと思いました、ステキです。