どうも。つじけ(tsujikenzo)です。このシリーズでは2021年8月からスタートしました「ノンプロ研EffectiveJavaScript輪読会」についてお送りします。
前回のおさらい
前回は、「オプションオブジェクトで、キーワード付き引数群を受け取ろう」をお届けしました。
今日は4回目で、「不必要な状態を排除する」をお届けします。
テキスト第6章「ライブラリとAPI設計」の項目56に対応しています。
今日のアジェンダ
- ステートフルAPIとは
- ステートレスAPIとは
- ステートレスAPIを選ぼう
ステートフルAPIとは
ステート(状態)がフルなAPIとはなんでしょうか。
テキストでは、話の流れに沿ってAPIと呼ばれていますが、これは、オブジェクトでもかまいません。
状態を持っているオブジェクトといえば、Dateオブジェクトが挙げられます。
new演算子で呼ばれるコンストラクタは、現在時刻を状態としてもつでしょう。
//ステートフルなオブジェクト
const d = new Date();
console.log(d); // => Wed Dec 22 2021 00:32:50 GMT+0900 (Japan Standard Time)
なので、このように、状態をもつオブジェクトを使って処理が進められます。
function myFunction56_01() {
//ステートフルなオブジェクト
const d = new Date();
console.log(d); // => Wed Dec 22 2021 00:41:07 GMT+0900 (Japan Standard Time)
const formatDate = Utilities.formatDate(d, 'JST', 'yyyy年MM月dd日 HH時mm分ss秒');
const strNow = `現在時刻は${formatDate}です`;
console.log(strNow); // => 現在時刻は2021年12月22日 00時41分07秒です
}
しかし、このコードは、あずかり知らずな箇所で、状態を変更する処理が書かれているばあい、破綻しかねません。
function myFunction56_02() {
//ステートフルなオブジェクト
const d = new Date();
console.log(d); // => Wed Dec 22 2021 00:47:43 GMT+0900 (Japan Standard Time)
//あずかり知らずな処理
d.setDate(31);
const formatDate = Utilities.formatDate(d, 'JST', 'yyyy年MM月dd日 HH時mm分ss秒');
const strNow = `現在時刻は${formatDate}です`;
console.log(strNow); // => 現在時刻は2021年12月31日 00時47分43秒です
}
ステートレスAPIとは
なので、状態をもたない(ステートレス)な、オブジェクトを実装しよう、というのがテキストに書かれています。
上記の例でいくと、このように書き換えができます。
function myFunction56_03() {
//ステートレスなオブジェクト
const formatDate = Utilities.formatDate(new Date(), 'JST', 'yyyy年MM月dd日 HH時mm分ss秒');
const strNow = `現在時刻は${formatDate}です`;
console.log(strNow); // => 現在時刻は2021年12月22日 00時51分49秒です
}
デフォルト値をもつようなオブジェクトを、ステートレスにする例がテキストに掲載されていました。
function myFunction56_04() {
//このコードは動きません
//ステートフル
c.fillText("text1", 0, 0); //デフォルト⾊
c.fillStyle = "blue";
c.fillText("text2", 0, 30);//⻘
c.fillStyle = "black";
c.fillText("text3", 0, 60);//黒に戻る
//ステートレス化
c.fillText("text1", 0, 0); //デフォルト⾊
c.fillText("text2", 0, 30, { fillStyle: "blue" });//⻘
c.fillText("text3", 0, 60);//デフォルト⾊
}
ステートレスAPIを選ぼう
INIファイルは、構造の単純なテキストファイルであり、設定ファイルのフォーマットとしてよく使われています。
テキストでは、サーバーの設定を行うINIファイルが用意されていました。
[Host]
address = 172.0.0.1
name = localhost
[Connections]
timeout = 10000
このファイルデータを処理するAPIを考えたとき、ホスト(サーバーのパソコンのこと)の状態を確認し、設定する必要があります。
const ini = INI.parse(src);
ini.setSection("Host");
const addr = ini.get("address");
const hostname = ini.get("name");
ini.setSection("Connection");
const timeout = ini.get("timeout");
const server=newServer(addr,hostname,timeout);
しかし、このままだと、Dateオブジェクトのときと同様、どこか違う場所からホストの状態が変更されている可能性もあり、破綻します。
ステートレスなAPIにするなら、このように書けるでしょう。
const ini = INI.parse(src);
const server = newServer(ini.Host.address, ini.Host.name, ini.Connection.timeout);
もし、ステートフルなAPIを実装するばあいは、ドキュメントで明示しなければならない、というルールをオススメしていました。
まとめ
以上で、「不必要な状態を排除する」をお届けしました。
次回は、「柔軟なインターフェイスのために、構造的な型付けを使う」 をお届けします。
参考資料
このシリーズの目次
- [EffectiveJavaScript輪読会8]一貫した規約を維持しよう
- [EffectiveJavaScript輪読会8]undefinedは「値なし」として扱う
- [EffectiveJavaScript輪読会8]オプションオブジェクトで、キーワード付き引数群を受け取ろう
- [EffectiveJavaScript輪読会8]不必要な状態を排除する
- [EffectiveJavaScript輪読会8]柔軟なインターフェイスのために、構造的な型付けを使う
- [EffectiveJavaScript輪読会8]配列と「配列のようなもの」を区別しよう
- [EffectiveJavaScript輪読会8]過剰な型強制を防ごう