SSブログ
API仕様を書く ブログトップ
前の10件 | -

実践API設計:目次 [API仕様を書く]

WEB+DB PRESS Vol.134

WEB+DB PRESS Vol.134

  • 出版社/メーカー: 技術評論社
  • 発売日: 2023/04/22
  • メディア: Kindle版

特集1「実践API設計」の構成が分かるように目次を作成してみました。
第1章 優れたAPI仕様とは何か
 特集のはじめに
 APIとは
   フレームワークや標準ライブラリのAPI仕様
   企業内でのAPI仕様
 優れたAPI仕様とは
   理解が容易
   変更が容易
   テストが容易
  API仕様でよくある問題点
   API仕様が書かれていない
   エラーの記述がない
   自動テストが存在しない
  API仕様に書くべきこと
   サービスの概要の説明
   個々のエンドポイントの説明
   エラーの説明
     パラメータの不正値
     誤った順序での呼び出し
     認証と認可のエラー
     そのほかのエラー
   まとめ

第2章 gRPCにおけるAPI仕様の書き方
 gRPCとは
 API仕様をどこに書くか
 サービスの概要の記述
 個々のエンドポイント(RPC)の説明
 エラーの説明
   パラメータの不正
     InvalidArgument ── 不正なパラメータ値
     NotFound ── リソースが見つからない
     OutOfRange ── 指定された範囲のデータがない
   誤った順序での呼び出し
     FailedPrecondition ── 事前条件が成立していない
   認証や認可のエラー
     Unauthenticated ── 認証できない
     PermissionDenied ── 認可できない
   サービスの概要に書くべきそのほかのエラー
     Canceled ── キャンセルされた
     DeadlineExceeded ── 処理がタイムアウトした
     Unknown ── 不明なエラー
     Internal ── 内部エラーが発生した
   個々のエンドポイントに書くべきそのほかのエラー
     AlreadyExists ── リソースがすでに存在する
     ResourceExhaused ── サービス側のリソースの枯渇
     Aborted ── 処理が中断された
   書く必要がないエラー
     Unavailable ── サービスが動作していない
     DataLoss ── データが失われた
     Unimplemented ── まだ実装されていない
 リストオプションの説明
 まとめ

第3章 API仕様ファースト開発
 開発順序
   API仕様の記述
   E2Eテストフレームワークの検討と実装
   テストコードの作成と機能の実装
   リファクタリングとカバレッジの確認
   Pull Requestのレビュー
 不具合の修正順序
   再現テストの作成と実装の修正
   リファクタリングとカバレッジの確認
 既存のエンドポイントの修正と新たなエンドポイントの追加
 まとめ

第4章 E2Eテストフレームワークの構築
 テストフレームワークの基本的な考え方
 マイクロサービス構成でのテストフレームワーク
   書きたいテスト
     レスポンスの確認
     依存サービスを正しく呼び出しているかの確認
   E2Eテストフレームワークのプロセス
     E2Eテストのプロセス間シーケンス
   依存サービスが外部サービスの場合の解決方法
   エラーのテストは簡単
     DeadlineExceededとCanceled
     Aborted
 非マイクロサービス構成でのテストフレームワーク
 E2Eテストフレームワークの骨格
   Test Suiteプロセスの骨格
   テスト対象マイクロサービスの骨格
   フェイクマイクロサービスの骨格
   テストコードの骨格
   そのほかの考慮項目
 まとめ

第5章 API仕様の技術的負債の返済
 技術的負債とは
 API仕様の負債の返済
   既存のエンドポイントを修正するケース
     ステップ1:既存のAPI仕様の更新(見なおし)
     ステップ2:既存のAPI仕様のテストコード作成と実行
     ステップ3:新たな修正のためのAPI仕様の再修正
     ステップ4:新たな修正に対するテストコードの作成
     ステップ5:新たな修正の実装
     ステップ6:リファクタリングとカバレッジの確認
   新たなエンドポイントを追加するケース
   既存のエンドポイントの不具合を修正するケース
 返済順序のまとめ
 E2Eテストのもう一つの利点:リファクタリング
 特集のまとめ

コメント(0) 

実践API設計 [API仕様を書く]

