Category Archives: Java

Java é simples: você que burocratiza seus projetos

Sempre me incomodou bastante toda esta história de que Java é uma linguagem verbosa e sistemas feitos nesta são complexos. Então resolvi escrever este post pra mostrar alguns erros cometidos por desenvolvedores que, realmente, tornam não a linguagem verbosa, mas sim seus projetos verdadeiras máquinas “burrocráticas”.

Este é um primeiro post sobre alguns erros que encontro: é capaz de surgirem outros em um futuro próximo.

Pra quê interfaces?

Este é um ponto que fica muito claro quando você programa algum tempo em plataformas como Grails, Ruby on Rails ou Node.js e, em seguida, pega um projeto de revitalização de legados feitos em Java. Lemos em diversos livros ou palestras o seguinte princípio:

“Programe para uma interface, não para uma implementação”

O princípio está corretíssimo, mas a pergunta fundamental que o motiva não é feita: pra quê preciso de uma interface? Respondo: para representar uma abstração, ou seja, aquilo que é essencial no serviço e compartilhado por todas as suas diferentes implementações.

Portanto, se só existe uma implementação de uma classe no sistema por que você precisa criar uma interface? Não há o que abstrair daí.

Dica um: crie interfaces apenas se existir mais de uma implementação do serviço cuja funcionalidade você deseja abstrair.

DAOs desnecessários quando se está usando um ORM

É outro erro que encontro com frequência: imagine que seu sistema possua doze classes de domínio, todas elas persistidas contra uma mesma base de dados (relacional ou não). Um padrão comum que observo é a geração abusiva de objetos e classes no sistema:

  • Uma interface para representar o DAO para cada entidade.
  • A implementação do DAO para aquela interface
  • Todos os DAOs são executados contra a mesma base de dados
  • O DAO expõe algumas consultas, mas estas em sua esmagadora maioria (quando não todas) são usadas por uma única classe do sistema..

Levando em consideração que o papel do DAO é acessar e escrever dados em um repositório de dados, e existe uma ferramenta chamada ORM, acho interessante levantar sempre algumas perguntas:

  • Dentro de um futuro próximo você se vê trocando seu SGBD por alguma tecnologia ou fornecedor completamente diferentes?
  • Seu projeto precisa lidar com diferentes tipos de persistência de acordo com o ambiente no qual é implantado?
  • Se você usa um ORM (como Hibernate, EclipseLink ou JPA) para todas estas classes de domínio, e todas são persistidas contra o mesmo repositório de dados, realmente preciso ter implementados N DAOs apenas para persistir o estado destas?
  • Se só há uma implementação do DAO, preciso realmente de uma interface?
  • As consultas expostas por seu DAO são usadas por mais de um componente do sistema?

Minha sugestão aqui é simples: os ORMs já nos oferecem um DAO genérico por padrão (pense no Entity Manager do JPA): tire proveito disto. É exatamente o que Grails faz e, como vejo há quase uma década, funciona muito bem! Nós não escrevemos DAOs em Grails: nossos serviços usam apenas as consultas que realmente precisam e, quando há uma consulta compartilhada, a expomos ao restante do sistema através de uma função.

Se você tem um serviço responsável por gerenciar a lógica de negócio que envolve uma ou mais classes de domínio, e também possuí um ORM que já lida bem com o processo de persistência, pra quê ficar criando DAOs que expõem consultas usadas por um único ponto do sistema para todo o resto?

Solução simples: escreva seu serviço com um conjunto de métodos públicos bem definido que exponha aos clientes do mesmo apenas o que deve ser visto (isto se chama encapsulamento). Se ele precisa interagir com o banco de dados, use este DAO genérico fornecido pelo ORM internamente em seu serviço e evite com isto criar uma série de componentes que apenas irão aumentar a quantidade de código que você precisará gerenciar no futuro.

Concluindo

Neste post expus apenas duas situações que vejo repetidas vezes em projetos Java e que podem facilmente ser evitadas. Entendo perfeitamente o que motiva a ocorrência destes erros: você quer fazer bem feito mas não refletiu a respeito das boas práticas que muito provavelmente lhe foram impostas e não apresentadas.

_ Ah… mas e se no futuro meu sistema precisar de…
_ Bom: se você sabe o que vai ocorrer, você não tem um “e se”, mas sim um “vai”, então aplique.
_ Mas o futuro é imprevisível, preciso me preparar para ele.
_ Bacana: que então você tenha uma base de código menos complexa pra poder se adaptar mais rápido a ele.

