Você tem a sua bela aplicação web clássica de multi-page e deseja mudar para o novo paradigma de single page – SPA.
Vou deixar as razões para usar ou não o “SPA” para outro artigo. Eu estou assumindo que você já tenha se decidido e que já tenha escolhido a sua tecnologia, vamos dizer, AngularJS 1.x ou AngularJS 2.x, mas você ainda está se perguntando:
- Quais as habilidades eu preciso ter na equipe?
- Do que eu deveria estar ciente?
- De onde eu devo começar?
- Qual seria a melhor abordagem?
- Como faço para estimar o tempo necessário?
Eu passei por isso várias vezes, então decidi compartilhar a minha experiência e espero que possa poupar tempo e paciência de alguém.
Treine sua equipe
Se eu tivesse que escolher a coisa mais importante para o sucesso desse processo de migração, diria: treine sua equipe!!
Realmente, eu não posso enfatizar isso o bastante.
Se seu time não está completamente alinhado em relação ao conhecimento e aos processos, isso irá falhar terrivelmente. O conhecimento básico necessário não é apenas sobre AngularJS (ou qualquer outro framework), você precisa ter uma compreensão profunda e sólida de JavaScript.
Aqui está minha lista preferida de recursos que eu costumo propor para minhas equipes e estagiários:
Livros
Conteúdo em vídeo
Pesquise por Angular e JavaScript nesses sites, e você vai encontrar um monte de material incrível.
Eu não vou indicar qualquer formação específica, porque eles continuam a acrescentar mais conteúdo diariamente, então é melhor você simplesmente pesquisar!
Defina uma estratégia
Em tudo o que fazemos, devemos definir uma estratégia, mesmo que seja uma bem básica – algo é sempre melhor do que nada.
Neste caso específico, é muito importante que você não comece a mudar o código em todo o lugar, caso contrário, você vai acabar com uma quantidade descontrolada de regressões e a frustração vai te matar.
Faça as coisas de forma incremental e você será capaz de continuar a adicionar funcionalidades ao seu app enquanto segue com esse processo de migração.
Esse é um ponto de incentivo muito importante quando você precisa fazer essa migração como parte de uma tarefa técnica, e a parte de negócio não vê um valor real sendo acrescentado antecipadamente.
É muito importante que você não pare o fluxo de novas implementações de recursos e continue dando o valor que o product owner solicita mais o aumento de desempenho e as características de usabilidade que um SPA permite.
Claro, há um pouco de um comprometimento aqui, e você não será capaz de colocar muitos recursos no seu sprint, mas não precisa parar completamente.
Aqui é a abordagem que eu gostaria de seguir:
Fase 1: Divida os controladores
Uma boa maneira é manter o paradigma de single-page de lado no início e migrar as views, uma a uma para Angular.
Fazendo dessa maneira, as páginas continuam a ser entregues como de costume pelo lado do servidor, mas todos os elementos dinâmicos serão processados com Angular. O site irá continuar a trabalhar e algumas views serão Angular, outras serão código legado e views alteradas ainda irão disparar uma atualização de página inteira.
MVC no back-end?
Durante este processo, você será “forçado” a limpar seus controladores do lado do servidor e fazer novos que retornem JSON em vez de HTML. Esses serão os endpoints de AJAX do seu serviço angular que irão lidar com todas as solicitações $http. Você irá terminar com um método de controlador para entregar a view HTML e um monte de outros métodos que implementarão o CRUD necessário. Eu aconselho a prefixar todas as rotas CRUD com /api/…, isso irá ajudar a isolar as rotas que retornam JSON daquelas que retornam HTML.
Sem pressão, leve o tempo que precisar. Enquanto isso, novas telas e melhorias que você tem no pipeline devem ser feitos diretamente no Angular.
Sem MVC no back-end?
Se você não estiver usando MVC no back-end, o processo deve ser mais ou menos o mesmo como descrito acima, com a exceção de que você pode querer usar outra tecnologia para lidar com suas requisições AJAX.
Aqui estão algumas opções, dependendo da sua tecnologia do lado do servidor:
A lista continua, e cada plataforma tem várias opções; escolha a sua!
Fase 2: Comece a gerenciar o estado com Angular
Isso vai levar algum tempo para você aprender e depurar.
Basicamente, você precisa mover todo o estado do usuário para Angular, mais especificamente em um service/factory angular que será usado por todos os controladores angular.
É esse mecanismo que permitirá que você mais tarde, usando F5 no navegador, ainda obtenha as informações necessárias de login do usuário e permissões.
Você conseguirá isso através da adição de um controlador ao servidor, no qual você pode fazer uma chamada AJAX e recuperar essas informações.
Fase 3: Adicionar ng-route
Uma vez que todas as views estão convertidas e são capazes de gerir o seu estado, é hora de adicionar o ng-route à mistura.
Não é obrigatório, mas isso deve idealmente ser uma missão única para todas as views. Se todos os itens acima estão concluídos, não irá tomar muito tempo.
O que você precisa fazer aqui é eliminar todos os métodos do controlador que renderizam HTML, deixando apenas aquele que entrega a página principal.
Ao mover todas as suas views de roteamento lógico para Angular deixando apenas as rotas de API no back-end (se você prefixou como eu disse anteriormente, elas serão fáceis de identificar.
Fase 4: A página de login
Com tudo isso, eu nunca mencionei a página de login e foi de propósito.
Você pode deixar isso para o final, porque atualizar a página toda vez que fizer um login/logout será útil para limpar algum JavaScript complicado ou mal escrito que você possa ter.
Mover a página de login para o paradigma single-page significa que você não faz um post de formulário para logar, você irá fazer por requisição ajax e você precisa popular o seu serviço de estado previamente preparado (Fase 2).
Você também tem que limpar essa informação assim que fizer o logout, ou você receberá um 401 a partir do servidor e é redirecionado para a view de login.
A lista de armadilhas
Durante o processo descrito acima, você vai enfrentar uma série de desafios.
Cada vez que eu tinha que fazer esse exercício, eu mantinha uma lista dos problemas que encontrei e como eu os resolvi.
Abaixo você encontrará essa lista. Vou tentar mantê-la atualizada, e você está convidado a enviar uma mensagem se tiver outras experiências que deseja compartilhar.
PF1: Convertendo o arquivo de página JavaScript para um controlador
Claro, você já está usando JavaScript em seu site, então o que você deve fazer com ele?
Se você já usa RequireJS ou qualquer outro mecanismo AMD, então é fácil, porque você já descobriu as suas dependências e encapsulamento.
Cada módulo RequireJS representa um Controller ou uma Factory ou Service no mundo Angular, então tudo que você precisa é mudar um pouco a maneira como você os declara.
Por outro lado, se você não prestar a devida atenção à maneira como você lida com seu JavaScript, então isso vai ser uma tarefa mais difícil.
O tempo que você irá gastar migrando cada página em uma view AngularJS irá depender muito do quão bem estruturado está seu JavaScript atual.
PF2: Quebrando o código em factories
Todo o código reutilizável deveria, ou melhor, deve ser levado para uma Factory ou Directive.
Bons exemplos disso são métodos relacionados a estado ou dados ou códigos para popups que são usados em várias views.
PF3: Pense quando é uma boa ideia dividir funcionalidades em vários módulos
Módulos em AngularJS são uma ótima maneira de encapsular a lógica ou mesmo de abstrair a lógica de negócios que pode mais tarde ser reutilizada em outras aplicações.
Dessa forma, você pode facilmente dissociar dependências e reutilizar o código mais tarde.
Pensar é uma boa ideia, não vai fazer você ficar mais lento e você vai economizar grandes refatorações no futuro.
PF4: Cuidado com conflitos de versão de biblioteca
Me lembro desse problema relacionado ao widget FileUpload baseado no jQueryUI. Estávamos usando esse widget jQueryUI que precisava de uma versão jQueryUI maior do que o resto de nossos controles.
Eu concordo que isso é uma coisa ruim de ter, mas esse era um site legado, e o cliente tinha implementado essa funcionalidade de upload em uma página separada e não queria atualizar as outras páginas.
De repente, estávamos substituindo uma versão do jQueryUI por outra e quebrando todo o site.
Tive um problema semelhante com um outro site, mas foi com o próprio JQuery. Diferentes versões do JQuery estavam sendo carregadas por diferentes componentes.
No mundo multi-page, essa é uma prática ruim, mas dificilmente um problema de ruptura, mas como nós mudamos para single-page, tivemos um conflito porque a página principal nunca muda.
Esteja ciente disso e force uma única versão para os seus componentes em toda a aplicação.
PF5: Eventos JQuery ligados ao documento
Esta é uma boa prática do JQuery que irá fazer você perder algum tempo.
O problema é que, em uma aplicação web multi-page, cada vez que você muda de página, começa do zero.
Em um cenário de single-page, o documento é sempre o mesmo, e os eventos associados a ele permanecerão lá, mesmo quando a view mudar.
Se chegarmos a uma view onde o event binds já está definido, vamos dizer para um clique de um botão, mover para outra página e voltar fará com que os eventos sejam ligados novamente, resultando em vários manipuladores de eventos para o mesmo evento.
Exemplo:
$(document).on('click', '#btnNext', function(){ ... });
Solução:
Use ng-click e manipule seu código no controller. Esse é a modo correto de fazer e deve ser sempre a solução preferida.
Agora pode haver casos em que você deseja apenas adiar a conversão para ng-click, então aqui estão algumas soluções temporárias:
Solução temporária 1: Se o event handler está ligado diretamente ao elemento… faça isso.
Solução temporária 2: Se nós precisamos fazer um delegate event handler, encapsule cada exibição com um div. Mova os event handlers do documento para esse encapsulamento div.
Solução temporária 3: Algumas vezes a mesma view/controller pode ser usada em mais de uma view pai. Um bom exemplo disso são popups, e a solução correta é encapsular em Directives, mas, se por alguma razão complicada no momento você não puder… Nesse caso, não podemos usar o encapsulamento div na view principal, porque ele não é sempre o mesmo, portanto, para esses casos extremos nós removemos o manipulador antes de adicioná-lo novamente:
var gotoNextPage = function(){ /* do your stuff */ }; $(document).off('click', '#btnNext', gotoNextPage); $(document).on('click', '#btnNext', gotoNextPage);
Evite isso e qualquer uma das soluções temporárias acima, se puder.
PF6: Controles/widgets baseados no jQuery serão uma dor no… pescoço
A maioria deles irá deixar de funcionar corretamente, principalmente devido a problemas relacionados a evento. Reserve uma quantidade substancial de tempo para isso, se você usar muitas dessas coisas. Menção honrosa para DatePicker, Dialog, jqGrid…
Um monte de alternativas já existem para a maioria deles, e você verá que encapsulá-los sozinho com uma Directive também não é geralmente uma alternativa ruim.
Portanto, antes de iniciar o processo de migração, identificar todos os seus controles que podem precisar ser trabalhados. Se você trabalhar com eles antes de iniciar uma migração de página, vai se sentir muito mais confiante em estimar o esforço.
PF7: A página de login ainda é uma página separada?
Isso vai exigir uma grande quantidade de refatoração, reescrita e pensamento.
Aqui está uma pequena lista de pontos doloridos:
- Esconder os menus e tudo o mais, enquanto você está na página de login.
- Redirecionar/atualizar corretamente a view quando você fizer login/logout.
- Lidar com as informações da sessão quando você fizer login/logout e pressionar F5: repensar tudo relacionado com os dados da sessão que estavam sendo manipulados do lado do servidor, como informações do usuário, autorização, dados contextuais etc.
- Segurança, algumas views terão que ser solicitadas a partir do servidor, sem validação de segurança: a principal mudança no paradigma será que você realmente precisa parar de se preocupar em esconder páginas do usuário. Sua principal preocupação é proteger os dados, não o HTML, e os dados ainda estão indo e vindo para o servidor; faça a segurança lá!
- Certifique-se de que todo o estado é reconstruído do lado do cliente, se o usuário pressiona F5: isso muitas vezes requer uma chamada AJAX separada para obter a informação extra do usuário com base no cookie que você já tem.
- Mover o código para uma security factory: certifique-se de todo esse código é “agrupado” em uma única factory reutilizável que é compartilhada por todas as views.
PF8: Lentamente comece a se livrar de todos os seletores jQuery
Este é o tipo de fim da linha para mim – quando você tem a view totalmente funcional, mas o jQuery ainda está sendo usado dentro de seus controllers Angular. Aproveite o tempo extra para se livrar deles. Você não deve ter qualquer seletor jQuery dentro de um controller. Ou substituir com as Directives e Services nativos, ou criar o seu próprio.
Coisas como $.ajax({}) ou $(“# mybutton ‘).on(‘click’, function(){}); devem ser banidas do seu código e substituídas por $http e ngClick, respectivamente.
Anotações finais
Eu não estou abordando quaisquer considerações de migração específicas para Angular 2.0, mas, para além das alterações de sintaxe, as considerações gerais permanecem as mesmas.
Este artigo foi baseado em minha experiência pessoal e eu tenho certeza de que muitos outros desafios estão faltando aqui. Se você tiver algo a acrescentar, por favor me escreva e eu ficarei feliz em enriquecer essa base de conhecimento.
Eu sou um colaborador regular do Experts-Exchange e, recentemente, respondi a uma pergunta sobre esse tema.
***
Alexandre Simões faz parte do time de colunistas internacionais do iMasters. A tradução do artigo é feita pela redação iMasters, com autorização do autor, e você pode acompanhar o artigo em inglês no link: http://www.instanceofanobject.com/blog/2015/10/22/from-multi-page-to-single-page.html