blog
ブログ
2021.12.23

Google Apps Script 社内向け開発規約

目次

1. 前提
2. 命名規則
3. 変数・定数の宣言
4. プロパティストア
5. コードの整形
6. コメント
7. 比較演算子
8. マジックナンバー(ハードコーディング)は禁止
9. スクリプトの高速化(スプレッドへのアクセスについて)
10.例外処理

 

1.前提

Google Apps Script は、Javascript がベースとなっている為、基本的には以下サイトの記載に従い実装するものとする。
Google JavaScript Style Guide

また、各コードについては基本的に以下手順にて JSLint でのチェックを行い、エラー(×印)の指摘が発生した箇所のみ全て解消するものとする。
(警告の発生箇所については修正不要)
JSLint

Source欄をクリアし、チェック対象のソースコードをコピー&ペースト

JSLint_手順1

Options欄にて許容設定項目(Allow…)を全て選択、JSLintボタンを押下して検証開始

JSLint_手順2

実行後、Source欄に表示される検証結果アイコンを確認、エラー(×印)の発生箇所を全て修正

JSLint_手順3

 

2.命名規則

共通前提

共通の前提として、以下の通りとする。
●規則対象:変数名・定数名(プロパティ含む)・クラス名・関数名
●スコープの区別:グローバルの変数・定数の場合のみ、接頭辞”gl”または”GL_”を含めるものとする
●命名の記法:クラスはアッパーキャメル記法、変数名・関数名はローワーキャメル記法、定数名・プロパティ名は大文字スネーク記法とする
●名称の言語:英語
●配列・コレクション系変数の名称:複数系での表記(values, entries等)とする
●接頭辞:変数については後続での説明通り、以下の表に従って名称にデータ型の略称を含めるものとする

データ型 略称(接頭辞)
論理型 (Boolean) bln
数値型 (Number) num
文字列型 (String) str
長整数型 (BigInt) bnt
シンボル型 (Symbol) sym
配列 (Array) ary
オブジェクト (Object) obj
関数 (Function) fnc

●その他、原則としてはGoogleのJavaScriptスタイルガイド内の”naming”項目の記載に従うものとする。
Google JavaScript Style Guide – 6 Naming

変数

( グローバル接頭辞 + ) 型接頭辞 + ( 形容詞 + ) 名詞 ( + アンダースコア )

let glNumMovedRowNumber = 11; // グローバル変数
function doSomething() {
    let numMovedRowNumber = 21; // ローカル変数
    let objDog = new DogClass(); // ローカル変数
    let objCat = new CatClass(); // ローカル変数
}
class DogClass {
    constructor() {
        this.strName = 'michael'; // 非定数フィールド
        this.blnFromStray_ = false; // 非定数フィールド(private)
    } 
}
function CatClass() {
    this.strName = 'jackson'; // 非定数フィールド
    this.blnFromStray_ = true; // 非定数フィールド(private)
}

定数(プロパティ)

( グローバル + ) 型 + ( 形容詞 + ) 名詞

let GL_ROW_NUMBER = 12; // グローバル定数
function doSomething() {
    let ROW_NUMBER = 22; // ローカル定数
}

クラス

( 形容詞 + ) 名詞 + Class

let objDog = new DogClass();
let objCat = new CatClass();
// クラス(class)
class DogClass {
    constructor() {
    }
}
// クラス(function)
function CatClass() {
}

メソッド(関数)

原則として、動詞 ( + 名詞 ) ( + アンダースコア )

let objDog = new DogClass();
objDog.outputData();
let objCat = new CatClass();
objCat.outputData();
class DogClass {
    constructor() {
    }
    outputData() {
        // publicメソッド
    }
    calc_() {
        // privateメソッド
    }
}
function CatClass() {
    this.outputData = function() {
        // publicメソッド
    };
    this.calc_ = functions() {
        // privateメソッド
    }
}

 

3.変数・定数の宣言

宣言キーワードについて

●変数の宣言はletを使用するものとし、varの使用は禁止とする。
●定数の宣言はconstを使用する。

宣言時のスコープ範囲の考慮

