MyBatis vs JPA: não existe tecnologia ruim.

“Afinal, o que é esse projeto?”

O projeto da empresa onde trabalho hoje é o que dá para chamar de ‘frankenstack’. MyBatis e JPA convivem dentro do mesmo projeto. O problema é que os ‘criadores’, ou seja, os membros iniciais que escreveram esse código, já tinham saído todos da empresa.

Nós, que ficamos, ou seja, o time atual, estávamos perdidos. Não havia um único documento explicando qual tinha sido o critério para misturar essas tecnologias. E, por isso, a situação só foi ficando pior.

No fim, dentro de um mesmo serviço, tinha gente fuçando XML para implementar funcionalidades parecidas enquanto outras pessoas modelavam entidades. Aquilo virou uma estranha ‘anarquia técnica’. O projeto foi se transformando num monstro cada vez mais difícil de manter, até que uma reunião acabou sendo convocada.

“Vamos padronizar isso tudo em uma única stack.”

Misturar tecnologias sem critério não é liberdade, é só confusão.

“Mas JPA não é lento demais para usar?”

O clima da reunião estava tenso. Principalmente o pessoal mais acostumado com MyBatis era fortemente contra padronizar tudo em JPA. O argumento principal deles era velocidade.

“Vocês não lembram daquela página de estatísticas feita com JPA que levava 20 segundos só para carregar? Se a gente escrever o SQL direto, sai em um segundo. Depender de uma caixa-preta que a gente não controla direito é arriscado.”

De fato, algumas lógicas estavam levando dezenas de segundos só para carregar dados. Mas eu tinha certeza de que aquilo não era problema da tecnologia, e sim de conhecimento de uso. Abri o notebook ali mesmo e puxei o famigerado ‘código dos 20 segundos’.

O código era terrível. Ele buscava um List<Entity>, mas cada vez que o loop encostava num objeto relacionado, fazia mais uma ida ao banco, uma por uma. Era o típico problema de N+1.

“Isso não quer dizer que o JPA é lento. Quer dizer que a gente mandou o JPA trabalhar de um jeito ineficiente. Olha só.”

Na hora, apliquei um Fetch Join e reduzi a consulta para uma única batida. Depois do deploy, o carregamento que levava 20 segundos caiu para 1 segundo. Foi o momento em que o olhar do pessoal mudou.

Antes de culpar a ferramenta, vale ler o manual primeiro.

Uma descoberta inesperada: não era bagunça, era um híbrido

Depois de desfazer o mal-entendido sobre JPA, bastava unificar tudo em JPA? Quando fomos olhar de perto, vimos que essa também não era a resposta certa.

Tentar resolver consultas estatísticas complexas ou downloads de Excel com centenas de milhares de linhas via JPA era complicado demais: o custo de transformação em objetos era alto, e escrever queries dinâmicas também era trabalhoso. Já o MyBatis era muito mais intuitivo e rápido para esse tipo de trabalho. Aí comecei a pensar: “Como será que outras empresas resolvem isso?” Frustrado, passei a noite no Google e em blogs técnicos.

Para minha surpresa, muita empresa de tecnologia não insistia em usar só JPA. Algumas recorriam a QueryDSL para consultas complexas com boa performance e outras, como nós, usavam MyBatis junto.

Foi quando caiu a ficha. “Então o pessoal que saiu não tinha misturado tudo isso sem pensar.”

Eles já conheciam os pontos fortes e fracos de cada ferramenta e tinham separado as responsabilidades de forma intencional. O verdadeiro problema é que foram embora sem documentar nada, e nós, que herdamos o sistema, acabamos brigando sobre por que aquilo não tinha sido unificado.

Além dos limites do JPA: QueryDSL e Projection

Daí surgiu outra pergunta: será que dava para tirar o MyBatis e resolver esse problema só com tecnologias do ecossistema JPA? É aqui que entram QueryDSL e Projection.

// 1. Interface que declara apenas os campos necessarios (sem precisar de DTO)
public interface DailyStat {
    String getDate();
    Long getTotalSales();
}

// 2. Buscar via QueryDSL ou um JPA Repository
// Apenas essas duas colunas sao SELECTadas do BD, por isso e tao rapido quanto MyBatis.
List<DailyStat> stats = repository.findDailySales();

Depois que entendi essas tecnologias, ficou bem menos atraente voltar para o inferno de XML do MyBatis. Dentro do próprio ecossistema JPA também dá para escrever queries de alta performance.

Conselho prático: parem de brigar e deixem coexistir

No fim, nosso time escolheu uma ‘coexistência com princípios’ em vez de uma ‘padronização absoluta’. (E, no longo prazo, a meta era migrar para QueryDSL.)

O interessante é que essa estratégia de sobrevivência que escolhemos, ‘JPA para escrita, ferramenta especializada para leitura’, do ponto de vista de arquitetura é uma forma bem básica do padrão CQRS(Command and Query Responsibility Segregation).

Não precisa nem sair dividindo o banco de dados de forma grandiosa. Só a filosofia de separar responsabilidades de comando e consulta no nível do código já deixa o projeto muito mais limpo.

Para fechar: a tecnologia não tem culpa

A gente vive discutindo coisas como “JPA é o melhor” ou “Não, MyBatis é que resolve no mundo real”. Mas o que aprendi com essa experiência é que não existe tecnologia ruim. O que existe são situações em que uma tecnologia é usada para o problema errado.

JPA é como uma varinha mágica, mas, se você errar o feitiço, ela explode. MyBatis é como um martelo resistente, mas pode fazer tudo parecer prego.

Se o seu time está enfrentando conflito por causa de código legado ou por preferências tecnológicas diferentes, para um instante. Talvez, no meio dessa confusão, exista um raciocínio profundo deixado por quem veio antes. Encontrar isso e transformar em regras claras é o caminho para virar um time de desenvolvimento realmente forte.

Deixe um comentário