Workflow Foundation /ou: Porque existem Comandos e comandos!

Posted: 13 de dez. de 2007 | . David Lojudice Sobrinho | tags: ,

Estou ansioso para por a mão no VS2008 e seus novos recursos, com destaque ao Workflow Foundation e seu designer. Para as minhas aplicações o WF se aplica perfeitamente, criando uma camada de abstração que fica faltando hoje: a de comandos! Se você é fã do Design Patterns (GOF) como eu, já sabe do que eu estou falando. Mas para tentar explicar melhor, vou contar minha historinha…

Hoje, usamos a seguinte arquitetura nos nossos projetos:

User Layer: Páginas ASPX, Serviços, WinForms, etc., que fazem chamadas ao nosso “Core”

Business Layer: Core - Aqui encontra-se os Managers. Só e somente os Managers sabem como fazer as coisas. Por definição nossa, os Managers só podem chamar uma classe “Proxy” ou evocar o nosso ORM e suas “Entities”.

Data Layer: Usamos o ORM (70%), nosso querido LLBLGen, ou SQL (5%) ou Proxies (25%) (aka Facade), que interconecta com outros sistemas.

A boa e velha “três camadas”. Não requer prática nem tão pouco habilidade.

Mas uma coisa me incomoda. Os Managers são formados por métodos simples e atômicos (SaveCustomer, GetAccount, PayMoney, etc.). Não tenho Manages ou outro tipo de classe que implementam o uma ação, uma intenção. Uma ação é mais complexa que um método do Manager. Na verdade é o agrupamento deles. Esse agrupamento / intenção / ação é conhecido como Command Pattern.

Exemplo: Toda vez que o usuário emite uma nota fiscal, o sistema notifica o sistema de estoque e logística. Se cada módulo do sistema tem seu Manager, imagino algo assim:

Empresa.Financeiro.NotaFiscalManager.Adicionar(notaFiscal)
foreach (NotaFiscalItemEntity notaFiscalItem in notaFiscal.Items)
{
Empresa.Estoque.EstoqueManager.Reduzir(notaFiscalItem)
}
Empresa.Logistica.EntregaManager.NotificaEntrega(notaFiscal)

Esse agrupamento de código é a ação de emitir uma nota fiscal. Mas onde colocar esse código? Hoje, tenho duas opções: Caso a ação esta amarrada diretamente à UI, fica lá mesmo. Ou no caso de ser reutilizada, criaria um método na classe NotaFiscalManager, algo NotaFiscalManager.Emitir().

A primeira opção é ruim, pois a inteligência do negócio está na camada de abstração errada. A segunda opção não é tão ruim, mas ainda assim está na classe errada, que não deveria conhecer os outros domínios/módulos dos sistemas.

Uma ultima opção, que não uso hoje, seria criar uma classe Empresa.Commands.EmitirNotaFiscalCommand. Aqui seria o lugar perfeito, no meu ver, para o código acima. Atenção ao fato do namespace ao qual a classe pertence ser Commands, que por definição é permitido chamar vários Managers de domínios distintos.

Mas já que o WF está ai, por que não criar um fluxo de sistema que fizesse o mesmo que EmitirNotaFiscalCommand? E agora com a possibilidade de ver o fluxo de maneira visual!

História contada, livros encomendados, opiniões bem vindas.

update: ver também BPM

3 comentários:

  1. Edmar disse...
  2. Dá-lhe Davi,

    Parabéns pelo post/blog! É bom ler algo em português sobre arquitetura/sistemas de vez em qdo.

    Eu continuo no mesmo estilo pragmático semi-imediatista de sempre, agora felizmente trampando com a família e em Floripa. Um pouco de saudades do mundo .NET/C#, mas tô começando a gostar novamente do PHP/MySQL/Linux.

    Continue escrevendo!

    Abração!

    Edmar

  3. CMilfont disse...
  4. Oi David, ao inves de command, use polimorfismo, ao inves de disparar um comando, faça com que cada classe tenha seu proprio metodo de execução.
    Trate injeção de regras dinamicas quando não dá para identificar.

  5. CMilfont disse...
  6. ah, e obrigado pelo comentario no meu post
    http://www.milfont.org/tech/2008/01/22/regras-dinamicas-no-domain-model-com-linguagens-de-script