Category Archives: desenvolvimento de software

Groovy/Grails, Spring e JavaScript Brasil por dentro – nossa arquitetura de comunidades

Cinco anos atrás escrevi este post descrevendo como era a arquitetura do Grails Brasil (hoje Groovy e Grails Brasil). As coisas caminharam bastante desde então: de um código fonte que tinha como objetivo atender um único site (Grails Brasil), pouco a pouco este evoluiu para que se tornasse uma solução capaz de atender qualquer comunidade.

Ao lançarmos o Spring Brasil demos o primeiro passo no que diz respeito a este objetivo: era essencialmente o código fonte do Grails Brasil com uma série de pequenas modificações (essencialmente a remoção de tudo o que era específico apenas daquele site). Já no caso do JavaScript Brasil demos o passo quase derradeiro: é o mesmo código fonte do Spring Brasil: todas as customizações (especialmente visuais), entretanto, passaram a ser o resultado de mudanças na configuração.

Acho que é interessante contar a história técnica por trás deste projeto (ela descreverá sua arquitetura). Curiosamente, não temos um nome para este código fonte: antes era “Grails Brasil”, hoje o chamamos de “Komunidade” ou o nome do site no qual estamos trabalhando.

A história

O início em PHP

A primeira versão do Grails Brasil veio em 2008 e era na realidade uma instalação do phpBB. Sim, você leu certo: o Grails Brasil era um site escrito em PHP. O criei para aprender Grails e o phpBB era uma solução muito interessante na época: fácil de instalar (fiz isto usando um assistente da Hostnet na hora do almoço) e manter. Além disto, era o que precisávamos na época: um fórum básico.

Esta solução nos atendeu bem por um ano ou dois. A hospedagem era relativamente barata, mas com o tempo foi ficando mais cara por dois motivos:

  • A comunidade cresceu bastante e sempre estávamos superando nosso limite de banda.
  • SPAM quase nos destruindo: gastava uma boa parte do meu dia apagando SPAM do site.

Em um primeiro momento fiz modificações no código do phpBB para reduzir estes problemas. Não tive bons resultados e por um tempo pensei seriamente em matar o projeto.

Segunda fase: primeira versão em Grails

Lá por 2008, 2009 tive meu primeiro contato com servidores cloud que passaram a se mostrar como uma alternativa bem mais viável (plano free tier da AWS pra ser mais preciso). Até então hospedagem Java era ou muito cara (pra mim) ou muito limitada (precisava enviar um WAR para o serviço que oferecia um Tomcat compartilhado, algo muito tosco).

Foi a oportunidade para poder finalmente ter a primeira versão em Grails do site. Dois objetivos me guiaram para esta mudança:

  • Meu custo com hospedagem deveria ser menor.
  • O problema do SPAM deveria ser definitivamente resolvido.

Foi escrita então esta primeira versão do site em Grails (versão 1.3.7, que foi usada até ano passado ou retrasado se não me engano – hoje usamos a versão 3.2.8). Dado que serviços como AWS costumam cobrar por processamento, foi o momento ideal para que eu pudesse otimizar ao máximo meu código (o que me levou a um conhecimento bem mais profundo da linguagem Groovy e da própria JVM).

E nisto foram tomadas uma série de decisões que são refletidas no código até hoje:

  • Dado que já existia uma base de posts vinda do phpBB, e este usa uma sintaxe chamada bbCode no armazenamento dos posts, a próxima versão do site deveria manter esta compatibilidade (até hoje usamos bbCode para escrever os posts).
  • As buscas não deveriam tocar o banco de dados: sendo assim adotamos o Lucene como nosso motor de indexação usado em todas as nossas consultas (já notou como são rápidas?).
  • Dado que meu objetivo era reduzir custos, e minha instância no free tier da AWS tinha 612 Mb de RAM, neste mesmo servidor deveriam ser executados o MySQL e o Tomcat. Logo o sistema poderia consumir, no máximo, 300 Mb de RAM (consome isto até hoje).
  • O site tinha de ser mais rápido que o phpBB (consegui, é ordens de magnitude mais rápido). Logo o que pudesse ser feito assincronamente deveria ser feito desta maneira (por isto e-mails não são enviados na hora, mas sim esporadicamente, assim como atualização de acessos e pontuação dos membros).
  • A esmagadora maioria dos acessos ao site são para simples consulta (10% se registram e menos ainda chegam a postar conteúdo), sendo assim SEO é prioridade (idem a busca).

E assim surgiu o Grails Brasil escrito em  Grails. Uma série de medidas foram tomadas para atingir estes objetivos, todas elas descritas neste antigo post (e as adotamos ainda hoje).

Terceira fase: Spring e JavaScript Brasil

Até 2015 o código do Grails Brasil se manteve essencialmente o mesmo, apenas com pequenas correções. A partir de 2016 começaram mudanças mais significativas.

A primeira delas dizia respeito à atualização do próprio Grails: passamos a usar a versão 3 e, pouco a pouco, fomos migrando até a versão 3.2.8, usada hoje. Por que levou tanto tempo para fazer este upgrade? A versão antiga me atendia muito bem. Uma boa decisão tomada lá atrás? Ter usado pouquíssimos plug-ins, o que tornou o upgrade muito fácil (em questão de horas estávamos na versão 3.0 do Grails). Além disto estava claro que precisávamos atualizar o código fonte para termos algo durável (Java 6??? Bora pro 8!).