Armas secretas: AWK

AWK é uma “arma secreta“: faz parte daquele conjunto de ferramentas que sempre estiveram ao seu lado (surge em 1977 e quase toda distribuição Linux a inclui), você a ignora durante toda a sua vida e em um belo dia resolve experimentá-la. É o momento em que aquele sentimento de “ENTÃO QUER DIZER QUE SOFRI TODOS ESTES ANOS A TOA???” aparece. :)

O que é AWK?

Trata-se de uma linguagem de programação cujo nome vêm das iniciais dos seus criadores (Alfred Aho, Peter Weinberger e Brian Kernighan – galerinha bruta) e nos permite escrever programas que tenham como fonte de dados arquivos texto. O mais impressionante é que você consegue resultados incríveis com pouquíssimas linhas de código.

É uma excelente ferramenta quando desejamos extrair inteligência de arquivos texto, especialmente logs. Sei que esta descrição é muito ruim, sendo assim, que tal irmos direto ao código?

Exemplo real: log de acesso do /dev/All

Sempre que alguém acessa o /dev/All é incluída uma linha em um arquivo de log nos informando a data, hora, IP do visitante e página visitada tal como no exemplo a seguir:

03/06/2015 10:20:00 186.213.73.169 http://www.devall.com.br
03/06/2015 10:20:01 34.13.3.69 http://www.devall.com.br
03/06/2015 10:20:20 186.213.73.169 http://www.devall.com.br
04/06/2015 10:20 186.213.73.169 http://www.devall.com.br/blog/info/3

Se quisermos saber quantos acessos tivemos por dia fica fácil pensar em um programa: dado que o caractere de espaço separa estes quatro campos basta escrever um parser simples na minha linguagem favorita e voilá: crio um acumulador para cada dia lendo o arquivo do início ao fim.

Mas e se eu te disser que consigo o mesmo efeito com apenas uma linha de AWK?

{contador[$1]++} END {for (j in contador) print j, contador[j]}

E como eu uso isto?

cat acessos.log | awk '{contador[$1]++} END {for (j in contador) print j, contador[j]}'

Gerando a saída:

03/06/2015 3
04/06/2015 1

Parece até mágica: agora vamos dissecar este código.

Entendendo o AWK

A sintaxe da linguagem é composta por dois elementos fundamentais: uma condição referente à linha corrente do arquivo sendo lido e o que deve ser executado caso esta condição seja satisfeita. Podemos resumir a sintaxe ao código abaixo:

condição {ações a serem executadas}

No nosso código temos claramente duas condições. Vamos à primeira:

{contador[$1]++}

Não há uma condição estabelecida, sendo assim o bloco entre chaves sempre será executado a cada linha lida. O código é tão simples que assusta: criamos uma tabela de hash cuja chave corresponda ao primeiro campo do arquivo.

Campo? Sim: por padrão AWK interpreta o caractere de espaço como um separador de campos. “$1” representa o primeiro campo (data), “$2” o segundo (hora) e por aí vai. Ao aplicar o operador “++” em meu hash, AWK automaticamente o interpreta como um valor numérico e o incrementa.

Ao final da leitura do arquivo temos uma tabela de hash tal como a exposta a seguir:

 ["03/06/2015" => 3, "04/06/2015" => 1] 

Note que não precisamos declarar nossas variáveis antes de usá-las, o que nos gera um código muito mais simples. Agora vamos à segunda condição:

 END { for (j in contador) print j, contador[j]} 

AWK possuí algumas variáveis e condições embutidas. Dentre estas encontra-se “END”: uma condição que é satisfeita apenas quando chegamos ao final do arquivo. E o que fazemos quando isto ocorre? Geramos um relatório de saída ao nosso usuário final.

Apenas iteramos sobre as chaves presentes em nossa tabela de hash usando a estrutura de controle “for” e, para cada uma destas, iremos imprimir seu valor, seguido do número de acessos que fomos incrementando a cada linha do arquivo.

Outro exemplo: validando arquivos

Alguns anos atrás precisei interagir com um sistema que salvava notas fiscais em arquivos textuais similares ao exposto a seguir:

0100|Bolacha Mabel|3.40
0100|Leite Itambé|2.00
0200|5,40

