Dúvida em estrutura em MVC

Para ajudar a clarear um pouco essas questões, cito abaixo um trecho de um livro de Martin Fowler:

Link para o livro do Martin Fowler:
http://books.google.com.br/books?id=vpHqYZcmeKsC&printsec=frontcover&dq=martin+fowler+padr%C3%A3o+de+arquitetura+de+aplica%C3%A7%C3%B5es+corporativas+mvc&hl=pt-BR&sa=X&ei=EN_DT8CnL4P26AGBoITZCg&ved=0CEEQ6AEwAA#v=onepage&q&f=false

No livro Utilizando UML e Padrões, Craig Larman fala sobre um outro tipo de controlador, que fica na camada de domínio ou modelo. É um controlador que possui conceitos de negócio, e pode coordenar diversas classes de negócio. Esse tipo de controlador pode representar um caso de uso ou o sistema como um todo.
Acho que a confusão se deve um pouco à existência de vários tipos de controladores.

Nesse mesmo livro (pág. 322 da 3a. edição), Craig Larman diz que no Processo Unificado e no método Objectory de Jacobson há três tipos de objetos:

  • objetos de fronteira - abstrações das interfaces (por exemplo, classes Swing).
  • objetos de entidade - objetos de domínio (negócio ou modelo) independentes da aplicação e geralmente persistentes.
  • objetos de controle - são tratadores de caso de uso - são os controladores que ficam na camada de domínio, de que falei.

Link para o livro do Craig Larman:
http://books.google.com.br/books?id=ZHtcynS03DIC&printsec=frontcover&hl=pt-BR&source=gbs_ge_summary_r&cad=0#v=onepage&q&f=false

[quote=al.barbosa]No livro Utilizando UML e Padrões, Craig Larman fala sobre um outro tipo de controlador, que fica na camada de domínio ou modelo. É um controlador que possui conceitos de negócio, e pode coordenar diversas classes de negócio. Esse tipo de controlador pode representar um caso de uso ou o sistema como um todo.
Acho que a confusão se deve um pouco à existência de vários tipos de controladores.[/quote]

Provavemente isso é uma tradução imprecisa para o padrão Mediator. A referência que você usou é em inglês?

[quote=ViniGodoy][quote=al.barbosa]No livro Utilizando UML e Padrões, Craig Larman fala sobre um outro tipo de controlador, que fica na camada de domínio ou modelo. É um controlador que possui conceitos de negócio, e pode coordenar diversas classes de negócio. Esse tipo de controlador pode representar um caso de uso ou o sistema como um todo.
Acho que a confusão se deve um pouco à existência de vários tipos de controladores.[/quote]

Provavemente isso é uma tradução imprecisa para o padrão Mediator. A referência que você usou é em inglês?[/quote]

Não, a referência é em Português. Na resposta anterior coloquei o link para a o livro on-line, é o Utilizando UML e Padrões do Craig Larman. Não é o padrão Mediator, da Gangue dos Quatro. O livro apresenta os padrões denominados GRASP (General Responsibility Assignment Software Patterns). São padrões e ao mesmo tempo princípios para atribuir responsabilidades. Alguns deles: Especialista na Informação, Criador, Acoplamento Baixo, Coesão Alta e Controlador. Além deles, o livro ensina alguns padrões da Gangue dos Quatro.

Cito abaixo um trecho do livro que fala sobre os padrões da Gangue dos Quatro:

[quote=Utilizando UML e Padrões - pág. 290]… durante a atividade de desenho (e codificação), aplicamos vários princípios de projeto OO, como GRASP e os padrões de projeto da Gangue dos Quatro (Gang-of-Four - GoF).
[/quote]

Cito abaixo uma explicação do livro sobre o GRASP:

Abaixo a definição do padrão Controlador no livro:

E abaixo a explicação do livro sobre a diferença entre o controlador GRASP e o controlador MVC:

Bom, esse trecho já diz tudo. Que o controller do MVC apenas “controla a interação e o fluxo de página da IU”.
É o que eu e o j0nny estavamos falando. E é por isso que ele quase some em desktop (esse controle é trivialmente feito pela linguagem).

Mas talvez daí suja tanta confusão sobre o papel do controller.

