API開発機能:どのAPIが良いですか?

おそらく、絶対にすべての読者がAPIを使用し、フレームワーク、ライブラリ、ウィジェットを、エンティティとメインアプリケーション間の一種の通信言語として使用します。 そして、おそらく、いくつかのAPIの方が使いやすいことと、明らかな問題があることにお気づきでしょう。 Vsevolod Shmyrov (@ vsesh )は、 Frontend Confについての彼のレポートで、そのデコードはカットの下にあり、 どのAPIが良いのかという質問に答えようとしました。



このストーリーは、Yandex.Maps APIの開発経験に基づいており、JavaScriptライブラリですが、その開発の原則と機能の多くは、サーバーAPIやスタンドアロンライブラリなどの他のタイプのAPIにも適用されます。 議論されるすべては、 パブリックA PIに関連しています。 同僚だけがライブラリのAPIに目を向ければ、どこかで何かを変更する必要があることを簡単に伝えることができるので、パブリックAPIの開発者が直面する問題はほとんど発生しません。



画像



ただし、レポートは、独自のAPIが必要かどうかの質問には答えません 。 読んだ後に長所と短所を比較検討し、それが必要かどうかを理解してください。 Vsevolodは、API開発者が直面する困難、解決すべき問題、他に何をすべきか、つまり、これらの4つの重要なポイントについて簡単に説明します。







スピーカーについて: Yandexのシニアインターフェイス開発者であるVsevolod Shmyrovは、Yandex.Maps APIとYandexマップデザイナーの開発に直接関与していました。



以下は、2017年のFrontend Confのレポートに関する資料です。たとえば、サポートされているブラウザーのバージョンのリストなど、いくつかの点は変更される可能性がありますが、優れたAPIの基準は依然として関連しています。 さらに、物語は楽しい読書であるVsevolodを代表して行われます。



簡単にする



APIはシンプルであり、できれば論理的でなければなりません 。 それは非常に単純であるように思われたので、うまくいかないかもしれません。 それにもかかわらず、人々はこの言葉にまったく異なる意味を入れています-単純さの程度は誰にとっても完全に異なっています。 私が話していることを理解できるように、否定的な例にまっすぐ行きましょう。



数年前、あるソーシャルネットワークのAPIに出会いました。 getFriendsメソッドがありました。



getFriends( ) => [ ]
      
      





実際、スライド上にJS擬似コードがあるという事実にもかかわらず、パラメーター付きのgetFriendsリクエストを送信し、友達のリストを受信したサーバーエンドポイントでした。 すべてが論理的であるようで、友人に尋ね、友人を得る。 このAPIで動作する私のコードは次のようになります。



 var friends = getFriends( );
      
      





しかし、何らかの理由で開発者はこれでは十分ではないと判断しました。 友達がいない場合、彼らは次のことをすることを決めました。空のリストの代わりにNullを取得します。