Já fazia um tempo que queríamos criar novas comunidades, então era também a hora de podar o código fonte, removendo tudo aquilo que só fazia sentido no Grails Brasil do novo código. Foi ótimo por que conseguimos otimizar ainda mais o que já tínhamos.

(hoje como consequência temos duas bases de código: uma para o Grails Brasil, outra que atende as outras comunidades para que pudéssemos manter as funcionalidades para os membros atuais do site)

Novos objetivos arquiteturais

Modificações do site em tempo de execução

Ao lançar novas versões do site sempre havia momentos nos quais me deparava com pequenos problemas de layout, conteúdo textual ou JavaScript nos quais detectava problemas logo após ter implantado a solução. Aí era necessário gerar um novo WAR e realizar todo o processo de deploy.

Isto ocorria por que sempre havia um ou outro ponto de configuração que ficava no próprio código fonte (o próprio HTML gerado pelo site, por exemplo, pode ser visto desta forma). Hoje todas as configurações encontram-se externalizadas no banco de dados. Com isto, se queremos modificar, por exemplo, o rodapé do site após a versão ter ido pro ar, hoje é possível.

Erros de layout devido a problemas no CSS? Ok, podemos mudar também. Apenas a título de curiosidade, o JavaScript Brasil passou por umas 20 correções de layout de ontem até hoje (23/8/2017). Sabe quantos deploys foram feitos? 1.

Além disto o conteúdo que aparece nas laterais do site, rodapé e cabeçalho também podem ser modificados hoje com o site em execução, o que nos permite trocar anúncios de uma forma muito mais ágil.

Não só isto: configurações de tarefas agendadas, acesso às integrações essenciais (e-mail, redes sociais e no futuro até mesmo a conexão com o SGBD) são hoje trocadas a quente.

Criação rápida de novas comunidades com o mesmo código fonte

O objetivo é que o “Komunidade” seja como o WordPress. Você baixa a distribuição, configura o acesso ao banco de dados, escolhe um tema e voilá, tá criado um novo blog ou, em nosso caso, uma nova comunidade.

A versão atual é exatamente assim. Pegamos o código fonte, definimos a configuração de acesso ao banco de dados, geramos o WAR, criamos um tema, configuramos no banco de dados do projeto os detalhes da comunidade (seu nome, regras de conduta, quais links são expostos, aonde ficam nossos arquivos de template de e-mail e temas visuais e mais uma série de outros detalhes), instalamos no Tomcat e pronto: uma nova comunidade surge.

Levou algo em torno de umas 4 horas para termos uma primeira versão aceitável do JavaScript Brasil (e nós nem sequer tocamos no código fonte do projeto).

Tornar a abertura do código fonte algo viável

Este tem sido o objetivo já faz algum tempo. Infelizmente ainda há informações no código fonte atual que não devem ser publicadas. Este é o principal motivo por que ainda não existe um repositório no GitHub com o código do Komunidade.

Mas posso dizer que o último release não deu mais um passo nesta direção, mas sim um salto quântico. A esmagadora maioria das informações que mencionei acima não existe mais. O objetivo agora é tornar este código fonte o mais fácil possível de ser mantido E entendido por novos colaboradores.

Mais do que tornar o código fonte mais legível, temos de ter uma distribuição do “Komiunidade” que possa ser usada também por não programadores. Algo como o WordPress.

(diga-se de passagem, uma pessoa que não sabe programar é que fez o tema do JavaScript Brasil, absolutamente sozinha)

Também falta melhorar a documentação do projeto: código Grails é muito fácil de ser entendido, mas não é o suficiente (nunca acreditei naquele papo de “meu código é minha documentação”).

Então, aos que sempre me pedem acesso ao código fonte o que posso dizer neste momento é isto: será eventualmente aberto, mas de uma forma correta e em grande estilo, não por pressão.

O futuro

Lá em cima mencionei que hoje temos duas bases de código: “Grails Brasil” e “Komunidade”, certo? Isto é temporário pois o objetivo é ter apenas uma. Mas como fazer isto se no código do Grails Basil há tanta coisa que só faz sentido nele?

Já estou trabalhando em uma arquitetura de plug-ins para este projeto (WordPress sempre é  inspiração). Sendo assim, tudo aquilo que era específico do Grails Brasil será transformado em um pequeno módulo, que possa ser instalado em uma instância do “Komunidade”.

Com isto é possível ter seções distintas em instalações separadas do Komunidade. É possível, por exemplo, termos uma seção em uma instalação do site que seja na realidade um plug-in. O core será bastante diminuto, e a seu redor os plug-ins orbitarão: tal como ocorre no Eclipse, Netbeans e, claro, no WordPress também.

No que diz respeito ao frontend, ainda temos receio a respeito de uma grande mudança, tal como a adoção de um framework JavaScript ainda tenho algum receio pois um dos nossos objetivos é ter código duradouro e, sinceramente, ainda hoje não vi soluções que tenham passado no teste do tempo (com exceção do jQuery talvez).

E enquanto isto vamos evoluindo pouco a pouco o código que temos. Esta é a história do projeto até agora, grandes novidades virão em breve como sempre. Espero que tenham gostado.

E se inscrevam no Spring Brasil e JavaScript Brasil, pois o principal objetivo por trás dos dois projetos é criar discussões bem acaloradas sobre estes temas!

