前のトピック: ケース スタディ 15: クラスタ化メトリック

次のトピック: ケース スタディ 17: 組み込み機能

ケース スタディ 16: ビジネス ロジックの設計パターン

多くのビジネス ロジックで使用できるいくつかの "設計パターン" があります。 それらの設計パターンはテストされ、適用可能なときにそれらを使用することで多くの時間を節約でき、ほとんどの場合、より効率的なビジネス ロジックを作成できます。 このケース スタディはそのようなデザイン パターンの 1 つに焦点を当てます。

更新カウンタの設計パターン

この設計パターンはほとんどすべてのビジネス ロジックで役に立つもので、あるイベント間の時間を測定するように意図されます。 そのようなビジネス ロジックの例は、可用性、ダウンタイム、平均故障間隔、平均回復時間、平均応答時間、平均解決時間、可用性が X 未満のコンポーネントの割合、時間どおりに解決されなかったケースの数などのビジネス ロジックです。

それらのビジネス ロジックすべてで共通の部分は、結果がそれらのビジネス ロジックが受信するさまざまなイベントのタイムスタンプに依存するということです。

ユーザのビジネス ロジックがこのデザイン パターンから利益を得ることができるかどうかを決めるための経験則は次のとおりです。ビジネス ロジックが、それが受信するさまざまなイベントのタイムスタンプに依存する場合、この設計パターンを使用する必要がある可能性が高くなります。

この設計パターンの骨格

このパターンを利用するビジネス ロジックのコードはフレームワークと実装の 2 つの部分に分割できます。 フレームワークには、ほとんどの場合固定され、さまざまなビジネス ロジックに対して変わらないコードが含まれます。 この部分は、可用性、および時間どおりに解決されないチケットの数の計算に対して同じです。 その実装には、各ビジネス ロジックに固有のコードが含まれます。

コードのそれら 2 つの部分を別々のビジネス ロジック モジュールに入れ、フレームワークのモジュールを別々のメトリックで再利用することを推奨します。

フレームワークのコードを以下に示します。

Dim g_PrevEventTimestamp

Sub OnLoad(time)
     g_PrevEventTimestamp = time
     InitializeStatusVariables
End Sub

Sub OnRegistration(Dispatcher)
     ' If there is a separate copy of status variables 
     ' for each registered resource depend on the registered
     ' resources you should set initial values to the
     ' status variables of the newly added resources here
End Sub

Sub OnPeriodStart(time)
     InitializeCounters
End Sub

Sub OnPeriodEnd(time, completePeriod)
     HandleEvent (time)
End Sub

Sub OnTimeslotEnter(time)
     HandleEvent (time)
End Sub

Sub OnTimeslotExit(time)
     HandleEvent (time)
End Sub


Function Result()
     Result = CalculateResult()
End Function

Sub HandleEvent(Time)
     Dim diff
     diff = TimeDiff( "s",Time,g_PrevEventTimestamp)
     UpdateCounters(diff)
     g_PrevEventTimestamp = Time
End Sub

実装モジュールのスケルトンを以下に示します。

' Define your status variables here. This can be one 
' simple global variable or many complex global variables
' depending on the business logic
Dim g_StatusVar_1, g_StatusVar_2, ... ,g_StatusVar_n

' Define your counters here. 
' This can be one simple global variable or many
' complex global variables depending on the business logic
Dim g_Counter_1, g_Counter_2, ... , g_Counter_n

Sub InitializeStatusVariables ()
     ' Set initial values to the various status variables
End Sub

Sub InitializeCounters ()
     ' Set initial values to the various counters
     g_Counter_1 = 0
     g_Counter_2 = 0
     '…
     g_Counter_n = 0
End Sub

Function CalculateResult ()
     ' Calculate the result. The result should depend on
     ' the values of the counters. It should not depend on
     ' the value of the status variables. It should not 
     ' change the values of the counters or the status 
     ' variables
End Function

Sub UpdateStatus(method, eventDetails)
     ' Update the value of the status variables based on
     ' the parameters (and posibly on the old value of the 
     ' status variables)
End Sub

Sub UpdateCounters(diff)
     ' Update the values of the counters based on their
     ' previous value, on the value of the status variables
     ' and on the value of the diff parameter.
     ' In many cases this calculation is also based on the
     ' value of Context.IsWithinTimeslot
End Sub

Sub OnEvent_1(eventDetails)
     HandleEvent (eventDetails.Time)
     UpdateStatus(“OnEvent_1”,eventDetails)
End Sub

Sub OnEvent_2(eventDetails)
     HandleEvent (eventDetails.Time)
     UpdateStatus(“OnEvent_2”,eventDetails)
End Sub

'...

Sub OnEvent_n(eventDetails)
     HandleEvent (eventDetails.Time)
     UpdateStatus(“OnEvent_n”,eventDetails)
End Sub

この設計パターンについてさらに説明するために、可用性の計算にこのパターンを実装した例を以下に示します。 この例では、ビジネス ロジック内の個別の 2 つのイベント ハンドラによって処理される UP および DOWN のイベントがあると仮定します。 可用性は、タイムスロット内の総時間に対する、システムが稼動されていた時間のパーセントとして定義されます。 システムのステータスは、最後に受信したイベント(UP または DOWN)のステータスであると仮定します。

実装するコードを以下に示します(フレームワークのコードは変更しません)。

' Status variable
Dim g_Status
' Counters.
Dim g_UpTime, g_TotalTime

Sub InitializeStatusVariables ()
     G_Status = “UP”
End Sub

Sub InitializeCounters ()
     g_UpTime = 0
     g_TotalTime = 0
End Sub

Function CalculateResult ()
     If g_TotalTime = 0 Then
          CalculateResult = Null
     Else
          CalculateResult = g_UpTime/g_TotalTime*100
     End If
End Function

Sub UpdateStatus(method, eventDetails)
     If method = “OnUP” Then
          G_Status = “UP”
     Else
          G_Status = “DOWN”
     End If
End Sub

Sub UpdateCounters(diff)
     If Context.IsWithinTimeslot Then
          G_TotalTime = g_TotalTime + diff
          If g_Status = “UP” Then
               G_UpTime = g_UpTime + diff
          End If
     End If
End Sub

Sub OnUp(eventDetails)
     HandleEvent (eventDetails.Time)
     UpdateStatus(“OnUp”,eventDetails)
End Sub

Sub OnDown(eventDetails)
     HandleEvent (eventDetails.Time)
     UpdateStatus(“OnDown”,eventDetails)
End Sub

このパターンにはいくつかのバリエーションがあります。 最も一般的なバリエーションの 1 つは、各種のエンティティに対して個別の時間カウンタを保持する必要がある場合です。 たとえば、解決時間を測定する場合、各オープン チケットに対して個別のカウンタを保持する必要があります。 この場合、1 つのチケットにのみ関連するイベントを処理する場合は、そのチケットのカウンタのみを更新するほうが効率的です。 共通のイベントが処理されるとき(OnPeriodEnd、OnTimeslotEnter など)は、すべてのチケットのカウンタが更新される必要があります。

: このパターンのこのバリエーションでは、各チケットに対して g_PrevEventTimestamp グローバル変数の個別のコピーを保持する必要があります。

このパターンの良い使用例のいくつかは、事前定義済みのコンテンツで見られます。 このパターンは事前定義済みコンテンツでは少し違った形で使用され、フレームワークと実装の間の区別はそれほど明白ではありません。