O caractere “|” era usado para separar os campos e havia diferentes tipos de registros dentro do mesmo arquivo. Aqueles que começavam com “0100” representavam um item da nota fiscal (nome do item e valor pago respectivamente), e “0200” o valor total da nota. Uma validação simples deste arquivo é verificar se o valor total bate com o somatório do valor pago em cada item.

O validador em AWK abaixo ilustra melhor a linguagem. Iremos salvá-lo em um arquivo chamado “prog.awk”.


BEGIN {FS = "|"}
$1 == "0100" { total += $3}
$1 == "0200" && $2 != total { print "Valor inválido. Total = ", $2, "Somatório = ", total}
$1 == "0200" && $2 == total {print "Arquivo OK"}

A primeira condição é executada quando o programa é iniciado, o que é representado pela condição “BEGIN”. Nesta linha definimos que o caractere separador de campos será “|” mudando o valor de uma variável embutida da linguagem que é o FS (Field Separator).

A segunda linha verifica se o campo 1 contém o texto “0100”. Se for o caso, iremos criar uma variável chamada “total” na qual iremos incrementar o valor presente no terceiro campo. (nota importante: evite o caractere vírgula ao lidar com números de pontos flutuante com AWK).

A terceira linha verifica se o arquivo é inválido. Primeiro checamos se o valor do primeiro campo é “0200” e se o valor do segundo campo desta linha é diferente ao que calculamos na variável “total”. Se for, iremos imprimir o erro para o usuário.

A quarta linha valida o arquivo fazendo o oposto do que foi feito na terceira.

E como executamos este programa no Linux?

 cat notafiscal.txt | awk -f prog.awk 

Mais recursos sobre AWK

O objetivo por trás deste post foi apenas mostrar com o que se parece a linguagem de programação para despertar sua curiosidade sobre o assunto. Claro que não cabiam aqui todos os detalhes a seu respeito, mas você os encontrará nos links abaixo:

AWK Community Portal – http://awk.info – o nome já diz tudo: é o portal da comunidade mundial com muitos links e textos interessantes a respeito.

AWK User Guide – http://www.math.utah.edu/docs/info/gawk_toc.html – é o texto que estou usando para me aprofundar na linguagem. Excelente leitura!

JAWK – http://jawk.sourceforge.net/ – Se você usa a JVM vai gostar de conhecer este projeto: é uma implementação completa do AWK para Java. Muito bom como linguagem embarcada!

AWK.net – https://awkdotnet.codeplex.com/ – Curte .net? Encontrei esta implementação, mas não cheguei a experimentá-la.

Notas finais

Minhas experiências recentes com AWK têm sido extremamente satisfatórias: em um de nossos projetos em que precisamos lidar com arquivos de log conseguimos um excelente ganho de produtividade conhecendo muito pouco a linguagem.

Espero que com este post mais pessoas incluam AWK em sua caixa de ferramentas, pois é algo que vale muito à pena aprender.

 

Minha experiência com MongoDB: erros, acertos e dicas

Um ano e meio atrás embarquei em um projeto que antes da minha entrada já havia adotado o MongoDB. Meu objetivo neste post é relatar alguns dos nossos erros e acertos.

O que deu certo

Não tivemos os problemas que lemos por aí como locks em bases de dados e o desempenho que obtivemos foi excelente. Montar um cluster com replicação de dados do tipo replica-set se mostrou um procedimento super tranquilo, assim como a configuração de sharding.

Se você tem estruturas de dados cujos atributos podem variar bastante de um elemento para outro em uma mesma coleção e não liga para redundância de informações, MongoDB se mostra uma solução muito interessante. Ele funciona.

Já sabia algum tempo atrás de algumas das suas limitações. É importante lembrar que limitação divulgada pelo fabricante não é defeito, mas sim característica. Uma limitação que surge “acidentalmente”, esta sim é um defeito. Aliás, na época cheguei a escrever sobre isto, alguns de vocês devem se lembrar. Aqueles pontos que falei em outubro de 2013 ainda se mantém (inclusive a versão em inglês deste site foi parar no Hacker News graças a este post).

