API設計:具体的アプローチと抽象的アプローチ-ベストプラクティス?


25

システム間で(ビジネスレベルで)APIについて議論するとき、チームには2つの異なる視点があります。一般抽象アプローチを好む人もいれば、そうでない人もいます。

例:単純な「個人検索」APIの設計。具体的なバージョンは

 searchPerson(String name, boolean soundEx,
              String firstName, boolean soundEx,
              String dateOfBirth)

具体的なバージョンを支持する人々は言う:

  • APIは自己文書化されています
  • わかりやすい
  • 検証は簡単です(コンパイラーまたはWebサービスとして:スキーマ検証)
  • キッス

私たちのチームの他のグループは、「これは単なる検索条件のリストです」と言うでしょう。

searchPerson(List<SearchCriteria> criteria)

SearchCritera {
  String parameter,
  String value,
  Map<String, String> options
}

おそらくいくつかの列挙型の「パラメータ」を作成します。

支持者は言う:

  • API(の宣言)を変更することなく、実装は変更できます。たとえば、基準やオプションを追加します。展開時にそのような変更を同期しなくても。
  • 具体的なバリアントでもドキュメントが必要です
  • スキーマ検証は過大評価されており、多くの場合、さらに検証する必要があります。スキーマはすべてのケースを処理できません
  • 別のシステムと同様のAPIが既にあります-再利用

反論は

  • 有効なパラメーターと有効なパラメーターの組み合わせに関する多くのドキュメント
  • 他のチームにとって理解するのがより難しいので、より多くのコミュニケーション努力

ベストプラクティスはありますか?文献?


3
「String first / name、boolean soundEx」が繰り返されることは、dryの明らかな違反であり、この設計が名前がsoundExに沿って進むことが予想されるという事実に対処できなかったことを示唆しています。そのような単純な設計ミスに直面して、より洗練された分析を進めるのは難しいと感じています
gnat

「コンクリート」の反対は「一般的」ではなく、「抽象的」です。抽象化はライブラリまたはAPIにとって非常に重要であり、この議論は真に基本的な質問をすることに失敗しており、かなり率直に言ってスタイルのささいな問題に固執しています。FWIW、オプションBの反論はFUDの負荷のように聞こえますが、API設計が半分であり、SOLIDの原則に従っている場合、追加のドキュメントや通信は必要ありません。
アーロンノート

@Aaronaughtは、そのことを指摘してくれてありがとう( "abstract")。翻訳の問題かもしれませんが、ドイツ語の「generisch」は私にはまだ問題ないようです。あなたにとって「真に根本的な質問」とは何ですか?
エリック

4
@Aaronaught:問題は抽象的ではありません。正しい修正は、「汎用」の反対が「具体的」であり、「具体的」ではないということです。
Jan Hudec

これに対する別の投票は、一般的なものと抽象的なものではなく、一般的なものと具体的なものに関するものです。上記の「具体的な」例は、実際には名前、firstName、およびdateOfBirthに固有のものであり、他の例はすべてのパラメーターの総称です。どちらも特に抽象的ではありません。タイトルを編集したいが、編集戦争を開始したくない:
マットフリーク

回答:


18

それは、あなたが話しているフィールドの数と、それらがどのように使用されるかに依存します。少数のフィールドのみを含む高度に構造化されたクエリにはコンクリートが望ましいですが、クエリが非常に自由な形式になる傾向がある場合、3つまたは4つ以上のフィールドがあると、具体的なアプローチはすぐに扱いにくくなります。

一方、汎用APIを純粋に保つことは非常に困難です。多くの場所で単純な名前検索を行うと、最終的に誰かが同じ5行のコードを繰り返すことにうんざりし、関数にラップすることになります。このようなAPIは常に、一般的なクエリと、最も一般的に使用されるクエリの具体的なラッパーのハイブリッドに進化します。そして、私はそれについて何も悪いことは見ていません。それはあなたに両方の長所を提供します。


7

優れたAPIを設計することは芸術です。時間が経過しても、良いAPIはありがたいです。私の意見では、抽象コンクリートのラインに一般的なバイアスはないはずです。一部のパラメーターは曜日と同じくらい具体的であり、一部は拡張性のために設計する必要があります(そして、関数名の一部など、具体的にするのは非常に愚かです) APIはコールバックを提供する必要があります。ドメイン固有の言語でさえ、複雑さを克服するのに役立ちます。

月の下で起こる新しいことはめったにありません。先行技術、特に確立された標準と形式を見てください(たとえば、フィードの後に​​多くのものをモデル化することができ、イベントの説明はical / vcalで作成されました)。頻繁に存在するエンティティが具体的であり、想定される拡張が辞書である場合、APIを簡単に追加できます。特定の状況に対処するための確立されたパターンもいくつかあります。たとえば、HTTP要求(および同様の)の処理は、RequestオブジェクトとResponseオブジェクトを使用してAPIでモデル化できます。

