View-first vs. MVC – Por que Lift é diferente?


Se você, caro leitor, desenvolve ou já desenvolveu aplicativos Web, deve estar cansado de ver essas três famigeradas letras: MVC, acrônimo de Model-View-Controller.

Se você programa em Java com Struts, sabe muito bem o que é uma Action.

Se você programa em Ruby com Rails, domina os ApplicationControllers.

Se você programa em PHP não tem idéia do que eu estou falando. Brincadeira! (perco o leitor mas não perco a piada).
Se você programa em PHP com CodeIgniter está bastante acostumado com os Controllers.

A arquitetura MVC reina absoluta entre os frameworks Web. Mas vamos lembrar porque é interessante fazer as coisas assim.

MVC e a separação de interesses

E o que essa arquitetura tem de tão fantástica? Ela simplesmente busca manter as coisas separadas. Modelo é modelo, apresentação é apresentação, não vamos bagunçar tudo em um grande bolo-fecal.ASP.
(Se você nunca mexeu em um grande arquivo .ASP de 3000 linhas cheio de HTML entremeado de lógica de negócio – e bugs -, e acha que ‘bolo fecal’ é ofensivo, é porque você tem sorte e não teve que ver essa nojeira!).

Apesar da quantidade de lógica que “vaza” para a camada de apresentação depender do framework que implementa o MVC, do engine de template que é usado e da disciplina do programador, o objetivo do MVC até que foi cumprido com sucesso.

Se você pegar uma aplicação razoavelmente bem feita, usando algum framework MVC poderá ver com clareza todas as classes do modelo, todas as classes que são os controller e todos os arquivos das Views.

De vez em quando, o desenvolvedor pode colocar uma lógica ou outra no template da View. Mas além disso, as coisas estão até que bem separadas.

O Lift ganha pontos aqui porque, ao contrário de PHP, ASP, JSP e outros engines de template, não é possível colocar lógica na View. Uma view em Lift é um simples XHTML e nada mais. É um modelo semelhante ao praticado pelo Apache Wicket.

MVC e uma lógica principal

Vamos pensar aqui, em linhas bem gerais, como é a fluxo de uma Request em um framework MVC:

  1. Chega uma Request para uma URL myApp/myController
  2. O framework mapeia essa URL para algum método do Controller MyController
  3. Esse método faz alguma lógica de negócio, e devolve algo que será no fim das contas a View
  4. A View, com base no estado do Model e do Controller mostra o que tem que mostrar na tela.

Perceba que a request no MVC está atrelada a uma lógica principal, que é basicamente o método invocado no Controller. Vamos tentar exemplificar.

Suponha que eu queira fazer uma tela para listagem de produtos e uma tela para edição de um produto específico. Eu teria as seguintes URLs.

/produtos/listar
/produtos/editar?prod=1234

E meu Controller teria dois métodos, um responsável por montar a tela de listar e o outro pela tela de editar.

Isso até que funciona muito bem, é fácil de fazer e de manter. O problema, é que atualmente, as aplicações Web estão ficando cada vez mais complexas, de modo que uma tela contém inúmeras funcionalidades concomitantes:

Uma tela de listagem de produtos, não apenas lista produtos. Na mesma tela temos uma lista de produtos no meio, um carrinho de compras mostrando o total de produtos na direita, uma lista de produtos sugeridos embaixo, e ainda um chat em tempo real no cantinho.

Já começa ficar complicado orientar nossa aplicação pelo Controller. Se pensarmos que o Controller vai se preocupar com a funcionalidade principal, temos que escolher uma para ele. Se escolhermos a listagem de produtos, quem vai cuidar da renderização das outras funcionalidades?

E ainda por cima, queremos manter nossas classes coesas e nossa View livre de lógica de negócio! Aí complicou.

Lift e a arquitetura “View First”

Foi pensando nesses cenários, muito comuns nas aplicações Web de hoje, que o criador do Lift, David Pollak, resolveu não seguir a abordagem MVC. Ao invés disso ele pensou em uma estratégia que é conhecida no meio como “View First”.