●スコープはできる限り小さく
 ●原則、変数・定数はなるべく狭いスコープで使用するようにする。
  優先はローカルスコープ(ブロックスコープ→関数スコープ)→グローバルスコープの順。
  ・ブロックスコープ:if, for, while等の処理ブロック単位の範囲を指すスコープ。
  ・関数スコープ:関数単位の範囲を指すスコープ。
  ・ローカルスコープ:ブロックスコープと関数スコープの総称。
  ・グローバルスコープ:関数・クラス等の外側で宣言される、プログラム全体を指すスコープ。
 ●グローバルで使用する変数・定数については、
  特定のスクリプトファイルのグローバル領域の先頭にまとめて宣言するか、
  専用のスクリプトファイルを作成する等して、一元管理を行うようにする。
  状況に応じてプロパティストア(後続で説明)の利用も考慮に入れる。

 

4.プロパティストア

●ファイルのIDや外部API類との接続情報等、
 動作環境や運用状況に応じて変更が発生するような設定値・定数値については、
 スクリプト内に定義せずにプロパティストアにて管理するようにする。
●プロパティについては基本的にスクリプトプロパティのみを使用すること。
 (スクリプトプロパティのみIDE上から管理可能な為。
  ドキュメントプロパティとユーザープロパティについては
  コード上以外から管理する手段がない為、基本的に使用禁止とする。)

 

5.コードの整形

ステートメント

●ステートメントの終わりにはセミコロン「;」をつける。
●特別な理由がない限り1行に1ステートメントを記述する。

ネストとインデント

●ネストする場合は必ずその深さの分のインデントを設定する。
●ネストを深くし過ぎない。(3つ程度が目安)
●GASの場合、Shift+Tabでまとめて自動でインデント整形が行える。

function doSomething() {
    let numCount = 0;
    while (true) {
        if (numCount++ > 20) {
            break;
        }
    }
}

縦に揃える

●一行が長いときには、縦に揃えることを意識する。長いメッセージを生成する際やオブジェクトや配列のリテラルを記述する際等に有効。

function createLongMessage(aryParams) {
    let strMessage = "";
    strMessage += "<b>code: " + aryParams[0] + "\n";
    strMessage += "status: "  + aryParams[1] + "\n";
    strMessage += "message: " + aryParams[2] + "</b>";
}
function createObjectVariable() {
    let objProgram = {
        type : 'Batch',
        lines : 1208,
        language : 'php'
    };
}

 

6.コメント

ドキュメンテーションコメント

●関数・クラス等には以下のリファレンスを参考としてドキュメンテーションコメントを記載すること。
Google Apps Script 公式ガイド – Best practices

/**
 * 指定した分数+秒数が何時間かを算出・返却するカスタム関数 … ★関数の説明
 *
 * @param {number} numMinute 分数 … ★引数の説明(@param {型} 説明)
 * @param {number} numSecond 秒数 … ★引数の説明(@param {型} 説明)
 * @return {number} 算出した時間 … ★返却値の説明(@return {型} 説明)
 * @Customfunction
 */
function calcHours(numMinute, numSecond) {
    let numHour = parseInt(numMinute / 60) + parseInt(numSecond / 3600);
    return numHour;
}

その他

●コードを見ればわかるような内容についてのコメントは不要。

