MVC: a essência e a web

Artigo que discorre sobre a essência do MVC e suas adaptações para a realidade Web.

Introdução

MVC é o acrônimo para "Model View Controller" (Modelo Visão Controlador), uma importante e conhecida estratégia para implementação de sistemas computacionais baseada na separação de responsabilidades. Ele foi criado por Trygve Reenskaug, no final dos anos 70 e foi amplamente utilizado até os dias de hoje, com diversas adaptações. Atualmente, boa parte dos frameworks PHP são estruturados para utilizar MVC ou pelo menos dar suporte para este padrão. Na verdade, muitos dizem ser MVC, mas, na verdade, usam uma variação do mesmo.

Embora a utilização básica seja muito simples de entender, sempre tive vários questionamentos durante a utilização prática deste padrão. Lendo um pouco de sua essência e sobre algumas de suas variações, algumas coisas ficaram ainda mais confusas e, realmente, não entendo porque alguns frameworks Web tomaram um certo rumo e não outro. Resumindo: não acho que o MVC seja a melhor estratégia para o ambiente web.

Neste artigo, vou compartilhar um pouco deste meu estudo, apresentar algumas referências sobre o assunto e alguns pontos de vistas pessoais. Espero que você, leitor(a), também possa expressar seus pontos de vista nos comentários para trocarmos experiências.

A essência do MVC

Para começar a investigar o MVC, nada melhor que ir até a sua essência: o MVC concebido por seu pai, Trygve Reenskaug. Encontrei alguns artigos sobre o MVC original, que podem lhe interessar. Uma curiosidade é que inicialmente o padrão se chamava Model View Controller Editor, embora o "Editor" não tivesse tanta importância quanto os demais agentes.

Segundo as próprias palavras de Trygve, a essência do MVC era servir de ponte entre o modelo mental do usuário e o seu respectivo modelo computacional, que é a representação do modelo mental humano em elementos computacionais. Ou seja, o propósito era fazer com que o usuário sentisse e interagisse com o modelo computacional imaginando que o modelo real estivesse sendo alterado como gostaria, como uma metáfora. Esta estrutura ainda seria útil para representar o modelo de formas diferentes, de acordo com o contexto, ou sob diferentes pontos de vista.

Ponte entre o modelo mental e o modelo computacional definido pelo MVC

Este padrão foi concebido para ser genérico o suficiente para ser de propósito geral, e especialmente útil para o desenvolvimento de sistemas envolvendo um volume de dados grande e complexo. Ele serviria como uma "extensão do modelo mental humano".

Primeiramente, vamos ver um resumo e curiosidades de cada elemento do tripé MVC, segundo a publicação de 10/12/1979:

  • Model: representam conhecimento. É uma representação de uma abstração na forma de dados computacionais (normalmente bytes).
  • View: é uma representação visual do modelo. Várias views podem representar o mesmo model, cada uma priorizando determinado conjunto de atributos, por exemplo. A view recupera informações do model realizando "perguntas" a ele. A view pode, inclusive, atualizar o model, mandando as mensagens apropriadas. E a view precisa conhecer a semântica de cada informação devolvida pelo model.
  • Controller: é uma ligação entre o usuário e o sistema. Ele arranja as views na tela. Ele provê formas do usuário se manifestar, através de apresentação de menus ou outros elementos. Ele recebe a interação do usuário, traduz ela e passa a diante (para o model ou view).

Com esta especificação inicial, nota-se afirmações estranhas para muitos, tais como "a view poder atualizar o model" ou "o controller apresentar menus". Além disso, cada elemento deste MVC não pode ser visto como uma "camada". Isso porque quando se pensa em camada, se imagina que uma está sobre a outra, formando uma pilha e, portanto, uma determinada camada só pode se comunicar com aquela que está imediatamente acima ou abaixo de si. No MVC original o Model é atômico e não se comunica com ninguém, embora precise oferecer respostas para as views que precisam representá-lo; a View pode se comunicar com o Model, perguntando coisas; e o Controller pode ser comunicar com o Model e com a View, informando interações do usuário.

Algo que eu acho que ficou faltando explicar melhor sobre o MVC original é que um sistema é composto por modelos que representam elementos do mundo real (por exemplo, pessoas, aulas, produtos, etc.) e elementos exclusivamente do mundo computacional (por exemplo, menu de opções de uma aplicação, conexão com banco de dados, título do documento HTML, etc). Como é que eles se encaixam? Por exemplo, para mostrar o menu da aplicação, devemos criar um model que representa o menu e depois uma view que renderiza este model? Como encaixar uma camada de layout/template adequadamente, sendo que podem existir interações vindas de elementos gerados pelo layout? Enfim, várias coisas não foram bem explicadas.