Acabo de publicar mais um guia: Usando Webpack

Acabei de publicar mais um guia pela Itexto: “Usando Webpack”. Este trabalho surgiu como um dos resultados das nossas pesquisas internas envolvendo o ferramental front-end (o próximo a ser publicado será sobre o npm).

Ao começar o estudo a respeito do vue-loader, algo que sempre me pareceu bastante complexo foi o Webpack, que é um module bundler baseado em Node.js (se você conhece Grails, pense em um “asset pipeline para HTML 5”). Não há como negar, o Webpack tem lá sua curva de aprendizado: por isto escrevi o guia com o objetivo de facilitar a adoção da ferramenta pela nossa equipe e, agora, vocês também.

Como todo guia da Itexto, este será um trabalho inacabado e totalmente aberto. Iremos evoluir o material conforme nossa experiência com ele progride e, dado que toda opinião é bem vinda, seu código fonte está totalmente disponibilizado no Github caso alguém mais queira dar sua contribuição.

É um guia escrito por um sujeito que pensa mais no back-end que n o front-end, sendo assim, espero que seja útil para você caso se encaixe neste perfil. :)

Você pode acessar o guia neste link: http://www.itexto.com.br/guias/?guia=usando-webpack

Espero que lhes seja útil!

Quando o comentário realmente documenta o código

Como alguém que lida com muito código fonte que não é de minha autoria, neste post vou listar algumas dicas para tornar seus comentários no código realmente úteis. São hábitos simples que, se bem seguidos, tornam a vida de quem manterá aquele sistema mais fácil e, portanto, aumentam a produtividade de toda a equipe.

Naturalmente, não irei incluir aqui todas as dicas possíveis, razão pela qual no final deste post irei citar algumas boas dicas de leitura sobre este assunto.

Não vou falar do óbvio: “o comentário deve dizer o que aquele método ou classe faz” ou “comentar o óbvio é bobagem” ou “comente apenas o necessário” pois, convenhamos, é chover no molhado ou mero “preenchimento de linguiça”.

Tudo é história

Todo software é gerado dentro de um contexto: a situação da equipe no momento em que foi criado, quem o escreveu, assim como seus conhecimentos naquela época, quais as tecnologias estavam em voga, etc.

Conhecer este contexto é muito importante para compreender as razões pelas quais o código se encontra em sua situação atual. Infelizmente, na esmagadora maioria das vezes em que encontramos o código pela primeira vez só temos conhecimento do seu estado atual se ignorarmos seu histórico no sistema de controle de versões (seja sincero, quantas vezes já percorreu aquele histórico ao ter seu primeiro contato com uma base de código pré-existente?).

Lidando com o passado – reconstruindo o histórico perdido

 

Comentários podem ajudar e muito aqui. Neste momento entra a primeira dica: use um sistema de controle de issues e replique informações deste sistema nos seus comentários. Como fazer isto? Basta mencionar o número da issue em seu comentário. Seguem alguns exemplos:


/*
Classe responsável pelo envio de e-mails no sistema /* (isto é óbvio) */
Issue na qual se encontra documentado o requisito que deu origem ao
requisito: http://meusistemadeissues/issue/825
*/
class EmissorEmail {

É bastante simples: com isto seus comentários não ficam imensos e quem estiver dando manutenção no sistema poderá entender melhor o contexto no qual aquele código foi criado. Um excelente local para se incluir este tipo de comentários é em código no qual você esteja corrigindo um bug, tal como no exemplo abaixo:

int diasEntreDatas(Date dataInicial, Date dataFinal) {
/*
Havia um erro no código abaixo que não considerava sábados e domingos,
gerando resultados inválidos.
Issue: http://seusistemadeversoes/issue/847
Alterado por Henrique Lobo - 1/3/2016 - 14:20
*/
}

Entra a segunda dica: assine seus comentários. Com isto, caso alguém encontre problemas no código que você alterou, poderá lhe procurar para obter maiores informações a respeito daquela situação que, talvez, não se encontrem documentadas no seu sistema de issues ou qualquer outra fonte de documentação.

Mais do que assinar os comentários, creio que também seja muito importante incluir a data e hora no mesmo. Isto contribuí para entender o contexto histórico daquela alteração e muitas vezes agiliza ao extremo a compreensão do problema e aplicação da solução. Esta portanto é minha terceira dica: date seus comentários.

Três dicas simples relacionadas ao histórico que, se aplicadas em conjunto, facilitarão demais a vida de todos:

  • Use um sistema de issues e o referencie em seus comentários
  • Assine seus comentários para que as pessoas possam lhe procurar (quem não tem culpa no cartório não se esconde)
  • Sempre inclua uma data nos seus comentários para saber quando a alteração foi realizada

Lidando com o passado recente

Há também aquelas situações nas quais você fez uma alteração no código mas não se sente 100% seguro a seu respeito, mesmo que tenha escrito testes para validar o comportamento esperado. É normal e te entendo perfeitamente. Nestes casos, não há problema algum em deixar comentada a versão anterior do código apenas para comparação com o que você fez, tal como no exemplo a seguir:


int soma(int x, int y) {
return x + y;
/*
Acho a versão anterior pura frescura, por isto substituí pela
minha alterantiva melhor otimizada e que não usa ifs!
Issue: http://www.meusistemadeissues.com/issue/13
Henrique Lobo - 2/2/2012 - 13:13
return (x > Integer.MAX_VALUE || y > Integer.MAX_VALUE) ? -1 : x + y;
*/
}

Lidando com o futuro (usando lembretes)

Muitas vezes a pressão do dia a dia faz com que precisemos incluir débitos técnicos em nossos sistemas. É normal: no futuro você vai resolver estas questões (se se lembrar delas).

A maior parte das IDEs hoje, além de sistemas de análise estática de código como o SonarQube oferecem suporte a um tipo especial de comentário: o “TODO”. Nunca o viu? É simples: vamos a um exemplo rápido e completamente fora da realidade.


boolean autenticar(String login, String senha) {

/*
TODO: meu gerente me obrigou a isto para o release 1.0.0 do sistema
Henrique Lobo - 12/3/2004 12:00
Issue: http://www.meusistemadeissues.com.br/issues/666
*/
if (login == "dede") {
return true;
}
}

Comentários do tipo TODO mostram pontos a serem melhorados no sistema. Na imagem abaixo podemos ver um exemplo do uso deste tipo de comentário no Eclipse (práticamente todas as IDEs possuem este recurso atualmente):

todo_eclipse

Mesmo que você não se lembre de ter feito o que estava no comentário, alguém do futuro saberá a respeito e poderá fazer algo a respeito.

Refatorando comentários?

Se você usa um sistema de controle de issues e assina e data seus comentários, passado algum tempo você talvez precise refatorá-los. Como assim?

De duas maneiras: você pode excluir aqueles comentários que envolvam código antigo (pois o tempo já mostrou que as alterações realizadas funcionaram) ou você pode simplesmente remover aqueles comentários que não agregam coisa alguma.

Resumindo: de tempos em tempos é uma boa prática apagar os comentários inúteis. Lembre que você tem o sistema de controle de versões e nele já está presente todo o histórico de alterações.

Não divulgue segredos

Parece estranho o que vou dizer, mas seu comentário pode expor segredos relativos à sua empresa ou contratante. Apesar de ter mencionado no início deste post que não iria mencionar o óbvio, me assusta a quantidade de informações sigilosas que programadores publicam em seus comentários. Alguns exemplos:

  • Credenciais de acesso a serviços ou servidores
  • “Recados” a outros membros da equipe – “Kico, resolva isto depois, ok?”
  • Críticas ao empregador ou outros membros da equipe
  • Críticas à natureza do próprio código fonte (isto você documenta como débito técnico no sistema de issues normalmente)

Quer um bom exemplo histórico? Algum tempo atrás vazou o código fonte do Windows 2000. Que tal ler o que a mídia da época comentou a respeito?

Lembre que remover commits do sistema de controle de versões não é uma tarefa trivial.

Boas leituras

Há dois livros muito bons que possuem capítulos dedicados aos comentários em código fonte:

Code Complete – Steve McConnell – Editora Microsoft (diga-se de passagem, o melhor livro que já li sobre programação em geral, leitura obrigatória) – Traduzido para o português pela editora Bookman

Clean Code – Robert C. Martin – Editora Prentice Hall – Traduzido para o português pela editora Alta Books

As duas traduções são muito boas e ambos são leitura obrigatória apesar da minha preferência pelo primeiro.

Concluindo

Não creio naquela história de que “a documentação do meu sistema é meu código”, no entanto, se for o caso, pelo menos bons comentários irão lhe ajudar na manutenção futura deste sistema.

Sobre minhas críticas ao “código como única documentação”, provávelmente será meu próximo post neste blog (ou quando encontrar uma forma mais polida de lidar com este assunto). :)

“Legado” é um termo maldito

O termo “legado”, quando aplicado a software sempre me incomodou: tanto que algum tempo atrás busquei uma melhor definição para esta palavra dentro do nosso contexto de TI. Hoje volto ao assunto para dizer que não uso mais a palavra “legado” com meus clientes e colegas e explico minhas razões.

O termo que todo mundo busca a definição (inclusive eu)

Fui um dos palestrantes da trilha de legados da QCon Rio 2015 e, para minha sorte (ou azar), fui o último a falar, o que me permitiu assistir a todas as apresentações sobre o assunto. O que achei interessante é que quase todos (inclusive eu) apresentaram seu próprio conceito de legado.

(e neste texto ainda apresento mais definições sobre legado, o que mostra ser um fenômeno global, e não uma particularidade daquele evento)

Claramente há algo errado aqui: se dentro de um contexto bem definido (ou ao menos aparentemente) há tantas definições para uma mesma palavra, surgem duas possibilidades:

a) A palavra não possuí um significado real
b) Devíamos ou categorizar este termo ou mesmo buscar outras palavras

A  má impressão criada pela nossa indústria

Diversas vezes um cliente chega para nós pedindo que executemos manutenções ou evolução em seus sistemas com frases do tipo: “temos este sistema legado, que me disseram ser velho e ultrapassado, mas não tenho dinheiro para reescrever do zero”.

Lendo o código fonte observo que foram usadas tecnologias como Spring BootGrailsPHP, JavaScript, JSF ou qualquer outra que é ativamente desenvolvida hoje. Pior ainda: o sistema tem no máximo 5 anos de idade. Não poderia ser categorizado como “velho”, e levando-se em conta que normalmente está em uso, muito menos “ultrapassado” ou “obsoleto”, pois claramente está satisfazendo objetivos de negócio ali.

