Introdução: Por que sua aplicação está perdendo dinheiro e você nem percebe
Você já se perguntou quantos usuários abandonam sua aplicação Java por causa de um botão "Comprar" mal projetado? Ou talvez o novo sistema de recomendações, no qual você trabalhou por um mês, na verdade piorou a conversão? No mundo do desenvolvimento, há muitas soluções "óbvias" que fracassam ruidosamente. A única maneira de não ficar adivinhando é o teste A/B em Java.
Neste artigo, vamos abordar como implementar um teste A/B completo diretamente em sua aplicação Java. Você aprenderá como dividir os usuários em grupos, conduzir o experimento e, o mais importante, — não cometer erros estatísticos. Sem enrolação, apenas código e prática. Vamos lá!
O que é teste A/B e por que um desenvolvedor Java precisa dele?
Teste A/B (ou teste de divisão) é um método de comparação de duas versões (A e B) de uma interface, algoritmo ou lógica, para entender qual delas funciona melhor. Simplificando: você mostra a 50% dos usuários o botão antigo e a 50% o novo, e observa onde há mais cliques.
Para aplicações Java, isso é especialmente relevante:
- Lógica de backend: Alteração do algoritmo de ordenação de produtos, recomendações, precificação.
- APIs e microsserviços: Teste de uma nova versão de endpoint em parte do tráfego.
- Componentes de UI: Se seu framework Java (por exemplo, Vaadin ou Spring MVC) renderiza HTML.
A ideia central: teste A/B em aplicações Java permite tomar decisões baseadas em dados, e não em intuição. Isso reduz riscos e melhora as métricas do produto.
Arquitetura do teste A/B: Pensando como um engenheiro
Antes de escrever código, vamos projetar o sistema. Precisamos de:
- Serviço de atribuição de variantes — quem entra em qual grupo.
- Repositório de experimentos — onde ficam as configurações (qual experimento está ativo, qual porcentagem de tráfego).
- Coletor de eventos — registro das ações do usuário.
- Analisador — ferramenta externa ou script para calcular estatísticas.
Neste artigo, focaremos nos dois primeiros itens, já que coleta e análise são tópicos para materiais separados.
Serviço de randomização: Que Deus nos livre de bugs no random()
A maneira mais simples de dividir o tráfego é usar Math.random(). Mas isso não é confiável: ao reiniciar a JVM, o usuário pode cair em outro grupo. Precisamos de uma randomização determinística baseada no identificador do usuário.
A melhor abordagem é usar hash do userId e pegar o resto da divisão. Assim, o usuário sempre verá a mesma versão enquanto o experimento estiver ativo.
public class RandomizationService {
public String assignVariant(String userId, String experimentId, int splitPercent) { // Usamos userId + experimentId para determinismo String seed = userId + ":" + experimentId; int hash = Math.abs(seed.hashCode()); int bucket = hash % 100;
if (bucket < splitPercent) { return "B"; // Nova versão } else { return "A"; // Versão de controle } }}Importante: hashCode() pode ser negativo, então usamos Math.abs(). Também vale considerar que a distribuição não será perfeitamente uniforme com poucos usuários, mas para 1000+ usuários, serve.
Exemplo real: Teste A/B no Spring Boot
Suponha que temos uma loja virtual em Spring Boot. Queremos testar um novo modelo de precificação: mostrar desconto apenas se o usuário passou mais de 30 segundos no site (versão B) contra o desconto normal (versão A).
\