O padrão MVC usado no ambiente Web

O padrão MVC foi concebido inicialmente para aplicações desktop, em que o model poderia ficar na memória RAM enquanto o usuário interagia com ele. Em determinado momento, o usuário poderia realizar operações para persistir este model em um dispositivo de armazenamento persistente, como um HD. Com o surgimento da Web e os sistemas dinâmicos para web, resolveram adaptar alguns conceitos consagrados usados para desenvolver aplicações desktop, e um deles foi o MVC.

O grande problema, é que o ambiente web é transacional, baseado em troca de pacotes HTTP entre cliente e servidor. Ou seja, o model não fica mais na memória RAM do computador do usuário como no sistema desktop, ele fica temporariamente na memória RAM do servidor, até gerar o pacote HTTP que será entregue ao usuário. Assim que o usuário realiza outra requisição, o model normalmente precisa ser recriado. É possível que o model fique na memória RAM do servidor, porém, isso normalmente é inviável, pois o ambiente web prevê que diversos usuários simultâneos estarão acessando o sistema e, como isso, é mais viável o consumo moderado de recursos de hardware do servidor.

O ambiente web essencialmente provê uma interface de acesso do usuário a um recurso. Isso é feito através de uma URL, logo, um cliente do ambiente web também consegue, teoricamente, acessar duas páginas distintas simultaneamente. No MVC, guardamos o "status" da aplicação (por exemplo, "o usuário está na tela de edição da sua senha e em nenhum outro lugar", ou "a janela de editar senha está aberta"), mas no ambiente web, ou precisaríamos de múltiplos status ou então não utilizar este conceito. O que quero dizer é que, se formos seguir tudo que foi idealizado pelo MVC para desktop no ambiente web, estaremos criando um sistema desktop que utiliza a internet como meio de acesso. Só que a internet é diferente!

A web possui uma arquitetura diferente e características de acesso diferentes. Por isso, acho que os exemplos dados pelo MVC para desktop não devem ser considerados, embora sua essência possa ser analisada.

O que tenho notado nos frameworks MVC de PHP (voltados para desenvolvimento web) é o seguinte:

  • Model: são as classes que representam entidades (que podem ser persistidas em bancos de dados ou não) e suas respectivas regras de negócio.
  • View: são arquivos essencialmente HTML com pequenos trechos dinâmicos para exibir estruturas de dados vindas do model ou do controller. Também podem existir classes "Helper", que ajudam a criar alguns elementos comuns em documentos HTML.
  • Controller: são classes que identificam que usuário acessou um link, submeteu dados por um formulário, ou que o navegador realizou uma requisição direta via Ajax ou similar. Estas classes decidem o que fazer com a requisição, manipulando models, escolhendo a view adequada e solicitando a renderização da mesma para gerar um documento HTML (ou outro tipo de arquivo) para ser devolvido pelo pacote HTTP.

Variações do MVC

Tenho visto vários frameworks e programadores dizer que a view não pode acessar diretamente o model. Pesquisando um pouco, constatei que esta é, na verdade, uma adaptação do MVC chamada MVA (Model View Adapter). O "Adapter" é um controller intermediador entre o Model e a View. Ou seja, tanto Model quanto View não interagem com ninguém, o "Adapter" se comunica com os dois e, se necessário, transfere os dados do model para a view.

Outra variação muito comum é o PAC (Presentation Abstraction Control). A diferença é que o PAC é formado por uma estrutura hierárquica de agentes e, cada agente, possui o trio de "Presentation" (para renderização), "Abtraction" (para regras de negócio) e "Control" (para controlar as interações). Os elementos "Control" são os únicos que podem realizar comunicações entre os agentes. Além disso, o elemento de renderização não acessa diretamente o modelo. Uma outra variação parecida com o PAC é o Hierarchical model–view–controller.

Lendo o artigo The Model View Controller pattern in web applications, ainda fui apresentado ao MMVC (Model Model View Controller), que achei bastante interessante pois especifica dois tipos de Model: um para as regras de negócio do domínio da aplicação (Domain Model) e outro exclusivamente para as regras de negócio relacionadas à aplicação (Application Model). Assim, a View só pode acessar o Application Model que, por sua vez, pode acessar o Domain Model (mas o contrário não deve ser possível). Isso enxuga seu controller e torna o seu Domain Model mais viável para testes unitários.

Algo importante para se destacar é que MVC não te obriga a utilizar classes. De fato, usar classes torna sua aplicação mais "elegante", mas abusar de classes torna a aplicação mais lenta e, em muitos casos, para coisas banais. Esta é também a opinião do criador do PHP (Rasmus Lerdorf) sobre o assunto, que você pode conferir no artigo The no-framework PHP MVC framework.