Fato é que muitas consultorias e profissionais normalmente ao invés de venderem a evolução do sistema preferem a reescrita por dizerem dar menos trabalho e sair mais barato (o que normalmente  é uma grande mentira e ainda escreverei sobre isto, mas enquanto isto, pode ler este excelente texto do Joel Spolsky).

A situação é ainda pior: já vi apresentações sobre “legados” na qual o palestrante usa o termo “evolução” e apresenta uma completa reescrita como resultado (atualmente uma das formas que esta reescrita vêm disfarçada é como micro-serviços).

Resultado: o termo “legado”, que deveria ter uma conotação positiva (conhecimento e experiência adquirida ao longo do tempo, conquista, satisfação por ter construído algo que é passado pra frente) passa a ser visto por muitos como um defeito.

(não creio que a maior parte dos profissionais e consultorias que vendam a reescrita imediata sejam mal intencionados. Na minha opinião o problema surge da nossa formação. Um dia ainda escreverei sobre isto)

Que termo uso agora

O mais óbvio e tedioso:  “software que você já tem” ou “software pré-existente” ou, ainda “software que não escrevi” ou algo similar pelas seguintes razões:

a) O cliente (que é quem realmente importa) entende o que estou dizendo imediatamente
b) Muitos clientes nunca ouviram o termo “legado”, o que evita a necessidade de explicar uma palavra que creio ser tão mal empregada em nosso idioma
c) Me fornece (e à indústria) um ponto inicial que possibilite uma melhor criação de sub-categorias que auxiliam na definição de estratégias

Sobre categorização

O termo “software que você já tem” é elementar: não consigo pensar em uma categoria superior a este (“software”, talvez :D) , mas consigo pensar em “tipos de software que você tem”. Segue uma pequena lista:

  • Aquele que temos o código fonte
  • Aquele que não temos o código fonte (sim, acontece e muito)
  • Aquele que é parte de sua infraestrutura (SGBD, Sistema Operacional, protocolos de rede)
  • Ou outra categorização qualquer que represente o nível de posse do cliente sobre um software

E esta categorização nos ajuda a pensar melhor o “seu software“. Ao analisar a situação do cliente (a mais importante), a comunicação fica mais simples e direta. É curioso que nas apresentações que vejo sobre legados só escuto sobre a primeira categoria: “aquele que temos o código fonte”. Aonde ele é executado? Como é o ambiente que o rodeia?

(é interessante notar que as pessoas confundem “legado” e refatoração, e esta é minha prinicpal crítica ao livro do Feathers – legado não é só o código)

A partir do momento em que um termo mais simples é usado na conversa, tudo flui, impressionante.

Minha antiga definição de “legado” não era uma definição

Ano passado busquei uma definição de legado e eis a que cheguei:

Sistema legado é aquele cujo controle foi perdido por seus principais stakeholders. – Definição Lobo Weissmanniana

Leia atentamente o que acabei de escrever: isto é uma definição? Hoje creio que não, pois não defini um termo, mas sim o problema fundamental do seu software.

O que é legado? Em português (e pensando no contexto brasileiro) é um termo que causa mais confusão que o necessário, haja visto os pontos que expus. Sendo assim, não irei mais me preocupar com a sua definição ou mesmo seu uso.

(ainda escrevo sobre um possível hype envolvendo este assunto (hype este que não se desenvolverá de forma saudável devido às falhas em nossa formação que comentei em parênteses anteriores))

Minimizando a necessidade do deploy em aplicações web monolíticas

O fato de termos uma aplicação monolítica não implica na necessidade de executarmos o procedimento de deploy (implantação) a cada pequena alteração. Neste post vou expor algumas técnicas simples e complexas que poderão lhe ajudar a atingir este objetivo.

Como exemplo vou usar o Grails Brasil, pois a esmagadora maioria das técnicas que aqui serão expostas são aplicadas neste projeto, que recentemente tem passado por importantes mudanças conforme evoluímos sua arquitetura.

HTML que pode ser externalizado deve ser externalizado

Em portais como o Grails Brasil é comum termos elementos da página que precisamos alterar com frequência, tal como exposto na imagem abaixo (me desculpem pela grosseria gráfica):

areas_html

Além de áreas como estas, é também necessário incluir trechos que sempre são alterados como, por exemplo, scripts de acompanhamento de tráfego como Google Analytics, propagandas, códigos de identificação do site ou mesmo trechos JavaScript que precisamos alterar com frequência.

São pequenos conteúdos que tornam o procedimento de implantação (por mais automatizado e lindo que seja) demasiadamente caro quando precisamos alterar apenas aqueles pontos.

A solução que adotamos consiste em externalizar estes conteúdos em um repositório centralizado que pode ser desde uma pasta no servidor, um bucket no serviço S3 da AWS, uma tabela em um banco de dados ou qualquer outra tecnologia de armazenamento que nos permita alterar este conteúdo de forma rápida e cômoda sem a necessidade de acionarmos o procedimento de implantação.

Claro que a solução não termina aí. Há casos nos quais o acesso a este repositório é lento, comprometendo o desempenho do site. Como resolver esta situação? Simples: cacheamos este conteúdo. Como mantemos o cache atualizado? Definindo uma data de expiração ou uma URL de limpeza que é acionada por usuários autorizados quando este conteúdo é alterado.

(o mesmo princípio pode ser aplicado a imagens, arquivos CSS e código JavaScript)

Links expostos no menu de navegação