Sobre desempenho a crítica que faço é sempre a mesma: benchmarks de internet não são válidos até que você tenha experiência no seu projeto. No nosso caso o que deu certo ocorreu por que satisfez dois requisitos.

  • As estruturas de dados tinham atributos que realmente variavam bastante. Algo com atributos fixos não seria adequado. Além disto documentos embarcados eram uma alternativa interessante: redundância de dados não era um problema.
  • Precisávamos de algo cujo tempo de escrita fosse o menor possível e sabíamos exatamente como estas estruturas deveriam se comportar.

Aonde estes dois requisitos se aplicavam, obtivemos sucesso.

E onde deu errado

Sabe estes dois requisitos que citei acima? São aonde vejo MongoDB funcionar perfeitamente até hoje nos projetos que passei. O principal problema foi causado por aquilo que mais temo: inércia mental.

Há aqueles momentos em que as pessoas estão tão habituadas com o modelo relacional que simplesmente não conseguem aceitar alguns fatos fundamentais sobre o MongoDB:

  • Ele não foi feito para lidar com relacionamentos entre diferentes documentos. Documentos embarcados funcionam bem, mas quando você vai lidar com documentos em outras coleções, ou mesmo na mesma, o máximo que você tem é um quebra galho.
  • MongoDB não foi feito para ter integridade referencial.
  • Se os atributos da sua estrutura de dados são fixos e previsíveis, o registro é a melhor opção, não o documento.
  • MongoDB não é uma base de dados relacional
  • Não há uma implementação nativa de transações ACID entre documentos e nem era objetivo dos projetistas deste SGBD fazer isto.

Se seu sistema exige relacionamentos e integridade referencial  por que não usar uma base relacional? Quer fazer bonito pra algum idiota? Use persistência poliglota! MongoDB e seu SGBD relacional favorito, cada um em seu galho. Por que não tirar o melhor dos dois mundos?

(implementar integridade referencial manualmente é muito triste)

Dicas

A seguir estão algumas dicas que ajudam bastante na adoção do MongoDB. Claro que há inúmeras outras, mas estas são as que considero mais importantes.

Use alguma biblioteca/framework de mapeamento

Uma boa opção é o Spring Data para MongoDB. O modo como lida com o mapeamento de relacionamento entre documentos é muito simples e próximo daquele que estamos acostumados a trabalhar com JPA.

(reparem na frase: “que estamos acostumados a trabalhar com JPA”. É a tentativa inconsciente de aproximar o MongoDB do modelo relacional! (ainda escrevo mais sobre isto no futuro))

Mas já lhe digo que o Spring Data para MongoDB não é perfeito: longe disto. Há bugs e limitações, mas o lado positivo é que se você abrir uma issue para a equipe de desenvolvimento do projeto e esta  for bem descrita (dica: envie código reproduzindo o problema), eles resolverão rapidamente o problema. Quase todas as issues que abri foram atendidas em no máximo duas semanas, algumas na mesma semana de abertura.

Há outras alternativas também, como o Morphia, que funcionam muito bem, mas como nosso projeto era baseado em Spring, era mais interessante usar algo pertencente ao mesmo stack.

(ao que tudo indica o desenvolvimento do Spring Data está bem mais ativo também)

Conheça BEM o driver Java (ou da sua linguagem) do MongoDB

Estes frameworks de mapeamento quebram um bom galho mas há um preço: muitas vezes são lentos. Em aplicações que precisem de alto desempenho você irá observar que seu gargalo não estará no MongoDB, mas sim no código Java presente nestas bibliotecas.

Sendo assim, conhecendo bem o driver Java do MongoDB irá lhe ajudar horrores na hora em que precisar lidar com estes gargalos. Se seu sistema for basicamente CRUD, aí sim você pode ficar apenas com as bibliotecas.

Outro ponto fundamental é que pelo driver Java você consegue fazer praticamente qualquer coisa no MongoDB. Muitas vezes há um ou outro recurso que não está presente ainda na sua API de mapeamento favorita.

Precisa de transacionalidade entre documentos com MongoDB?

Se respondeu a sim esta pergunta e não quer usar uma base relacional, sua vida acaba de ficar  difícil, mas não impossível. MongoDB oferece atomicidade em operações sobre um único documento, mas não entre documentos. Sempre tenha isto em mente.

Você pode implementar manualmente transacionalidade entre documentos, mas esta será bem limitada. No site do MongoDB há um tutorial que você pode consultar. O problema é que isto dá muito trabalho.

Vou falar sobre uma solução melhor para este problema mais a frente.

Não pensou no espaço que estes bancos de dados ocupam?