WEB+DB PRESS Vol.134

WEB+DB PRESS Vol.134

  • 出版社/メーカー: 技術評論社
  • 発売日: 2023/04/22
  • メディア: Kindle版

4月に発売された「WEB+DB PRESS Vol.134」で特集1「実践API設計」を執筆していますが、そこから部分的に紹介します(目次は、こちらです)。

第1章「優れたAPI仕様とは何か --- よくある問題と記述すべき事柄」の冒頭で次のように述べています。
 今日、多くの企業がWeb サービスとしてさまざまなサービスを提供しています。Webサービスは、iOS、Android、ブラウザといったフロントエンドと、それらに対して機能を提供するバックエンドサービスから構成されます。バックエンドサービスが提供するさまざまな機能はAPI (Application Programming Interface)として定義され、フロントエンドから呼び出されます。フロントエンドは、バックエンドサービスが提供する機能を使ってユーザーへ提供する機能を実現します。
 定義されたAPI を介することで、フロントエンドとバックエンドサービスが、独立して、異なるプログラミング言語で開発できます。その結果、バックエンドサービスの開発チームは、定義されたAPI どおりにバックエンドサービスが正しく動作することを保証する責任を負います。つまり、API 定義に従って正しく動作することを、フロントエンドを接続することなく、自動テストで確認することが求められます。
 Web サービス開発の中で意外と難しいのが、バックエンドサービスのAPI を設計し、そのAPI 仕様を記述し、そしてテストファーストによるテスト駆動開発を行うことです。この特集では、それらが何を意味し、開発者にとって日々の活動で何をしなければならないかを解説します。

(太字で青にしている部分は、このブログで強調するためのものです)

長年、デジタル複合機を中心とした組込システムの開発に従事してきましたが、リコーを退職した後、2017年9月から、ウェブサービス(バックエンド)の開発に従事してきました。

当初から驚いたのが、バックエンドのサービスのAPIは定義するが、そのAPIで定義したエンドポイントを直接呼び出してサービスの機能を確認テストを書くことがほとんどないことです。つまり、さまざまなモジュールの単体テストはあるのですが、すべてを結合して一つの実行バイナリにして、APIで定義されたエンドポイントを外部から呼び出すテストコードがないことです。

この6年間で見られた問題点の多くは、「API仕様でよくある問題点」で次のように述べています。
 筆者はこれまで、Web サービス開発だけでなく、組込みシステムを含むさまざまなソフトウェア開発に従事してきました。それらの開発を通してAPI 仕様のさまざまな問題を目にしてきましたが、主なものとしては次の3つが挙げられます。
  • API仕様が書かれていない
  • エラーの記述がない
  • 自動テストが存在しない
 この結果、開発現場でよく起こるのは次のようなことです。
  • 正確な仕様は、実装コードを読まないとわからない
  • どのような場合にどのようなエラーが返ってくるかは、実装コードを読まないとわからない
  • 自動テストがないため、API がどのように振る舞うのかを簡単に知る方法がない
 これらの3つの問題をもう少し詳しく見ていきます。

記事では、これらの問題点をさらに詳しく説明しています。

ここでの問題点は、この6年間で働いてきたソラミツ、メルペイ、カウシェの3社で入社した当初に、私が目にしたバックエンドのサービス開発のほぼすべて(ただし、メルペイで私が最初に担当したマイクロサービスを除く)で目にしてきたものです。

その都度、この特集記事で述べたことを実践して改善していきました。改善は、単に私一人が行うものではなく、同じチームのメンバーが上記の問題を起こさないように開発を行ってくれるように、意識も行動も変わってくるようにするというものです。結果として、上記の問題を残さないようにする開発組織へと変わっています。

3社での経験から、おそらく多くの企業でこの問題は見られるのではないかと思っています。

関連記事:「伸ばすのが難しい能力

(2023年8月15日追記:下記は、『WEB+DB PRESS, Vol.134』のp.12より引用)

API仕様が書かれていない

 API 仕様が書かれていないというのは、次のような状況を指します。
