C++のためのAPIデザイン2章(2)

日が空いてしまいましたが,続き.

2.3 最小限の完全性

APIは最小限に完全であるべき.すなわち,可能な限り小さくするが,
必要以上に小さくはしないこと,とこの本では主張している.
APIは将来の保守性,完全性,使用者との約束,これらを維持するためには
必要な物だけを実装し,できるだけ最小限の公開インタフェースを設けることが大切である.
過度に一般性や将来性を見込んで実装したAPIは,将来の変更の足枷になる
(変更すればユーザのコードに影響が出るため,変更できない)上に,将来不要になるケースも多い.
APIは一度実装してしまえば削除できない,という大前提を肝に銘じて置かなければならない.
"""不確かなときは書かずにおけ"""である.

仮想関数の追加について

最小限の完全性を実現する際には仮想関数の追加には慎重にしないといけない.
基本クラスへの実装変更がユーザのコードへ有害な結果をもたらしたり,
ユーザが基本クラスの仕様を把握せずにAPIを拡張したりすることによる
弊害が大きくなったりする.

コアAPIとコンビニエンスAPIの分離

APIの利便性を増すためには,基本機能をまとめた
(複数のAPI操作を行い,より高度な操作を提供する)
APIを提供することは有用である.
しかし,一方でそのようなAPIを提供すると,デバッグや保守性に負担が生じる.
そこで,この本ではコアAPIと高度な操作を提供するAPIを分離して
別ラッパークラス・ライブラリとして提供することを提案している.
確かに,1つのクラスの中に基本操作と高度な操作を提供するAPIの両方を実装すれば,
APIの複雑性が増し保守などの負担が増加する.
また,使用者はコアAPIを使えば良いのか,高度なAPIを使えば良いのかわからなくなるだろう.

2.4 使いやすさ

できるだけドキュメントを読まなくても使えるAPIがbetter.学習のしやすさも重要.
使いやすさ != 解明しやすさ,であることを覚えておこう.

間違いの防止

APIのパラメータに同じ型のものが並んでいるだけで間違いを誘発する.

bool checkFunc( bool isAlive, bool isHuman )
{ ... } 

上記のような関数があった時,使用者はどちらが何のフラグであるかをドキュメントで調べなければならない.また,間違えて実引数を渡し間違える可能性もある.

このような場合は

enum class eAlive
{
   EA_ALIVE,
   EA_DEAD
};
...
bool checkFunc( enum eAlive, enum eHuman );

のようにすると呼び出す方も引数の順番などを意識する必要がなくなる.

この手のことは先日読んだEffectivePythonにも書かれてたな.C++に名前付き引数があれば更にこの辺に強くなれるんだけど(一応Boostにはある).

相互独立性

APIの呼び出しによって他のAPIに副作用を与えてはならない.
APIの呼び出し順によって結果がことなるとか怖いな,と思う.

プラットフォーム独立性

公開インタフェースにプラットフォームごとに切り替わるAPIを書かないこと.
これをやると,ユーザコードで切り替え用のコードを書く必要があったり,プラットフォームの数だけユーザに
コードの追加を強制させることになったりと,いろいろと影響しそうだ.
基本的に統一されたAPIの中でプラットフォームごとの差分を吸収させるような実装であることが望ましい.