API設計ガイドライン
はじめに
一貫性のあるAPI設計は、アプリケーションの作成を容易にします。APIコールの命名や引数の順番などの規約を覚えやすくし、エラーのないコードをできるだけ簡単に書けるようにする必要があります。
API設計の決定には、いくつかの重要な懸念事項があります。
- 一貫性:APIコールと引数を覚えやすいこと。
- バージョン管理:APIの拡張を容易にし、設計上の行き詰まりを回避する。
- フットプリント:Duktape内部とアプリケーション・コール・サイトのコード・フットプリントを最小にする。
- パフォーマンス:あるAPIの設計は、他のものより優れたパフォーマンスを可能にします。
この文書では、一般的なAPI設計の問題点とトレードオフについて、いくつかの注意点を提 供しています。この文書は、完全なものであることを意図しておらず、出てきた現実的な問題 をカバーしているに過ぎません。
ネーミング
APIコール
全てのAPIコールは小文字で、アンダースコアで区切られ、接頭辞は duk_
で始まっています。 Duktapeの内部で、公開APIに含まれないものも、この規則に従った呼び出しがあります。 公開APIのコールは、公開APIヘッダー(実際には配布ファイルにある duktape.h
の一部)とAPIドキュメントに記述されています。
値スタック項目を操作するための既存の規約です。
duk_get_XXX()
はスタック上の値を変更することなく値を取得します。もし値が期待された型と一致しない場合、何らかのデフォルト値(NULLや0など)が返されます。duk_require_XXX()
はスタックにある値を変更せずに値を取得します。もし値が期待された型と一致しない場合は、エラーがスローされます。duk_to_XXX()
は、値をインプレースで目的の型に変換します。
Varargs API コールを使用します。
- 例えば
duk_error_va()
のように、末尾に_va()
を付けた名前になります。- 既存の例外:
duk_push_sprintf()
.
- 既存の例外:
安全/保護された通話に関する既存の規約。
- すべてのコールはデフォルトではアンセーフです。
duk_pXXX()
のコールは protected、つまりエラーをキャッチします。 APIコールの戻り値は成功かエラーを示し、エラーは通常バリュースタックを介して渡されます。duk_safe_XXX()
の呼び出しは安全で、すなわちスローしませんが、成功/エラーの表示は行いません。- 既存の例外:
duk_safe_call()
は現在この規約にマッチしていません: protected call (エラーをキャッチして成功/失敗のインジケータを返す) です。
- 既存の例外:
引数
小文字、アンダースコアで区切る。 他に厳密なガイドラインはなく、現在の名称もある。
ctx
idx
,obj_index
,from_index
,to_index
,index1
,index2
arr_index
flags
,enum_flags
len
,ptr
,key
引数名は避けてください。
index
: strings.h の関数と衝突する。
Typing
戻り値
duk_bool_t
が真/偽の値を返します。duk_idx_t
は値スタックインデックスに使用する。duk_int
は、符号付きと符号なし両方の値を表現する必要がある一般的な戻り値です。- Duktape/C 関数の戻り値用の
duk_ret_t
。
引数
duk_idx_t
は値スタックインデックスを表し、duk_uarridx_t
は ECMAScript の配列インデックスを表します。duk_uarridx_t
は ECMAScript の配列インデックスを表します。duk_size_t
はバイト長 (文字列、バッファなど) を表します。void *
: 汎用的な void ポインタ。- 文字列データポインタ:
const char *
. - バッファデータポインタ:
void *
.
Varargs APIコール
Vararg APIコールのバリエーションは、アプリケーションが非Varg APIコールのバリエーションを使用するのが面倒な場合に提供されます。 例えば、最初にフォーマットされた文字列を作成し、それを duk_push_string()
でプッシュするのは面倒でしょうから、 duk_push_sprintf()
が提供されています。
Flags vs. variants
よくある問題は、フラグで制御される多様な動作を提供するAPIコールがあるべきか、それともそれに対応する個別のAPIコールのセットがあるべきか、ということです。
一般に、APIでは個々のAPIコールが好まれる。
- フラグ定義を覚えたり組み合わせたりする必要がないため、アプリケーションでの呼び出しサイトが簡単になる。
- 個々のAPIコールは、個々の内部実装か、フラグを取る内部ヘルパーのどちらか、内部実装に最も適した方に簡単にマッピングすることができる。 マクロ呼び出しのサイトでフラグをチェックすることは可能だが、マクロがフラグを複数回評価することになり、APIマクロ保証に反することになる。
- flagsフィールドの構築やデコードを行わないため、最高のパフォーマンスを実現できる。
- APIに改良されたコールが追加されても、個々のコールを新しいプロバイダにマッピングするのは簡単なので、APIの混乱を放置したままでもバージョンアップは簡単にできる。
動作フラグを持つコールが少ない方が望ましい状況もある。
- APIコールが多くの機能を提供し、個々のコールのバリアントのセットが非常に大きくなる場合、フラグがより適切かもしれない。
- APIコールの動作が、時間とともに新しい制御フラグを進化させそうな場合、 フラグがより適切かもしれない。
例えば、 duk_def_prop()
はこの両方の条件に当てはまります。 フラグを使用することのデメリットは、以下の通りです。
- API のマクロでフラグをデコードして、個々の内部実装を呼び出すことは簡単ではありません。
- フラグを渡すことによるパフォーマンスコストは小さく、呼び出し先でフラグをデコードすることによるパフォーマンスコストは相対的に大きくなります。