さて、私のコードは適切に見え始めました:



 var friends = getFriends ( ); If (friends) { // … } else { // … }
      
      





大丈夫です、基本的にはまだ使いやすいです。 しかし、開発者はそこで停止しないことを決定し、次のロジックを作成しました。1人の友人がいる場合、リストは返されませんが、この友人は1人だけです。



APIは簡単ではなく、非論理的であることが明らかになります。 私のコードは次のようになり始めました:



 var friends = getFriends( ); If (isUser(friends)) { /*…*/} elseif (friends) { /*…*/} else { /*…*/}
      
      





原則として、2つの条件で問題ありません。 ここでの問題は別の場所にあります。 このソーシャルネットワークのAPIを使用するすべての開発者は、APIを使用するために追加のチェックを作成します。 おそらくこのあたりのどこかに線を引いて、悪いAPIと良いAPIを言うことができます。



良いAPIとは、あまり書き過ぎないAPIです 。 APIで何らかのメソッドを使用し、引き続きデータを処理します。恐ろしい条件を記述する必要はありません。



要約すると、 インターフェースは次のようになります。





一貫性があるということは、APIに同じデータ型で機能するメソッドがある場合、これらのデータ型は同じ方法で記述される必要があることを意味します。



 iCanShowYou({x: 1, y: 1}); NoUCant([1, 2]); ButIMust(Point);
      
      





たとえば、Maps APIでは、座標データタイプがよく使用されます。これらのデータタイプは、緯度と経度の配列としてフォームに表示されます。 そして、それらはどこでも説明されています。つまり、XYオブジェクト、Long Latオブジェクト、または一般に2つのオブジェクトを受け入れるメソッドはありません。 座標はどこでも配列で表されます。



しかし、もちろん上記のすべてが機会を犠牲にしてはなりません。 単純に説明できない複雑なタスクがいくつかあり、入力時に多くのパラメーターが必要になることがあります。 または、APIでのメソッドの結果はサードパーティに依存します。 次に、各状況を個別に検討する必要があります。次に、このような問題をどのように解決するかを少し説明します。



 someAwesomeMethod( elem, /* required */ index, /* = "key" */ startValue, /* = 0 */ endValue /* = 1 */ );
      
      





上記の例では、任意の4つの引数を取るメソッド。 最も可能性の高いケースを推測し、標準パラメーター値を書き留めて、これらのケースが解決されるようにします。



大部分のユーザー(この場合、ユーザーはAPIを使用する開発者)がメソッドに必要な最小限の引数を渡し、追加の問題を解決するために、追加の引数を既に記述している必要があります。



 new ymaps.GeoObject( geometry, /* {Object} */ properties, /* {Object} */ options, /* {Object} */ );
      
      





この例では、オブジェクトごとにパラメーターをグループ化します。 他の言語では、特定のクラスまたはインターフェースのクラスまたはインスタンスにすることができます。 つまり、GeoObjectは特定のジオメトリを持つことができ、ポイント、ライン、ポリゴンにすることができ、名前などの特定のプロパティを持ち、色などのオプションを持ちます。 これらすべての引数に大きな違いはありませんが、 より便利にするためにそれらを数学的に分割ました 。 そして率直に言って、ジオメトリの変更はプロパティよりもはるかに少ないです。



 new ymaps.GeoObject(geometry), //  new ymaps.Placemark(coord), //  “Point”
      
      





また、特別なソフトウェアヘルパーも作成します。 先ほど言ったように、オブジェクトはポイント、ライン、ポリゴンになります。 たとえば、ポイントをより頻繁に使用し、特別なPlacemarkクラスを作成しました。これは、入力として抽象的なジオメトリではなく、座標のペアのみを取り込みます。



不確かな結果の場合、これはまったく別のタスクです。 松葉杖をフェンス囲む必要がある場合がありますが、パブリックAPIでのみ誰でも見ることができ、問題を複雑にします。



 geolocation.get() .then(function (result) { // success }, function (error) { // error });
      
      





geolocation.getメソッドは、ユーザーの現在の位置またはエラーのいずれかが存在するプロミスを返します。 間違いが発生する可能性があるため、このメソッドでpromiseを使用する必要がありました。さらに、このメソッドは非同期です。 Geolocation.getはデフォルトでブラウザの位置情報を使用しますが、これはすべてのブラウザがサポートしているわけではありません。



次のように機能し、開発者はgeolocation.getコードに書き込み、このコードが実行され、そのようなウィンドウがブラウザーにポップアップ表示されます。







サイトのユーザーは、サイトがその場所を取得することを許可または拒否することができます。 しかし、一部のブラウザにはバグがありました-クロスをクリックするか、ページのどこかをクリックすると、このウィンドウは消え、geolocation.getは値を返しませんでした。値なしでハングしました。 したがって、30秒以内に人が何も押さなかった場合、またはこのウィンドウが消えた場合、タイムアウトをリダイレクトする必要がありました。 これはあまり美しくありませんが、それでもコードの安定性を高めるのに役立ちます。



原稿が燃えない



このセクションは後方互換性についてです。 おそらくそのような場合がありました。

あなたは休んでいて、多分これは休み、おそらく夜、リラックスしていて、突然誰かがあなたに電話をして、生産で何も機能せず、製品が壊れていると言います。 そして、最後のリリースは3週間前であり、すべてが正常であり、破損するものは何もなかったことを何らかの形で思い出します。 彼らが言うように、トラブルの前兆はありません。

あなたは緊急に作業ネットワークに接続し、デバッガを開き、何が起きているのかを理解し始め、突然、すべてがあなたの側で良いことを理解します。 使用したAPIが壊れました。 より正確には、それは壊れさえしませんでした、それは単にあなたが期待した方法ではなく、異なる方法で働き始めました。 これは、下位互換性が壊れていることを意味します。



下位互換性



下位互換性は、一度公開されたインターフェースが将来サポートされるという保証です 。 原則として、それは無限に良いでしょうが、実際には、現在のメジャーバージョンのフレームワーク内です。



一般に、すべてが論理的であり、実行されました、動作します-触れないでください



何か新しいことをするために、傍観者のどこかでそれをしてください、古いものに触れないでください。 しかし、それほど単純ではありません。 下位互換性により、新しいコンポーネント 、新しいインターフェイスの開発に非常に強い制限が課せられます。これについて詳しく説明します。



最初に、新しいインターフェイスを公開することにした場合、開発者の自由度を考慮する必要があります。







開発者の自由度が高いほど、サポートに必要なリソースが多くなります。 1つの方法でしか使用できないモジュールが1つあるとします。 次に、2番目のモジュールを取得しました。1番目のモジュールを使用できるようになり、2番目のモジュールを使用できるようになり、両方のモジュールを一緒に使用できるようになりました。 その後、100個のモジュールを取得し、それらを使用すると、想像もできないような膨大な数の組み合わせや予期しない状況が発生します。 これにより、予期しないエラーのリスクが高まります



さらに、これをすべて維持するのは非常に費用がかかります。追加の単体テスト、統合テストを追加し、各マイナーバージョンの前にすべてを確認する必要があります。



それでもエンティティを公開することにした場合は、インターフェイスが拡張可能であることを考慮する必要があります。



例を見てみましょう。 かつては原則として存在するメソッドballoon.setPositionがありました。 そこで、xとyの下に示されている2つの座標、緯度、経度を送信することができました。



 balloon.setPosition( x, y//   )
      
      





先ほど言ったように、すべての座標は2つの引数ではなく1つで記述されます。どちらも必須の引数であるためです。 したがって、それらを1つの引数[x、y]にまとめて、必須としてマークすることをお勧めします。 次に、緯度と経度に加えて投影を許可するといいと思いました。デフォルトの投影がありますが、何らかの独自の投影を設定できます。 投影オプションを追加することもできますが、その後、おそらく他のオプションを追加する必要があります。 その後、すぐにオプションを作成し、内部に投影を指定し、将来的に他のキーを追加できるようにすることにしました。 つまり、インターフェイスを拡張可能にし、将来の開発を妨げません。



新しいインターフェイスが将来「ブロッカー」になるかどうかを理解するために、先ほどお話ししたことはすべて必要ですか?



もう一度例に戻りましょう。 むかしむかし、オーバーレイエンティティでgetLayoutメソッドを公開することにしました。 当時、HTMLLayoutシンボルクラスの実装である単一のレイアウトがありました。 次のようなインターフェースを公開できます。



 overlay.getLayout() // HTMLLayout
      
      





将来的には、html以外のレイアウトを作成できなくなります。 したがって、HTMLLayoutを返すILayoutインターフェイスを返すメソッドを作成しました。



 overlay.getLayout() // ILayout // HTMLLayout, CanvasLayout…
      
      





また、APIを使用する開発者は、ニーズに応じて、CanvasLayoutなどに切り替えるように設定できます。



APIをコンポーネントごとに実行する必要があることを認識し、メソッドが非同期になった場合、この場所にモジュールの読み込みを追加する機会があるため、Promiseを一般的に考えて追加しました。



バグ修正



しかし、完璧なものは何もなく、 遅かれ早かれ エラーは どの API にも 漏れます 。 誤ったアーキテクチャ上の決定が行われたことが起こります。 私たちの場合、ブラウザAPIに焦点を合わせて閉じました。 一部のインターフェイスは失敗し、やり直す必要があるという結論に達しました。 この場合、一部の開発者はメソッドを非推奨としてマークし始めます。



私たちはこの慣行を本当に歓迎しません。 おそらく、6年以内に40のメジャーリリースがあり、11番目のバージョンで何らかのメソッドが登場し、15番目で非推奨になり、20番目で完全に削除されたAPIがあるときに出くわしました。 ドキュメントの仕組みを理解するには、ドキュメントを理解する必要があります。 非推奨のメソッドを使用すると、APIが自然に大きくなり、ドキュメントを使用するのが便利ではなくなります。



エイリアスをよく使用しますが、これも原則としては良い解決策ではありません。 たとえば、アイコンのモックアップがあり、この場合、「グレー」という単語の両方のスペルを使用します。一部のユーザーはアメリカ語で書き、一部は英語で書きます。



 presets.get('islands#greyicon'); presets.get('islands#grayicon');
      
      





タイプミスを発見したとき、私たちはメソッドで同じことをしました。



しかし、下位互換性で最も重要なことは、 すべてを修正できるわけでないということです。 私のお気に入りの漫画で歌われているように、時々あなたは手放して忘れる必要があります。



約2年前、APIバックエンドをあるサーバーテクノロジーから別のサーバーテクノロジーに書き換えました。 次のように使用されるAPIを使用する開発者:参照による



  https://api-maps.yandex.ru/2.1/?lang=ru_RU&mode=debug 


スクリプトをページに接続し、すべてが完全に機能しました。



Node.jsに移行し、突然ユーザーから苦情が寄せられました。 これはアンパサンドでした-一部のユーザーは、特別な記号「&」が付いたリンクをコピーしました。これは、htmlではアンパサンドとして扱われ、適切に機能します。 しかし、一部のユーザーはこのリンクをそのままコピーしました。つまり、サーバーではなくそのようなリクエストが送信されました。 これが発生すると、パラメーター「mode」の代わりに「amp; mode」が発生し、次のエラーが発生しました。 古いバックエンドは、「;」記号をアンパサンド記号とともにパラメーターの取得セパレーターと見なしたため、これを処理しました。 つまり、ラング、モード、そして空のアンプがたくさんありました。



何人のユーザーがこのようなリクエストを行ったかを見て、これが正しくないことを全員に説明できないことに気付きました。 そのため、単にミドルウェアを追加しました。ミドルウェアはgetパラメーターからアンプを削除し、そのパラメーターを処理した後にのみ削除します。 はい、それは愚かですが、あなたはそれと共に生きなければなりません。



メジャーリリース



しかし、すべてがそれほど絶望的というわけではありません。後方互換性の間違いは、あなたの人生が終わるまで悩まされることはありません 。 最後まで、次のメジャーバージョンまで。







約3年前、API 2.1のメジャーバージョンをリリースして、サポートするブラウザーのリスト更新することにしました。 APIバージョン2.0は、非常に古く、IE 6をサポートしていました。 しかし、残念ながら、2.1ではIE 8を引き続きサポートしています。3年前はかなり最新のブラウザーだったからです(現在IE 8はすでに弱いサポートになっています)。

正直に言うと、私たちの間だけで、平日はIE 8のシェアが4%前後であり、週末には1%未満しか低下しません。 会社でIEを使用している場合は、十分に更新してください。
そのため、ブラウザーのリストを更新することも後方互換性の問題であり、APIは古いブラウザーでは機能しないため、このバージョン2.1と呼ばれています。 同時に、彼らは、それが必要ではない場合でも、すべて外に出て、下位互換性を破ることに決めました。 これらのすべてのエイリアスと、下位互換性のために維持する必要のある松葉杖からコードクリーンアップし、IE 6の古い親友を削除しました。



メジャーバージョンが万能薬はないことは明らかです。新しいメジャーバージョンのリリースは、APIを使用する開発にとってストレスの多いものです 。 ドキュメントを再度クリーンアップする必要があるため、メジャーバージョンにinしない方がよいでしょう。 メジャーバージョンのリリースでは、引き続きコードの書き換えが強制されます。つまり、ユーザーに強制しない限り、APIはあまり良くありません。 部分的な解決策は、特別な操作モードです。



仕事の「特別モード」



JavaScriptには厳密な厳密な使用」モードがあります。同じコードを記述すると、視覚的には同じように見えますが、処理方法が少し異なります。 同様の動作モードがありますが、目的はまったく異なります。



  https://api-maps.yandex.ru/2.1/?lang=en_RU&coordorder=longlat 


getパラメータcoordorderがあります。これは、前述の配列内の座標順序を制御するために使用できます。 デフォルトでは、緯度はlonglatです。 経度、緯度(緯度経度)を渡すことができます。 異なるジオシステムは異なる座標順序を使用します。 したがって、getパラメーターを指定すると、異なる操作モードが取得されます。



API全体の動作は少し異なるため、計算ではこれを考慮する必要があります。



後方互換性について他に言えることはありますか? あなたが思うかもしれないように、後方互換性はコードだけでなく影響します。







ビジュアルAPI、つまり何かを表示するAPIを開発している場合、ビジュアルコンポーネントとの後方互換性があります 。 少し前に、マップコントロールを更新したAPIの新しいマイナーバージョンをリリースしました。 今ではファッショナブルであるように、それらはより軽く、より平らになりましたが、実際にはサイズは変わりませんでした。 なぜこれをしたのですか? 理論上、巨大なボタンを作成したり、半円形にしたり、アイコンを変更したり、アイコンを完全に削除したりできますが、これは後方互換性に違反します。



APIでコントロールを作成したとき、開発者が独自のコントロールを追加する機会を開発者に提供することは素晴らしいことだと考えました。 つまり、上からではなく、真ん中です。 したがって、ボタンの標準レイアウトを大きくした場合、サイトの開発者はレイアウトに行きます。 そのため、新しいマイナーバージョンを作成する場合は、これを考慮して考慮する必要があります。







また、カスケードでは非常に頻繁に下位互換性が損なわれることに注意してください。 私たちの場合、ブラウザの何かが壊れています-APIの何かが壊れています。







ユーザーの共有の約80%を既に持っている1つのブラウザーで、MouseEventイベントのサインが突然サインを変更したときに、このような少し悲しい面白いケースがありました。 マウスホイールをスクロールすると、プラスではなくマイナスになり始めました。 当然、人がマウスホイールで地図をズームしようとすると、地図から離れ始めました。 ブラウザが修正するまでの2日間は、1日に約3000通の手紙を受け取りました。 あなたが理解するように、通常、最もストレスの多い日でさえ、約10通の手紙が到着します。つまり、 人々はカードが突然その行動を変えたことを本当に不快に感じました。



見知らぬ人の間で



このセクションはJavaScript APIに専念していますが、それでも非常に興味深いものです。 APIは外部のコンテキストで動作しますが、どういう意味ですか? map APIを使用する最初のサイトがあり、すべてが正常に機能するとします。 APIを使用する2番目のサイトがありますが、jQueryライブラリも使用します-すべて正常に動作します。 また、マップAPIと一部のevil.jsを使用する3番目のサイトがあり、何らかの理由で基本的なメソッドを再定義しています







以下の例では、indexOfがマイナス1を返さないというエラーがあります。 どうやらこのメソッドの開発者はIE 6をサポートすることに決め、実際のindexOfの存在を確認せず、次のように書きました。



 Array.prototype.indexOf = function (item) { for (var i = 0; i < this.length; i++) if (item ==this [i]) return i; };
      
      





この場合、APIは自然に壊れます。 または、たとえば、次のコードに出くわしました:



 * { transition: 2s all ease; }
      
      





何らかの理由で、誰かがページ上のすべてをアニメーション化するようなCSSセレクターを作成しました。



この記事のフレームワークでは、これに対処する方法については詳しく説明しません。原則として、これは常に可能であるとは限りません。詳細については、こちらを参照してください。



しかし、リソースを使う必要があることも強調したいと思います。 通常、これは次のように発生します。ユーザーの苦情は、リンクが接続された状態で、何かが機能していないというサポートを受けます。 開いて、APIで何かが壊れているように見えます。 CSS、JSを検討し始めましたが、これは必ずしも便利ではありません。 また、外部コンテキストで実装されているJSライブラリまたはAPIを開発している場合、これに時間を費やす必要があります。



製品がわからない



前述のように、APIは製品であり、製品の使用方法はわかりません。 - 2.0 , , .







, - 150*150 , . , 2.0 , . , 2.1 , . — , , .







, , , . API.



指標



API, API. , , - , , , . , API.



. , , , — 5000*4000. , - , , .



, , , , . , , , .







, API, API. , , , , API. , — , , .







, : , ( ). , , , . , , API , , .

, , -.
API Iframe , , . html Iframe, , Iframe , , , , , .







API, , , . API .

API — API.

— , , .







JSDoc. , , , , API .







, . , , API, « », « » - . , , . , .







API: , . - , JSFiddle. , .



.







, , , - ( , ). , , , . , : «, , ». . , . , , , .



Call me maybe



, API . , API. , API , API. , , , , , . , .







, - , , , - API, - . .







, , , . API , , , , , API.







.







« », . - . , - . .







, , , .







, , .









, API , , «» . . .



 <script src=" .../constructor/?um={id}&width=514&height=326 "></script>
      
      





, , API. , , API , , . , , . , , , .



, . , , , . , 2.0 2.1 . - , , - .



, API, , - API. , , . , - — API.



まとめ



:





, :





Frontend Conf , 28 29 , , , , :



  • Chris Lilley (W3C). WebFonts in 2018: Everything Changes.
  • (GP Solutions). Elm, ?
  • (KeepSolid). , .


, — 4 5 Frontend Conf Moscow , . 3 , ++, .




All Articles