PS: Também gosto muito desse livro. Tenho impresso em casa, e já li de ponta-a-ponta.

Isso. O Martin Fowler diz que Controlador é usado em vários contextos diferentes. Acho que daí surge uma certa confusão.

Gostei muito desde tópico, e me deu a entender que eu estava pensando em MVC de forma errada. Tipo, utilizava o MODEL somente para a comunicação com o banco, e o CONTROLLER usava como a camada de negócios, que acredito que seja a entrada o processamento e saida para view.

Posso estar errado, trabalho com PHP e agora estou estagiando e aprendendo (também) J2EE para web.

Gostaria que alguem me desse um pequeno exemplo de aplicação, ou seja, como funcionaria se eu tivesse por exemplo uma tabela CLIENTES e quisesse mostrar dados do cliente, assim como cadastrar, alterar e excluir.

Posso esta pedindo muito, mas um pequena explicação irá me ajudar a compreender o que eu possa estar ou não fazendo de errado.

Atendendo ao pedido, e para ficar mais claro o padrão MVC, resolvi colocar um exemplo simples de CRUD para Web no padrão MVC.

Estou seguindo a abordagem sugerida no livro Core Servlets e Javaserver Pages, de Marty Hall e Larry Brown, capítulo 15: como integrar servlets e JSP: a arquitetura Modelo Visão Controlador (MVC). Abaixo um link para o livro on-line (este link está em Inglês, tem o livro à venda em Português).

http://www.pdf.coreservlets.com/MVC.pdf

A classe ServletCliente funciona como o controlador MVC.

Os JSP´s funcionam como a view.

Na parte do modelo, utilizo a classe RoteiroCliente. Nessa classe aplico o padrão Roteiro de Transação (Transaction Script) do livro Padrões de Arquitetura de Aplicações Corporativas, de Martin Fowler. Essa é a classe em que coloco as regras de negócio. Neste exemplo as únicas regras de negócio são: o cliente deve ter 18 anos de idade ou mais, e o seu nome não pode ser vazio. Cito abaixo a página 72 do livro do Martin Fowler, que fala sobre a possibilidade de usar Roteiros de Transação como modelo:

Poderia também utilizar uma classe de domínio como modelo - isso seria o padrão Modelo de Domínio citado acima (e o DDD - Domain-Driven Design). Porém o Martin Fowler recomenda utilizar um Mapeador de Dados (para o mapeamento objeto-relacional) ao utilizar um Modelo de Domínio mais rico, ou um Registro Ativo (padrão em que o modelo e o acesso a dados ficam na mesma classe) para domínios simples. Como eu não quis entrar na complexidade do mapeamento objeto-relacional neste exemplo, e queria separar o acesso a dados das regras de negócio, decidi utilizar o Roteiro de Transação.

A classe ClienteTO funciona como um Transfer Objetc, ou Objeto de Transferência de Dados. Esta classe serve apenas para transportar dados entre as camadas - não é propriamente uma classe de negócios.

E utilizo a classe ClienteDAO.java para interagir com o banco de dados. Ela é um Data Access Object. Para o exemplo funcionar, não coloquei um acesso real a banco de dados. Criei uma List na classe para armazenar os dados. Num caso real eu iria colocar o SQL nesta classe. Pode parecer que a classe ClienteDAO tem métodos muito parecidos com a classe RoteiroCliente. Isso acontece porque trata-se de um CRUD simples. A classe RoteiroCliente encapsula a regra de negócio, enquanto ClienteDAO encapsula o acesso a banco de dados. Num caso muito simples, é possível que sejam apenas uma classe - isso seria o padrão Registro Ativo, do livro Arquitetura de Aplicações Corporativas do Martin Fowler, pág. 165.

Segundo o Martin Fowler o valor do MVC está em duas separações:
1 - separar a apresentação do modelo (conforme trecho citado acima)
2 - separar a vista do controlador.

Cito abaixo um trecho em que ele fala sobre a segunda separação (pág. 317):

Por isso eu não acho muito útil o MVC para aplicações Java desktop na maioria dos casos. Porém acho importante a primeira separação: separar a apresentação do modelo - para esse tipo de aplicação.

Abaixo o código do exemplo:

index.jsp

[code]<%@page contentType=“text/html” pageEncoding=“UTF-8”%>

JSP Page

Aplicativo Exemplo CRUD Clientes

Regra de Negócio: um cliente tem que possuir no mínimo 18 anos.

Entrar [/code] listaClientes.jsp

[code]<%@page contentType=“text/html” pageEncoding=“UTF-8”%>
<%@page import=“to.ClienteTO”%>
<jsp:useBean id=“lista”
scope=“request”
class=“java.util.List<to.ClienteTO>”/>
<jsp:useBean id=“erro”
scope=“request”
class=“java.lang.String”/>

Lista

Cadastro de Clientes

Novo Cliente Início <% for(ClienteTO c:lista) { %> <% } %>
Nome Idade Opções
<%=c.getNome()%> <%=c.getIdade()%> Alterar Excluir
<% if(erro != null) { %> <%=erro%> <% } %> [/code]

cliente.jsp

[code]<%@page contentType=“text/html” pageEncoding=“UTF-8”%>
<%@page import=“to.ClienteTO”%>
<jsp:useBean id=“dado”
scope=“request”
class=“to.ClienteTO”/>
<jsp:useBean id=“erro”
scope=“request”
class=“java.lang.String”/>
<%!
String blanknullStr(String s) {
return (s==null) ? “” : s;
}
%>

JSP Page

Cadastro de Clientes

"> Nome*:
Idade*:
<% if(erro != null) { %> <%=erro%> <% } %> [/code]

ServletCliente.java

[code]package servlet;

import java.io.IOException;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import roteiro.RoteiroCliente;
import to.ClienteTO;

/**
*

  • @author calazans
    */
    @WebServlet(name = “ServletCliente”, urlPatterns = {"/ServletCliente"})
    public class ServletCliente extends HttpServlet {

    RoteiroCliente roteiro = new RoteiroCliente();

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    String acao = request.getParameter(“acao”);

     if(acao == null) acao = "listar";
     
     if(acao.equals("listar")){
         listar(request, response);
     } else if(acao.equals("iniciarInclusao")){
         iniciarInclusao(request, response);
     } else if(acao.equals("iniciarAlteracao")){
         iniciarAlteracao(request, response);
     } else if(acao.equals("incluir")){
         incluir(request, response);
     } else if(acao.equals("alterar")){
         alterar(request, response);
     } else if(acao.equals("excluir")){
         excluir(request, response);
     } else {
         listar(request, response);
     }
    

    }

    private void listar(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List lista = roteiro.carregarTodos();
    request.setAttribute(“lista”, lista);
    despacha(request, response, “listaClientes.jsp”);

    }

    private void iniciarInclusao(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    despacha(request, response, “cliente.jsp”);
    }

    private void iniciarAlteracao(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    int codigo = Integer.parseInt(request.getParameter(“codigo”));
    request.setAttribute(“dado”, roteiro.carregarPorCodigo(codigo));
    despacha(request, response, “cliente.jsp”);
    }

    private void incluir(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ClienteTO cliente = new ClienteTO();
    try{
    String nome = request.getParameter(“nome”);
    int idade = parseIdade(request.getParameter(“idade”));
    cliente = new ClienteTO(0, nome, idade );
    roteiro.incluir(cliente);
    listar(request,response);
    }catch(Exception e){
    request.setAttribute(“dado”, cliente);
    request.setAttribute(“erro”, "Ocorreu o seguinte erro: " + e.getMessage());
    despacha(request, response, “cliente.jsp”);
    }
    }

    private void alterar(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    ClienteTO cliente = new ClienteTO();
    try{
    int codigo = Integer.parseInt(request.getParameter(“codigo”));
    String nome = request.getParameter(“nome”);
    int idade = parseIdade(request.getParameter(“idade”));
    cliente = new ClienteTO(codigo, nome, idade );
    roteiro.alterar(cliente);
    listar(request,response);
    }catch(Exception e){
    request.setAttribute(“dado”, cliente);
    request.setAttribute(“erro”, "Ocorreu o seguinte erro: " + e.getMessage());
    despacha(request, response, “cliente.jsp”);
    }
    }

    private void excluir(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    int codigo = Integer.parseInt(request.getParameter(“codigo”));
    try{
    roteiro.excluir(codigo);
    listar(request,response);
    }catch(Exception e){
    request.setAttribute(“erro”, "Ocorreu o seguinte erro: " + e.getMessage());
    List lista = roteiro.carregarTodos();
    request.setAttribute(“lista”, lista);
    despacha(request, response, “listaClientes.jsp”);
    }
    }

    private int parseIdade(String idade) throws Exception{
    try{
    return Integer.parseInt(idade);
    }catch(Exception e){
    throw new Exception(“Campo idade deve ser um valor numerico”);
    }
    }

    private void despacha(HttpServletRequest request, HttpServletResponse response, String pagina)
    throws ServletException, IOException {
    RequestDispatcher rd = request.getRequestDispatcher(pagina);
    rd.forward(request, response);
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    processRequest(request, response);
    }

    @Override
    public String getServletInfo() {
    return “Servlet para Manter Clientes”;
    }
    }[/code]