APIを設計する前に、含まれない側面も含めて、側面についてブレインストーミングを行いますが、注意する必要があります。そのような例は、言語、執筆の方向、エンコーディング、ロケール、タイムゾーン情報などです。倍数が表示される可能性がある場所に注意してください。単一の値ではなくリストを使用してください。たとえば、videochatシステム用のAPIを設計している場合、2人ではなくN人の参加者を想定すると、APIははるかに便利になります(現時点での仕様はそのようなものですが)。

抽象的であることは、複雑さを大幅に減らすのに役立ちます:3 + 4、2 + 2、および7 + 6のみを追加するための計算機を設計する場合でも、X + Y(Xの技術的に実行可能な境界とY、およびADD_3_4()、ADD_2_2()、...の代わりにADD(X、Y)をAPIに含める

全体として、いずれかの方法を選択することは技術的な詳細にすぎません。ドキュメントには、頻繁な使用事例を具体的な方法で記述する必要があります。

データ構造側で何をするにしても、APIバージョンのフィールドを提供します。

要約すると、APIはソフトウェアを扱う際の複雑さを最小限に抑える必要があります。APIを評価するには、公開される複雑さのレベルが適切である必要があります。APIの形式の決定は、問題のあるドメインの安定性に大きく依存します。したがって、この情報が複雑さの方程式に影響する可能性があるため、ソフトウェアとそのAPIがどの方向に成長するかについての推定が必要です。また、APIデザインは、人々が理解するためにあります。あなたがいるソフトウェア技術分野に良い伝統があるなら、それが理解を助けるので、それらからあまり逸脱しないようにしてください。あなたが書いた人を考慮に入れてください。上級ユーザーは汎用性と柔軟性を高く評価しますが、経験の少ないユーザーはコンクリートに慣れているかもしれません。ただし、そこにいるAPIユーザーの大部分に注意し、

文学の面では、美しさは隠れた最適性(および何らかの目的への適合性)を知覚することだと思うので、「美しいコード」のリーディングプログラマーに自分の考えを説明することをお勧めします。


1

私の個人的な好みは抽象的であることですが、私の会社のポリシーは具体的なものに私を固定します。それは私にとっての議論の終わりです:)

あなたは両方のアプローチの長所と短所を一覧表示するのに良い仕事をしました、そして、掘り続けるならば、あなたは両方の側を支持する多くの議論を見つけるでしょう。APIのアーキテクチャが適切に開発されている限り(つまり、今日どのように使用され、将来どのように進化および成長するかについて考えてきた場合)、どちらにしても大丈夫です。

反対の視点で私が持っていた2つのブックマークは次のとおりです。

抽象クラスを好む

好意的なインターフェース

「APIはビジネス要件を満たしていますか?成功の基準は明確に定義されていますか?スケーリングできますか?」と自問してください。これらは従うべき本当に簡単なベストプラクティスのように見えますが、正直なところ、それらは具体的なものよりもはるかに重要です。


1

抽象APIの検証が必ずしも難しいとは言いません。条件パラメーターが十分に単純であり、相互の依存関係がほとんどない場合、パラメーターを個別に渡すか配列で渡すかに大きな違いはありません。あなたはまだそれらすべてを検証する必要があります。しかし、それは基準パラメーターとオブジェクト自体の設計に依存します。

APIが十分に複雑な場合、具体的なメソッドを持つことはオプションではありません。ある時点で、おそらく、多くのパラメーターを使用するメソッド、または必要なユースケースのすべてをカバーしない非常に単純なメソッドのいずれかになります。消費APIの設計における私の個人的な経験に関しては、APIレベルでより汎用的なメソッドを用意し、アプリケーションレベルで特定の必要なラッパーを実装する方が良いでしょう。


1

変更引数はYAGNIで却下する必要があります。基本的に、ジェネリックAPIを異なる方法で使用する少なくとも3つの異なるユースケースが実際にない限り、次のユースケースが発生したときに(そしてユースケースがあるときに変更する必要がないように設計する可能性はかなり低い場合、あなたは明らかに一般的なインターフェイス、期間が必要です)。そのため、変更を試みようとしないでください。

どちらの場合でも、展開のために変更を同期する必要はありません。後でインターフェイスを一般化する場合、下位互換性のために、より具体的なインターフェイスをいつでも提供できます。しかし実際には、どのデプロイメントにも非常に多くの変更が加えられるため、いずれにせよそれを同期するため、中間状態をテストする必要はありません。私もそれを議論とは思わないでしょう。

