想定読者
- GASを「コピペで動かしてる」段階から、保守できるコードへ進めたい人(題材は校務スプレッドシート自動化)
- セル単位ループで遅い/6分でタイムアウト/無人実行がこける、を直したい人
この記事のゴール
「動くけど怖いGAS」を「壊れにくいGAS」にする最小の型を4つだけ。
型1: セルループをやめ、配列で一括read/write
校務集計が遅い・落ちる原因の9割はこれ。getValue()/setValue()をループで叩くとAPI往復が回数分発生する。
NG(遅い):
for (let r = 2; r <= last; r++) {
const v = sheet.getRange(r, 3).getValue(); // 1行ごとに往復
sheet.getRange(r, 5).setValue(v * 2);
}
OK(速い):
const rng = sheet.getRange(2, 1, last - 1, sheet.getLastColumn());
const values = rng.getValues(); // 1回でまとめて読む
const out = values.map(row => [row[2] * 2]); // メモリ上で計算
sheet.getRange(2, 5, out.length, 1).setValues(out); // 1回でまとめて書く
往復が「行数回」→「2回」になる。数百行で体感が変わり、6分制限の事故も減る。
型2: トリガーは onEdit に詰め込まない
onEditは編集のたびに走り、重い処理を入れると編集が固まる・多重実行する。集計や転記は時間主導トリガーに逃がす。
// 1日1回など、時間主導トリガーから呼ぶ
function dailyAggregate() {
// 型1の一括処理をここで
}
onEditは「フラグを立てるだけ」、実処理は時間主導、と役割を分ける。
型3: 6分の壁は「続きから」で越える
GASは1実行6分(消費者向け)で強制終了。長い処理は処理位置をPropertiesServiceに保存し、トリガーで再開する。
function chunkedJob() {
const props = PropertiesService.getScriptProperties();
let cursor = Number(props.getProperty('cursor') || 0);
const BATCH = 200;
// cursorからBATCH行だけ処理 → cursor += BATCH を保存
props.setProperty('cursor', String(cursor + BATCH));
// 残りがあれば後続トリガーを1個だけ作って自分を呼び直す
}
「全部一度に」をやめ、「200行ずつ続きから」にするだけで止まらなくなる。
型4: 失敗を黙らせない(try/catch+通知)
無人で回す校務スクリプトは、こけても気づけないのが一番怖い。
function safeRun(fn) {
try {
fn();
} catch (e) {
// 自分のGmailや管理シートにエラーを残す
MailApp.sendEmail(Session.getActiveUser().getEmail(),
'GASエラー: ' + fn.name, String(e.stack || e));
throw e; // ログにも残す
}
}
「動いてるはず」を「動いた/こけたが分かる」に変える。
まとめ(保存版)
- セルループ禁止、配列で一括read/write
- onEditに重い処理を入れない、集計は時間主導トリガー
- 6分の壁はカーソル保存+分割実行で越える
- try/catch+通知で「無人でこけても気づける」
この4つだけで、校務GASは「コピペで怖い」から「任せられる」に変わる。
元理科教員が校務をGAS/AIで時短していく記録を出しています。設問別正答率の自動集計など実例はプロフィールから。