RoteiroCliente.java

[code]package roteiro;

import dao.ClienteDAO;
import java.util.List;
import to.ClienteTO;

/**
*

  • @author calazans

  • Roteiro de Transação de Cliente
    */
    public class RoteiroCliente {

    private ClienteDAO clienteDAO = new ClienteDAO();

    public void incluir(ClienteTO cliente) throws Exception {
    validar(cliente);
    clienteDAO.incluir(cliente);
    }

    public void alterar(ClienteTO cliente) throws Exception{
    validar(cliente);
    clienteDAO.alterar(cliente);
    }

    public void excluir(int codigo) throws Exception{
    clienteDAO.excluir(codigo);
    }

    public ClienteTO carregarPorCodigo(int codigo){
    return clienteDAO.carregarPorCodigo(codigo);
    }

    public List carregarTodos(){
    return clienteDAO.carregarTodos();
    }

    private void validar(ClienteTO cliente) throws Exception{
    if(cliente.getIdade() < 18){
    throw new Exception(“Idade invalida.”);
    }
    if(cliente.getNome() == null || cliente.getNome().equals("")){
    throw new Exception(“Nome invalido.”);
    }
    }
    }[/code]

ClienteTO.java

[code]package to;

/**
*

  • @author calazans

  • Transfer Object de Cliente
    */
    public class ClienteTO {
    private int codigo;
    private String nome;
    private int idade;

    public ClienteTO(){
    codigo = 0;
    nome = “”;
    idade = 0;
    }

    public ClienteTO(int codigo, String nome, int idade) {
    this.codigo = codigo;
    this.nome = nome;
    this.idade = idade;
    }

    public int getIdade() {
    return idade;
    }

    public String getNome() {
    return nome;
    }

    public int getCodigo() {
    return codigo;
    }

    public void setCodigo(int codigo) {
    this.codigo = codigo;
    }

    @Override
    public boolean equals(Object obj) {
    ClienteTO c = (ClienteTO) obj;
    if(c.getCodigo()==this.getCodigo()) return true;
    else return false;
    }
    }[/code]

ClienteDAO.java

[code]package dao;

import java.util.ArrayList;
import java.util.List;
import to.ClienteTO;

/*

  • To change this template, choose Tools | Templates
  • and open the template in the editor.
    */

/**
*

  • @author calazans

  • Data Access Object de Cliente
    */
    public class ClienteDAO {
    private List listaClientes = new ArrayList();
    public ClienteDAO(){
    listaClientes.add(new ClienteTO(1, “Francisco Paulo Souza”, 31));
    listaClientes.add(new ClienteTO(2, “Maria Joana Souza”, 29));
    listaClientes.add(new ClienteTO(1, “Paulo Franco Silva”, 32));
    }

    public ClienteTO carregarPorCodigo(int codigo){
    for(ClienteTO c:listaClientes){
    if(c.getCodigo()==codigo) return c;
    }
    return null;
    }

    public List carregarTodos(){
    return listaClientes;
    }

    public void incluir(ClienteTO cliente) {
    cliente.setCodigo(novoCodigo());
    listaClientes.add(cliente);
    }

    public void alterar(ClienteTO cliente) throws Exception{
    for(int posicao = 0; posicao<listaClientes.size(); posicao++){
    if(listaClientes.get(posicao).equals(cliente)){
    listaClientes.set(posicao,cliente);
    return;
    }
    }
    throw new Exception(“Cliente nao localizado.”);
    }

    public void excluir(int codigo) throws Exception{
    for(ClienteTO c:listaClientes){
    if(c.getCodigo() == codigo){
    listaClientes.remove©;
    return;
    }
    }
    throw new Exception(“Cliente nao localizado.”);
    }

    private int novoCodigo(){
    int maior = 0;
    for(ClienteTO c:listaClientes){
    maior = c.getCodigo() > maior ? c.getCodigo() : maior;
    }
    return ++maior;
    }
    }[/code]

