Table of Contents
導入事例
マイクロサービスアーキテクチャは、スケーラブルで独立した、そして弾力性のあるソフトウェアシステムを構築するための優位なパターンになっています。しかし、モノリシックなアプリケーションから分散サービスへのシフトは、サービス間の密なカップリング、未クリア境界、およびテストとデプロイメントの難しさを取り入れる新しい複雑さをもたらします。SOLID原則を適用して、これらの課題を解決します。これらの5つのオブジェクト指向設計ガイドラインは、サービス境界とサービス間のコミュニケーションに適応し、そのサービスがより容易で、その利点を拡張し、各アプリケーションが実現する、具体的な目的を達成するために、各サービスが容易になります。
SOLID原則とは?
SOLIDは、保守可能で拡張可能なオブジェクト指向のコードを奨励する5つの設計原則を表すRobert C. Martin(Uncle Bob)によって導入された頭字語です。 マイクロサービスコンテキストでは、これらの原則は、それらの間で装飾、集中されたサービス、明確な契約に翻訳します。
単一責任原則(SRP)
クラスまたはモジュールは、一つだけ、変更する理由を持つ必要があります。マイクロサービスでは、これは各サービスが単一のビジネス機能またはサブドメインを所有するべきであることを意味します。例えば、注文管理サービスは、支払い処理や在庫追跡ではなく、ライフサイクルイベントを注文するだけを処理するべきです。これにより、変更のブラスト半径を減らし、サービス自体にデプロイ可能になります。
開封/閉塞式原則(OCP)
ソフトウェアのエンティティティティは、拡張機能が開いているが、修正のために閉じられるべきです。マイクロサービス、サービスは、既存のコードを変更することなく、新しい機能で拡張できる安定したインターフェイス(APIまたはイベント契約)を公開する必要があります。これは、バージョン化されたAPI、イベントスキーマの進化、またはプラグインアーキテクチャによって達成されることが多いです。
リスコフ置換原理(LSP)
サブクラスのオブジェクトとプログラムの正しいさに影響を与えずに置き換えられるべきです。マイクロサービスの場合、LSPはサービスインタフェースの異なる実装(例えば、StripeからPayPalに切り替えることができる支払いゲートウェイ)が一貫して動作し、消費者を破壊することなく交換できることを確認します。
インターフェースの分離原理(ISP)
多くのクライアント固有のインターフェイスは、汎用インタフェースよりも優れています。マイクロサービスでは、これは、各消費者のニーズに合わせて、小規模で集中した API やイベントの定義に翻訳されます。たとえば、顧客サービスは、プロファイル検索、アドレス管理、および単一性「顧客」ルートの代わりに、個別のエンドポイントを公開する可能性があります。
依存性反転原理(DIP)
抽象的な依存関係、矛盾しない。マイクロサービスでは、サービスは、メッセージブローカー、APIゲートウェイ、またはサービスメッシュなどの抽象的なインターフェイスに依存するべきではなく、他のサービスへのハードコードされた参照。これにより、実装の交換、回路遮断器の導入、またはビジネスロジックを変更することなくキャッシュレイヤーを追加することができます。
なぜSOLID原則がマイクロサービスに重要なのか
マイクロサービスは、これらの資質を達成するために、明確に境界線、緩いカップリング、および高い凝集を必要とします。SOLIDの原則は、これらの資質を達成するために実証済みのフレームワークを提供します。それらなしで、チームは頻繁に「分散モノリス」のようなアンチパターンに落ち、サービスが共有データベースやチャットAPIを介して緊密に結合されます。SOLIDを適用することで、アーキテクチャレベルでの懸念の分離を強化することによってこれを防ぐことができます。
また、サービスが増えるにつれて、依存関係が管理されていない場合、変更のコストは指数関数的に上昇します。SOLIDの原則は依存性を明示的に維持し、逆に、チームが独立してサービスを展開できるようにします。これにより、独立したデプロイ性、スケーリング、およびレジリエンスの目標と直接調整します。
マイクロサービスにおけるSOLID原則の適用の利点
維持性の向上
各サービスが単一の責任を持っているとき、サービスを変更することは、ほとんど他人に影響を与えません。例えば、認証サービスに新しいユーザー検証ステップを追加すると、ユーザープロファイルサービスの変更を必要としません。この分離は、回帰試験スコープとデプロイメントリスクを大幅に削減します。チームは、独自の年配で個々のサービスの更新を解放することができます。
拡張性の向上
SRPとISPで設計されたサービスは、自然により一層の粒状です。この粒度は、組織がより高い需要を経験するコンポーネントだけをスケールアップすることができます。例えば、ビデオストリーミングプラットフォームはメタデータ検索サービスから独立してトランスコーディングサービスをスケールアップする可能性があります。依存関係は反転(DIP)であるため、サービススケールは、上流または下流パートナーをスケーリングする必要はありません。
柔軟性と再利用可能な優れた柔軟性
インターフェイスの分離は、サービスが消費者が必要とするものだけを露出することを保障します。これは、カップリングを最小限に抑え、複数の消費者間で再利用可能なインターフェイスを作ります。例えば、電子メール、SMS、プッシュ通知用の別々のインタフェース付きの通知サービスは、変更を必要としない注文、請求、およびアカウントサービスによって再利用できます。オープン/クローズド原則は、既存のインターフェイスを変更することなく、新しい通知チャンネル(例、WebSocket)を追加することができます。
より良いテスト可能性
よく定義されたインターフェイスを持つ分離されたサービスはテストがはるかに簡単です。 ユニットは、コンクリートサービスではなく抽象化(DIP)に依存するサービスをテストすることで、開発者はモックやスタブを使用することができます。 各サービスがテストハーネスに対する分離で実行できるため、統合テストはよりシンプルになります。 より高いテストカバレッジは、生産のインシデント数とより速いフィードバックループを少なくします。
故障許容および弾性
DIP に付着することにより、サービスは、メッセージキューやサービスメッシュプロキシなどの抽象的な通信チャネルに依存しています。これらの抽象化は、サービスロジックを変更することなく、レトリー、タイムアウト、回路ブレーカ、およびバルクヘッドを実装することができます。例えば、メッセージブローカー(DIP)を介して支払いイベントを送信する注文サービスは、決済サービスが一時的に利用できなくなった場合でも、後で処理のためにイベントがキュートされるため、引き続き機能します。
より簡単なオンボーディングとチームAutonomy
サービスはSRPとISPに従うとき、その責任は明確で限られています。 新しい開発者は、サービスの目的を迅速に理解することができます。 チームは、他の人の深い知識を必要としない関連サービスのセットを所有することができます。 これは、マイクロサービスが約束する自律的、機能的なチームの種類を可能にします。
マイクロサービスにおけるSOLIDの実用的応用
SRPによるサービス境界の定義
ドメインを境界のコンテキストに分解し始めます。各コンテキストはサービスになります。例えば、eコマースシステムでは、カタログ、カート、注文、支払い、出荷、レビューの別々のサービスを作成します。各サービスは、そのデータとビジネスルールを所有しています。責任を混合する「ユーティリティサービス」の作成を避けてください。
OCPとISPで安定したインターフェースを設計
インターフェイス定義(コントラクト)を protobuf、OpenAPI、または AsyncAPI を使用して作成します。これらのインターフェイスがバージョン管理され、拡張可能であることを確認してください。例えば、「作成する順序」イベントには、フィールドが含まれている必要がありますが、オプションのプロパティを介して将来のフィールドを許可します。既存のものを変更する代わりに、新しいエンドポイントやメッセージタイプを追加することによって変更を破らないでください。
LSPによる置換性の確保
複数のサービスが同じインターフェイス(例えば、複数の決済ゲートウェイアダプタ)を実装し、契約を標準化する。 任意の実装が期待される動作に従う統合テストを書く(例えば、支払いを受け入れると、一貫性のあるエラーコードで成功または失敗を返す)。 これは、ゲートウェイを安全に交換する。
メッセージングとサービスメッシュによる依存性を反転
サービスBにダイレクトHTTPコールを作成する代わりに、Aサービスがメッセージブローカー(Kafka、RabbitMQ)にイベントを公開するか、サービスメッシュ(Istio、Linkerd)を使用するサービスがあります。サービスメッシュは、再試行、タイムアウト、および回路破壊ポリシーを処理することができます。サービスA内のビジネスロジックは、基礎的なネットワークに無関心のままです。
課題と考察
マイクロサービスにおけるSOLID原則を適用することは、課題を伴わないものではありません。 過剰セグメント化(ISPは積極的に適用されます)は、チャットインターフェイスとあまりにも多くのサービスにつながることができ、運用上のオーバーヘッドを増加させます。 同様に、厳密なSRPは、チームが「nanoservices」をもたらす、すべての小さなユニットのマイクロサービスを作成するためにチームを引き起こす可能性があります。 バランスは重要です。
もう一つの課題は、バージョンアップと後方互換性です。 OCP の後には、慎重な非推奨ポリシーが必要です。 スキーマのレジストリ(Confluent Schema Registry、Apicurio)などのツールは、互換性レベルを管理するのに役立ちます。
最後に、チーム文化と組織のアライメントの問題。 明確な所有権とコミュニケーションがなければ、SOLIDサービスは組織習慣(例えば、共有データベースや共有ライブラリ)を通じて密接に結合することができます。 継続的な統合とDevOpsのプラクティスは、独立したデプロイをサポートする必要があります。
コンテンツ
マイクロサービスアーキテクチャにおけるSOLID原則を採用することは、銀製の弾丸ではありませんが、保守可能でスケーラブルで弾力性のあるシステムの構築のための強力なガイドです。 明確な責任、安定した契約、置換性、微粉砕されたインターフェイス、および反転された依存性に焦点を当てることで、チームは分散システムの多くの一般的な下落を回避することができます。 設計の投資は、システムが成長し、進化するにつれてオフに費やされます。 続きを読みます、FLTL[F]FOLT]の原則:[FOLT]:[FOLT]:[FORT]:[FORT]:[FORT]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[F]:[