O Backbone, na minha opinião, é maravilhoso. Você não precisa mudar a sua forma de pensar JavaScript e de brinde ganha uma arquitetura extremamente minimalista, produtiva e que não pretende mudar os paradigmas que você já conhece sobre o desenvolvimento front-end. Mas como nem tudo são flores, infelizmente, o Backbone possui um defeito: a sua camada de apresentaçãoview.
Na minha opinião, formada ao longo de dois anos de convívio com a tecnologia, ela apenas funciona e nada mais. Basicamente, ela cumpre o seu papel: consome dados e os exibe. E ponto.
Com o tempo, comecei a perceber que às vezes eu carregava as minhas views com alguma lógica — coisa que afeta diretamente a saúde de escalabilidade do aplicativo, afinal, vide o SRP, a ideia é que a camada de apresentação apenas sirva para exibir coisas, mas nunca jamais processar algum tipo de lógica.
Pois bem, aliando a minha paixão por modularização e desacoplamento, decidi, portanto, substituir a minha camada de apresentação nativa do Backbone por algo novo e que, ao que tudo indica, é superior: o React.
Quando se integra React com Backbone, muita gente ainda utiliza a camada de views para renderizar os componentes do React, o que, na minha opinião, é errado. O ideal é que você substitua, de cima para baixo, a camada de apresentação completamente. Em outras palavras, só e somente só React — esqueça Backbone para a apresentação.
Contudo, estudando bastante a interoperabilidade das duas tecnologias, acabei injetando muita responsabilidade para o mecanismo de rotas que o Backbone oferece. Afinal, por quê?
As teclas de um piano são emissoras de eventos!
No site do React, temos a seguinte chamada: JUST THE UI. Em português brasileiro sobre tradução livre, “Apenas a Interface do Usuário”. Isso significa que quando alguém pressionar um botão (o de enviar um formulário de cadastro, por exemplo), o responsável por fazer algo com os dados escritos pelo nosso cliente NÃO É O BOTÃO. A responsabilidade dele é uma só: avisar alguém que o usuário está submetendo aquele formulário.
Pois bem, eis o porquê da imagem do piano: as teclas em si não emitem os sons que ouvimos. Eles [os sons] são produtos de algum mecanismo emissor, desencadeado pela tecla.
Quando eu trouxe o React para o Backbone, abri minha cabeça e passei a trabalhar consistentemente com Event-Driven Progamming. Quando um botão é pressionado, um evento é engatilhado — e agregado! — através do Backbone.Events para que então ele possa ser escutado por uma entidade qualquer…
[…] entidade qualquer […]
Um amissíssimo meu e também adorador do Backbone, o Renan Carvalho, certa vez encontrou uma informação bem importante no Change Log do Backbone:
0.5.0 — July 1, 2011
[…] Controller was renamed to Router, for clarity. […]
Desde que ele me concedeu essa informação, passei a pensar melhor em como eu poderia aproveitar o mecanismo de rotas — e eis a entidade que estava se responsabilizando por ouvir os eventos emitidos por algum componente escrito sobre o React.
Passei a interpretar o “Router” do Backbone como sendo um Controller só que com um nome “alternativo”. Por isso, os listeners do meu Backbone.Events ficavam no método construtor do meu singular arquivo de roteamento — um simples router.js. Na prática, eu tinha isso:
initialize: function () { Backbone.history.start({ pushState: true, hashChange: false, root: '/' }); Backbone.Events.on('form:register:submit', function () { // ... }); Backbone.Events.on('form:register:clear', function () { // ... }); Backbone.Events.on('avatar:upload', function () { // ... }); }
E, entre nós, esta solução resolvia muito bem o meu problema. Até que eu tive um sonho…
Eu estava numa sala toda branca e ouvia à clássica Ode to Joy, do Beethoven. No sonho, comecei a cismar que a solução não era suficiente e então desacoplei de forma inerente a responsabilidade de listening do meu Router para módulos autônomos.
Mas uma vez que a plataforma que o Backbone me oferece consiste em Routing, Presenting e Modelling, quem seria o meu módulo autônomo então? Bom, ele não existe. Até agora…
Graças à parte criativa e funcional que habita o meu cérebro nos momentos de bom sono, a resposta era traduzida em um Controller. Eureca! Este é o meu módulo autônomo!
Quando acordei pela manhã de ontem, procurei no Google por um plug-in que eu já sabia que existia: o Backbone.Controller. Antes de sequer fazer o seu download para implementação, dei uma olhada nos seus recursos e posteriormente no código fonte.
Felizmente ou infelizmente, não me agradou. Uma bazuca para formigas: muita coisa desnecessária. Se eu o usasse, estaria contradizendo uma das razões que tenho para utilizar Backbone, que é o peso leve.
Então, decidi por mim mesmo criar o meu Controller. Criei um novo documento de texto e defini a sintaxe para JavaScript. Esse foi o resultado:
var Controller = { extend: function (obj) { return function (params) { if (obj && obj.initialize) obj.initialize(params); }; } }; module.exports = Controller;
Em suma, o script é simples. Criei um objeto chamado Controller
e injetei nele um método chamado de extend,
que retorna uma function
.
A ideia do método extend
é uma cópia do design das entidades do Backbone, onde initialize()
é o método construtor e somente deve ser invocado caso o mesmo exista.
Para utilização, junto as pastas collections
, models
e components
que compõem o meu aplicativo, eu trouxe à vida a famosa pasta controllers
. Lá, criei um arquivo chamado Controller.js
— com a primeira letra capitalizada pois, por convenção, o seu retorno é um object
— e adicionei a ele o conteúdo acima.
Dentro da mesma pasta, tenho ainda um IndexController.js
, que será instanciado quando o meu Router disser. A sua implementação:
var Controller = require ('./Controller') , MyComponent = require ('../components/MyComponent') , Popup = require ('../components/Popup'); module.exports = Controller.extend({ initialize: function () { this.render(); Backbone.Events.on('popup:open', this.openPopup); }, render: function () { React.render(new MyComponent, $('.app').get(0)); }, openPopup: function () { React.render(new Popup, $('.popup').get(0)); } });
Algumas considerações:
- Para gerenciador de módulos, estou a utilizar o webpack com CommonJS;
- Estou utilizando .JSX para os componentes;
Backbone
eReact
são bibliotecas pré-carregadas para todo/qualquer módulo da minha aplicação. Optei por isso pela recorrência de uso.
E por fim, o Router
vai agora fazer literalmente jus ao seu nome:
var IndexController = require ('./controllers/IndexController'); module.exports = Backbone.Router.extend({ routes: { '(/)': 'index' }, initialize: function () { Backbone.history.start({ pushState: true, hashChange: false, root: '/' }); }, index: function () { new IndexController; } });
Perceberam? Os eventos ficam por conta dos controladores e não mais do roteador. Agora cada controlador é responsável pela lógica dos seus componentes, desacoplando e modularizando ainda mais o aplicativo.
Para a nossa felicidade, o Controller que criamos vai além: a sua aplicabilidade transcende o seu uso por aqui.
Eu o nomeei como Controller, mas tecnicamente ele é abstrato. Isso significa que aquela pequena porção de código que torna o Controller um produto não é restrita. Você pode fazer daquele fragmento o que você quiser — ele é elástico; ele é a manifestação de uma ideia que pode assumir várias formas.
A implementação foi em JavaScript puro e o ganho foi na economia de uso: ele é somente o que precisa ser, sem tirar; sem colocar.
No mais, para desestressar e homenagear a quem participou do meu sonho que me trouxe tantos ganhos, Ode to Joy para vocês!