Java などの言語で書かれている公開API を構成するクラスやメソッドに、標準のJavadoc形式があるにもかかわらず何も書かれていない。
 これを、通信方式としてGoogle が開発しているgRPCを使っているバックエンドサービスに当てはめてみます。gRPCでは.protoファイルにprotobufsと呼ばれるAPI の定義を記述しますが、そのファイルの内容が次のような状況になります。
単にサービスのエンドポイント(rpc)の定義やメッセージ構造体の定義が書かれているだけで、説明がほとんど書かれていない。

コメント(0) 

API仕様を書く(Mercari Engineering Blog編) [API仕様を書く]

API仕様を書く」と題して一連の記事を書きましたが、gRPCに関する内容を改めてMercari Engineering Blogとして書きました。



コメント(0) 

API仕様を書く(まとめ) [API仕様を書く]

「API仕様を書く」として私自身の過去の経験を書いたものを読みやすく並べてみました。
ちょうど同じような内容が『A Philosophy of Software Design』に書かれていました。

A Philosophy of Software Design

A Philosophy of Software Design

  • 作者: John Ousterhout
  • 出版社/メーカー: Yaknyam Press
  • 発売日: 2018/04/06
  • メディア: ペーパーバック

関連する章は、第12章「Why Write Comments? The Four Execuses」と第15章「Write The Comments First」です。第12章では、コメントを書かない理由として多くのソフトウェアエンジニアが挙げる理由について反証しています。第15章ではコメントを最初に書くことの有用性を説いています。ここでのコメントは、私が述べているAPI仕様に関する部分も含まれています。

翻訳はされないようなのですが、分かり易い英語で書かれていますので、ぜひ読まれることをお勧めします。

コメント(0) 

API仕様を書く(7) [API仕様を書く]

「API仕様を書く(6)ー gRPC protoファイル(2) ー」からの続き)

きちんとしたAPI仕様を書いていない場合、そのAPIのテストコードは当然のことながら、正常ケースだけだったり、不正なパラメータが渡されたときにどのように振る舞うかは実装のソースコードを見ないと分からなかったりします。さらに、「エラー翻訳」(「例外翻訳」)を行っていない実装は、いつのまにか返されるエラーが変わってしまっていることも起こり得ます。

おそらく多くの大学ではAPI仕様の書き方も含めてAPI設計の教育は行われていないと思います。そして、社会人となってから、個々のソフトウェアエンジニアがAPIの仕様をどの程度記述するかは、その人が属したソフトウェア開発組織の文化に影響を受けると思います。

私自身、gRPCを用いたソフトウェア開発では、前職のソラミツが初めてでした。そこでは、protoファイルには何も仕様が書かれていない理由は、それが大学の学生が作成したものだからだと思っていました。しかし、それは学生が書いたからではなく、そもそもAPI仕様を書くことを行ったことがない人達が書いたものだったからです。つまり、企業でソフトウェア開発をしているソフトウェアエンジニアであっても、仕様を書かない人が圧倒的に多いのではないかということです。

リコーに勤務していた頃は、さまざまなAPIをレビューしましたが、やはりきちんと書いてこないソフトウェアエンジニアが圧倒的に多かったです。その中でも、NDAを結んだサードパーティへ提供するAPIなのに、これはないだろうとう不完全なAPIが多くありました。

不備が多いAPI仕様は、不具合が多いAPI実装を生み出し、そして、サードパーティから問い合わせが多くなり、結果として長期的な開発コストを増加させます。これは、サードパーティへ提供するソフトウェアではなくても、会社内で閉じているソフトウェアでも、長期的な開発コストを増加させる結果となります。

マイケル・C・フェザーズの言葉を置き換えると次のようになるかと思います(「ネーミング」を「API仕様」と読み替えてます)(『レガシーコード改善ガイド』)。
API仕様は設計の中心である。優れたAPI仕様はシステムの理解を助け、作業を容易にする。しかし、貧弱なAPI仕様はシステムの理解を妨げ、後でシステムを扱うプログラマに辛い日々を送らせる。
(おわり)


コメント(0) 

API仕様を書く(6)ー gRPC protoファイル(2) ー [API仕様を書く]

(「API仕様を書く(5)ー gRPC protoファイル ー」からの続き)

