コードを見るだけで、APIが何をしているのかを常に知る必要がありますか?


20

最近、私は自分のAPIを開発しており、そのAPI設計への投資に興味を持ち、API設計を改善する方法に強い関心を持っています。

数回登場した側面の1つは(私のAPIのユーザーによるものではなく、トピックに関する私の観察中の議論による)です。

たとえば、談話レポについてはGitHubでのこの議論を参照してください。

foo.update_pinned(true, true);

(パラメータ名、ドキュメントなどを知らずに)コードを見るだけでは、何をしようとしているのか推測できません。2番目の引数はどういう意味ですか?推奨される改善策は、次のようなものにすることです。

foo.pin()
foo.unpin()
foo.pin_globally()

そして、それは物事を明確にします(2番目の引数はfooをグローバルに固定するかどうかでした、私は推測しています)、この場合、後者は確かに改善されることに同意します。

ただし、コードを見ただけでは何をしているのかわからない場合でも、異なるが論理的に関連する状態を設定するメソッドが、個別のメソッド呼び出しではなく、1つのメソッド呼び出しとしてより適切に公開される場合があると思います。(したがって、パラメータ名とドキュメントを調べて調べる必要があります-個人的には、APIに不慣れな場合は常に何をしてもかまいません)。

たとえばSetVisibility(bool, string, bool)FalconPeerで 1つのメソッドを公開し、次の行を確認するだけです。

falconPeer.SetVisibility(true, "aerw3", true);

あなたはそれが何をしているのか分からないでしょう。falconPeer論理的な意味での「可視性」を制御する3つの異なる値を設定しています。パスワードのみで参加要求を受け入れ、検出要求に応答します。これを3つのメソッド呼び出しに分割すると、APIのユーザーは、「可視性」のすべての側面を設定するために1つのメソッドを公開するだけで他のユーザーに設定を忘れさせる「可視性」の側面を設定することになります。さらに、ユーザーが1つのアスペクトを変更する場合、ほとんどの場合、別のアスペクトを変更する必要があり、1回の呼び出しで変更できます。


13
これがまさに、いくつかの言語が名前付きパラメーターを持っている理由です(名前付きパラメーターを強制することもあります)。たとえば、次の簡単なupdate方法で多くの設定をグループ化できますfoo.update(pinned=true, globally=true)。または:foo.update_pinned(true, globally=true)。したがって、あなたの質問への答えは言語機能も考慮に入れるべきです。言語Xの優れたAPIは言語Yには向かないかもしれませんし、逆もまた同様です。
バクリウ14年

合意-ブール値の使用をやめましょう:)
Ven

2
それはとして知られている「ブールトラップ」
user11153

@Bakuriu Cでさえ、仮に整数であったとしても列挙型を持っています。ブール値が優れたAPIデザインである現実の言語は存在しないと思います。
ドーバル14年

1
@Dovalあなたが言っていることはわかりません。OPがブール値を使用したという理由だけでブール値を使用しましたが、私のポイントは渡された値とはまったく関係ありません。例えば:setSize(10, 20)のように読みやすいではありませんsetSize(width=10, height=20)random(distribution='gaussian', mean=0.5, deviation=1)。彼らは強制という名前のパラメータのブール値を持つ言語では、列挙型/名前付き定数を使用したとまったく同じ情報量を伝えることができることが可能なAPIで良いです。
バクリウ14年

回答:


27

それを3つのメソッド呼び出しに分割したくないという希望は完全に理解できますが、ブールパラメーター以外のオプションもあります。

列挙型を使用できます:

falconPeer.SetVisibility(JoinRequestOptions.Accept, "aerw3", DiscoveryRequestOptions.Reply);

または、flags enum(言語がサポートしている場合):

falconPeer.SetVisibility(VisibilityOptions.AcceptJoinRequests | VisibilityOptions.ReplyToDiscoveryRequests, "aerw3");

または、パラメータオブジェクトを使用できます。

var options = new VisibilityOptions();
options.AcceptJoinRequests = true;
options.ReplyToDiscoveryRequest = true;
options.Password="aerw3";
falconPeer.SetVisibility(options);

パラメータオブジェクトパターンには、他にも便利な利点がいくつかあります。パラメータのセットを簡単にやり取りしてシリアル化し、指定されていないパラメータに「デフォルト」値を簡単に指定できます。

または、ブール値パラメーターを使用することもできます。Microsoftは、.NET Framework APIを使用して常にそれを行うように思われるので、肩をすくめて「彼らにとって十分であれば、私にとって十分だ」と言うことができます。


パラメータオブジェクトパターンには、「これを3つのメソッド呼び出しに分割すると、APIのユーザーが他の設定を忘れて「可視性」の1つの側面を設定する可能性があります」という問題があります
ロード14

本当ですが、状況が良くなると思います(完璧でない場合)。ユーザーがインスタンス化してVisibilityOptionsオブジェクトを渡すことを余儀なくされた場合、(運が良ければ)VisibilityOptionsオブジェクトに設定したい他のプロパティがあることを思い出させるかもしれません。3つのメソッド呼び出しのアプローチでは、呼び出しているメソッドに関するコメントのみを通知する必要があります。
BenM 14年

6

明らかに、ルールには常に例外がありますが、あなたがよく説明したように、読み取り可能なAPIを使用することには特定の利点があります。ブール引数は、1)意図を明らかにせず、2)ブールフラグに応じて異なることが発生するため、実際には2つ必要な関数を呼び出すことを意味するため、特に厄介です。

主な質問はむしろ:APIをより読みやすくするためにどれだけの労力を投資したいですか?外向きになればなるほど、より多くの労力を簡単に正当化できます。他の1つのユニットのみが使用するAPIである場合、それほど大きな問題ではありません。全世界がそれに負けるようにすることを計画しているREST APIについて話しているなら、あなたはそれをより理解しやすくするためにいくらかの努力を投資することもできます。

あなたの例に関しては、簡単な解決策があります:どうやら、あなたの場合、可視性は単なる真偽ではありません。代わりに、「可視性」と見なすものがすべて揃っています。1つの解決策はVisibility、これらのさまざまな種類の可視性をすべてカバーするクラスのようなものを導入することです。これらを作成するためにBuilderパターンをさらに適用すると、次のようなコードになる可能性があります。

Visibility visibility = Visibility.builder()
  .acceptJoinRequests()
  .withPassword("aerw3")
  .replyToDiscoveryRequests()
  .build();
falconPeer.setVisibility(visibility);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.