Anexei um diagrama ilustrando essa arquitetura. O diagrama é apenas para mostrar a estrutura de camadas, não corresponde exatamente aos pacotes java.

Fiz esse projeto no NetBeans. Anexei o projeto.

Concluo dizendo que esta é uma forma de estruturar a arquitetura do sistema. Há várias outras formas possíveis. A arquitetura do sistema tem que ser sempre pensada de acordo com as características do sistema. No livro do Martin Fowler há várias abordagens de camadas, e explicações sobre quando utilizar uma ou outra abordagem. A quem se interessar, coloco o link:

http://books.google.com.br/books?id=vpHqYZcmeKsC&printsec=frontcover&dq=martin+fowler+padr%C3%B5es+arquitetura&hl=pt-BR&sa=X&ei=NCbvT9bQLKPX6gHJ_NSXBg&ved=0CDYQ6AEwAA#v=onepage&q=martin%20fowler%20padr%C3%B5es%20arquitetura&f=false


Obrigado amigo. Irei dar um olhada para bem entender e não mais fazer errado.

:smiley:

Recomendo fortemente tu dar uma estudada sobre DDD (domain driven design) de Eric Evans. Se possível compre o livro pois é muito bom.

Em termos de arquitetura de camadas essa “filosofia” define 4 camadas:

  • UI (interface com usuário)
  • Aplicação (controladores, frameworks, etc…)
  • Domínio (negócio/regras, entidades)
  • Infraestrutura (consumo de serviços de outros sistemas: banco de dados, email, webservices)

o enfoque está na camada de domínio, a qual representa os conceitos do problema, e deve ter o mínimo possível de dependência com outras tecnologias (frameworks, etc) pois no mundo real não existe tecnologia (enviar um email tem o conceito “enviar email” e não “m = new SimpleEmail(); m.set… m.send();”). No livro é descrito várias técnicas para isolamento do negócio, conceitos como VO, Repository, Services, Módulos, Fábricas, Agregadores… (Alguns do GoF com roupa nova :slight_smile: )

Em comparação com o MVC eu vejo o DDD como uma evolução, em termos de conceito. Alguns podem falar que é igual ao MVC com a camada de infra.
Mas se estudar sobre, vai ver que é muito mais profundo, claro, específico e aplicável.

Quanto ao DAO, com uso de ORM (JPA, hibernate, etc…), dependendo da complexidade da aplicação eu vejo desnecessário, mas se for usar, use o conceito de Repository e coloque as implementações na camada de infra, pois o padrão DAO foi criado pra resolver problemas de suporte a multiplos bancos de dados na época que usavamos JDBC.

A vantagem que você verá de imediato é a facilidade de testar sua aplicação, manutenter e evoluir, e irá pensar primeiro no domínio do negócio e depois na solução técnica.

Pra mim também sempre foi na camada model , mas aonde eu trabalhava isso era feito na camada de controller em actions.

Agora mexo com EJB e não utilizo mais DAOs , pois entendo que eles são desnecessários.

O que utilizo são classes de serviços , interfaces que fornecem acesso aos EJBs que por sua vez sim fazem o trabalho de isolar realmente a lógica da aplicação das demais camadas.

No meu model só tem entidades que represetam tabelas do banco.

Acho que conceitualmente é muito organizado e faz divisão clara do MVC.

Como disseram não é errado dizer que é no model , porque no momento em que foi criado isso não era descrito.