gRPCから返すコードについては、Go言語用のこちらの定義が分かりやすいです。個々のコードは定義を読めば使い方は分かるかと思います。

API仕様には、gRPCで提供するサービスが提供する機能に応じて、どのような場合にどのコードが返されるかを書く必要があります。ただし、UnknownInternalに関しては注意が必要です。

Go言語のgRPC用のミドルウェアでは、statusパッケージ※1を使わずに生成したerrorを返すと、コードとしてUnknownが返されます。たとえば、DBへのアクセスして返されたerrorをそのままRPCのerrorとして返すと、コードはUnknownとなります。つまり、Unknownとは適切にコードが指定されなかったことを意味します。RPCが提供する機能に対する適切なコードを返すためには、「エラー翻訳」(Javaで言うところの「例外翻訳」)を行う必要があります。適切なエラー翻訳を行うためには、RPCが提供する機能に対して概念的に正しいコードを仕様に定義する必要があります。
※1 google.golang.org/grpc/status
※2 『Effective Java 第3版』の「項目 73 抽象概念に適した例外をスローする」

返すコードとしてのでInternalは、呼び出した側の問題ではなく、呼び出された側の何らかの不変式(invariant)が成立していないときに返します。言い換えると、設計上のバグと考えられるものはInternalを返すことになります。Java言語で言えばAssertionErrorが明示的にスローされるような場合です(『API設計の基礎』の「第3章 防御的プログラミング」)。

UnknownInternalは、どのRPCでも返される可能性があるので、個別のRPCの説明(前の記事の③)に書く必要はなく、サービス全体の説明(前の記事の①)に書けばよいと思います。どちらも、「呼び出し側の問題ではなく、呼び出された側の実装の問題なので、開発者への報告を求める」の旨が書かれていればよいかと思います。

続き

コメント(0) 

API仕様を書く(5)ー gRPC protoファイル ー [API仕様を書く]

(「API仕様を書く(4)」からの続き)

RPCの実装も通常のライブラリを作成するように「防御的プログラミング」を必要とします。すなわち、以下の状態に正しく対処する必要があります
  • パラメータ値不正
  • 呼び出し順序不正
  • 設計ロジックの誤り
最初の二つは呼び出した側の誤りのですので、そのような不正呼び出しに対して、どのようなエラーを返すかを記述する必要があります。三つ目は設計ロジックの誤りです(これらの三つの詳細な説明については、『API設計の基礎』の「第3章 防御的プログラミング」を参照してください)。

