Por que colocar a lógica de negócios no modelo? O que acontece quando tenho vários tipos de armazenamento?

70

Eu sempre pensei que a lógica de negócios deve estar no controlador e que o controlador, uma vez que é a parte do "meio", permanece estático e que o modelo / exibição deve ser selado através de interfaces. Dessa forma, você pode alterar a lógica de negócios sem afetar mais nada, programar vários modelos (um para cada banco de dados / tipo de armazenamento) e dezenas de visualizações (para diferentes plataformas, por exemplo).

Agora, li nesta pergunta que você deve sempre colocar a lógica de negócios no modelo e que o controlador está profundamente conectado à visão.

Para mim, isso realmente não faz sentido e implica que cada vez que eu quero ter meios de suportar outro banco de dados / tipo de armazenamento, preciso reescrever todo o meu modelo, incluindo a lógica de negócios.

E se eu quiser outra visão, tenho que reescrever a visão e o controlador.

Alguém pode explicar por que isso é ou se eu errei em algum lugar?

Steffen Winkler
fonte

Respostas:

69

A resposta de ElYusubov é a principal: a lógica do domínio deve entrar no modelo e a lógica do aplicativo no controlador.

Dois esclarecimentos:

  • O termo lógica de negócios é bastante inútil aqui, porque é ambíguo. Lógica de negócios é um termo genérico para toda a lógica com a qual os executivos se preocupam, separando-os de meros aspectos técnicos, como armazenar coisas em um banco de dados ou renderizá-las em uma tela. Tanto a lógica do domínio ("um endereço de email válido se parece com ...") quanto os fluxos de trabalho / processos de negócios ("quando um usuário se inscreve, solicita seu endereço de email") são considerados lógica de negócios, com o primeiro claramente pertencendo ao sendo o último modelo a lógica de aplicação que entra no controlador.
  • MVC é um padrão para colocar coisas em uma tela e que permite ao usuário interagir com ele, ele não especifica o armazenamento em tudo . A maioria das estruturas MVC são estruturas de pilha completa que vão além do mero MVC e ajudam a armazenar seus dados e, como os dados que devem ser armazenados geralmente são encontrados no modelo, essas estruturas oferecem maneiras convenientes de armazenar seu modelo. dados em um banco de dados, mas isso não tem nada a ver com o MVC. Idealmente, os modelos devem ser independentes de persistência e a mudança para um tipo diferente de armazenamento não deve afetar o código do modelo. Arquiteturas de pleno direito têm uma camada de persistência para lidar com isso.
Waquo
fonte
4
A maioria das estruturas MVC meio que mistura todo o material de armazenamento / banco de dados no modelo para facilitar o armazenamento de seus modelos (geralmente fazendo com que você estenda a classe de modelo das estruturas). Esta é provavelmente a fonte de confusão. Tecnicamente, o código do modelo que você escreve deve ser o modelo real (camada de domínio), enquanto o código fornecido pela estrutura deve lidar com o armazenamento (camada de persistência). Por exemplo, algo como User.find (...) (com User sendo um modelo) funciona porque a estrutura implementou o padrão de repositório como parte do Modelo.
Waquo
3
View-Controller-Model-Storage é o princípio geral (embora a relação entre M, V e C deva ser visualizada como um triângulo). Quando sua estrutura combina armazenamento em seu "modelo", funciona da seguinte maneira: View-Controller- (o modelo herda o armazenamento da estrutura).
Waquo
2
O View-Controller-Model-Storage é bastante bruto, porque não deve ser plano. Por exemplo, quando um controlador faz algo como User.find (...) para obter um modelo, ele pergunta diretamente à camada de armazenamento, em vez de passar pela camada de domínio.
Waquo
2
Em arquiteturas com camadas mais cuidadosas, seria algo como UserRepository.find (). Por "modelo", quis dizer a classe "modelo" fornecida pela estrutura, da qual você herda. O objeto usuário retornado por User.find () é um modelo de um usuário no sentido de que alguém modelado o que um usuário é, como um usuário se comporta ...
Waquo
11
@flipdoubt business logic é qualquer lógica que deve ser mantida igual se você portou do mvc para dizer um aplicativo uwp.
Andy
23

Você e grandes partes do mundo da programação parecem entender mal quais são os papéis das partes do MVC. Em suma, são eles:

Modelo = lógica do domínio

Ver = lógica de saída

Controlador = lógica de entrada