É comum termos em nossos menus de navegação links que apontem para outros sites. No caso do Grails Brasil ocasionalmente precisamos incluir ou remover estes links, tal como ocorre quando, por exemplo, a itexto lança algum treinamento.

Novamente a mesma técnica se aplica: os menus são mais um item de configuração em nosso banco de dados. Conforme incluímos ou removemos registros neste repositório, menus surgem ou desaparecem do site.

Atualmente o link que leva ao blog do Grails Brasil é exposto usando exatamente esta funcionalidade, tal como pode ser visto na imagem abaixo:

menu_grails_brasil

Scripts (linguagens embarcadas)

Se sua arquitetura for bem definida, conforme o tempo passa o núcleo do sistema vai se tornando cada vez mais estável e, com isto, a necessidade de alteração do mesmo diminui significativamente. É o que ocorreu com o Grails Brasil: hoje todo o núcleo do sistema, que é essencialmente o seu mecanismo de processamento de postagens (cases, perguntas e notícias) não requer mais modificações (a última foi feita uns dois anos atrás).

No entanto ocasionalmente ocorre a necessidade de adicionar comportamentos ao redor deste núcleo. Por exemplo: ao finalizar a postagem de uma notícia publicar o evento em alguma rede social. Ao invés de modificar o código fonte do sistema hoje, o que fazemos é disparar eventos específicos para eventos bem definidos no sistema.

Com isto, o evento “postar notícia” dispara o script “disparo_noticia”, que publica algo em uma rede social ou envia um e-mail para alguém. É necessário desativar o envio deste e-mail? Fácil: trocamos o script com a aplicação executando e não precisamos nos preocupar com uma nova implantação.

Este é apenas um exemplo do uso de scripts. Já falei bastante a respeito deste assunto no meu canal do YouTube conforme você pode ver nesta playlist do meu canal.

Plug-ins

Scripts são uma solução excelente quando queremos lidar com eventos, mas e quando precisamos trocar uma regra de negócio ou mesmo adicionar novos módulos ao sistema com ele em execução?

Uma alternativa fascinante e que estamos explorando para uma futura versão do Grails Brasil é a adoção de plug-ins. A ideia é relativamente simples mas muito difícil de ser implementada: novas funcionalidades para o seu sistema são encapsuladas em módulos carregados em tempo de execução pelo seu programa, tal como ocorre o tempo inteiro com sua IDE favorita.

Imagine que em um futuro próximo seja de nosso interesse adicionar um módulo de cadastro de vagas no Grails Brasil (está planejado). Há dois caminhos: podemos incorporar este novo código à base já existente ou implementar um plug-in que seria instalado no servidor. No momento em que este fosse ativado um novo link seria exposto na barra de navegação do site e os usuários teriam acesso a esta nova funcionalidade.

Deu algum problema neste novo módulo (algo extremamente comum em novas funcionalidades)? Fácil: trocamos o plug-in em tempo de execução. É um dos principais ganhos que tanto se fala por aí em arquiteturas baseadas em micro-serviços. A diferença é que você pode ter isto hoje sem eles.

Hoje vejo dois caminhos nesta direção:

  • OSGi – te permite construir estes módulos no formato de bundles, que são carregados dinamicamente pela sua aplicação sem a necessidade desta ser reiniciada. É uma tecnologia maravilhosa e muito madura (existe desde 1999) mas que infelizmente não vemos ser muito divulgada ultimamente.
  • Implementar a sua própria plataforma de plug-ins. É um procedimento extremamente trabalhoso, sendo assim requer uma analise muito bem feita a respeito do custo de construção e implementação.

(há um terceiro caminho também que seria o projeto Jigsaw, mas não tenho o acompanhado já faz algum tempo)

Data sources configurados via JNDI

Outro recurso importante e muitas vezes negligenciado. Se você disponibilizar à sua aplicação a fonte de dados via JNDI, não é necessário (dependendo do seu servidor de aplicação) reiniciar sua aplicação caso, por exemplo, você precise alterar a configuração do pool de conexões ou mesmo trocar completamente de banco de dados.

JNDI não é apenas para data sources

É importante lembrar que JNDI não é usado apenas para se obter um data source. Na realidade, qualquer tipo de objeto pode ser disponibilizado via JNDI. Sendo assim não é difícil imaginar uma arquitetura na qual plug-ins que representem regras de negócio ou mesmo módulos sejam disponibilizados pelo servidor de aplicação através desta interface.

Nunca fiz isto, mas já ouvi algumas experiências positivas nesta direção. É um procedimento raro mas não inviável.

Conclusões

Mostrei neste post algumas técnicas interessantes que possibilitam ao arquiteto projetar soluções nas quais a necessidade de executarmos o procedimento de implantação pode ser extremamente reduzida. Vão desde soluções simples como a externalização de recursos estáticos (HTML, JavaScript, imagens, CSS), passando pela adoção de scripts usando linguagens embarcáveis como Groovy, chegando a soluções mais complexas como a implementação de uma arquitetura de plug-ins e, finalmente, expondo um uso pouco conhecido do JNDI.

Em todas as soluções o problema a ser solucionado é o mesmo: componentização. Se você quer minimizar a necessidade de uma implantação, o foco deve ser no projeto de soluções que tenham um modelo de componente bem definido. Tendo isto, a implantação se torna um evento raro.