Yeap, eu já havia falado sobre isto antes. As bases de dados do MongoDB podem crescer bastante se você não ficar atento. Leve isto em consideração se não quiser levar um susto com o custo do seu storage. É sempre bom fazer algumas simulações do ambiente de produção antes de adotar o MongoDB: irá lhe poupar muito tempo, dinheiro e saúde.

Lembra aquela solução que havia prometido? Ei-la!

Considere seriamente a adoção do TokuMX ao invés do MongoDB

tokutek

Sabia que o MongoDB tem um irmão gêmeo bem mais charmoso? Trata-se de uma distribuição alternativa chamada TokuMX: também é open source e é desenvolvido por uma empresa chamada TokuTek.

Bom: o que ele tem de bom?

  • Resolve seu problema de espaço de armazenamento: uma de nossas bases no MongoDB ocupa 400Mb. No TokuMX? 15Mb.
  • TokuMX implementa transação ACID entre documentos. Sim, você leu certo, e ela funciona MUITO bem.
  • Apresenta desempenho bastante superior

E o melhor: 100% compatível. Se você trocar sua instalação MongoDB pelo TokuMX sua aplicação não notará diferença alguma além da melhoria de desempenho. Até este momento só vi dois poréns com o TokuMX:

  • Ainda não há uma distribuição para Windows.
  • Infelizmente as bibliotecas atuais não oferecem suporte nativo à implementação ACID do MongoDB: você terá de usar o driver nativo para obter este resultado. Existe uma issue no projeto Spring Data pedindo este suporte, mas não é prioritária ainda (mesmo eu pedindo :) ).

Treine BEM a sua equipe

Este é um ponto fundamental: você precisa expor para os membros do seu time o modo como devemos pensar a persistência fora do modelo relacional. É a única cura que conheço para o problema da inércia mental.

Conclusões

Estas foram minhas experiências com o MongoDB. Quanto mais cedo você detectar estas dificuldades que mencionei, melhor. Espero com este post ter dado minha contribuição. Devo confessar que até hoje a maior parte das reclamações que vejo sobre o MongoDB não são culpas da ferramenta, mas sim do seu mal uso.

E, pra finalizar MESMO: experimentem o TokuMX, é um produto muito superior e vai te poupar muito tempo. :)

Integrando Groovy e Java

Groovy não deve ser visto como uma linguagem alternativa ao Java, mas sim complementar (e vice-versa). Mesmo em meus projetos Grails costumo ter partes escritas em Java (ou Clojure) por uma razão simples: é bom ter as ferramentas certas para cada tipo de problema, e se eu posso ter mais de uma e as domino, a pergunta que fica é: por que não?

Então neste post vou mostrar algumas maneiras que você pode integrar suas bases de código Groovy e Java para assim obter o melhor dos dois mundos. É importante ressaltar que aqui só vão ser expostas algumas das estratégias que costumo usar.

Java chamando Groovy

java_chama_groovy

Groovy como linguagem embarcada

Possivelmente esta é a estratégia mais comum: você já possuí um sistema escrito em Java e quer oferecer pontos de extensão para o usuário final sob a forma de scripts (que podem estar armazenados em um sistema de arquivos, banco de dados, nuvem ou qualquer outro local mágico de sua preferência). Assim seu trabalho como arquiteto/desenvolvedor diminui: você apenas fornece a estrutura básica sob a forma de um framework e os pontos de customização passam a ser feitos pelo próprio usuário final.

O fundamental

Como fazer? Já gravei agluns vídeos sobre isto pra você. O fundamental você pode ver abaixo:

Melhorando o desempenho

Mas esta é apenas a primeira parte do seu trabalho e o resultado vai ser um sistema razoavelmente lento. Como melhorar isto? Ensino no vídeo a seguir:

Sobre o vídeo acima, uma nota: hoje já tenho algumas técnicas que podem aumentar ainda mais a performance de scripts Groovy: em breve gravo um novo vídeo expondo como fazer isto (mas o acima resolve a maior parte dos seus problemas, se não todos).

Garantindo a segurança

Ter uma linguagem embarcada em seu sistema Java é muito bom, mas há um problema: segurança. Como evitar que código mal intencionado entre na sua vida? Imagine que seu usuário final escreva um script Groovy como o abaixo:


System.exit(1)

Ensino como resolver este problema em outro vídeo.

