モチベーション
最近業務で、社内の他のチームに提供するAPIを開発している。
関わっている人が少なければ、みんなで近くに座って都度仕様について相談していけばいい。(感覚的には〜7人くらい?)
しかし、会社全体の人数が多く、関わるチームも複数いるため(サービスのモバイルアプリ担当、Webフロント担当、バックエンド担当…など)包括的で都度更新されるドキュメントがないと開発効率が悪い。
とはいえ、API提供チームとしては、実装になるべく多くの時間を使いたい。具体的には以下の条件を満たす手法があればよい:
- ドキュメント作成にかける時間を短くできる
- 作成したドキュメントの内容が正確(最新であることが必須)
一番原始的な手法として、ドキュメントをちまちま人手で書いていく…というものがある。 ただ、それでは自チームのリソースを割いてしまうことと人為的なドキュメンテーションミスもあるだろうことから、開発中のプロジェクトでは、APIサーバのソースコードからswagger-uiを自動生成したものを簡易ドキュメントとして用意していた。 しかし、以下のような不満点もあった。
- アプリケーションにイレギュラーな改良を加えると、ドキュメントの自動生成ができなくなる
- 自動生成したい場合は自分でドキュメント生成ソフトウェアの改良をする必要がある
- リクエストとレスポンスの対応を完全に自動生成できるわけではなく、ちょっとしたドキュメントの追加ができない
そんな折、雑談中に @yosuke_furukawa さんから Documentation Driven Contracts という手法を教えてもらった。
DDCとは何か
DDCの前提として: Consumer Driven Contracts
Documentation Driven Contracsts
Pactのサイトに記載されている説明によると、Documentation Driven Contractsとは以下のようにして設計・実装をする手法であるとのこと。
- ドキュメントを作成する
- Documentationのフォーマットに従ってContractsを書く
- Providerの検証をする
- consumerからproviderへのsample requestを作成する
- ProviderをStubして、Consumerの実装をする
- consumerへのstub responseを作成する
1. ドキュメントを作成する
APIドキュメントを作成する。
APIドキュメントフォーマット仕様として、API Blueprintというものがある。
API BlueprintではMSONというMarkdownっぽいフォーマットを利用している。 ぱっと見たところ、Markdownを使っていたらそんなに違和感はなさそう?
仕様は以下:
API Blueprint Specification | API Blueprint
これで最初にAPIの説明、エンドポイント、メソッド、リクエストとレスポンスについてドキュメントを書いてしまう。
ドキュメントのレンダリング
API Blueprintのレンダリングツールもあった。 これでMSONからHTMLのドキュメントを生成することができる。
https://apiblueprint.org/tools.html#renderers
こんなAPIドキュメントのHTMLを生成することができる模様。
![plugin](/images/content/blog-ja/2017/05/apispec.png)SS from: snowboard
2. Providerの検証をする
API blueprintでドキュメントを書いたら、その仕様にもとづくテストを実行する。
dreddというツールは、API blueprintのspec fileからリクエストを自動生成してレスポンスを検証してくれるとのこと。
3. ProviderをStubして、Consumerの実装をする
[API blueprint](https://apiblueprint.org/tools.html#mock servers)に対応するmock server toolはいくつか開発されている。
drakovでは以下のようにコマンドラインからAPI blueprintのspec fileをもとにサーバを起動することができる。
drakov -f "../com/foo/contracts/*.md"
Consumer(APIクライアント)開発者は、このモックサーバをもとに開発を進めることができる。
DDCによるメリットとデメリット
メリット
Providerの実装前にConsumerも開発を進めることができる
Providerが先にドキュメントさえ書いておけば、Providerの実装を待たずにConsumerもstub serverを使ってクライアントの実装を進めることができる。
理想だけを言えば、Providerでの実装が完了してからConsumerの実装をするのがよいだろう。 しかし、実際にはスケジュールその他の制約のため、ある程度並行して作業を進めなければいけない場面もあると思う。
実際に、私の業務ではProvider(APIサーバ開発者)はAPI実装前にリクエスト・レスポンスのサンプルをSlackに貼り付けて「こんな感じでどうですか?」とか書きながらConsumer(クライアント開発者)と並行して実装を進めている場面があった。 なので、この手法はわりと現場でも受け入れやすい気がしている。
ドキュメント作成と同時に実際のinout/outputのサンプルを作成できる
APIサーバを開発する側の設計の進め方として、以下のようなやり方が考えられる。
- APIサーバで実現することを考える
- リクエスト/レスポンス例を考える
- 他の開発者からFBをもらう
- FB後、実装開始
API blueprintで仕様を書くと、上記の1~3にあたる部分がカバーできる。
ドキュメントに従った検証が簡単にできる
さらには、API blueprintに対応しているテストツールを使えば自分で書いたドキュメントにAPIサーバが追従できているかどうかのテストも簡単にできる。
ドキュメントを書いてさらにテストを書く、という2度手間にならなくてよい。
デメリット
Contractsを過信しそう
Cosnumerがstub serverで開発を進めた場合はstubを過信することについて注意が必要だと思う。 人的リソースに余裕がない場合、ドキュメントですべてのリクエスト・レスポンスのパターンを記載できないのではないだろうか。
例えば正常系については最低限記載できても、すべての異常系を網羅できるかはドキュメント作成者のシステム理解度に依っているかもしれない。
品質を重視するプロジェクトであれば、Providerの検証・Stubを使った実装に加え、本物のサービス同士を結合した結合テストをしなければいけない。
ドキュメンテーションコストはそれなりにある
DDCはドキュメンテーションを前提にしている。 このドキュメンテーションは当然開発者が書くので、そのコストはしょうがない。
環境整備コスト
Privider validationまでやるのであれば、以下の準備が必要。
- Provider validation toolの導入
- ローカルマシンで実行するだけなら事前に書いたAPI blueprintのspec fileを用意するだけ
- CI環境設定
- リクエストの向け先をどうするか、データ注入どうするか、とかを検討する必要がある
- Provider validationをテストのステップに組み込む
所感
コストはかかるものの、やってみる価値はあると思った。
コストを考慮して以下のような入れ方が考えられるが、
- 梅: swagger-uiで簡易ドキュメントだけ用意する
- 竹: swagger-ui + 手書きドキュメント
- 松: API blueprint
- Privider validation + HTML rendering まで
- 松プラス: API blueprint
- Privider validation + HTML rendering + stub server for cusumer
梅はさすがに雑すぎてあんまりConsumer的には嬉しくない、竹は中途半端なので、がっつり依存してる結合テストツールがないのであれば松までいけるといいのかなと思う。
まだプロジェクトに実投入できるかわからないけど、実投入したらレポートを書きます。