Category Archives: desenvolvimento de software

webpack

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!

comentario_agradavel

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). :)

IBMS360-1

“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))

componente

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. :)

 

logoJawr

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

Recomendo que você leia meu último post

Repensando micro serviços (microservices)

A questão dos micro serviços ainda me acompanha. Desde a publicação do meu último post sobre o assunto venho recebendo feedback de diversas pessoas além de ter entrado em contato com tantas outras. Com a mente um pouco mais clara (ao menos espero) chegou a hora de expor minhas conclusões correntes sobre o assunto.

A grande questão: é SOA?

soa

A conclusão que cheguei é quase óbvia: sim e com poucas novidades. Alguém que me influenciou fortemente este ponto foi Steve Jones em um dos seus posts (a propósito, excelente blog). Outra fonte muito importante foi o modelo de referência SOA desenvolvido pelo OASIS em 2006 que você pode baixar aqui.

O modelo de referência do OASIS é um documento bastante árido mas que lido com atenção nos fornece um sólido conceitual para entender, de fato, o que é SOA.

O que é SOA?

Citando o modelo de referência do OASIS, SOA seria

(…) um paradigma que visa organizar e usar funcionalidades (capabilities) distribuídas que podem pertencer a distintos donos (ownership domains). Provê uma maneira uniforme de oferecer, descobrir e interagir e usar as funcionalidades visando gerar efeitos no mundo real de forma consistente com as expectativas dos consumidores e de forma mensurável.” (Reference Model for Service Oriented Architecture 1.0, linhas 863-867)

Há um conceitual muito importante (e interessante) neste documento que é importante divulgar aqui. O que é um efeito no mundo real? É o resultado do uso de um serviço por um cliente que gera a alteração no estado compartilhado entre este e seu consumidor e outras entidades que pertençam ao mesmo domínio.

Imagine um sistema de compras online: há mais de um serviço interagindo, como, por exemplo, operador de cartão de crédito, estoque, etc. Ao finalizar uma compra, o estado compartilhado por todos estes participantes será alterado: a conta do comprador terá um valor abatido e o estoque terá sua quantidade reduzida. O mundo se alterou: o estado interno do serviço não faz parte do mundo real (algo interessante para pensar hoje na hora de dormir). Este é o primeiro dos três conceitos fundamentais de SOA neste modelo de referência: efeito.

E o que é um serviço dentro deste conceitual? Segundo o modelo de referência, um serviço seria o mecanismo que permite acessar as funcionalidades (capability) que interessam o consumidor. Momento loop: o que é uma funciondalidae (capability)? É um efeito no mundo real provido por um serviço. O provedor de um serviço deve sempre oferecer duas informações aos interessados em interagir com este:

  • O modelo de dados e comportamento exposto através de sua interface.
  • A informação mínima para que o interessado em seu uso saiba que está usando o serviço certo para suas necessidades.

Estas informações são fundamentais para que o serviço possa ser descoberto. Ainda mais importante: é também interessante que o consumidor do serviço também se apresente, assim torna-se fácil descobrir quem supre a necessidade de quem. Este é o segundo dos três conceitos fundamentais de SOA neste modelo de referência: visibilidade (seção 3.2.1 do modelo de referência).

Finalmente, não faria sentido termos todos estes serviços isolados. Faz-se necessário que estes interajam de alguma maneira. No caso, pode ser tanto como troca de mensagens, como também alterando o estado de um recurso compartilhado (como um banco de dados) ou mesmo através de chamadas HTTP (REST). Para que SOA se consolide, faz-se necessário que o terceiro conceito fundamental se manifeste: interação. 

Há alguns pontos interessantes neste documento. Busque por ESB e você não encontrará menção alguma. É dito apenas que os serviços devam ser visíveis, exatamente como é dito na literatura sobre micro serviços. Outro ponto importante: vemos também que pela mensageria ou REST já teríamos uma interação bem definida. Ainda mais bacana, como no caso dos micro serviços temos um sistema no qual todos já estão por padrão no mesmo domínio, temos efeitos no mundo real o tempo inteiro.

Interessante que se você ler novamente o texto de Martin Fowler e James Lewis sobre micro serviços e logo em seguida o modelo de referência OASIS verá que o primeiro é na realidade uma vesão agradável do segundo.

Então, temos aqui SOA novamente, mas o modo de aplicação é distinto. A principal diferença que vejo é a ausência do ESB e também o fato de os serviços se conhecerem a priori. Como menciono no meu primeiro post sobre o assunto, acredito que conforme o sistema cresça um ESB ou diretório de serviços acabará surgindo novamente, o que pode acabar com o prefixo “micro”.

“Produtos, não projetos” é inviável

product

Outro ponto interessante nesta discussão sobre micro serviços é o conceito de produtos, e nao projetos. A idéia é simples: a equipe seria dividida em funcionalidades. Então eu seria responsável pelo serviço A e você pelo B, e esta seria nossa única responsabilidade. Lindo né? O problema é que não vai funcionar por um motivo bastante simples: você não quer ociosidade entre os seus funcionários.

Devemos ficar inativos enquanto não houver necessidade de alteração em nossos serviços? Ou será que na prática não iriamos simplesmente passear entre os serviços? Acredito que o passeio não é só consequencia, mas também necessidade. Ainda mais se levarmos em consideração que em equipes ágeis o conhecimento do todo se mostra fundamental.

