PHPのモジュラーモノリスとマイクロサービスの比較は、モジュール数、コードの古さ、アーキテクチャの人気で決まるものではありません。明確な境界を維持していれば、エンタープライズアプリケーションは単一デプロイメント内で健全に成長できます。逆に、早まった分割は、単純な内部呼び出しを契約、キュー、リトライ、調整上の問題から成るネットワークへ変えてしまう可能性があります。
有用な問いは「マイクロサービスを使うべきか」ではなく、「どのビジネス機能が独立して進化し、障害が発生し、デプロイされ、スケールする必要があり、それをそのように運用するコストを負担できるか」です。答えは目標図ではなく、ドメインと実際の運用から導くべきです。
機能の成長は分離サービスを必要としない

統合、非同期プロセス、プロダクト領域を追加しても、それぞれが独自のサービスを持つ必要があるわけではありません。モノリスは、運用上の一貫性を失わずに、明確に区切られたモジュール、バックグラウンドジョブ、キュー、外部システム用アダプターを含められます。
最初の介入は通常、内部結合を減らすことです。請求モジュールが注文クラスを直接インポートし、そのテーブルを変更し、在庫の内部ルールを把握している場合、コードを別リポジトリへ移しても問題は自動的には解決しません。ネットワークとデータの結合へ変わるだけです。
モジュラーモノリスは、各機能が明示的な内部インターフェース、方向付けられた依存関係、独自のルールを持つことを目指します。PHPでは、ドメインごとの名前空間、アプリケーション契約、薄いコントローラー、定義済みのユースケース、永続化や外部API向けアダプターとして具体化できます。すべてを一緒にデプロイすることは、こうした境界と両立します。
アーキテクチャ変更前に分析すべきこと
技術を議論する前に、ビジネス機能を特定してください。例として、注文管理、カタログ、アイデンティティ、請求、文書処理、通知があります。機能は必ずしもエンティティや画面と同義ではなく、同様の理由で変更されるべきルールと判断をまとめるものです。
- 所有者:ルールを保守し、変更の優先順位を決め、インシデントに対応する者を定めます。
- データ:各機能が作成・管理する情報、それを変更できる者、必要な横断参照を特定します。
- クリティカルフロー:検証、外部依存、非同期ステップを含め、重要な操作の流れを図示します。
- 変更頻度:頻繁な変更と単発の変更を区別します。頻度だけでは不十分であり、チームやリリースの調整を強いるかが重要です。
- 負荷特性:対話型トラフィックを、CPU、メモリ、ストレージ、サードパーティー呼び出しを多用するタスクから分離します。
- 障害の影響:ある機能が数分または数時間劣化した場合に何が起きるか、ビジネスの中核が継続運用できるかを定めます。
この棚卸しにより、共有トランザクション、他モジュールのテーブルへの直接クエリ、コントローラー内に重複したルール、複数ドメインを更新するスケジュールタスクなど、しばしば隠れたままの依存関係が明らかになります。これらを解消せずに抽出すると、形式上は分離されても機能的には絡み合ったサービスになります。
モジュラーモノリスを維持すべき6つの兆候
以下の兆候は、責務を分散させるより先に内部設計を強化することを支持します。
- 変更が複数モジュールをまたぐことが多い。ビジネス機能が注文、価格、請求を協調して変更する必要があるなら、分離はデプロイメントと契約を増やしかねません。
- 即時一貫性が中核である。重要な不変条件を保つために単一のデータベーストランザクションが必要な操作では、分散境界は複雑な補償判断を追加します。
- チームが小さい、または所有権を共有している。複数サービスでは、各単位ごとに運用規律、オンコール、パイプライン、バージョン、診断が必要です。
- 負荷が同様にスケールする。コンポーネントが同じペースで増加し、切り出せるボトルネックがない場合、分離に明確な利点はありません。
- ドメイン境界がまだ不安定である。ルール、用語、責務が絶えず変わるうちに機能を抽出すると、境界を早まって固定します。
- 可観測性と自動化が限定的である。構造化ログ、メトリクス、トレース、アラート、再現可能なデプロイメントがなければ、ネットワークホップのたびにインシデント調査のコストが上がります。
モノリスを維持することは、グローバルなコードを受け入れることではありません。目標は、他とプロセス、リポジトリ、リリースを共有していても、モジュールが論理的な自律性をもって進化できることです。
独立サービスを正当化する6つの兆候
抽出は、1つだけが現れたときではなく、以下の条件が複数組み合わさる場合により妥当です。
- 限定され理解しやすい責務がある。サービスには具体的な使命、凝集したルール、独自のドメイン言語があります。
- 自身のデータを所有できる。テーブルへの直接アクセスを許すのではなく、ストレージを管理し、合意済みの操作、イベント、クエリを公開します。
- 真に独立したデプロイメントが必要である。その変更サイクルは、中核とすべてのリリースを調整せずに進められる必要があります。
- 負荷が異なる。変換、検索、ファイル生成、集中的な計算のプロセスでは、異なるスケーリングとリソースが必要になる場合があります。
- 障害を分離できる。その機能が応答しない場合でも、リトライ、保留状態、遅延処理によって、システムは明示的に劣化できます。
- 十分な運用上の所有権がある。チームまたは責任者が、そのライフサイクル、アラート、インシデント、セキュリティ、互換性を保守できます。
APIだけでモジュールがマイクロサービスになるわけではありません。独立性は、データ、デプロイメント、運用、他アプリケーションの内部実装に依存せず判断できる能力にも依存します。
責務を分離すると現れるコスト
関数呼び出しは、HTTP呼び出し、キューメッセージ、リモートクエリとは異なる形で失敗します。抽出後には、レイテンシー、タイムアウト、サービス間認証、レート制限、部分的な可用性低下、非互換なバージョンが現れます。
一貫性モデルも変わります。あるサービスが操作を確定しても、別のサービスがイベントを受信または処理しない場合、状態をどう検出するか、効果を重複させずにどうリトライするか、必要に応じてどう補償するかを決める必要があります。イベントコンシューマーは冪等でなければなりません。たとえば、メッセージを2回処理しても、文書を2件発行したり2回請求したりしてはなりません。
運用は複雑になります。リクエスト相関、分散トレース、メトリクスダッシュボード、ログ保持、シークレット管理、バックアップポリシー、リカバリーテストが必要になります。さらに、各契約には互換性ルールが必要です。オプションフィールドの追加は通常、セマンティクスの変更、フィールド削除、既存の状態を新しい意味で再利用することより破壊的ではありません。
PHP内での移行アーキテクチャ
最もリスクの低い経路は、抽出前にモジュール化することです。各機能にアプリケーション層を定義し、コマンドまたはクエリを受け取り、明確に定義された結果を返すユースケースを設けます。重要な依存関係を表す場合は、データベースアクセスをリポジトリまたはポートの背後に隠してください。すべてのクラスを目的のない抽象化にしてはいけません。
モノリスの他の部分は、そのエンティティやテーブルではなく、公開された内部インターフェースを通じてモジュールを利用すべきです。非同期通知が必要なら、制御された一点からドメインイベントまたは統合イベントを発行します。トランザクショナルアウトボックスパターンは、ビジネス上の変更と保留中イベントを同一トランザクションに記録し、後続プロセスが確実に配信できるようにするうえで役立ちます。
この段階で、境界が実在するかを検証できます。内部インターフェースが際限なく増大する、他モジュールのプライベートオブジェクトを要求する、または各ユースケースで共有トランザクションを必要とするなら、まだ分離の有力な候補ではありません。
最初のサービス境界の定義方法
最初のサービスは、説明しやすい責務と中核への限定的な依存関係を持つべきです。インフラストラクチャを書く前に、4つの要素を文書化してください。
- 責務:どの判断を行い、何を明示的に対象外とするか。
- APIまたはイベント:入力、出力、エラー、認証、タイムアウト、冪等性。
- データの所有権:何を保存するか、どの外部識別子を保持するか、契約を通じてどの情報を照会するか。
- 互換性:遅延メッセージを含め、バージョン変更中にプロデューサーとコンシューマーがどのように共存するか。
テーブルの写しとしてAPIを設計することは避けてください。契約は、後の変更を阻害する永続化の詳細を露出するのではなく、ビジネス上の操作または事実を表現すべきです。
例:バックオフィスを断片化しない文書処理
案件を管理し、文書を生成、検証、保存する必要があるPHPバックオフィスを考えてみましょう。最初は、処理を内部モジュールとして配置できます。生成リクエストを受け取り、ジョブを記録し、非同期タスクを実行して、ユーザーに見える状態を更新します。
生成が大きく異なるリソースを消費し、特定の変換依存関係を必要とし、独自のスパイクを受け、必要最小限のデータを含む文書リクエストで動作できる場合、抽出は妥当になります。文書サービスは案件テーブルを自由に照会すべきではありません。バックオフィスは、識別子、適用テンプレート、データバージョン、宛先を含む指示を送信でき、結果はイベントまたは照会可能な状態として返されます。
その前に、テンプレートは出力構造を定義する一方、モデルはドメインデータまたはAIシステムを指し得ることを明確にするのが適切です。文書分類にAIを導入する場合は、限定されたユースケース、代表性のあるデータによる評価、センシティブな判断における人間レビュー、データ保護、コスト管理、プロバイダー障害時の手作業またはルールベースの代替手段が必要です。
抽出前の確認事項

抽出を孤立した技術的デプロイメントとして扱わないでください。すべてのユーザーへの変更告知とは異なる、制御された操作のサブセットに対する段階的な有効化を定義してください。動作を検証する間、共存とロールバックの計画を維持します。
- ユニットテストおよび統合テストに加え、プロデューサーとコンシューマー間の契約テスト。
- レイテンシー、エラー、リトライ、保留中キュー、重複、プロセス完了までの時間のメトリクス。
- モノリス、キュー、サービスをまたいで操作を追跡するための相関ID。
- リカバリー手順:安全な再実行、状態の照合、バックアップ、復元。
- サービスが利用できない場合の機能劣化に関する明示的なルール。
- 終了基準:抽出が複雑さを移しただけでなく、具体的な問題を軽減したことをどの証拠が示すか。
最良のアーキテクチャ判断とは、不釣り合いなプラットフォームを押し付けずに、プロダクトの進化を守るものです。モジュール化され、計測可能で、適切に境界付けられたPHPモノリスは、ある機能が検証可能な独立性の必要性を示すまで、多くの場合に正しいステップです。