function doSomething(numTemperature) {
    if (numTemperature == null) { // 引数がnull
        console.log("未設定");
    } else if (numTemperature >= 0) { // 引数が0以上
        console.log("0以上");
    } else { // 引数が0未満
        console.log("0未満";
    }
}

●GASのIDEでは、Ctrl + / で現在カーソルのある行や複数行の選択範囲をコメントイン・コメントアウトできる為、
 「/* ~ */」によるブロックコメントよりも「//」を使用した方が使い勝手が良い場合がある。

 

7.比較演算子

一致・不一致の比較について

●一致・不一致の比較については、データ型も含めて厳密に比較をする「===」と「!==」を使用すること。
 (演算子「==」と「!=」は左辺と右辺のデータ型が異なっていてもデータ型を変換した上で比較をする為、
  データ型の差異まで含めた厳密な一致・不一致の比較にはならない)

function doSomething() {
    console.log(12 == '12'); // true
    console.log(12 === '12'); // false
  
    console.log(12 != '12'); // false
    console.log(12 !== '12'); // true
}

 

8.マジックナンバー(ハードコーディング)は禁止

●メンテナンス性を著しく損なう為、マジックナンバー(ハードコーディング)は使用禁止とする。
 以下の観点には特に留意すること。
 ・行数、列数
 ・係数
 ・セルのアドレス
 ・配列やオブジェクトの要素数
 ・引数
 ・ファイル名、パス名
 ・パスワード
 ・URLやメールアドレス

function doSomething() {
    let objTargetRange = SpreadsheetApp.getActiveSheet().getRange(5, 3, 11, 19); // セル範囲
    let objTargetFile = DriveApp.getFileById('1U2RtRuPwD3JJzmsD_kJQAyO_66bpwRpp'); // ファイルID
    MailApp.sendEmail({to: 'test@gmail.com', subject: 'test', body: 'test', htmlBody: '', from: ''});  // メールアドレス等
}

 

9.スクリプトの高速化(スプレッドへのアクセスについて)

共通前提

●GASでは1スクリプト辺りの実行時間制限が6分(ビジネスプランなら30分)、
 一日辺りの総実行時間制限が90分(ビジネスプランなら6時間)となっている。
 この為、APIのアクセス回数を減らす等して、処理速度を少しでも向上させること。
Google Apps Script 公式ガイド – Googleサービスの割り当て

配列の利用

●スプレッドシートのデータやGmailのメッセージをはじめ、GASで取り扱うデータは、
 特に理由のない限りは直接操作をせずに配列に格納して処理するようにすること。
 都度APIアクセスを行うより、一括でAPIアクセスして配列で処理する方が処理時間が速くなる。
●スプレッドシートで複数のセルを取り扱う場合は、getValues・setValuesを使用して、配列を利用するようにすること。

function doSomething() {
    let objTargetSheet = SpreadsheetApp.getActiveSheet();
    let aryTargetValues = sheet.getDataRange().getValues();
    /* 中略(配列で取得したaryTargetValuesへの処理を実施) */
    objTargetSheet.getRange(1, 1, aryTargetValues.length, aryTargetValues[0].length).setValues(aryTargetValues);
}

シートへのレコード追加

●シートにレコードを追加する場合は、appendRowを使うことで配列から直接レコードを追加することができる。

function doSomething() {
    let objTargetSheet = SpreadsheetApp.getActiveSheet();
    sheet.appendRow(["Mick", "Keith", "Ron", "Charlie", "Brian", "Bill"]);
}

テーブル走査

●テーブルの走査をする場合には、getDataRange・getValuesを用いてデータを二次元配列として取得して操作すること。
 各行・各セルで都度シートにアクセスすると遅くなる為、そのような実装は避ける。

function doSomething() {
    let aryTargetValues = SpreadsheetApp.getActiveSheet().getDataRange().getValues();
    for (let i = 1; i < aryTargetValues.length; i++) {
        // 各行・各セル毎の処理
    }
}

シートの最終行・最終列

●シート最終行・シート最終列は、それぞれgetLastRow・getLastColumnで取得可能。

function doSomething() {
    let aryTargetValues = SpreadsheetApp.getActiveSheet();
    let numLastRow = sheet.getLastRow();
    let numLastColumn = sheet.getLastColumn();
    for (let j = 1; j <= lastRow; j++) {
        for (let i = 1; i <= lastColumn; i++) {
            // セル毎の処理
        }
    }
}

アクティブシートとシートの保護

●シートが一つのみのブックについては、getActiveSheetでシートを指定すると良い。
 ユーザーがシート名を変更した場合でもコードを変更せずに動作可能であり、高速化の面でも有利となる。
●複数シートが存在するブックの場合は、getSheetByName等を使用してシートを特定する。
 この場合、ユーザーがシート名を変更しないように運用するか、シート名の変更が発生する場合はコードの修正が必要となる。
●確実にシート名の変更を防止したい場合には、対象のシートを非表示にするか、シートを保護する等、干渉を受けないように対処を行うこと。

スプレッドシート上のデータはテーブル形式推奨

●スクリプトで主に操作対象となるスプレッドシートのデータは、特に理由がない限りテーブル形式とする。
 getRange・getLastRow・getLastColumnといった、
 GoogleAppsScriptで用意されている専用関数でのシートアクセスをスムーズに行う為にも、以下観点に留意すること。
 ●A1セルから構成する
 ●空白行・空白列を設けない
 ●セルの結合を使わない
 ●見出しは1行で構成する
 ●同じ種類のデータはシートを分けない

 

10.例外処理

●例外が発生する可能性のある処理については、try ~ catchでの制御を行うこと。
●例外catch時には、ログ出力・メッセージボックス・メール通知等で例外内容をユーザーへ通知すること。

function doExceptionHandling() {
    try {
        // 主処理
    } catch (e) {
        // 例外処理
        Browser.msgBox(e);
    } finally {
        // 終了処理
    }
}
contact

ご相談・ご質問等ございましたら、お気軽にお問い合わせください。

翻訳