0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

サーキットブレーカーの設定にOCPは生かせるか①

Posted at

前置き

サーキットブレーカーのパターンは、UML(統一モデリング言語)の考え方を適用する上で、最も教科書的な事例の一つです。

状態遷移モデル(State Machine Diagram)

サーキットブレーカーが 「何であるか(What)」 を定義します。

アクティビティ図(Activity Diagram)

サーキットブレーカーが 「どのように振る舞うか(How)」 を定義します。

1. 状態遷移モデル(State Machine Diagram)として

サーキットブレーカーは、「状態(State)」を持つ、典型的なステートマシンです。

🟢 状態1:CLOSED (クローズド)

振る舞い

正常な状態。リクエストはすべて下流のサービスに通過します。

監視

失敗率をカウントしています。

🔴 状態2:OPEN (オープン)

振る舞い

危険な状態。リクエストはすべて即座に失敗させます(Fail Fast)。
下流のサービスには一切リクエストを送りません。

監視

一定時間(例: 30秒)が経過するのを待っています。

🟡 状態3:HALF_OPEN (ハーフオープン)

振る舞い

テスト状態。「お試し」のリクエストを1回だけ下流のサービスに通過させます。

監視

その1回のリクエストが成功するか失敗するかを監視しています。

2. アクティビティ図(Activity Diagram)として

「どのような条件やユースケース(=アクティビティ)で遷移するのか」は、以下のアクティビティ図(プロセスの流れ)として完璧に表現できます。

アクティビティ図の例

image.png

サーキットブレーカーの設定にもOCP思想を適用

サーキットブレーカーの「設定を変更したい」という要求は、

オブジェクト指向の設計思想(特にカプセル化)

を適用する完璧なユースケースです。

・アクティビティ図で登場するロジック = 「振る舞い (Behavior)」

・設定(閾値や時間) = 「属性 (Attribute / State)」

として、対応付けられます。

オブジェクト指向の基本は、この「振る舞い」と「属性」を1つのオブジェクトにカプセル化し、「属性(設定)」の変更が「振る舞い(ロジック)」のコード修正を必要としないようにすることです。

カプセル化されるデータ(属性)

アクティビティ図上のロジックが 「使用するデータ」 は、以下のようにカプセル化されます。これらはサーキットブレーカー・オブジェクトの内部的な「属性」です。

image.png

ロジック(振る舞い)との関係

この設計の長所点は、アクティビティ図で示した

「複雑な振る舞い」(ロジック)を、execute()のような単一のメソッドとして実装できる

ことです。

そして、failureThresholdresetTimeoutといった

「属性(設定)」 は、そのオブジェクトの内部に隠蔽(カプセル化)

されます。

❌ 悪い設計(カプセル化なし=ハードコーディング)

もしカプセル化しないと、ロジックはこうなります。

image.png

閾値を「10回」から「20回」に変更したい場合、このexecuteRequestという 「振る舞い(ロジック)」自体を「修正」 し、再コンパイル・再デプロイする必要があります。

これはOCP(オープンクローズド原則)に違反します。

✅ 良い設計(カプセル化あり)

thresholdtimeoutを「属性」としてカプセル化します。

image.png

閾値を変更したい場合、cb.setConfig(20, 60000)を呼び出すだけで、「振る舞い(ロジック)」を一切修正せずに挙動を変更できます。これこそがカプセル化の恩恵です。

ドメイン駆動の文脈に応じた保守性

コアドメインは仕様(ビジネスルール)がコロコロ変わりやすいため、それを支えるインフラ(特にサーキットブレーカーのようなレジリエンス機構)も、その変更に追随しなければなりません。

これは、クリーンアーキテクチャの同心円の依存の向きと安定性を考えたらあたり前のことです。

スクリーンショット 2025-10-10 071815.png

したがって、コアドメインを支えるサーキットブレーカーの設計は、

「閾値(threshold)やタイムアウト(timeout)といった“属性”」が「最も頻繁に変更される」

ことを前提として設計しなければなりません。

この「変更のしやすさ(保守性)」という要件を満たすためには、オブジェクト指向の設計原則、特に「カプセル化(属性と振る舞いの分離)」が絶対に不可欠です。

振る舞い(ロジック)

executeRequest()のアクティビティ図(状態遷移ロジック)自体は、安定しており 「修正に閉じる」

属性(ポリシー)

failureThreshold
resetTimeoutMs
currentState
failureCount
lastFailureTime

コアドメインの要求に応じて 「変更(拡張)に開く」 必要がある。

ドメイン特性に準拠していない時

もし、この閾値がロジックにハードコードされていたらカプセル化違反です。

そのため、コアドメインのビジネス要件(例:「もっと応答性を高めたいので、タイムアウトを3秒から1秒に変えよう」)が変わるたびに、

アプリケーションのロジック(振る舞い)まで「修正」 して再デプロイする必要

があり、アジリティ(俊敏性)が著しく損なわれます。

まとまった単位での属性群

failureThreshold
resetTimeoutMs
currentState
failureCount
lastFailureTime

これらの属性の型は、果たして最初から定義すべきでしょうか?
それとも、必要になってから定義するYAGNI原則で考えるべきでしょうか?

実はこの5つの属性は、サーキットブレーカーというパターンを成立させるための「最小限の構成要素」そのものです。

YAGNIの対象ではない「核」

YAGNIの原則は、

「将来必要になるかもしれない追加機能」を実装しない

というものです。 ですが、この5つの属性は「追加機能」ではありません。

これらは「サーキットブレーカー」という オブジェクトの「核となる定義」 です。

currentState がなければ、そもそもステートマシンが成立しません。

failureCountfailureThreshold がなければ、「Closed → Open」へ 遷移するロジック(=回路を“切る”ロジック) が書けません。

lastFailureTimeresetTimeoutMs がなければ、「Open → Half-Open」へ 遷移するロジック(=回路を“復帰”させるロジック) が書けません。

このうち どれか1つでも欠ければ、それはもはや「サーキットブレーカー」パターンとは呼べない、不完全なオブジェクトになってしまいます。

YAGNIを適用すべき部分

では、サーキットブレーカーにおいてYAGNIを適用すべき部分はどこでしょうか?
答えは、この「核」以外の 「追加機能」 です。

successThreshold

Half-OpenからClosedに戻るために必要な「連続成功回数」。
(多くの場合「1回」で十分なため、最初はハードコードしておき、必要になってから属性として定義してもOK)

name

ログやメトリクスに出力するための名前。

metrics_exporter

状態遷移を外部(Prometheusなど)に通知するための依存オブジェクト。

結論

車のオブジェクトを設計する際、「engine(エンジン)」や「wheels(車輪)」を「必要になってから定義する」ということはありません。
それらは「車」の核となる定義で、すべて揃っているべきものだからです。

同様に、上で挙げた5つの属性は「サーキットブレーカー」の核となる属性定義です。

これらは、保守性やOCPのために(ロジックから分離された属性として)最初からすべて考慮・設計すべきです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?