Usando bibliotecas escritas em Groovy já compiladas

Você quer adicionar ao seu projeto Java uma biblioteca ou framework escrito em Groovy. É bastante simples: basta que você adicione esta biblioteca e suas dependências ao classpath do seu projeto e os distribua junto com sua aplicação quando esta for compilada.

Uma nota importante deve ser feita: para evitar chateação, sempre inclua neste caso a biblioteca groovy-all. Esta vêm na distribuição oficial do Groovy e você pode referenciá-la em seu projeto Maven como no exemplo abaixo (basta mudar o número da versão para o que seja compatível com o seu projeto):

<dependency>
    <groupId>org.codehaus.groovy</groupId>
    <artifactId>groovy-all</artifactId>
    <version>2.4.0-beta-3</version>
</dependency>

Esta dependência é importante pois já carrega o Groovy completo (o nome já entrega) e também as classes do GDK (Groovy Development Kit). Evite incluir apenas groovy-lang.

Código Groovy gera bytecode Java normal. Sendo assim, basta que suas classes Java usem as classes Groovy como se fossem… classes Java simples.

Usando código fonte Groovy usando Maven

maven-logo

Seu projeto está sendo escrito em Java e Groovy. Como você organiza seu projeto? Minha experiência principal é com Apache Maven, sendo assim aqui vou expor um exemplo bem rápido de como usar o plugin GMavenPlus.

Este plugin é uma reescrita do antigo GMaven com uma série de novos recursos. O uso é bastante simples: você só precisa incluir as pastas src/groovy e test/groovy para seu código Groovy, que vai ser compilado junto com o código Java.

Como usar o plugin? O caminho mais rápido e direto é você copiar os exemplos presentes neste link. Use o exemplo “joint compilation” que mostra como colocar em um mesmo projeto Maven Java e Groovy lado a lado.

E como seu código Java vai referenciar o Groovy? Exatamente como se fosse código Java convencional. :)

Groovy chamando Java

groovy_chama_java

Executando código Java compilado

Um dos principais pontos de venda do Groovy é justamente o fato de apresentar uma sintaxe próxima à do Java e também executar código Java de forma nativa. Lembre-se sempre desta regra:

Código Groovy vira bytecode Java padrão

Groovy pode executar qualquer código Java sem a necessidade de alteração. Basta que todas as dependências necessárias estejam no classpath do seu projeto. E como executá-lo? Exatamente como se fosse código Groovy. E sabe o que é bacana? Quando código Groovy executa código Java, Java vira Groovy!

Código Java que é essencialmente estático passa a ser dinâmico: você pode alterar os métodos presentes em código Java já compilado, por exemplo, exatamente como se fosse Groovy. Em 2009 escrevi alguma coisa a respeito, que você pode ler neste link.

Como Grails usa código Java?

Anos atrás escrevi um post sobre isto. Para ler, clique neste link.

Executando código fonte Java

Basta usar o GMavenPlus, exatamente como mostrei neste mesmo post. :)

Concluindo

Neste post expus algumas soluções de integração Groovy e Java. Há outras soluções (Gradle, por exemplo), mas como não tenho tanta experiências com estas, preferi não falar a respeito (no futuro aprendendo melhor provavelmente surgirá um post aqui).

Muitas dúvidas que vejo no Grails Brasil são do tipo: “como uso [sua biblioteca favorita Java] com Groovy/Grails”? Resposta simples: exatamente (ou quase em raríssimos casos) como faria se fosse em um projeto Java convencional!

Outro ponto importante: muitas pessoas me procuram dizendo que vão trocar Java por Groovy ou vice-versa: bobagem. Como disse no início deste post, o ganho na plataforma Java está no uso em conjunto de diversas linguagens. O uso exclusivo (só Java ou só Groovy) é tolo: pra que transformar o mundo em um prego?

Falando de Spring 4.0 na Java Magazine 130

Acaba de sair a edição 130 da Java Magazine na qual há um artigo que escrevi sobre as novidades do Spring 4.0. Nele falo sobre a evolução do framework e detalho alguns aspectos desta nova versão como, por exemplo, o suporte a WebSocket,  Spring Boot (em ambos os casos mostro exemplos rápidos de uso das tecnologias), Groovy e mais alguns aspectos.

Detalhes do artigo podem ser vistos neste link. Meu próximo artigo será sobre Spring Boot, até lá!