みなさん、こんにちは!
タカハシ(@ntakahashi0505)です。
弊社でお仕事をする場合に、「こういうコーディングルールでやろうね」というのを、自分自身または一緒にお仕事をするパートナーさんにお伝えすべく、VBAのコーディングガイドラインを作成しておりました。
昨今、Google Apps Scriptのお仕事も増えつつありますので、コーディングガイドラインのGAS版を作りました。
あくまで、弊社ではこう…というものなので、いろいろとご意見、好み、その他、色々とあるかもしれませんが、一部でも皆様のご参考になれば幸いです。
なお、本ガイドラインは、2020/02/05にサポートされました「V8ランタイム」に対応したものです。
命名規則
変数、定数、関数などにつける名前を、識別子といいます。
識別子は一定のルールを守っていれば、自由に命名できますが、スクリプトの読みやすさや開発効率を考えて以下の点に留意します。
- 中身や役割がわかるような意味のある名前をつける
- 英単語を使い、日本語は使わない
ある程度長い名前でも alt + / で単語補完が使えるので、意味がわからないよりは長い方がマシです。
変数名・定数名
ブロックスコープ、ローカルスコープの変数名・定数名はキャメル記法で書きます。
変数の内容が明確かつ宣言から近い距離で完結するのであれば
- url
- body
- message
- thread
- number
- sheet
などの単一単語での変数名も問題ありません。
また、コンテンツアシストでメソッドの引数などで使われている変数名を使用するのは、とても効果的です。
スプレッドシートを代入する変数、定数で以下を使うのは一般的です。
- ss
データ型に合わせて、以下接頭語で始める方法もありますが、それら接頭語を付与せずにデータ型を想定できる単語を使用するのが理想です。
- str:String
- date:Date
- rng:Range
- sheet:sh
状況に応じて以下接頭語も使うことができます。
- row:行
- col:列
- min:最小
- max:最大
- avg:平均
以下については広く一般に使われており、短くてシンプルな名称でも可読性には影響を与えませんので、使っても問題なしです。
- i, j, k:カウント変数
- obj:一時的なオブジェクト変数
GASは変数とそのデータ型については寛容で、数値型の値を入れていた変数に、文字列型の値を上書きするといった処理も可能です。
トラブルの元になるので、その変数がどの型なのかわかるような名称を心がけるとよいでしょう。
配列や集合の変数名
配列や集合の場合、複数形の変数名にします。
- values
- sheets
- messages
- threads
- events
関数名
関数名もアルファベットのキャメル記法で書きます。
また「~かどうか」を返すBoolean型のFunctionプロシージャに関しては
- is~
- has~
- can~
を使うとわかりやすいですし、if文の条件式にそのまま突っ込めたりしてかっこいいです。
クラス名は、通常の関数名と区別する為に、先頭を大文字で始めるのが一般的です。
グローバルスコープの定数、プロパティストアのキー
グローバルスコープの定数、プロパティストアーのキーはアルファベットのスネーク記法で書きます。
const TAX_RATE = 1.08; const USER_ID = 'hogehoge';
変数・定数の宣言
const→letの順に優先する
再代入が必要ないものであれば、constキーワードによる定数を優先的に使用します。
再代入が必要であればletによる変数を使用します。varを使う必要はほぼありません。
スコープはできる限り小さく
原則、変数・定数はなるべく狭いスコープで使用するようにしましょう。
優先はブロックスコープ→ローカルスコープ→グローバルスコープの順です。
それにより可読性と安全性が高まります。理由もなくグローバル領域には記述しないように…。
ただし、グローバルで使用する定数の場合は、以下のプロパティストアの利用も考慮しつつ、特定のスクリプトファイルのグローバル領域の先頭にまとめて宣言をしておくのもよいでしょう。後で値を変更するときに、わかりやすい位置にあると便利です。
プロパティストア
GASではプロパティストアに、プロジェクトやドキュメントに紐付く形でデータを格納しておくことができます。
ファイルのIDや外部と接続するために必要な情報をスクリプトから分離して安全に管理することができます。
プロパティストアにはいくつか種類がありますが
- プロジェクトに紐づくデータ:スクリプトプロパティ
- ドキュメントに紐づくデータ:ドキュメントプロパティ
- 実行ユーザーに紐づくデータ:ユーザープロパティ
という使い分けをします。
コードのフォルム
ステートメント
GASでは自動でステートメントの末尾が判別されますが、判別が常に正しいとは限らないので、ステートメントの終わりにはセミコロン「;」をつけます。
また、特別な理由がない限り1行に1ステートメントを記述します。
ネストとインデント
ネストであれば必ずその深さの分のインデントを加えてください。理想としては深さは3つまでがいいですね。
function myFunction1() { for (let i = 1; i <= 10; i++) { if (i % 3 === 0 || i % 5 === 0) { continue; } console.log(`iの値:${i}`); } }
インデントをそろえる場合は、Shift + Tab キー活用すると、自動でそろえてくれます。
複数の行を選択しても、GASが判断して整形してくれるので、大変便利です。
縦に揃える
一行が長いときには、縦に揃えることを意識すると可読性が高まります。
長いメッセージを生成するときや
let body = ""; body += "[info]n"; body += values[row][0] + "n[hr]"; body += values[row][1] + "n("; body += values[row][2] + ")[/info]";
オブジェクトや配列のリテラルを記述するときなどに有効です。
function myFunction() { const person = { name : 'Bob', age : 25, sex : 'male', job : 'Engineer' }; console.log(person.name); }
状況によって、使い分けてください。
コメント
コードを見てわかるコメントは不要
一般的にコードを見ればわかるような内容についてのコメントは不要です。
例えば以下のようなパターン。
if (n > 50){ //nが50より大きい場合 console.log('50より大きい'); } else if (n < 50){ //nが50より小さい場合 console.log('50より小さい'); }
コメント入れなくてもわかることはコメントしなくてOK!
ドキュメンテーションコメント
関数を作成する際に、ドキュメンテーションコメントを設定し、その役割や引数、戻り値を記載するようにしましょう。
また、ドキュメンテーションコメントを入れることで、スプレッドシートで利用するカスタム関数使用時に、補完の候補としたり、詳細情報を表示したりできるので便利です。
/** * 指定した金額の税込価格を返すカスタム関数 * * @param {number} 金額 * @return {number} 金額 * @Customfunction */ function ZEIKOMI(price) { const TAX_RATE = 0.1; return price * (1 + TAX_RATE); }
「//」によるコメントを優先
Ctrl + / で、現在カーソルのある行や複数行の選択範囲をコメントイン、コメントアウトできるので、「/* ~ */」によるコメントよりも「//」を優先して使用します。
比較演算子
演算子「==」と「!=」は左辺と右辺のデータ型が異なっていても、データ型を変換した上で比較をします。
一方で、演算子「===」と「!==」は左辺と右辺のデータ型が異なっていることを厳密に判断して比較します。
function myFunction() { console.log(5 == '5'); //true console.log(5 === '5'); //false console.log(5 != '5'); //false console.log(5 !== '5'); //true }
したがって、データ型も含めて厳密に比較をする「===」と「!==」を優先して使用するようにしましょう。
マジックナンバーは禁止
マジックナンバーは使用禁止です。メンテナンス性を著しく犠牲にします。マジックナンバー、ダメ!
マジックナンバーになりやすいポイントとしては
- 行数、列数
- 係数
- セルのアドレス
- 配列やオブジェクトの要素数
- 引数
- ファイル名、パス名
- パスワード
- URLやメールアドレス
などがあります。
ユーザーの干渉・省略
テーブルの走査
テーブルの走査をする場合には、getDataRangeメソッド、getValuesメソッドを用いてデータを二次元配列として取得して操作することを優先します。
function myFunction() { const values = SpreadsheetApp.getActiveSheet().getDataRange().getValues(); for(let i = 1; i < values.length; i++){ //処理 } }
最終行はgetLastRowメソッドで取得することができますが、配列での処理を優先しましょう。
function myFunction() { const sheet = SpreadsheetApp.getActiveSheet(); const lastRow = sheet.getLastRow(); for(let i = 2; i <= lastRow; i++) { //処理 } }
アクティブシートとシートの保護
シートが一つであれば、getActiveSheetメソッドでシートを指定するようにします。
ユーザーによるシート名の変更にも対応でき、高速化の面でも有利です。
一つのシートで運用できるよう、工夫しましょう。
また、複数シートが存在する場合は、getSheetByNameメソッドなどを使用する必要があります。
この際、ユーザーがシート名を変更しないように運用する必要があります。
絶対に保護したい場合には、対象のシートを非表示にしたり、シートを保護することで、干渉を受けないようにすることができます。
構造データの使用
スクリプトで主に操作をするスプレッドシートのデータは、特に理由がない限りテーブル形式になるように心がけましょう。
- A1セルから構成する
- 空白行・空白列を設けない
- セルの結合を使わない
- 見出しは1行で構成する
- 同じ種類のデータはシートを分けない
つまり、ピボットテーブルを作成できるデータの整理の仕方が望ましいです。
データを構造データで持つかどうかが、それを操作するプログラムの作りやすさに大きく影響します。
A1セルからデータが存在する最終行と最終列までの範囲を取得するgetDataRangeメソッドや、シートに行を追加するappendRowメソッドを使うことができます。
スクリプトの高速化
GASではスクリプトの実行時間に6分という厳しい制限が設けられています。
APIのアクセス回数を減らして、処理速度を少しでもあげましょう。
配列の利用
スプレッドシートのデータやGmailのメッセージをはじめ、GASで取り扱うデータは、直接操作をするよりも、配列に格納して処理する方が、格段に処理速度を向上させることができます。
スプレッドシートで複数のセルを取り扱う場合はgetValuesメソッド、setValuesメソッドを使用して、配列を利用します。
function myFunction() { const sheet = SpreadsheetApp.getActiveSheet(); const values = sheet.getDataRange().getValues(); //配列valuesに対する処理 sheet.getRange(1, 1, values.length, values[0].length).setValues(values); }
これはかなり重要なテクニックなので、必ずマスターしたいところです。
シートにレコードを追加する
シートにレコードを追加する場合は、appendRowメソッドを使うことで配列から直接レコードを追加することができます。
function myFunction(){ const sheet = SpreadsheetApp.getActiveSheet(); sheet.appendRow(配列); }
範囲の指定が不要で、Sheetオブジェクトに直接実行できます。
グローバル領域
どの関数にも属さない領域をグローバル領域といいます。
グローバル領域へのステートメント記述は、実行順がわかりづらくなります。
特に理由がない限りは記述しないようにしつつ、記述する場合も特定のgsファイルの一番上にまとめて記述するほうがいいでしょう。
また、グローバル領域で宣言した(グローバル変数)は全ての関数からアクセスすることができ、変更を加えることもできます。
望まない影響を受ける可能性があるので、極力使わないようにしましょう。
まとめ
以上、Google Apps Scriptのコーディングガイドラインでした!
良いガイドライン見つけたら、随時更新していきますね。