文書化に関しては、どちらのソリューションも使いやすく、明白な場合があります。しかし、それは重要な議論です。実際のケースで使いやすいようにインターフェースを実装します。時には特定の方が良いかもしれませんし、時にはジェネリックかもしれません。


1

私は抽象的なインターフェースのアプローチを好むでしょう。これらの種類の(検索)サービスにクエリを配置することは一般的な問題であり、おそらく再び発生します。さらに、より一般的なインターフェイスを再利用するのに適したより多くのサービス候補を見つけることができます。これらのサービスに一貫性のある共通インターフェイスを提供できるようにするために、インターフェイス定義で現在特定されているクエリパラメーターを列挙しません。

以前指摘したように、インターフェイスを変更せずに実装を変更または拡張する機会が好きです。別の検索条件を追加しても、サービス定義に反映される必要はありません。

明確に定義された簡潔で表現力の高いインターフェースを設計することは間違いありませんが、追加のドキュメントを常に提供する必要があります。有効な検索条件の定義範囲を追加しても、それほど負担にはなりません。


1

今まで見た中で最高の要約は、Rustyのスケールであり、RustyのAPI Design manifestoと呼ばれるようになりました。私はそれを強く推奨することができるだけです。完全を期すために、最初のリンクからスケールの概要を引用します(上にあるほど良く、下にあるほど悪い):

良いAPI

  • 間違えることは不可能です。
  • コンパイラ/リンカーは、あなたがそれを間違えることを許しません。
  • コンパイラーは、間違っていると警告を出します。
  • 明らかな使用法は(おそらく)正しい使用法です。
  • 名前は、その使用方法を示しています。
  • 正しく実行しないと、実行時に常に破損します。
  • 一般的な慣例に従ってください。正しく理解できます。
  • ドキュメントを読んで、正しく理解してください。
  • 実装を読むと、正しく理解できます。
  • 正しいメーリングリストのスレッドを読んでください。正しく理解できます。

悪いAPI

  • メーリングリストのスレッドを読んでください。間違っています。
  • 実装を読んで、あなたはそれを間違えるでしょう。
  • ドキュメントを読んで、あなたはそれを間違えるでしょう。
  • 一般的な慣例に従ってください、あなたはそれを間違えるでしょう。
  • 正しく実行すると、実行時に破損することがあります。
  • 名前は、それを使用しない方法を示します。
  • 明らかな使用法は間違っています。
  • コンパイラは、正しく設定すると警告を表示します。
  • コンパイラ/リンカーは、あなたにそれを正しくさせません。
  • 正しくすることは不可能です。

ここここの両方の詳細ページには、各ポイントの詳細な説明が付いています。APIデザイナーにとっては必読です。これを読んだことがあるなら、Rustyに感謝します。


0

素人の言葉で:

  • 抽象的アプローチには、具体的なメソッドを構築できるという利点があります。
  • 他の方法は真実ではありません

UDPには、独自の信頼できるストリームを構築できるという利点があります。では、ほとんどの人がTCPを使用しているのはなぜですか?
svick

ユースケースの大部分についても考慮されています。いくつかのケースは非常に頻繁に必要になるため、それらのケースを特別なものにすることが可能です。
ローマスージー

0

SearchCriteriaアイデアを少し拡張するとANDOR基準の作成などの柔軟性が得られます。このような機能が必要な場合は、これがより良いアプローチです。

それ以外の場合は、使いやすさを考慮して設計してください。APIを使用する人にとってAPIを簡単にします。頻繁に必要とされる基本的な機能(名前で人を検索するなど)がある場合は、それらを直接提供します。上級ユーザーが高度な検索を必要とする場合でも、を使用できますSearchCriteria


0

APIの背後にあるコードは何をしていますか?柔軟なものであれば、柔軟なAPIが適しています。APIの背後にあるコードが非常に具体的である場合、その上に柔軟な顔を置くことは、APIのユーザーがイライラし、APIのふりをするすべてのものにイライラすることを意味しますが、実際には達成できません。

個人検索の例では、3つのフィールドすべてが必要ですか?そうだとすると、単純に機能しない多数の使用が可能になるため、基準リストは不適切です。そうでない場合、ユーザーに不要な入力を指定するよう要求するのは悪いことです。V2でアドレスによる検索が追加される可能性はどのくらいですか?柔軟性のあるインターフェイスは、柔軟性のないインターフェイスよりも簡単に追加できます。

すべてのシステムが非常に柔軟である必要はなく、すべてを作成しようとしているので、Architecture Astronautingも同様です。柔軟な弓が矢を放ちます。柔軟な剣は、ゴム製の鶏と同じくらい便利です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.