Nessa arquitetura o ponto de acesso de nossas páginas não é o Controller, mas a View. Pense assim, é a View que vai definir o que vai ter na tela e onde essas coisas vão aparecer.

Então cada um desses “blocos de funcionalidade” será mapeado para um Snippet. Cada pedacinho da tela será renderizado por um Snippet diferente, de uma maneira bastante componentizada.

Um Snippet é o equivalente Lift de um Controller, só que no caso é a View quem “chama” o Snippet, e não o contrário.

Vamos ver uma View em Lift, que nada mais é que uma página XHTML:

<!-- Topo -->
<div class="lift:Usuario.boasVindas">
 Bem vindo, <span id="usuarioLogado" />
</div>

<!-- Listagem de produtos -->
<div class="lift:Produtos.lista">
  <ul id="produtos">
    <li id="produtoItem">Produto1 - 9,99</li>
  </ul>
</div>

<!-- Chat Real Time em Comet -->
<div class="chatWindow">
  <div id="mensagens">
    <ul class="lift:comet?type=Chat">
      <li>Line 1</li>
      <li class="clearable">Line 2</li>
      <li class="clearable">Line 3</li>
    </ul>
  </div>
  <form class="lift:Form.ajax">
    <input class="lift:ChatIn" id="chat_in">
    <input type="submit" value="Chat">
  </form>
</div>

Observe que nessa View temos três funcionalidades bem distintas:

  • Um topo com uma mensagem personalizada para o usuário logado, que possivelmente pode ser reaproveitado em todas as telas do sistema.
  • Uma listagem de produtos.
  • Uma janelinha de Chat real-time usando Comet.

Essa View, que poderíamos chamar de /produto/lista.html agora é o ponto de entrada da nossa Request. A partir dessa View serão chamados três diferentes Snippets, cada um responsável por renderizar um pedacinho da View!

O interessante dessa abordagem “View First” é que podemos facilmente criar componentes utilizando os Snippets, e reaproveitá-los em diferentes Views.

Não vou focar muito nos Snippets agora, mas para você, curioso leitor, uma amostra do que poderia ser o Snippet de listagem de Produtos. Note como é sucinto, rápido, prático, bonito, elegante, charmoso, funcional etc etc :

object Produtos {
  def lista = {
    "#produtoItem" #> Produto.findAll.map(p => p.nome + " - " + p.preco)  
  }
}

A ligação com o elemento da view é feito por uma espécie de Seletor CSS. Nesse caso estamos pegando o <li id="produtoItem"> e repetindo para cada produto encontrado no modelo.

Moral da História

Nesse post relembramos um pouco da filosofia MVC e os motivos que levaram a sua concepção e aprendemos um pouco sobre a filosofia “View First” que é um dos fundamentos do framework Lift.

Para os iniciantes em Lift, essa mudança de filosofia pode ser meio estranha, podendo causar um pouco de confusão, desconforto, nojo, náuseas, já que a imensa maioria dos desenvolvedores Web esta bastante acostumada com o MVC.

Minha sugestão é: Faça um teste, brinque um pouco com o Lift para sentir um pouco essa arquitetura.

Você pode acabar gostando.

Anúncios

4 comentários sobre “View-first vs. MVC – Por que Lift é diferente?

  1. A grande sacada do Lift na minha opiniao foi juntar a simplicidade e escalabilidade do modelo orientado a ações, essencia do HTTP, presente no Struts e Rails com a linguagem mais humana do modelo orientado a componentes do JSF. Obvio que com um pouco de código extra dá pra usar a filosofia do View First em outros frameworks como o Struts. Mas acho que o objetivo de um framework é justamente diminuir a quantidade de código. Ponto para o Lift.

    • É, e ponto para o Scala, que permite fazer umas coisas muito legals.

      Outra coisa que eu acho fantástica é poder atrelar os elementos de Forms com Closures. Você consegue capturar o contexto na closure, aí fica tudo muito fácil.

Os comentários estão desativados.