Isso significa que o modelo é responsável por toda a lógica comercial: tudo relacionado a desenhar widgets em uma tela, dirigir uma impressora, gerar dados como HTML, analisar solicitações HTTP etc. etc. não pertence ao modelo.

No entanto, muitas das modernas estruturas chamadas "MVC" realmente não fazem MVC, ou identificam incorretamente suas partes. Muitas vezes, o que é chamado de "modelo" é a camada de persistência do modelo, enquanto a lógica de negócios fica no que eles chamam de "controlador"; o controlador real geralmente é apenas um ponto de entrada central com uma tabela de roteamento e um pouco de código nos "controladores" individuais para despachar a entrada que eles recebem para os processos de negócios corretos. O que essas estruturas chamam de "visualização" é realmente um pouco de tudo: alguma lógica de apresentação (Visualização), um pouco de manipulação e validação de entradas (Controlador) e algumas outras lógicas de negócios (Modelo). A maior parte da visão atual é geralmente chamada de "modelos".

Você também pode querer ler sobre a arquitetura multicamada; onde o MVC é meio unidirecional (o fluxo é Controller -> Model -> View), a multicamada é uma via bidirecional (Apresentação -> Lógica -> Dados -> Lógica -> Apresentação) e várias estruturas que pretendem fazer MVC realmente executam três camadas, renomeando Presentation to View, Logic to Controller e Data to Model.

tdammers
fonte
2
Acredito que você deturpa o Model ("Model = domain logic"), na minha opinião, é mais um recipiente para a população com dados, que são renderizados usando uma View, na forma mais pura do padrão MVC. Certamente, em casos de uso muito simples, você pode tratá-lo como a "lógica do domínio", mas eu asseguro que a maioria dos sistemas que existem vale a pena superar isso muito rapidamente. Melhor dividir a "lógica do domínio" em uma camada / classe separada, por exemplo, uma camada de serviço.
A. Murray
@ A.Murray: É claro que o Modelo não precisa ser um blob de código monolítico, e separá-lo em persistência, estruturas de dados e lógica de domínio geralmente faz muito sentido. Ainda assim, o MVC agrupa essas três preocupações no Modelo. De qualquer forma, quando seus controladores e visualizações contêm lógica de domínio, não é mais o MVC real.
Tdammers #
@ Tdammers, eu gosto da ordem de sua resposta e seu foco na lógica. Na sua opinião, aonde pertencem as preocupações de aplicativos como persistência e processamento de transações? Parece que MVC deve ser um acrônimo de quatro letras como MVCS, em que S é para serviço.
flipdoubt
15

Para realmente isolar a lógica de negócios e separá-la da infraestrutura da camada de apresentação, ela deve ser encapsulada pelos serviços de aplicativo. A arquitetura MVC é uma maneira de implementar a camada de apresentação e deve permanecer nesse escopo, delegando toda a lógica de negócios a esses serviços de aplicativos. Pense nos modelos de visualização como adaptadores entre a visualização e os dados que precisam ser exibidos e / ou lidos. O controlador medeia a interação entre modelos de visualização, visualizações e serviços de aplicativos que hospedam a lógica de negócios.

Os serviços de aplicativo implementam casos de uso de negócios e são dissociados da camada de apresentação, seja MVC ou outra coisa. Por sua vez, os serviços de aplicativos podem hospedar scripts de transação ou um design controlado por domínio .

Para armazenamento, o serviço de aplicativo pode fazer referência a um repositório ou a qualquer abstração de um mecanismo de persistência. Diferentes implementações podem ser suportadas abstraindo o acesso aos dados em uma interface. Normalmente, essas abstrações são vazadas e são apenas parcialmente portáveis ​​nas implementações e geralmente é uma tentativa fútil de atingir a portabilidade total.

ATUALIZAR

Minha sugestão é baseada na arquitetura hexagonal . Em uma arquitetura hexagonal, seu modelo de domínio (lógica de negócios) está no centro. Esse núcleo é encapsulado por serviços de aplicativos que atuam como fachada . Os serviços de aplicativo são classes simples que possuem métodos correspondentes aos casos de uso em seu domínio. Para uma discussão aprofundada sobre serviços de aplicativos, consulte Serviços em Design Orientado a Domínio . O exemplo de código contém um PurchaseOrderServiceserviço de aplicativo para um domínio de compra. (Observe que um serviço de aplicativo não implica o uso de design controlado por domínio.)

Em uma arquitetura hexagonal, uma camada de apresentação MVC é um adaptador entre o modelo de domínio (lógica de negócios) e uma GUI. O modelo de domínio não está ciente da camada de apresentação, mas a camada de apresentação está ciente do modelo de domínio.