(lembrando que componente pode não ser código executável, tal como exemplificado no caso dos recursos estáticos externalizáveis exposto neste post)

Nosso foco atual no projeto “Grails Brasil” é chegar ao momento em que a implantação se torne algo extremamente raro. Ironicamente para chegar a este resultado temos executado implantações diárias nas quais pouco a pouco vamos incorporando nossa própria arquitetura de plug-ins que queremos tornar pública em breve. :)

 

Modularizando JavaScript com Spring MVC e Jawr

javascript-logoEste post inicia uma série na qual vou expor técnicas que visam aumentar a manutenibilidade de código Javascript. Convenhamos: é uma linguagem de programação legal, porém muitas vezes o hype que a envolve nos impede de ver seus aspectos negativos. Neste post tratarei de uma das cicatrizes da linguagem que é a dificuldade que enfrentamos na modularização do código.

O problema: modularizar JavaScript usando Spring MVC

Se você tem a sorte de trabalhar com Grails tem à sua disposição uma solução maravilhosa que é o plugin resources que nos permite definir “módulos Javascript”. Infelizmente do lado Spring da cerca não temos algo tão popular. O que é um módulo Javascript?

Uma unidade de código que funciona em conjunto.

Muitas vezes esta unidade não é apenas um arquivo, mas vários, e é neste ponto que o problema começa a se manifestar. Imagine um módulo composto por dois arquivos: biblioteca.jsbiblioteca2.js. Sua equipe pode ter achado interessante dividi-lo em dois arquivos para paralelizar o esforço e com isto evitar todos aqueles incômodos relacionados ao merge de arquivos. Nesta situação, toda vez que você precisa usar este módulo, irá inserir em suas páginas código similar ao exposto a seguir:


<script type="text/javascript" src="/resources/js/biblioteca.js"></script>
<script type="text/javascript" src="/resources/js/biblioteca2.js"></script>

Ou então você poderia ter algum script que unisse os dois arquivos. O problema é que seria necessário modificar o seu processo de build e também fornecer garantias de que o arquivo gerado fosse sempre o mais atualizado possível (não é uma solução tãão bacana assim).

Agora, voltemos ao nosso exemplo. Imagine que este nosso módulo dependa do jQuery. Neste caso teríamos sempre de escrever o seguinte código em nossas páginas:


<!-- jQuery sempre irá ser carregado primeiro -->
<script type="text/javascript" src="/resources/js/jQuery.js"></script>
<script type="text/javascript" src="/resources/js/biblioteca.js"></script>
</span><script type="text/javascript" src="/resources/js/biblioteca2.js"></script>

Ainda pior: imagine que a ordem de carregamento dos arquivos biblioteca.jsbiblioteca2.js seja importante. Agora sua equipe precisa ser informada a respeito. Se for uma aplicação de uma única página, não será lá um grande problema, mas imagine uma aplicação maior, com mais de um template, etc. A coisa começa a se complicar.

A imagem a seguir expõe bem a situação do nosso projeto. Temos uma biblioteca composta por dois arquivos que depende de uma terceira:

jawr_dependencias

Não seria bacana se houvesse uma ferramenta que nos permitisse resolver os problemas a seguir de uma forma simples?

  • Documentar as dependências entre os nossos arquivos Javascript de tal forma que seja fácil para a equipe entender a organização interna do projeto.
  • Garantir que os arquivos sejam sempre carregados na ordem correta.
  • De alguma maneira otimizar o modo como estes arquivos são enviados ao browser: compressão via gzip, talvez até mesmo um merge dos arquivos.

Jawr entra em cena

logoJawr

Jawr é uma ferramenta que tem como objetivo resolver os três problemas que expus acima e mais alguns. Neste post irei tratar de uma parte bem pequena deste projeto: aquela que lida com Javascript. A grosso modo Jawr é um servlet que iremos inserir em nosso projeto fictício. Este servlet organizará nossos módulos Javascript em bundles.

O que é um bundle? É um módulo, tal como expus acima. Mais do que isto, um bundle alguns atributos fundamentais do nosso módulo:

  • Que arquivos compõem o nosso módulo
  • Em que ordem estes arquivos devem ser carregados
  • Quais as dependências do nosso bundle, isto é, que código este precisa para funcionar?

Voltando ao nosso projeto percebe-se que há dois bundles: biblioteca e jQuery, que podemos representar gráficamente tal como na imagem a seguir:

Nossos bundles

Nossos bundles

Poderíamos pensar em um bundle único composto pelos nossos arquivos da biblioteca e o do jQuery. O problema é que sabemos que jQuery será usado por diversos outros pontos da nossa aplicação: sendo assim é interessante que modularizemos esta parte a fim de que seja reaproveitada em outras partes do projeto.

Incluindo Jawr em nosso projeto

Nosso projeto é baseado em Maven. Sendo assim, para incluirmos o Jawr basta adicionar a dependência no arquivo pom.xml tal como no exemplo a seguir:

<dependency>
    <groupId>net.jawr</groupId>
    <artifactId>jawr</artifactId>
    <version>3.3.3</version>
</dependency>

Como disse logo acima, Jawr é essencialmente um servlet. Sendo assim temos também de alterar o arquivo web.xml para que fique similar ao exposto a seguir:

<!-- Servlet para lidar com Javascript -->
<servlet>
   <servlet-name>JavascriptServlet</servlet-name>
   <servlet-class>net.jawr.web.servlet.JawrServlet</servlet-class>

		<!-- Aonde se encontra o arquivo de configuracao -->
   <init-param>
       <param-name>configLocation</param-name>
       <param-value>/jawrJavascript.properties</param-value>
   </init-param>
   <init-param>
       <param-name>mapping</param-name>
       <param-value>/bundle/js/</param-value>
   </init-param>
   <load-on-startup>1</load-on-startup>
</servlet>
<!-- O mapeamento de URL -->	
<servlet-mapping>
   <servlet-name>JavascriptServlet</servlet-name>
   <url-pattern>/bundle/js/*</url-pattern>
</servlet-mapping>

Preste muita atenção no mapeamento de URL. Na documentação oficial do Jawr este é configurado para que lide com todos os recursos que terminem com a extensão .js. O problema com esta abordagem é que muitas vezes não queremos que todos os nossos arquivos Javascript sejam carregados como bundles. Talvez você queira ir adotando aos poucos a ferramenta em seu projeto (esta é a principal razão que vejo). Em nosso caso, Jawr só irá lidar com aqueles recursos Javascript que se encontrem na url /bundle/js/*. Nota importante: repare no parametro de inicialização mapping. Se for usar uma configuração como esta, este obrigatóriamente deve estar definido.

Configurando os bundles

No mapeamento do servlet foi incluído um parâmetro chamado configLocation. Em nosso projeto baseado em Maven este arquivo se encontra em /src/main/resources/jawrJavascript.properties. É neste arquivo que iremos definir todos os nossos bundles. Abaixo está um exemplo deste arquivo:

# Altere aqui caso esteja no seu ambiente de desenvolvimento
jawr.debug.on=false

# Devemos enviar os bundles compactados?
jawr.gzip.on=true

# De quantos em quantos segundos o servlet deve verificar se as configuracoes foram
# alteradas. Extreammente util em tempo de desenvolvimento!
jawr.config.reload.interval=30

# Primeiro bundle de exemplo: jQuery
# O identificador do bundle sempre é o que aparece antes do ‘.id’
# neste caso, é jquery
jawr.js.bundle.jquery.id=/bundle/js/jQuery.js
jawr.js.bundle.jquery.mappings=/resources/js/jquery-2.1.0.min.js

# Incluindo uma dependencia
jawr.js.bundle.biblioteca.id=/bundle/js/biblioteca.js
jawr.js.bundle.biblioteca.mappings=/resources/js/biblioteca.js, /resources/js/biblioteca2.js
jawr.js.bundle.biblioteca.dependencies=jquery

Um bundle Javascript é definido no arquivo com o prefixo jawr.js.bundle.[identificador do bundle]. A primeira linha, que termina com .id define como será a URL que define o nosso bundle. O bundle jQuery, por exemplo, sempre será carregado quando a URL /bundle/js/jQuery.js for acionada, enquanto o bundle biblioteca, pela URL /bundle/js/biblioteca.js.

Voltemos nossa atenção para o bundle biblioteca. A segunda linha da sua definição (mappings), define quais os arquivos que o compõe e a ordem na qual devem ser carregados. A terceira linha define quais as suas dependências. Neste caso, apenas uma: o bundle jquery.

Tendo feito isto temos todos os bundles em nosso projeto prontos para serem usados. O próximo passo é trabalhar no arquivo JSP.

Alterando o arquivo JSP

O projeto Jawr vem com uma biblioteca de tags bastante útil. Abaixo podemos ver um exemplo de sua aplicação:

<%– A declaração da biblioteca de tags –%>
<%@ taglib uri="http://jawr.net/tags" prefix="jwr" %>

<%– Carregando o bundle biblioteca –%>
<jwr:script src="/bundle/js/biblioteca.js"/>

E o que ocorre quando carrego a página? Obtenho o resultado a seguir:

<script type="text/javascript" src="/itexto/bundle/js/gzip_N1063700552/bundle/js/jQuery.js" ></script>
<script type="text/javascript" src="/itexto/bundle/js/gzip_N745101183/bundle/js/biblioteca.js" ></script>

Primeiro será inserida a dependência do bundle biblioteca e, em seguida, o código fonte do bundle biblioteca. Repare nas URLs: o Jawr irá automáticamente cachear os recursos Javascript. E sabem o que é mais legal? Ele também envia o Javascript comprimido (se o modo de depuração estiver desativado (veja as notas no arquivo que expus acima)). E não é só o conteúdo Javascript comprimido. Os dois arquivos que compõem o módulo biblioteca também são mesclados em um só, diminuindo assim o número de requisições necessárias. Simples assim. :)

Concluindo

Nese post apresentei uma pequena parte do projeto Jawr. Há mais neste servlet, que também pode ser usado para gerenciar recursos CSS e imagens. É importante salienar que a documentação do projeto é excelente: bem escrita e fácil de ser consultada.

Claro que a questão da modularização não termina aqui. Esta é apenas uma das soluções possíveis. Recentemente topei com um ebook online (e gratuito) chamado Writing Modular JavaScript with AMD, CommonJS & ES Harmony que trata da questão de uma forma muito mais profunda. Entra aí também o modo como escrevemos JavaScript (que não tratei neste post) e alguns outros pontos sobre os quais pretendo escrever mais a respeito em um futuro próximo.

O código fonte deste post pode ser acessado no meu GitHub: https://github.com/loboweissmann/jawr-testes