Alguns outros links interessantes:

Opinião do Autor

Bom, na minha opinião, MVC para Web gera uma pancada de arquivos e muito trabalho. Claro que esta característica é proposital e também tem benefícios, caso a arquitetura esteja adequadamente estruturada. Mas acho que a web é muito singular para que se utilize algo feito para desktop e que foi "adaptado para web".

Para mim, o importante é separar: (i) elementos de acesso a dados (comunicação com o BD); (ii) elementos com regras de negócio de cada entidade da aplicação; (iii) elementos exclusivos para renderização. Ou seja, o meu problema com o MVC para Web é justamente com o Controller. Em algumas situações vejo malabarismos no código-fonte só para não quebrar as regras do MVC. E não estou falando de fazer gambiarras, mas saber que o MVC deve ser usado para ajudar e não para prejudicar.

Durante este meu estudo sobre a essência do MVC, acabei me deparando com um conceito que eu não conhecia até então, que é o DCI (Data Context Interaction), que é uma abordagem bastante interessante de encarar a implementação de casos de usos em aplicações. Mas isso é assunto para outro post.

3 comentários

Diego Figueiró Dias disse...

Como tudo por ai, o MVC tem suas vantagens e desvantagens. Eu implementei um framework baseado em MVC simples e a vantagem maior que eu vi nele e também em outros é a modularidade, onde posso colocar em um controller as páginas relacionadas a uma determinada funcionalidade, tipo um cadastro de reuniões que fiz, onde em um controller faço todas as operações de inserção, consulta e atualização através dele, cada operação dividida em actions diferentes, o que me facilita encontrar um problema e entender o sistema melhor depois ou também expandir as funcionalidades mantendo um certo contexto no código.

Eu entendo o controller muito como o meio de campo de um time de futebol, onde ele recebe coisas da view, passa para o model, que pode ou não repassar para uma view, por exemplo, distribuindo as coisas, centralizando e descentralizando, de certa forma. Existem outras formas de conseguir isso, mas vi no MVC uma forma elegante de fazer.

Sobre a carga de classes e a perda de desempenho que podem ocasionar, isso é um assunto polêmico, tem gente que defende que perder algum desempenho mas ganhar em simplicidade na manutenção e no entendimento do código é melhor, outros não, mas no final é ver o que é mais adequado a cada caso e se a perda é realmente significativa.

Usar MVC é uma forma de manter organização no código, usado com moderação ainda acho uma alternativa muito boa. E o bom é justamente isso, a gente não está preso no conceito formal da coisa, sempre pode-se usar como base e criar algo mais adequado.

Rubens Takiguti Ribeiro (autor do blog) disse...

Diego, obrigado pelo seu comentário.

Você tocou num ponto interessante e que eu até esqueci de citar no artigo: a modularidade. Bom, na verdade o MVC original não falava nada de "módulos", nem de "múltiplos controllers com um front-controller" e nem do conceito de "action". Estes, provavelmente foram adaptações para a web.

A divisão em módulos (cada um com um conjunto de controllers) não é exclusividade do MVC, mas é algo muito útil para escalabilidade.

Eu conheço este conceito de action como você citou (agrupando actions relacionadas no mesmo controller, pois manipulam a mesma entidade ou algo do gênero). Por exemplo: um controller "Usuario" ter as actions "inserir", "alterar", "excluir", etc.

Mas o conceito de actions, pra mim, deveria ser outro. Pra mim, um controller no ambiente web deveria ser responsável apenas pela execução de um caso de uso. O agrupamento deve ser feito a nível de módulos e sub-módulos. Por exemplo: módulo "Usuario", e os controllers "Inserir", "Alterar", "Excluir", etc. E as actions seriam as operações realizadas dentro de cada controller. No caso do controller "Inserir", consideraríamos o evento "POST" como uma action.

Por que isso? Porque assim você não carrega vários métodos que não serão usados ao carregar um controller para realizar um caso de uso.

Ou então, a implementação da action (da forma como normalmente é vista) deveria ser implementada fora do controller e não como um método do mesmo.

Cezar Luiz disse...

Oi Rubens, a pouco conheci seu blog e achei muito boa a qualidade dos artigos.

Minha experiência com o MVC é da seguinte maneira, eu acabei adaptando - acredito eu - um modelo para minha necessidade.

MVC + REST onde eu tenho as rotas, que faz a comunicação com o Controller, este com o Model, muito da lógica as vezes fica na Rota, que ela por sua vez envia os dados para a View.

Foi algo que eu achei bem produtivo, estou gostando desse "MVC + Rest".

Pode ver mais no meu github, estou utilizando para meu TCC.

http://github.com/CezarLuiz0/tcc

Obrigado.