Essa solução certamente possui partes móveis do que uma solução que coloca a lógica de negócios no controlador e você deve considerar os inconvenientes e os benefícios. A razão pela qual sugiro é porque prefiro manter a lógica de negócios dissociada da camada de apresentação para combater a complexidade. Isso se torna mais importante à medida que o aplicativo cresce.

eulerfx
fonte
Parece que você está descrevendo um bastardo do MVC e MVVM que possui controladores e modelos de exibição. Além disso, acho que a arquitetura que você está descrevendo pode ser um pouco pesada para as necessidades do OP.
Waquo 21/11
para ser sincero, gosto mais da resposta de Waquo. Principalmente porque não tenho idéia do que você quer dizer com 'serviços de aplicativos'. Você poderia explicar esse termo? Meu GoogleFU não está funcionando aqui como parece.
Steffen Winkler
11
@Waquo Concordo que a arquitetura proposta pode ser um exagero, mas deve ser considerada. Não mencionei o MVVM, que é simplesmente outra maneira de implementar uma camada de apresentação. Os serviços de aplicativo se aplicam, independentemente de você usar MVC ou MVVM, e nada que eu sugeri indica qualquer combinação dos dois.
eulerfx
1

Depende do que você entende por lógica de negócios. Qualquer "lógica" que dê significado ao conteúdo do modelo deve estar no modelo. Na questão vinculada, a resposta mais votada parece definir "lógica de negócios" como algo relacionado a dados; isso faz sentido do ponto de vista de que os dados de uma empresa são seus!

Certa vez, vi um exemplo do criador do Rails (eu acho) que estava falando exatamente sobre isso - não colocando "lógica de negócios" no modelo. Seu exemplo foi uma classe de controlador e método para registro e login de aplicativos - uma senha fornecida em texto sem formatação foi criptografada antes de ser inserida ou consultada no modelo (um banco de dados).

Não consigo pensar em um exemplo melhor de algo que não seja da lógica do controlador e que pertença diretamente ao modelo.

O modelo pode ser uma interface para inúmeros repositórios de dados, aliviando as preocupações de portabilidade. É aqui que se pode encontrar confusão sobre se a interface do modelo é realmente o "controlador".

De um modo geral, o controlador vincula o modelo e a visualização (que são as principais características do aplicativo.) No desenvolvimento do Cocoa, pode ser simplista ao ponto em que o controlador é manipulado por meio da GUI do XCode (objetos e ligações do controlador).

A seção "Padrões de Design" do GoF no MVC, citada de maneira vaga:

A tríade de classes MVC é usada para criar interfaces de usuário no Smalltalk-80. O Model é o objeto do aplicativo, o View é sua apresentação na tela e o Controller define a maneira como a interface do usuário reage à entrada do usuário. O MVC dissocia visualizações e modelos estabelecendo um protocolo de assinatura / notificação entre eles. O diagrama a seguir mostra um modelo e três visualizações. Deixamos de lado os controladores por simplicidade.

MVC é tudo sobre UIs. O foco está no modelo e na visualização - definindo e exibindo dados. Observe o "protocolo de inscrição / notificação" - é aqui que o seu controlador entra. Você pode criar todas as visualizações que desejar; desde que sigam o protocolo, você nunca precisará tocar no modelo ou no controlador.

Se você está falando especificamente sobre desenvolvimento web, IMHO muitas estruturas populares da web são rápidas e flexíveis com o termo MVC e suas definições de componentes.

Duque
fonte
Sou desenvolvedor de C # / Java (apenas alguns projetos lá). Parece que eu não entendi o que o modelo faz. Colocar a 'lógica de negócios' no controlador realmente foi apenas um efeito secundário (minha linha de pensamento foi 'ok, eu tenho o modelo de dados (leia-se: conexão / armazenamento de banco de dados), então minha lógica de negócios precisa entrar no controlador porque Eu tenho que aplicá-lo antes de armazenar os dados no banco de dados '. Apenas tenho que mover tudo do nível do controlador para baixo. Na verdade, isso resolve um problema que eu tinha atualmente (suportando MySQL e MSSQL em um programa)
Steffen Winkler
0

Por que você não introduz uma camada de serviço?

Então seu controlador ficará mais enxuto e legível, e todas as suas funções serão ações puras.

Você pode decompor a lógica de negócios o quanto for necessário na camada de serviço. A reutilização do código é melhor e não há impacto nos modelos e repositórios.

Anil
fonte