NTTテクノクロスの遠藤です。
この記事は、NTTテクノクロスアドベントカレンダーシリーズ1の15日目の記事になります。
記事のまとめ
- 以下のような条件でWebアプリを立てることを考えた場合、Google スプレッドシートは一定有力であるという趣旨の紹介を行ってます
- ランニングコストをかけたくない
- 自分以外の人が管理する
- かつ、管理するユーザがエンジニアでない
- 同時に、Google Apps Scriptでの開発時に使えるTipsをエンジニア向けにまとめています
慣れたUIで操作でき、誰にでも譲渡可能なWebアプリを、コスト0で簡単にホストできる。
そんなスプレッドシート+GASの魅力をぜひ紹介させてください。
はじめに
Google スプレッドシート(以下スプレッドシート)+Google Apps Script (以下GAS)をマクロ的に使うのは一般的ですが、
スプレッドシートはHTMLサイトのホストもやってくれます。
Googleアカウントのみで使用可能で、DBの役割も持ちつつ、Webサーバ、フロントエンドまで無料でやってくれるのは素晴らしいの一言です。
一方で、開発者目線では制約や使いづらさを感じる場合もあるかなと思います。
今回は、そんなスプレッドシート+GASで作成したWebアプリの概要と開発時に行った工夫を紹介しつつ、
改めてその魅力に触れていきます。
開発経緯
飲食店で働く友人から、バイトの方の勤務日を調整できるアプリが欲しいと言われました。
詳細は伏せますが、要件は以下のような簡単なものです。
- 機能
- アンケートで出勤/休日の調整を取る
- 調整状況を可視化する
- 休日希望が多すぎるなどの場合に、必要に応じて再調整を依頼する
- LINE WORKSに通知したい
- 機能外
- スプレッドシートをDBにしたい(使い慣れているため)
- 内部利用なので、ユーザー数は少なめ
- ランニングコストかからないようにしたい
アプリ+技術スタック概要
アプリの構成
アプリの作りはシンプルです。
- ✅ フロントエンド シフト希望日を入力するフォーム
- 画面は1画面のみ
- 回答者を選択し、希望日を入力する
- ✅ スプレッドシートをDBとして使う各種バックエンド機能群
- 申請内容保存シートへのRead/Write
- コンフィグ管理/メンバー管理用シートからのRead
- 回答集計+シフト表描画
- ✅ LINE WORKS Incoming Webhook のAPIを叩いて通知を行う機能
- 回答依頼、集計結果共有、調整依頼などをLINE WORKSに通知
DB
シートをDBとして使用します。
今回は以下の3シートを用意しました。
ソースコード構成
基本はform.htmlと任意のgsファイルという構成。
ここではメインとなるフォーム系機能(html, UI, データアクセス)の他、裏で動いて回答を集計する集計処理、LINE WORKS通知処理を持たせています。
コードの中身は長くなるのでここでは省略。
src/
├─ schema.gs # シート構成定義(後述)
├─ data.gs # データアクセス
├─ core_aggregate.gs # ビジネスロジック:集計処理
├─ infra_lineworks.gs # インフラ:LINE WORKS通知
├─ ui_webapp.gs # UI:WebAppのUI周り
└─ form.html # フォーム
デプロイ方法
- GASのプロジェクト画面右上から「デプロイ」ボタンを選択
- 任意の設定を行い「デプロイ」
- 最初はアクセスできるユーザーを「自分のみ」にすると事故がない
- 「ウェブアプリ」という名前のURLが得られるので、末尾に"?page=form"と付けてアクセス
- form.htmlで作った画面が起動する
これで一連のGAS開発の流れは終了です。シンプルですね。
ここまでができれば、スプレッドシートをコピーして必要な値を設定すれば別環境も簡単に作れます。
GASの使いづらいポイント
とはいえ、普通にGASを使うと諸々困るポイントが出てきます。
今回は私の行ったこれらへの対処もご紹介します。
- Web UIでの開発がしづらい。ローカルで記述したい場合、コピペで貼り付けというフローになってしまう
- シートをDBとして使っている関係上、以下のような使いづらさがある
- 列名称の変更や移動など、シートの操作をするとアプリが動かなくなる
- ファイルを丸ごと共有しないと、スクリプトだけでは動かせない
※他に”速度が遅い+実行制限が厳しい”という重めの課題がありますが、今回は用途を踏まえて無視しました。
開発Tips紹介
開発Tips1: claspによるローカルからの快適な開発
GAS開発を普通に行うとWebUIでのコーディングを強いられ、結構不便です。
UIになれない、Git管理できない、コーディングエージェントが使いづらい 等
この辺りの課題は、claspを使うことでローカルからコード全体のデプロイが可能になり、解決しました。
※Webアプリのデプロイもclaspで可能なようですが、今回は未実施
claspとは?
Googleが提供する、Apps Scriptをコマンドラインから操作できるツールです。
インストール
npm install -g @google/clasp
# 基本的な使い方
# 1. Googleアカウントでログイン
clasp login
# 2. spreadsheetとの紐付け
# .clasp.json に scriptId を記載することで紐付け
# 3. コードをプッシュ
clasp push
# 4. 変更を監視して自動プッシュ
clasp push --watch
関連ファイル
.clasp.json(必須)
{
"scriptId": "1abc...xyz",
"rootDir": "./src"
}
.claspignore(推奨)
gitignoreなどと同様です
**/**
!src/**/*.gs
!src/**/*.html
!src/**/*.json
pushすると、以下のようにスクリプト類がGASにアップロードされます。
「デプロイ」ボタンからの操作は同様です。
※今回使いませんでしたが、claspではデプロイまで自動化が可能なようです。
開発Tips2: シートのスキーマ定義
シートというコード定義できない+UIからぽちぽちする必要がある要素は、エンジニアからすると扱いづらいです。
そこで、今回は以下のようなアプローチを取りました。
シート定義のJSON管理
schema.gsでシート定義を集約し、
- シートの作成
- シートからの値取得
などをJSON定義を経由して行うようにしました。
var SHEET_SCHEMAS = {
// システム設定シート
config: {
name: 'config',
description: 'システム設定(Key-Value形式)',
headers: ['設定項目', '値'],
columns: {
key: '設定項目',
value: '値'
}
},
// メンバーマスタシート
members: {
name: 'members',
description: 'メンバー一覧',
headers: ['ユーザーID', '表示名', 'メールアドレス', '有効'],
columns: {
userId: 'ユーザーID',
displayName: '表示名',
email: 'メールアドレス',
isActive: '有効'
}
},
// 勤務可能日リクエストシート
requests: {
name: 'requests',
description: '勤務可能日の申請履歴',
headers: ['申請日時', '申請者ID', '申請者名', '対象月', '勤務可能日', 'メモ'],
columns: {
submittedAt: '申請日時',
userId: '申請者ID',
displayName: '申請者名',
targetMonth: '対象月',
availableDates: '勤務可能日',
memo: 'メモ'
}
}
};
これにより、以下のような効果があります。
メリット
- 物理名と論理名の切り離し: 人間が読みやすい名称とプログラムで扱う名称を分離。開発者もユーザーも使いやすい
-
可読性の向上:
row[1]のようなインデックス依存でなく、論理名を使ったアクセスが可能 - 耐久性/利便性の向上: シートが崩れた、シート定義を変更したいという場合にコードから復元/変更が可能
// ❌ Before: インデックス依存で脆弱
var data = sheet.getDataRange().getValues();
for (var i = 1; i < data.length; i++) {
var userId = data[i][0]; // 0って何?
var displayName = data[i][1]; // カラム順変更でバグる
var email = data[i][2];
}
// ✅ After: スキーマ定義を使用
// getColumnIndex_()は別に定義されたヘルパー関数
var headerRow = data[0];
var userIdIdx = getColumnIndex_(headerRow, 'members', 'userId');
var displayNameIdx = getColumnIndex_(headerRow, 'members', 'displayName');
var emailIdx = getColumnIndex_(headerRow, 'members', 'email');
for (var i = 1; i < data.length; i++) {
var userId = data[i][userIdIdx];
var displayName = data[i][displayNameIdx];
var email = data[i][emailIdx];
}
終わりに:触って気づいたスプレッドシートの魅力
記事内容は以上となりますが、最後に改めて今回気づいたスプレッドシート+GAS開発の魅力を紹介させてください。
1. 非エンジニアフレンドリー
アプリの管理者が非エンジニアである場合、以下のような問題がよくあるかと思います。
- PaaS/IaaSサービスのアカウント登録や使用が難しく管理を委譲できない
- 単なるデータや設定値の補正であっても、操作がわからず担当者ではできない
これに対しスプレッドシートは
- Googleアカウントは多くの人が持っており壁になりづらい
- 表形式の入力画面は多くの人にとって慣れている
という点から有効です。
2. 配布が簡単
アプリを他環境に配布するとなった場合、相手がGoogleアカウントさえ持っていれば、以下の手順で完了します。
- スプレッドシートを共有ディレクトリにコピーして受け渡す
- コンフィグ/メンバーなど環境特有の設定値を埋める
- ウェブアプリとしてデプロイ
- バッチ系がある場合、トリガーから実行タイミングを指定
3. コスト0かつインフラ管理不要
- サーバー不要
- データベース不要
- 監視ツール不要
- スケーリング不要(できないとも言える)
4. claspの仕様やシートのJSON定義で、開発ストレスはある程度軽減可能
clasp+シートのJSON定義により、GASの開発はわりかしストレスなく行えるようになりました。
また、claspでのpush先はscriptIdで定義されるため、
複数用意/デプロイのスクリプトで調整するなどすれば、環境分離のようなことも可能になり、より利便性も高められそうです。
// 開発環境
{
"scriptId": "1abc...dev",
"rootDir": "./src"
}
// 本番環境
{
"scriptId": "1xyz...prod",
"rootDir": "./src"
}
詰まるところ、
慣れたUIで操作でき、誰にでも譲渡可能なWebアプリを、コスト0で簡単にホストできる+エンジニア目線でも比較的開発しやすい
というのがスプレッドシート開発の魅力です。
想定ユーザ/管理者がIT慣れしていなければいない程、これは有効だと思います。
ぜひ、スプレッドシート×GAS開発試してみてください!




