Lógica de negócio vs lógica de aplicação

Olá, pessoal!

Quando começamos a trabalhar com a camada de aplicação, popularizada nos últimos anos pelo Domain-Driven Design, ficam dúvidas sobre sua verdadeira função e sobre qual código devemos colocar nela. Escrevi dois artigos anteriormente que ajudam a elucidar essas questões <<aqui>> e <<aqui>>.

Neste terceiro, mostro uma divisão mais clara entre lógica de negócio e lógica de aplicação e algumas dicas para não confundirmos as duas. Espero que gostem!

LÓGICA DE NEGÓCIO (BUSINESS/DOMAIN LOGIC)

Compreende todo o código que lida com regras de negócio, ou seja, código que diz o que determinada área de negócio faz. Por exemplo, em uma área que trata de assinaturas de revistas, aplicar uma determinada política de desconto nas assinaturas é uma regra de negócio.

Toda lógica de negócio deve residir na camada de domínio (business/domain layer), distribuída entre diversos tipos de objetos como entidades, value objects, (domain) services, entre outros.

Lógica de negócio NÃO envolve preocupações técnicas, como acesso a dados, exportação de dados em formato de arquivos, notificações, etc. Ela sequer sabe em qual tipo de aplicação ela está sendo usada (mobile, desktop, web, sendo exposta via REST?).

LÓGICA DE APLICAÇÃO (APPLICATION LOGIC)

Tomando o exemplo anterior, para concluirmos uma assinatura de uma revista, além da lógica de negócio envolvida, existe uma série de outras preocupações que devem ser atendidas para completarmos essa “user story / use case”, como, por exemplo, cuidar do controle transacional e fazer o log da operação. Portanto, a lógica de aplicação é quem coordena todas essas operações, garantido que a user story “assinar uma revista” seja atendida com sucesso.

Toda lógica de aplicação reside na camada de aplicação (application layer), distribuída em serviços de aplicação, cada um deles com uma responsabilidade bem definida, que significa atender determinado use case.

ONDE VAI O CÓDIGO? ALGUMAS DICAS…

Dito tudo isso, fica fácil saber o que é e onde vai código de negócio e código da aplicação. No entanto, vale reforçar com algumas dicas:

1. Lógica de aplicação coordena as operações e não as implementa, ou seja, um serviço de aplicação simplesmente faz uso de lógica de domínio e demais serviços técnicos. Portanto, código que lida com logging, por exemplo, ainda é código de infraestrutura.

2. Observe se os serviços de aplicação possuem condicionais e loops. Isso pode ser um smell de que há código ali que deveria estar encapsulado em alguma classe de negócio ou de infraestrutura.

3. Observe como se dá a interação entre os objetos de domínio. O mais simples possível é que um serviço de aplicação interaja com um objeto de domínio e com seu repositório para obtê-lo/persisti-lo:

// método de um serviço de aplicação responsável pelo cancelamento de pedidos
// .......
var pedido = this.repositorioDePedidos.ObterPor(idDoPedido);
pedido.Cancelar();
// ......

4. Caso haja uma sequencia de interações entre vários objetos de domínio, verifique se essas operações representam um conceito do domínio, isto é, se aparecem sempre juntas. Em caso afirmativo, encapsule-as em um serviço de domínio. Por exemplo, se sua lógica de aplicação coordena o crédito em uma conta bancária, o débito de outra conta e a geração de movimentos de crédito e débito no extrato, esse conjunto de operações poderia ser encapsulado em um serviço de domínio responsável por uma “transferência bancária”.

5. Podem haver casos onde uma sequencia de interações entre objetos de domínio não forma obrigatoriamente um conceito único, ou seja, em um determinado serviço de aplicação, ela aparece na íntegra, enquanto em outro serviço, apenas parte dela é necessária. Vejamos um exemplo:

// método de um serviço de aplicação
// ........
var pedido = new Pedido();
this.repositorioDePedidos.Adicionar(pedido);
// ........
politicaDeDescontos.Aplicar(cliente, pedido);

// ........

No exemplo acima, o serviço de aplicação implementa um use case onde um novo pedido é criado e imediatamente já é aplicado um desconto a ele. Suponha agora que tenhamos outros use cases, onde usuários com permissões diferentes em momentos diferentes, podem criar pedidos sem aplicar nenhum desconto e podem aplicar descontos em pedidos já existentes. Cada combinação dessas ficaria em um serviço de aplicação diferente (*).

(*) Esta última dica é uma sugestão de Scott Millett, em seu livro “Patterns, Principles and Practices of Domain-Driven Design”.

LÓGICA DE APLICAÇÃO FORA DOS SERVIÇOS DE APLICAÇÃO

Em alguns softwares que não possuem uma camada de aplicação, a lógica de aplicação costuma ficar em uma camada mais externa. Por exemplo, em uma aplicação ASP.NET MVC, essa lógica reside nas actions dos controllers. Para evitar repetição, em geral, a lógica de aplicação acaba ficando distribuída, parte nas actions e parte em recursos do framework utilizado (no caso do ASP.NET MVC, é comum o uso de filters para lidar com preocupações técnicas, como tratamento de exceções, logging, autorização, entre outros).

Embora a solução acima seja mais simples e até mais divulgada, eu recomendo fortemente concentrar essas operações em serviços de aplicação, principalmente em softwares mais complexos e que pretende-se manter ao longo dos anos. (Indico a leitura dos artigos citados no início deste.)