gRPCのprotoファイルの例として、https://grpc.io/docs/guides/ には次のようなサンプルが掲載されています。
// The greeter service definition. ①
service Greeter {
  // Sends a greeting ②
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name. ③
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings ④
message HelloReply {
  string message = 1;
}
番号(①、②、③、④)は私が説明用につけたものです。

①には、定義するサービスの説明を書く必要があります。この例では、RPCが一つしかないですが、通常は複数のRPC定義が書かれますので、サービスが提供する機能の概要を書く必要があります。サービスによっては、数行ではなく、10行以上の説明になることもあるかと思います。

②には、簡単にRPCの説明が書いてあれば十分かと思います。なぜなら、RPCの細かな振る舞いやリクエスパラメータにおける事前条件を説明しようとすると、パラメータである構造体やレスポンスである構造体のフィールドが同じ箇所に書かれていないので、②に書くには不適切かと思います。実際、私が仕事で書いているマイクロサービスにはRPCの定義が30個以上あります。

③は、RPCに対応したリクエストパラメータの構造体定義ですので、そのRPCの振る舞いを書くのはこの部分が適切かと思います。さらに、以下のことも書き加える必要があります。
  • リクエストの構造体の各フィールドに許される値
  • 許されない値が設定されていた場合に返されるエラー
たとえば、Hellonameフィールドが空を許さないのであれば、空が指定されたらどのようなコードが返されるかと記載する必要があります。

不正なパラメータの場合、単純にリクエストのフィールドの値が仕様で要求される形式や値を満たさないのであれば、InvalidArgumentでよいかと思います。そうではなくて、たとえば指定されたデータがデータベースに無いのであれば、NotFoundかもしれません。

gRPCには成功のOKを含めて標準のコードが17個定義されています(Go言語用の定義はこちら)。どのような場合に、どのようなエラーコードを返すかは、きちんと設計し、かつ、API仕様に明確に記述しなければなりません。つまり、③の部分に明確に記述する必要があるということです。

上記の例では、実際には何も書かれていません。nameが空でもよいのか、空を許すとしたらそれは何を意味することになるのか、空を許さないとしたら空の場合どのエラーコードが返されるのか、呼び出すのに認証は必要ないのかとかです。

④のレスポンスについては、理解するために必要な説明を書く必要があります。自明の場合には、何も書かなくてもよいかもしれません。

続き

コメント(0) 

API仕様を書く(4) [API仕様を書く]

(「API仕様を書く(3)」からの続き)

2017年8月末でリコーを退職して、ソラミツ社で働き始めました。技術的にはgRPCを使ったサーバー側の開発に加わることになりました。

gPRCに触れたのはその時が初めてですが、RPC(Remote Procedure Call)そのものは、Xerox社のCourierとよばれるRPCに1984年から接していましたし、後にSunのRPCを使ったツール開発(MessagingToolと分散コンパイルツール)も行っています。Courierは、XNS(Xerox Network Systems)の各種サーバーのプロトコルを記述するのにも使われており、プロトコル仕様はかなり丁寧に書かれていたと記憶しています。

gRPCは、RPCの定義を.protoファイルに書いてprotocでコンパイルしてスタブを生成します。RPCはその名前が示す通り、Procedure Callであり、Procedureを定義する訳です。呼び出しのパラメータ、呼び出し結果のレスポンスなどをstructとして定義します。また、エラーを通知するためにステータスコードを返すことができるようになっています。ステータスコードは、Javaに例えるとメソッドがスローする例外に相当します。

開発されていたサーバーのgRPCの定義である.protoファイルの中を見ると、何も書かれていませんでした。Javaで例えると、「公開APIのクラスやインタフェースの定義が書かれている.javaファイルに一切Javadocが書かれていない」という状態でした。

『Effective Java 第2版』を読まれたことがあるエンジニアであれば、そのようなクラスやインタフェースは公開APIとしては不適切であることは認識できると思います。『Effective Java 第2版』で該当する項目と章は以下の通りです。
  • 項目44 すべての公開API 要素に対してドキュメントコメントを書く
  • 第9章 例外
もちろん、『Effective Java』はJavaに関する内容なので、.protoファイルでは、そのエッセンスだけを適用して読み替える必要があります。簡単にまとめると、以下のことをAPI仕様として書く必要があります。
  1. 各PRCの説明
  2. 各PRCのリクエストパラメータとレスポンスパラメータの説明
  3. リクエストパラメータの制約(事前条件)とそれに違反したときに返されるステータスコードの説明
  4. RPC呼び出しの制約(事前条件)とそれに違反したときに返されるステータスコードの説明
  5. RPCを実行したときに起きる可能性のあるエラーとそれに対して返されるステータスコードの説明
何も書かれていなかったので、サーバー側のシステムを理解することを目的として、私自身ですべての仕様を.protoファイルの中にコメントとして書きました。仕様を書きながら、不備も多く見つけましたし、gRPCを直接呼び出してテストするコードを書いて、必要あればサーバー側のコードを修正したりもしました。

上記の1.から5.までについては、次回もう少し詳しく書きたいと思います。

続き

コメント(0) 

API仕様を書く(3) [API仕様を書く]

(「API仕様を書く(2)」からの続き)

私自身が開発のグループリーダーであった1701Gが組織として存在していた2013年7月から2015年5月までの期間を除けば、リコーでの8年間は、自分で何かを設計することは非常に少なく、誰かが設計したものをレビューすることが圧倒的に多かったです(残念ながら1701Gのときも、私自身はレビューやデバッグをすることはあっても、自分で設計や実装まで行うことは少なかったです)。

2009年9月にリコーで働き始めたのですが、当時はある大規模なソフトウェア開発がJavaで行われていました。しかし、ソフトウェア開発経験が浅いソフトウェアエンジニアが大量に投入されていて、誰も『プログラミング言語Java 第4版』も『Effective Java 第2版』を読んだことがない状況でした。それに加えて、マルチスレッドプログラミングが行われており、私がレビューしたほとんどのコードは間違っていました(「マルチスレッドプログラミングにおける重要な4要件」)。それで、やはりきちんと学習させる必要があるということで、リコーでもJava研修を始めることにしました。

1701Gの期間を除けば、様々なソフトウェア開発組織の新規APIのレビューやコードをのレビューを行っていたのですが、振り返ってみると、やはりAPI仕様を書くことは、多くの開発者が不得意としていたという印象があります。特に、NDAを結んで外部のサードベンダーに公開するSDKのAPIに関しては、使う側のことを考慮したAPIに出会うことは少なく、様々な修正を指導していました。

今から言えることは、きちんとしたAPI仕様を書かせるには、「場」である開発の現場で指導し続けなければならないということです。そして、「指導し続ける」には、以下の条件が揃っている必要があると思います。
  1. 指導対象者のエンジニアより、開発組織内で高い地位にあること
  2. 自分の部下を育成するという意味で指導を根気よく続けられること
同じ年代のエンジニアに何かを注意したり指導したりするのは、なかなか難しいです。さらに、別の組織やグループのエンジニアに対して指導するのはさらに難しいです。そのため、やはり1.が重要だということです。講演で、「どのようにして指導してきたのですか」と聞かれることがあるのですが、「開発部長としての立場で強制的に指導していました」と答えることが多いです。それは、API仕様を書くことだけでなく、テストファーストで開発することや、不具合が発生したら再現テストを最初に書かせるといったさまざまなソフトウェア開発の側面での指導が含まれます。

リコーでの最後の2年は、1.の条件は成立していなかったのですが、私のレビューを積極的に受けていたのは、その多くが私のJava研修の修了生達でした。

続き

コメント(0) 

API仕様を書く(2) [API仕様を書く]

(「API仕様を書く(1)」からの続き)

2003年からリコーに転職する2009年まで従事したデジタル複合機のコントローラソフトウェア開発プロジェクト(ピーク時は約100名のソフトウェアエンジニアが従事)では、私が提唱したある方式に基づいて完全なテスト駆動開発を行っていました。そのソフトウェア開発もレイヤ構成のソフトウェアであり、多くはプロセスとして実装され、プロセス間通信をCORBAで行っていました。

今日で言えば、マイクロサービス化してサービス間で通信してシステムを実現しているようなものです。各プロセスは下位層のハードウェアからのイベントと上位層のUIからユーザ指示のイベントの両方を処理する必要があるため、個々のプロセス内ではマルチスレッドプログラミングが行われているというものでした。品質を担保するために、当時としては複写機業界ではトップクラスのテスト駆動開発を行っていました(「マルチスレッドプログラミングにおける重要な4要件」)。

各サービス(プロセス)が提供するAPI仕様は、プロジェクト全体でかなりきちんと書かれていました。このプロジェクトでは、私も中核となる最も複雑な処理を行うサービスを担当して、API仕様を書いて、実装して、テストを書いて、そしてマルチスレッドのデッドロックやrace conditionをひたすらデバッグしていました(さらに付け加えると、開発部門の部長もしていました)。

このプロジェクトでは、API仕様を書く書かないの選択肢は個々のサービス担当者に委ねられることはなく、プロジェクト全体で書くことが強制されてたような気がします(あるいは、ある程度私が強制させていたのかもしれませんが、もうあまり覚えていません)。

振り返ってみると、1984年から2009年までその多くを富士ゼロックスグループで過ごし
、自分自身も多くのAPI仕様を書いてきたので、自分が担当するモジュール、ライブラリ、サービスのAPI仕様を、「利用者の視点を意識して」書いてから実装を行うことが、ソフトウェアエンジニアとして当たり前だと思っていました。そして、一緒に仕事をした多くのソフトウェアエンジニアが同じだったと思います。

2009年8月に富士ゼロックス情報システムを退職して、リコーに転職したのですが、そこは同じ複写機業界でありながら、ソフトウェア開発に関しては全く違う世界がありました。

続き

コメント(0) 
前の10件 | - API仕様を書く ブログトップ