Pode até ser viável em alguns lugares, mas acredito que seja apenas em alguns lugares ou situações nas quais os serviços terão evolução constante e contínua.

SOA pode significar várias coisas? Não.

multiplas_coisas

O artigo de Fowler e Lewis sobre micro serviços depois recebeu um box entitulado “Microservices and SOA” que não irá lhe responder se micro serviços são ou não uma forma de SOA: apenas lhe dirá que há pessoas que dizem que sim e outras que dizem o contrário. O problema é o argumento usado de que  “SOA pode significar várias coisas”. Papo furado.

Ainda pior: se você reconhece que o público possuí dificuldade em saber a definição de algo, por que se esquivar do problema e não simplesmente buscar popularizar o real significado do termo? Dada a imensa literatura existente sobre SOA hoje apontando para o mesmo significado dizer algo assim é falso. A não ser, é claro, que você queira vender o velho como se fosse algo novo, não é mesmo?

(uma das pessoas que comentou o post de Steve Jones sobre SOA e Micro serviços aponta para o fato de que Fowler e Lewis inclusive cometeram uma falácia grave neste ponto. (esta é a falácia))

Digo mais: se quisermos ser levados a sério temos de evitar esta postura. Pouco tempo atrás mencionei um exemplo similar neste blog ao falar sobre tempo real. Indo além, se algo “significa várias coisas” é por que temos na realidade uma classificação e não um objeto disforme. Exemplo: a palavra animal pode significar várias coisas a um distraído, como coelho, cachorro, homem, etc. No entanto, sei que animal é uma classe que contém subdivisões, cada uma destas apontando para um tipo de animal diferente.

O mesmo acredito que ocorra com SOA. Há o conceito fundamental de SOA, aquele apresentado no modelo de referência que citei acima. E há as diferentes formas nas quais este é implementado, o que geraria uma subclassificação. Uma destas classificações provávelmente será a de micro serviços.

Micro serviços são uma reação

A impressão que tenho neste momento é que micro serviços são uma reação ao modo predominante que vimos SOA ser aplicado (usando ESBs). Algo muito similar ao que vimos com a popularização do REST, que era uma resposta aos webservices baseados em SOAP.

É uma maneira de implementar o SOA com menos elementos e de uma forma mais “light” removendo o ESB e tornando os micro serviços.

(perguntei ao Steve Jones se micro serviços podem ser vistos com uma reação ao SOA tradicional. A sua resposta foi bastante interessante e pode ser lida neste link)

 

SOA é para integrar sistemas e micro serviços para integrar componentes de um mesmo sistema? Não.

Em uma discussão muito interessante e rica com um colega sobre o assunto foi levantado o seguinte ponto:

“SOA não é uma arquitetura para desenvolvimento de sistemas mas sim para integração entre sistemas distintos ao contrário de micro serviços que são uma solução para o modo como interagem sistemas de uma mesma aplicação.”

Antes de mais nada é muito importante sempre nos lembrarmos o que o “A” de SOA significa: Arquitetura. Quando estou integrando diferentes sistemas estou na realidade criando e projetando um novo sistema.  A diferença é que os componentes podem não pertencer ao mesmo domínio de propriedade.

Mais que isto: é importante salientar que nem toda integração é SOA. Se integro meu site com o PagSeguro, por exemplo, será que poderia dizer estar eu implementando um SOA? E se eu defino que todos os sistemas da minha empresa irão expor uma API REST, é SOA?

Indo além: observando o modo como SOA é implantado em diversas empresas vemos que estamos na realidade criando um sistema composto por diversos outros sistemas, todos eles pertencentes a um mesmo domínio de posse, ou seja,  à uma mesma empresa. De novo, algo muito similar ao descrito na arquitetura de micro serviços hein? (de novo a mesma coisa)

Então, não: SOA não é apenas uma estratégia de integração, mas sim uma estratégia arquitetural na modelagem de sistemas. Especialmente se formos levar em questão que o analista SOA também faz a análise dos processos de negócios internos do cliente. De novo, olha o projeto de sistemas aí.

ESB é algo maligno? Não.

Em algumas discussões vi emergir a impressão de que ESBs seriam algo maligno. Discordo: o maligno é o mal uso da ferramenta. Aliás, é interessante observar que Fowler e Lewis em seu box “Microservices and SOA” terminam com uma postura nesta direção ao dizerem que “talvez micro serviços sejam SOA feito direito”, baseando-se no fato de terem vistos diversos projetos baseados em ESB fracassarem.

Eles se esqueceram de algo básico: ver uma estratégia fracassando algumas vezes não quer dizer que esta sempre irá falhar, mas sim que temos um indício de que pode ter sido mal aplicada.

Conclusões

Estes foram os principais pontos que enfrentei ao me questionar a respeito dos micro serviços. O mais importante na minha opinião é o reconhecimento de que micro serviços são na realidade uma outra estratégia na aplicação do SOA.

Acredito que pensar de forma distinta, vendo micro serviços como algo completamente distinto equivale a jogar fora anos de experiência na aplicação do SOA. Todo este conhecimento (especialmente a respeito do que não funciona) deveria ser mais valorizado na minha opinião.

Pode ser que eu mude de idéia no futuro. Isto, claro, irá depender muito das opiniões de vocês a este respeito. E você, passada esta semana, o que pensa a respeito dos micro serviços?