CONCLUINDO…

Lógica de negócio/domínio e lógica de aplicação são tipos diferentes de lógica. Saber diferenciá-las e onde colocá-las no software torna o código mais legível, mais coerente com o negócio e com o modo pelo qual o usuário opera o software, mais coeso e fácil de testar.

Para saber mais sobre o assunto, indico os livros de Domain-Driven Design:

Domain-Driven Design: Tackling Complexity in the Heart of Software
Implementing Domain-Driven Design
– e o já citado Patterns, Principles, and Practices of Domain-Driven Design

Espero que tenha passado a ideia de forma clara. Comentem aí!

[]s

Anúncios

8 comentários em “Lógica de negócio vs lógica de aplicação

  1. Se eu disser que já faz algumas semanas que eu tava ensaiando pra te perguntar como diferenciar um serviço de Aplicação de um de Domínio acredita? 😛

    Toda vez que o Renan me pergunta alguma coisa com relação à arquitetura e serviços eu preciso dar uma lida em algo antes de falar pra ele e geralmente acabo dizendo um “vou perguntar pro BigUncle depois mas pelo que li é isso que acabei de falar” hehe.

    A dificuldade maior pra mim é que nunca peguei casos onde existe uma separação clara como o sol entre regra de aplicação e negócio (ou talvez tenha mas por inexperiência não consigo captar). Geralmente minhas “Application Services” nada mais são que classes AlgumNomeService e contém só métodos de uma única linha que não faz nada além de chamar o Repository pra CRUD. Acabo até me perguntando até que ponto vale a pena escrever um teste pra um método desse tendo que Stubear ou Mockar, e compreender coisas como CQRS acaba sendo um pouco difícil (a propósito comprei aquele livro que você me indicou do Adaptive Code via C# 🙂 e o Cap. 2 fala apenas poucos parágrafos sobre CQS e CQRS).

    Mas no workshop de O.O. e arquitetura de software VAI ter uma aula fera disso tudo, NÉ? hahaha

    1. E ai, cara, vlw por comentar.
      Sobre o CQRS, coincidentemente, vou dar uma palestra amanhã na empresa (perdeu! hahaha).
      Sobre os CRUDs, ou o sistema é muito básico (só CRUD) mesmo e ai toda a arquitetura sugerida pelo DDD acaba sendo complexidade demais OU estão erradamente tratando tudo como CRUD (telas que exibem e atualizam tudo de uma só vez ao invés de serem telas mais inteligentes, que realizam uma operação específica do negócio).

      Qto aos workshops, tô devendo, tô enrolado hehehe…preciso dar foco maior pra sair….guentaí…

      (Depois fala o que achou do livro!)
      []s

  2. Parabéns pelo artigo. Fiquei curioso para saber na prática como vc resolve o problema do item (4), poderia codificar um exemplo?

    1. Olá
      Obrigado, David.

      Não existe mágica. Você precisa conversar com o cliente (aquele que entende aquela área de negócio) para aprender com ele a ponto de você captar que um grupo de operações formam um único conceito de domínio.

      Dei um exemplo didático da transferência bancária, que poderia ser algo como:

      contaOrigem.Debitar(valor);
      contaDestino.Creditar(valor);

      // trocado por
      transferenciaBancaria.TransferirEntre(contaOrigem, contaDestino, valor);

      Veja, o exemplo é bem bobo – em termos de economia de linhas – mas serve para ilustrar a ideia: o serviço é uma operação existente no negócio, presente na linguagem ubíqua (termo do DDD, linguagem usada entre devs e especialistas de negócio) e encapsula operações (crédito e débito) que, dentro de uma transferência bancária, devem existir juntas.

      ATENÇÃO: não force a criação de um serviço só para juntar um monte de coisa. Ele só deve existir quando os critérios acima forem atendidos e quando não fizer sentido acomodá-los em uma entidade/value object já existente. No exemplo acima, “Creditar” iria receber e debitar da conta origem ou “Debitar” iria receber e creditar na conta destino??

      ATENÇÃO: a palavra serviço neste comentário refere-se, obviamente, a um serviço de DOMÍNIO.

      Espero ter clareado!
      []s

      1. Excelente, dentro da camada de domínio como ficaria a estrutura organizacional .Dominio\Servicos\TransferenciaBancaria.cs?

      2. Organize os namespaces também por operações de negócio e não por tipos de objetos.
        Por exemplo:
        \Movimentacoes\
        \Receitas\
        \Despesas\

        Eu costumo criar uma pasta para cada agregate (todas as entidades/vo + o repositorio correspondente).

  3. Ola Robson, primeiramente parabéns pelo excelente conteúdo.

    Ultimamente tenho lido sobre Clean Architecture, que basicamente utiliza vários conceitos de arquitetura cebola e hexa (que você ja citou em outras postagens).
    Ao ler seu post, fiquei com a seguinte dúvida:

    Existe alguma diferença entre um serviço de aplicação e um interactor(citado muitas vezes como uma classe que abstrai um user case ou um user story)?

    desde ja agradeço

    Abraços

    1. Oi, Rodrigo
      Obrigado!

      Só vi esse termo sendo usado pelo Uncle Bob, e pelo que ele diz, como vc bem descreveu, é exatamente a mesma ideia de um serv. de aplicação (apenas outra terminologia).

      []s!

Participe! Vamos trocar uma ideia sobre desenvolvimento de software!

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s