アプリケーションとアプリケーションを連携させる
概要
この記事は、現場で役立つシステム設計の原則〜変更を楽で安全にするオブジェクト指向の実践技法を読み学習した内容を Ruby on Rails のコードに例を変換してまとめ直したものです。
また、書籍では Java のコードを例にしており、Ruby on Rails の慣習とは一部異なる部分があるので、その部分はオミットした内容となっています。
この記事では、業務アプリケーションにおける決済システムや認証システムなどの他の外部アプリケーションとの連携方法とその設計について記述しています。
アプリケーションとアプリケーションを繋ぐ
業務アプリケーションにおいては、「消費者が使うスマートフォンアプリと連動した販売管理システムを実現できるか」、といった社内や社外のアプリケーションといかにスムーズに連携できるかが重要な課題となる。
アプリケーションを連携する四つのやり方
アプリケーション間の連携は、基本的にはデータのやりとりであり、以下の四つの方式がある。
-
ファイル転送
- ファイルを使ってデータを受け渡す
- メリット
- 主要な設計課題はファイル形式。これが決まればファイル作成・取り込み処理は比較的単純に実現できる
- 問題点
- ファイル形式を変更する場合の影響が大きい(変更しづらい)
- 一定量のデータを蓄積してから転送するため、データの発生と実際の処理との時間差が生まれやすい
-
データベース共有
- 共通のデータベースを使ってデータを共有する
- メリット
- データの受け渡しが即時に可能
- 問題点
- セキュリティの観点から好ましくないことが多い
- 共有するテーブルを通じてプログラムが密結合になりやすい(変更がしづらい)
-
Web API
- HTTP を使ってリクエスト/レスポンス形式でデータをやり取りする
- メリット
- 必要な時に必要な内容だけをやりとりできる
- HTTP 通信を使うので、広い範囲のシステムと連携ができる
- 問題点
- 設計の自由度が高いため、適切な設計判断が難しい
- 一度決めた API を変更することが難しくなりやすい
- 「リクエストを送ってレスポンスを待つ」という同期型の処理方式が、運用面と性能面の制約になることがある
-
メッセージング
- メッセージ基盤を使って非同期にデータ(メッセージ)を送る
- メリット
- 送る側も受け取る側も任意のタイミングで処理できる(非同期)
- 非同期メッセージングによって、アプリケーション間の独立性が高く疎結合になる
- 並行に処理することで大量の処理を捌くことが可能
- 問題点
- 従来の同期型の処理とは異なる設計と運用のノウハウが必要
- 安定したメッセージング基盤の構築と運用が必要
この中で特に Web API についてはさらに以下のようなメタ的な特徴がある。
- アプリケーションの連携方式として採用されることが多い
- Web API の設計の良し悪しがソフトウェアの変更容易性に大きく影響する
これらの理由により、以下では Web API を使ったアプリケーションの連携について詳しく述べる。
Web API の仕組みを理解する
HTTP 通信を使ったアプリケーション間の連携の基本の約束事
Web API を使ってアプリケーション間で行う処理は基本的に次の二つ。
- あるアプリケーションが別のアプリケーションからデータを取得する
- あるアプリケーションが別のアプリケーションにデータを登録する
どちらの場合においても、 Web API を利用する側(クライアント)が要求(リクエスト)を送り、 Web API を提供する側(サーバー)が応答(レスポンス)を返すという形式となる。
Web API でアプリケーション間をスムーズに連携するには、この要求と応答の間に約束事が必要となる。
HTTP 通信で連携する場合の基本の約束事は次の四つ。
- 要求の対象を指定する(URI)
- 要求の種類を指定する(HTTP メソッド)
- 処理の結果を伝える(HTTP ステータスコード)
- 応答内容の表現形式(JSON や XML)
以下でそれぞれの約束事について詳しく述べていく。
要求の対象を指定する(URI)
Web API はデータのやり取りの手段であり、その対象となるデータを指定するための約束事が URI である。
また、この対象となるデータを リソース と呼ぶ。
リソースは、静的な固定データの場合もあれば、要求時に動的に生成する場合もあるが、 Web API を利用する側はその違いを意識する必要はなく、適切な URI を指定するだけで良い。
以下はユーザーに関するデータを取得する場合の例。
| 形式 | スキーム://ホスト名/リソースへのパス |
|---|---|
| 例 | https://api.example.com/users/1234 |
| 意味 | HTTPS を使ってホスト api.example.com が持つ識別番号 1234 番目のユーザのデータ |
要求の種類を指定する(HTTP メソッド)
URI で指定したリソースに対して、どのような処理を行うかを指定するための約束事が HTTP メソッド である。
基本的な HTTP メソッドは以下の四種類である。
| HTTP メソッド | 説明 | 成功時の HTTP ステータスコード |
|---|---|---|
| GET | データを取得する | 200 OK |
| POST | データを作成する | 201 Created |
| PUT | データを更新する | 200 OK または 201 Created または 204 No Content |
| DELETE | データを削除する | 200 OK または 202 Accepted または 204 No Content |
データを取得する GET
連携先にアプリケーションからデータを取得する方法が GET である。
https://api.example.com/books/1234
{
"id": 1234,
"title": "本のタイトル",
"author": "著者名",
"description": "概要の説明"
}
書籍の一覧を取得する場合は以下のように ID を指定せずに取得する。
http://api.example.com/books
また、GET メソッドでは、問い合わせの条件を URI の一部に含めることで対象を絞り込むことができる。
以下のように取得でき、books の次の「?」以降の部分を クエリパラメータ と呼ぶ。
下記の例のように、複数のパラメータを指定する場合は「&」で区切る。
http://api.example.com/books?category="ソフトウェア設計"&within="1年"
Web API を設計する際の課題の一つが、このクエリパラメータの設計となる。
- 対象のリソースを一意に指定する ID や、リソースのグループを指定するカテゴリ名はクエリパラメータよりも URI のパスで表現すべき
- 省略できない必須の条件は URI のパスで表現すべき
- あくまでオプショナルな絞り込み条件をクエリパラメータで表現すべき
データを登録する POST と PUT
相手のアプリケーションにデータの登録をする際には、POST と PUT の二つの方法がある。
| メソッド | 対象の指定方法 | 説明 |
|---|---|---|
| POST | books | 書籍データを登録し、ID を発行してもらう |
| PUT | books/1234 | ID が 1234 の書籍データを更新する |
POST が依頼される側が ID を発行するのに対して、PUT は登録を要求する側が ID を指定する。
この時、PUT では登録を要求する側のアプリケーションが、依頼される側のアプリケーションのリソースの識別体系を事前に知っている必要がある。
また、PUT は返すべき応答内容の規定もないので、応答内容をどうするかの決め事も必要となる。
つまり、PUT は POST よりもアプリケーション同士が密結合になりやすい。
このため、データの登録はできるだけ POST で行うとアプリケーションの独立性が高まり修正・拡張が容易となる。
更新の依頼も POST で行う
更新は、以下のような方法で POST でも実現できる。
https://api.example.com/books/1234/updates
この時、book/1234を実際に上書き更新するか、book/1234以下に新しい書籍データを履歴として追加するかといった更新内容は、 Web API を提供する側のアプリケーションに任せることで、アプリケーション間の独立性を高めることができる。
そして、リクエスト後に存在を確認したい場合は、book/1234の内容を GET で取得する。
データの登録と相手の状態を同時に扱う PUT よりも、POST による登録と GET による状態の取得を組み合わせることが、アプリケーション間の依存度を下げる好ましい設計と言える。
データを削除する DELETE
相手のアプリケーション上のリソースを削除する方法として、DELETE メソッドがある。
| メソッド | 対象 | 説明 |
|---|---|---|
| DELETE | books/1234 | ID が 1234 の書籍データを削除する |
| DELETE | books | 全ての書籍データを削除する |
DELETE も PUT と同様に以下のような決め事を必要とし、アプリケーション間の依存度を高める要因となる。
- 削除の実際のタイミング
- 削除の妥当性のルール
- 削除がうまくいかなった場合の挙動
アプリケーション間の依存度を下げるために以下のように POST メソッドで削除を依頼する方法もある。
https://api.example.com/books/1234/deletions
この形式だと、削除をどう実行するかの判断や、どのようにデータの削除を実現するかは依頼を受け取った側のアプリケーションに任せることができる。
エラー時の約束事
アプリケーション間の連携でうまくいかなかった場合の HTTP ステータスコードとレスポンスの内容は以下の通りとなる。
| コード | テキスト表現 | 説明 |
|---|---|---|
| 400 | Bad Request | 要求が不正 |
| 403 | Forbidden | 要求が禁止されている |
| 404 | Not Found | 要求されたリソースが見つからない |
| 500 | Internal Server Error | サーバー内部でエラーが発生した |
- 400 番台のエラーは API を利用する側に問題がある
- 500 番台のエラーは API を提供する側に問題がある
- アプリケーション内部のエラーであるので、そのエラー内容を詳細に返すべきではない
// GET books/1234
// ステータスコード 404 Not Found
{
"error": "書籍番号 1234 に該当する情報はありません",
}
// ステータスコード 500 Internal Server Error
{
"error": "書籍番号 1234の処理を正しく完了できませんでした",
}
また、API を利用する側・提供する側でそれぞれどのようなエラーメッセージを出力すべきかについての考え方は以下の通り。
- API を利用する側
- API を利用する側がエラーにどう対応するかを判断する手がかりを提供する
- API を提供する側の内部の詳細な情報は不要
- API を提供する側
- エラー原因を調査するために API 内部のより詳細な情報が必要
良い Web API とは何か
使いにくい Web API の特徴
以下のような特徴を持つ肥大化した API を「 One Size Fit All 」(「大は小を兼ねる」)API と呼ぶことがある。
- データを取得するために指定するパラメータが多い
- 取得したデータの項目数が多い
- 登録時に指定しなければいけないパラメータが多い
ありとあらゆるデータ項目を返せば、どのような場合でも必要なデータが含まれるので一見問題ないように思えるが、実際には以下のように利用側・提供側双方にデメリットがある。
- API を利用する側
- 単純なデータ取得においてもそれに関係のないパラメータまで理解する必要がある
- 特定のデータを取得するために、受け取ったデータ項目から必要なデータ項目だけを取り出す処理が必要
- 複雑なパラメータの場合は、利用時の約束事を理解して使用しないと障害が発生しやすい
- API を提供する側
- パラメータを増やせば増やすほど、API を提供するプログラムに if 文が増える
- 複雑なパラメータ内容をチェックするロジックによって、プログラムが乱雑になり変更・拡張が難しくなる
つまり、大は小を兼ねる API のように、汎用的な API は、一つの API でなんでもできるように見えて実際には個々の利用シーンでは使いにくい。
アプリケーションを組み立てるための部品を提供する
Web API という単語は以下の二通りの意味で使われている。
- 利用する側でアプリケーションを組み立てるための部品のセット(本来の API の意味)
- 利用する側でプログラミングせずに利用できる完成品(API というよりは Web サービス)
ここでは前者のプログラミング部品としての適切な API 設計について考える。
まず、良い API は、様々なアプリケーションを組み立てるために役に立つことが重要である。
つまり、組み立てやすく、変更しやすい、適度な大きさに分割した部品である。
以下は、API の粒度と実現できる機能の多様性・組み立ての複雑さの関係を表した表である。
| API の粒度 | 実現できる機能の多様性 | 組み立ての複雑さ |
|---|---|---|
| 小さい | 幅広い | 複雑 |
| 大きい | 限定的 | 単純 |
良い API 設計とは、組み立ての多様性を維持しつつ、組み立ての負担が増えすぎない適切な大きさの部品を用意することである。
発展性に富んだ API 開発のやり方
単純なことを簡単にできる API の提供から始める
柔軟性に富み、かつ、組み立てが簡単な API を最初から実装することは難しい。
なので、最初の一歩としては、簡単な用途を簡単に実現できる API を開発することから始める。
そして、実際にアプリケーションを組み立ててみながら、API の修正や拡張を行なっていく。
// リクエスト
GET members/1234
// レスポンス
{
"name": "山田太郎",
"email": "taro.yamada@example.com"
}
動かしながら設計を発展させていく
簡単な API であれば、フレームワークを利用して短時間で実装できるので、API を利用する側に実際に使ってもらい、ニーズを満たしているかをすぐに検証できる。
API を開発する際に詳細な仕様ドキュメントを作成する手法は時間がかかるし、作り始めてから仕様・考慮漏れが発生することもある。
初期の検証段階から、API を実際に作って利用する側に試してもらい、フィードバックをもとに API を修正・拡張していくことで、良い API を早く確実に作り上げることができる。
API を利用する側と API を提供する側の共同作業の環境を整える
早い段階から動く API を提供して、実際に動かしながら発展させていくためには、それらを支援する以下のようなツールを利用することが有効。
-
Web API 開発用のフレームワークやライブラリ
- 素早く簡単に API を開発できる
- Ruby on Rails, Spring MVC など
-
API ドキュメントやテスト画面を自動生成するツール
- ソースコードから API 仕様書とテスト環境を自動生成
- Swagger UI など
-
開発チーム間のコミュニケーションツール
- 開発チーム間で疑問点を解消したり、改善要望をフィードバック
- チャットサービスなど
API を提供するコントローラクラスのソースコードを解析して、自動的に API ドキュメントと、会話的にテストができる画面を生成するツール。
生成する API 仕様とテスト環境は以下の通り。
- エンドポイントの URL の仕様
- 出力ファイル(JSON)の形式
- パラメータの仕様
- curl で実行する場合のコマンドライン
- パラメータを画面から入力して API を実行し応答内容を表示できるフォーム
これにより、API を利用する側へ最新のソースコードがそのまま反映された、最新のテスト環境と仕様書を、 API を提供する側の労力なしに提供できる。
これらのツールを活用することで以下のサイクルを短い間隔で何回も繰り返すことが簡単にできる。
- API 原案の提示と意見交換
- 合意した API の開発
- テスト環境とドキュメントの自動生成
- フィードバック
- フィードバックをもとにした改良
- 改良結果の確認
中核となる API のセットを設計する
上記の開発サイクルは、小さな部品を用意するという API の設計方針とも一致する。
大きな API は、仕様の検討も実装も検証も時間がかかるが、用途が明確で小さな API はそれらが全て容易である。
用途が明確で小さな API の設計原則は以下の通り。
- 登録と参照を分ける
- リソース(データの塊)の単位を分ける
登録と参照を分ける
例えば、指定席を予約する API で、予約が POST された時のレスポンスの API 設計としては以下の二つの選択肢が考えられる。
- POST のレスポンスとして、予約内容の詳細を返す
- POST のレスポンスは予約番号だけを返し、予約内容はその予約番号で別途 GET する
アプリケーションを組み立てる部品としては後者のように登録の API と参照の API を分ける方が柔軟にアプリケーションを組み立てることができる。
| 目的 | API | 説明 |
|---|---|---|
| 予約の登録 | POST reservations | レスポンスとして予約番号 2345 を返す |
| 予約の参照 | GET reservations/2345 | 予約番号 2345 の予約内容を返す |
この形式にすると、予約結果の参照方法や応答内容に変更があっても、予約登録の API には影響を与えずに修正・拡張ができる。
参照と登録を別の API に分離するのは、関心事を分離し、プログラムの記述をわかりやすくシンプルにする設計の基本原則である。
リソース(データの塊)の単位を分ける
次のような会員情報の登録と参照を行う Web API を考える。
- 氏名
- 性別
- 生年月日
- 連絡先
- 住所
| 目的 | API | 説明 |
|---|---|---|
| 会員の登録 | POST members | 会員情報を渡してレスポンスとして会員番号 1234 を受け取る |
| 会員の参照 | GET members/1234 | 会員番号 1234 の会員情報を返す |
上記のような API 設計だと、氏名だけが必要な場合でも毎回、性別/生年月日/住所を取得することになる。
これに対して、用途別により小さな単位のデータを受け取る API を提供する方法がある。
用途別の小さな単位の API の例
| API | 説明 |
|---|---|
| GET members/1234/name | 会員番号 1234 の氏名を返す |
| GET members/1234/gender | 会員番号 1234 の性別を返す |
| GET members/1234/dateOfBirth | 会員番号 1234 の生年月日を返す |
| GET members/1234/address | 会員番号 1234 の住所を返す |
情報を変更する場合も、毎回全ての情報を更新するのは良い API ではない。その場合も変更が起きそうなリソースに限定した API を提供する。
対象のリソースを限定した API の例
| API | 説明 |
|---|---|
| PUT members/1234/contactMethods/telephone | 電話番号の変更 |
| PUT members/1234/address | 住所の変更 |
このように、対象とするリソースを必要な最小単位に分けることを重視して設計する。
API の修正や変更に時間がかかり、なかなか安定しない時は、より小さな単位に分割すべき明らかな兆候である。
Web API のバージョン管理
以下のように URI にバージョン番号を入れるという考え方がある。
http://api.example.com/v2/members
しかし、プログラミングの部品を提供することを重視する Web API では、全体のバージョン管理を行うことにあまり意味がない。
リソースを小さな単位に分ける API では、新たな小さな API の追加が中心であり、既存の API には何も影響がないため、API としてバージョン管理する意味がない。
古い API と新しい API が同時に存在する場合は、API 全体のバージョン管理ではなく、個別の古い API の廃止の予告と実施を緩やかに行なっていく。
古い API の廃止のフローの例
- 新しい API を追加しても、互換性のため古い API も提供する
- 古い API は残すが、「303 See Other」を返すように変更する(新しい API の情報を返す)
- 古い API のレスポンスとして「404 Not Found」を返すように変更する
- API 自体を削除する
API を複合したサービスの提供
アプリケーション間で連携する場合、API を提供する側が部品だけでなく、もっとまとまった機能をサービスとして提供することも考えられる。
この場合、API を提供する側は、二階層で構築する。
- 複合サービスを提供するレイヤ
- 基本 API を提供するレイヤ
しかし、複合サービスを開発する際に、API を提供する側に、API を利用する側の知識が入り込んでしまうとアプリケーション同士の結合度が密になり、お互いのアプリケーションの修正・拡張がしづらくなる。
アプリケーションの独立性を維持するためには、可能な限り複合サービスは、API を利用する側が開発すべきである。
API を提供する側は、利用する側のアプリケーションを組み立てるための部品の提供に専念するのが、アプリケーション間の独立性を保つ良い API 設計である。
ドメインオブジェクトと Web API
データ形式とドメインオブジェクトを変換する際に起こる不一致
ドメインモデルで設計した場合、Web API の主な役割はドメインオブジェクトと JSON などのテキスト表現との変換である。
-
GET: ドメインオブジェクト -> JSON -
POST: JSON(もしくはフォームパラメータ) -> ドメインオブジェクト
しかし、JSON とドメインオブジェクトの間に以下のような不一致があり、それが大きい時に不都合な場合がある。
- データ構造の不一致
- 関心事の不一致
データ構造の不一致
ドメインオブジェクトは、コードの重複を防ぐ目的で、ロジックの整理を軸にクラス分けして、情報のかたまりを構成する。
それに対して、API で使うデータ形式はデータだけが関心事であるため、できるだけ単純化された構造のほうが使いやすい。
つまり、データだけに注目すると、ロジックの整理を重視したドメインオブジェクトの階層構造を、そのまま階層的なデータ構造として、API で使うデータ形式として表現することはあまり意味がない。
関心事の不一致
ドメインオブジェクトの持つ全ての情報が、API を利用する側で必要であるとは限らない。
このような関心事のズレは、アプリケーションが異なる以上必ず発生するので、ドメインオブジェクトと JSON の単純なマッピングで対応できないケースでは以下のようにレスポンス用のオブジェクトへ変換する。
class BookSerializer < ActiveModel::Serializer
# 必要な項目だけを指定する
attributes :id, :name, :price, :published_at, :author, :book_type
# 単純なマッピングでは対応できないメソッド
attribute :book_comments do
object.book_comments.map do |book_comment|
{
id: book_comment.id,
comment: book_comment.comment
}
end
end
end
また、登録リクエスト時においても、ドメインオブジェクトが期待するデータ項目が全て POST されるとは限らない。
その場合は、以下のようなリクエスト用のオブジェクトへ変換し、必要な項目をデフォルト値や任意の生成ロジックで補う。
class BookRegistrationForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :name, :string
attribute :price, :integer
attribute :published_at, :date
attribute :author_id, :integer
validates :name, presence: true
validates :price, numericality: { greater_than: 0 }
# リクエストには含まれないが、ドメインオブジェクトが期待するデータ項目
def book_code
"BOOK-#{SecureRandom.hex(4)}-#{Time.current.strftime('%Y%m%d')}"
end
# JSONからモデルに変換
def to_domain
Book.new(
name: name,
price: price,
published_at: published_at,
author_id: author_id,
book_code: book_code
)
end
end
レスポンスオブジェクトやリクエストオブジェクトは、プレゼンテーション層のビューとして定義し、元のドメインオブジェクトはドメイン層で定義する。
(上記の Rails の例の場合、app/serializersやapp/formsのような専用のディレクトリに配置する)
また、全ての Web API でこのような変換を作り込む必要はなく、あくまでドメインオブジェクトと外部形式の不一致を吸収するための変換が必要な時のみ導入する。
導出結果と生データのどちらを返却するか
Web API の設計で、議論となるのは以下のようなケースを元データのままやり取りするか、加工や計算の結果をやりとりするのかということである。
- マスタ項目のコードと名称
- 合計の計算
- 日付データの形式
マスタ項目のコードと名称
マスタ項目とは業務システム・Web サービスで頻繁には変更されず、複数の機能・画面・システムで共通して使用されるデータ
例:
- 都道府県一覧
- 通貨一覧
- 国一覧
返却方法の選択肢としては以下の三つ。
- コードのみ
- あとでコードから名称を取得できるようにそれに対応した API を別途用意する
- マスタ情報を API を使って共有する場合は、この方法を選択する
- ただし、利用する側と提供する側の結合度が高くなるので基本的には避けたい
- 名称のみ
- 名称の重複の可能性があるので厳密さに難あり
- 返却情報が名称のみで十分であれば、わかりやすく良い選択肢(例: 都道府県名称)
- コードと名称の両方
- 名称の重複を考慮する場合の選択肢
- この場合はコードから名称を取得する API は必要ない
計算ロジックの置き場所
導出可能な計算ロジック(明細データの合計や誕生日からの年齢計算など)を Web API を提供する側に置くか、API を利用する側に置くかについては、そのロジックをどちらのアプリケーションが管理すべきかで判断する。
- API を提供する側が計算ロジックを管理する場合は、計算結果を返す API だけを提供する
- 業務ルールと呼べないような単純な計算であれば、利用する側がシンプルになるように API を提供する側で計算する
- 基礎データの変更があっても利用する側の影響は小さい
- 計算ルールが API を利用する側のアプリケーションに依存したロジックであれば、API は基礎データのみ返し、利用する側で計算する
- 基礎データの変更が利用する側のコードに大きく影響する
日付データの形式
以下のような日付データの形式(ISO 8601)は、ライブラリや実行環境において、この形式が実際にどのように解釈されるかばらつきがある。
特に、末尾のタイムゾーンが無視された変換が起きてしまう場合はある。
2016-10-16T14:30:15+09:00
人間にとっての通常の表現に合わせるために、日時の扱いはできるだけシンプルに、かつ、あいまい性がないようにする。
- 基本的には、日付と時刻は別の項目として扱う(日付だけならタイムゾーンは関係ない)
- 時刻は「+09:00」のような記述ではなく、「14:30:15」のように記述する。秒が不要であればさらに簡略化し、「14:30」のように記述する
- 時刻を現地時間として解釈するか標準時間として解釈するかは、API の約束事として決めておく
複数の API との複雑な連携
連携先のアプリケーションが複数となると、一つの連携先を立てると別の連携先が立たず、というように仕様をどこで合意するかの選択肢があいまいとなる。
このようなケースの場合に、Web API の設計をどうすべきかを以下で述べる。
共通部分と個別対応部分を明確にする
接続相手が複数の場合も、それぞれの API を利用する側の目的や都合を理解するところから始める。
そして、API の修正・拡張をやりやすくするために、API を次の三種類に分けて検討する。
- コアとなる基本 API
- どの利用者にも共通し、どの利用のニーズも満たすことができる API
- 関心事を小さな単位に分け、登録と参照を別の API にした、最小単位のセットとして提供する
- 拡張 API
- 利用者がより使いやすいようにコアの基本 API を組み合わせた複合 API
- どの利用者にも共通に使えるものだけを用意する
- 個別対応 API
- 特定の利用者のニーズを満たすための API の集合
- 複合 API が中心だが、場合によっては基本 API を特別に変更した API の提供も検討できる
個別対応を共通化し、API を進化させる
個別対応の API が増えてくると開発や運用の対応先が増えて大変になっていく。
対処法は以下の通り。
- API を基本/拡張/個別対応にグルーピング(前項で行った対応)
- それぞれのグループの間で API を移動
- 複数の利用者へ同じような個別対応 API を提供していることを見つけたら、共通利用のための拡張 API や基本 API に移動する
- 基本 API や拡張 API を特定の利用者だけが利用していることに気がついたら、個別対応 API に移動する
このように、共通性の高い部分、個別対応の部分を常に実情に合わせることを継続的に行うことで、Web API の一貫性を保ち、見通しの良い状態を維持できる。
また、個別のニーズに対応しつつ、他の利用者のニーズとも合致したら、共通 API に組み込んでいくという進化型の Web API は、環境の変化に対応して API の価値を高め続けることができる。
非同期メッセージングを使って複数アプリケーションを連携させる
連携するアプリケーションが増えてくると、アプリケーション間の接続関係も複雑になり、連携の改善や拡張がやりづらくなる。
このような場合は、Web API ではなく非同期メッセージングによる連携が有力な選択肢となる。
非同期メッセージングによる連携のメリットは以下の通り。
-
相手のアプリケーションの稼働状況から独立してメッセージを送ることができる
- 非同期メッセージングは、メッセージ基盤を仲介して通信するため、相手のアプリケーションと直接通信は発生しない
- 相手のアプリケーションが稼働していなかったり、大量データの処理に時間がかかっていても、無関係にメッセージを送ることができるので、Web API のようにエラーや処理待ちが発生しない
- 連携のテストもメッセージ基盤とのメッセージのやり取りのテストだけでよくなる
- 複数のアプリケーションが複雑に連動する場合でも、それぞれのアプリケーションは、メッセージング基盤との通信接続だけ意識して、独立して開発・テストを進めることができる
-
共通の中間加工をやりやすい
- アプリケーション間連携のためのデータ構造の変換やデータの表現形式の変換をそれぞれのアプリケーション上ではなく、メッセージング基盤上で行うことができる
- メッセージ内容から配送先を変更したり、特定の内容のみを配送する、などといったフィルタリングも可能
- 個々のアプリケーションは連携のための加工や判断処理から解放され、それぞれの処理内容に集中した単純な構造にできる
-
人間の仕事のやり方に合わせた処理を実現しやすい
- アプリケーション間でメッセージを送りあって非同期に連携する方法は、人間が電子メールを使って連絡しあう方法と同じであり、人間の仕事のやり方をそのままシステムの処理形態に反映しやすい
- 人間の関心事をそのままの単位でプログラミングの単位とするオブジェクト指向の考え方と同様に、人間の実際の仕事のやり方に合わせることで、システムの構造がわかりやすくなり、修正・拡張がやりやすくなる
参考文献
この記事は以下の情報を参考にして執筆しました。