Tópico anterior: Estudo de caso 15: Métricas agrupadas

Próximo tópico: Estudo de caso 17: Funcionalidade integrada

Estudo de caso 16: padrões de design da lógica de negócios

Há diversos padrões de design que podem ser usados em muitas lógicas de negócios. Esses padrões foram testados e usá-los quando aplicável pode economizar muito tempo e, na maioria dos casos, pode criar uma lógica de negócios mais eficiente. Este estudo de caso concentra-se em um padrão de design.

Atualizar padrão de design de contadores

Esse design padrão é útil em quase todas as lógicas de negócios, cujo objetivo é medir o tempo entre determinados eventos. Os exemplos de lógicas de negócios são: lógicas de negócios para a medição da disponibilidade, o tempo de inatividade, o tempo médio entre falhas, o tempo médio de restauração, o tempo médio de resposta, o tempo médio de resolução, a porcentagem de componentes com disponibilidade menor que X, o número de ocorrências não resolvidas na hora, etc.

A parte comum para todas as lógicas de negócios é que o resultado depende da data e hora de vários eventos recebidos..

O princípio básico para decidir se a lógica de negócios pode se beneficiar desse padrão de design consiste em: se a lógica de negócios depender da data/hora dos diversos eventos que recebe, ela provavelmente deve usar este padrão de design.

Esqueleto do padrão de design

O código de uma lógica de negócios que utiliza este padrão pode ser dividida em duas partes: uma estrutura e uma implementação. A estrutura contém o código que, na maioria dos casos, é fixo e não é alterado para as diversas lógicas de negócios. Essa parte é a mesma para o cálculo de disponibilidade e para o número de tickets não resolvidos na hora. A implementação contém o código que é específico para cada lógica de negócios.

É recomendável colocar essas duas partes do código em módulos de lógica de negócios distintos e reutilizar o módulo da estrutura em diferentes métricas.

O código da estrutura é demonstrado abaixo:

Dim g_PrevEventTimestamp

Sub OnLoad(time)
     g_PrevEventTimestamp = time
     InitializeStatusVariables
End Sub

Sub OnRegistration(Dispatcher)
     Se houver uma cópia separada de variáveis do status 
     'para que cada recurso registrado dependa dos recursos
     'registrados, é necessário definir valores iniciais para
     as variáveis de status dos recursos recém adicionados aqui
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

Aqui está a estrutura do módulo de implementação:

' Defina aqui as variáveis de status. Ela pode ser uma 
' variável global simples ou diversas variáveis globais complexas
' dependendo da lógica de negócios
Dim g_StatusVar_1, g_StatusVar_2, ... ,g_StatusVar_n

' Defina os contadores aqui. 
'Isso pode ser uma variável global simples ou muitas
' variáveis globais complexas dependendo da lógica de negócios
Dim g_Counter_1, g_Counter_2, ... , g_Counter_n

Sub InitializeStatusVariables ()
     'Defina os valores iniciais para as diversas variáveis de status
End Sub

Sub InitializeCounters ()
     'Defina os valores iniciais para os diversos contadores
     g_Counter_1 = 0
     g_Counter_2 = 0
     '…
     g_Counter_n = 0
End Sub

Function CalculateResult ()
     'Calcular o resultado. O resultado deve depender
     'dos valores dos contadores. Ele não deve depender
     'do valor das variáveis de status. Ele não deve 
     'alterar os valores dos contadores ou das variáveis 
     ' de status
End Function

Sub UpdateStatus(method, eventDetails)
     Atualizar o valor das variáveis de status com base
     ' nos parâmetros (e possivelmente no valor antigo das 
     ' variáveis de status)
End Sub

Sub UpdateCounters(diff)
     Atualizar os valores dos contadores com base nos
     'valores anteriores, no valor das variáveis de status
     'e no valor do parâmetro diff.
     'Em muitos casos, esse cálculo tem como base
     ' o valor de 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

Para melhor explicar este padrão de design, tem-se um exemplo da implementação deste padrão para calcular a disponibilidade. Esse exemplo supõe que há eventos para UP e DOWN que são tratados por dois manipuladores de eventos diferentes na lógica de negócios. A disponibilidade é definida como o percentual de tempo no qual o sistema está ativo a partir do tempo total no período de atividade. O status do sistema é considerado o status do último evento recebido (ATIVO OU INATIVO).

Veja a seguir o código da implementação (o código da estrutura não é alterado):

' variável de status
Dim g_Status
' Contadores.
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

Há diversas variações neste padrão. Uma das variações mais comuns é quando um contador de tempo distinto deve ser mantido para entidades diferentes. Por exemplo, ao medir o tempo de uma solução, um contador distinto deve ser mantido para cada ticket aberto. Nesse caso, ao manipular um evento relevante apenas para um ticket, é mais eficiente atualizar apenas o contador daquele ticket. Quando um evento comum é manipulado (como OnPeriodEnd ou OnTimeslotEnter) os contadores de todos os tickets devem ser atualizados.

Observação: essa variação do padrão requer que uma cópia separada da variável global g_PrevEventTimestamp seja mantida para cada ticket.

Alguns exemplos úteis sobre o uso deste padrão podem ser encontrados no conteúdo predefinido. Tenha em mente que esse padrão é usado de modo diferente no conteúdo predefinido, e a separação entre a estrutura e a implementação não é tão evidente.