Só tem três camadas então vai ser em uma delas MVC , sempre achei errado colocar no controller pq sempre tive a visão que essa camada era de gerenciamente e view de apresentação, então sempre pareceu errado colocar regra de negócios nelas.

Sobrando apenas o MODEL

[quote=fabioFx]Recomendo fortemente tu dar uma estudada sobre DDD (domain driven design) de Eric Evans. Se possível compre o livro pois é muito bom.

Em termos de arquitetura de camadas essa “filosofia” define 4 camadas:

  • UI (interface com usuário)
  • Aplicação (controladores, frameworks, etc…)
  • Domínio (negócio/regras, entidades)
  • Infraestrutura (consumo de serviços de outros sistemas: banco de dados, email, webservices)

o enfoque está na camada de domínio, a qual representa os conceitos do problema, e deve ter o mínimo possível de dependência com outras tecnologias (frameworks, etc) pois no mundo real não existe tecnologia (enviar um email tem o conceito “enviar email” e não “m = new SimpleEmail(); m.set… m.send();”). No livro é descrito várias técnicas para isolamento do negócio, conceitos como VO, Repository, Services, Módulos, Fábricas, Agregadores… (Alguns do GoF com roupa nova :slight_smile: )

Em comparação com o MVC eu vejo o DDD como uma evolução, em termos de conceito. Alguns podem falar que é igual ao MVC com a camada de infra.
Mas se estudar sobre, vai ver que é muito mais profundo, claro, específico e aplicável.

Quanto ao DAO, com uso de ORM (JPA, hibernate, etc…), dependendo da complexidade da aplicação eu vejo desnecessário, mas se for usar, use o conceito de Repository e coloque as implementações na camada de infra, pois o padrão DAO foi criado pra resolver problemas de suporte a multiplos bancos de dados na época que usavamos JDBC.

A vantagem que você verá de imediato é a facilidade de testar sua aplicação, manutenter e evoluir, e irá pensar primeiro no domínio do negócio e depois na solução técnica.

[/quote]

Não confunda MVC com camadas, essa eh uma confusao comum. Mas elas nem passam perto de ser a mesma coisa. Por isso o DDD não é uma evolução do MVC, na verdade ele nada tem a ver com MVC, nem o conceito das camadas logicas (interface, negocios, acesso a dados) ou como na definicao do Evans (interface, aplicacao, negocios, infra) não tem nada a ver com o Model-View-Controller.

Model-View-Controller é um pattern criado para separar a interface com o usuario do resto da aplicacao. View é a interface, Controller uma fina camada separadora e Model é todo o resto incluindo as 387 possíveis camadas mais banco de dados sistema de arquivo, acesso a web service e afins.

[quote=Rodrigo Sasaki]Pra mim o Model era a parte que lidava só com dados, sem regra nenhuma de negócio aplicada (Entidades e DAOs, basicamente).
[/quote]

Também conhecido como modelo anêmico :smiley:

Model -> É composta pelas classes Action, Service e DAO. Cada entidade deve possuir esse trio.
As classes Actions são responsáveis pelo recebimento dos parametros originados na view e pela obtensão da conexao… e as envia à classe Service
As classes Services são as que guardam todas as regras de negócios. Solicitam às classes DAO as listas de dados ou inclusões. exclusões e updates…
As classes DAO fazem somente a parte de persistência, gerando listas de dados ou fazendo inclusões e atualizações…

  • Uma classe Action conversa somente com a classe Service que conversa somente com a classe DAO
    Action <–> Service <–> DAO

obs: Esse formato facilita bastante o uso de transactions, uma vez que a conexão criada na action é enviada por referência a todos os métodos que farão parte da regra de negócios.

View -> É a camada de interface ao usuário
Controller -> Controla as requisições fazendo a comunicação entre a View e a classe Action

Estava lendo um artigo sobre o assunto: http://imasters.com.br/gerencia-de-ti/tendencias/a-evolucao-do-mvc-para-rest

Durante a leitura, pensei comigo: “O cara misturou os conceitos, vai ser massacrado nos comentários”

Para minha surpresa (e tristeza?), a maioria adorou o artigo.

Os únicos que apontaram os erros foram taxados de haters e trolls.

Infelizmente, as vezes funciona mais ser simpático do que ter razão.