Compartilhar com
9 minutos para ler O Firebase oferece uma ferramenta poderosa e fácil de usar para implementar testes A/B em apps. O Felipe Valio, Desenvolvedor na Sinch, percebeu que, para os resultados serem confiáveis, existem alguns detalhes não muito óbvios que precisam ser considerados. Nesse artigo ele conta mais sobre os seus aprendizados e dá dicas para quem quer seguir com os testes com a ferramenta. Confira!
Quem já leu o meu artigo anterior sabe que possuo alguns apps os quais desenvolvo nos meus momentos livres. Recentemente decidi fazer testes A/B neles, uma decisão natural para qualquer app que atinja um certo grau de maturidade. Para realizar os testes resolvi utilizar o Firebase porque 1) é gratuito e 2) ele tem evoluído bastante, ganhando notoriedade como uma arca de ferramentas para aplicativos móveis. Uma simples busca no Google do tipo Firebase A/B Testing iOS revelou algumas dúzias de artigos, blogs e tutoriais. Lendo alguns percebi que todos ensinam os mesmos passos, então escolhi o que mais me agradou e coloquei as mãos na obra.
O Firebase possui uma ferramenta para fornecer configurações remotas (remote config). Estas configurações são basicamente chaves-valores simples. O app, assim que é aberto, tenta ler estas configurações remotas do servidor do Firebase. Os testes A/B são feitos sobre estas configurações remotas. O Firebase distribui cada usuário para um dos grupos existentes no teste, e para cada grupo entrega um valor específico de configuração. Veja um exemplo. Podemos definir uma configuração chamada `cor_do_botao` com o valor padrão `azul`. Se quisermos realizar um teste sobre esta configuração podemos criar alguns grupos e, para cada um, definir um valor diferente, como por exemplo:
O Firebase se encarrega de monitorar o desempenho de cada um desses grupos de acordo com as métricas desejadas pelo desenvolvedor. Quando um número suficiente de usuários participar do teste, podemos tomar a decisão de qual grupo se saiu melhor. O primeiro grupo é sempre chamado grupo de controle (control group). Toda configuração remota possui um valor default, o qual é atribuído ao grupo de controle. Se o app falhar ler a configuração remota (porque o celular está sem conexão, por exemplo), o app deve saber lidar com isso definindo seu próprio valor default para cada configuração. Idealmente, estes valores default definidos no app são os mesmos valores default definidos no Firebase. Se estas regras forem seguidas, o grupo de controle será essencialmente o app normal, como os usuários o vêem. O objetivo dos testes A/B passa a ser encontrar variações no app que se saiam melhor do que o grupo de controle.
O app que desejo testar oferece ajuda para resolver cubos mágicos. Gratuitamente, ofereço o resolvedor para cubos tradicionais (de tamanho 3x3x3), mas também ofereço resolvedores para cubos de outros tipos, estes os quais sendo acessíveis apenas para quem realizar a compra de um in-app purchase não-consumível. Querendo aumentar a taxa de compras por usuário, decidi mexer um pouco na tela de compra para deixá-la mais atrativa, da seguinte forma:
A primeira tela (A) é a existente até então. Na segunda (B) inseri uma tabela listando melhor as vantagens de se tornar premium. Como senti que a tela B ficou um pouco anêmica devida à remoção do cubo ilustrativo, fiz a terceira variação (C) contendo tanto a tabela quanto o cubo. Os resultados obtidos neste teste estão na tabela a seguir:
Segundo este resultado, claramente as telas B e C foram péssimas idéias. Fiquei um pouco desapontado com isso, mas decidi seguir em frente, afinal nem todas as idéias são boas e eu queria testar várias outras hipóteses.
Após realizar cerca de cinco diferentes testes, todos deram o mesmo resultado: o grupo de controle se mostrou o melhor. Concluí com isso que duas opções seriam possíveis: 1. Eu só tenho idéias ruins, ou 2. Não estou utilizando corretamente o Firebase Deixando a minha mediocridade de lado, resolvi olhar melhor para o Firebase para entender o que poderia estar acontecendo. A primeira idéia que tive para validar o Firebase foi o que chamei de inverter um teste. O que fiz foi tratar a tela B como grupo de controle e testar então o impacto de substituí-la pelas telas A ou C. O resultado segue na tabela abaixo:
Este resultado se mostrou contraditório, pois a tela A, que anteriormente havia ganho, agora perdeu feito para a tela B. Aparentemente o grupo de controle sempre ganha, independente do que ele representa. O segundo teste chamei de *teste placebo*. Nele, criei três grupos, mas o app não fazia distinção entre cada um, logo o resultado esperado seria que os três grupos empatassem. No entanto, o resultado foi o seguinte:
Este teste foi mais frustrante ainda, porque foi o único em que o grupo de controle perdeu. No entanto os grupos B e C empataram, o que seria esperado.
Um ponto que a documentação do Firebase não cita é como tratar os usuários que estão com o app desatualizado. Quase sempre que desejamos fazer um teste precisamos lançar uma atualização do app preparando-o para suportar os possíveis cenários do teste. Os usuários que não atualizarem não deveriam participar do teste, caso contrário estragariam o resultado. Logo, é necessário utilizar algum mecanismo para filtrar os usuários que podem participar do teste.
Ao configurar um teste no Firebase, é possível especificar a versão do app em que o teste rodará, porém esta configuração traz dois inconvenientes. Um deles é que o app não poderá receber novas atualizações enquanto o teste não terminar. O segundo é que de alguma forma esta opção do Firebase é bugada, eu mesmo já criei alguns testes filtrados por versão que simplesmente receberam zero usuários.
É possível configurar para cada teste um evento de analytics chamado evento de ativação. Apenas usuários que enviarem um evento pré-definido poderão participar do teste em questão. Para explorar este recurso, quando o app carregar, comecei a enviar um evento chamado `ExperimentTrigger_X`, onde `X` é um identificador único do experimento. Desta forma, quem enviar este evento certamente estará utilizando a versão do app adequada para participar do teste. Infelizmente esta abordagem demonstrou um problema. A quantidade de usuários que participou do teste foi menos da metade da quantidade de usuários que enviou o evento de ativação. Isso fez com que o teste progredisse bem mais devagar. Um possível motivo para isso é o fato do Firebase demorar um certo tempo (cerca de um dia) para processar os eventos de analytics, o que causaria um atraso para cada usuário entrar no teste. Este atraso talvez possa impactar no resultado do teste.
Um outro recurso disponível é o de filtrar por propriedade de usuário. O app pode definir propriedades para cada usuário que serão enviadas ao Firebase. Para explorar esta opção, criei uma propriedade chamada `ExperimentOptIn`, cujo valor é uma lista de identificadores de experimentos, no formato `|X|Y|Z|`. Ao configurar o teste, seria criada uma regra do tipo `ExperimentOptIn contains |X|`.
Quando a leitura da configuração remota falha, os valores default são utilizados. No entanto, isto pode interferir no resultado do experimento, pois usuários poderiam entrar em grupos onde o app não se adaptaria como esperado. Nos meus testes, falham cerca de 5% das leituras da configuração remota. Para evitar este problema, apenas em caso de sucesso é enviado o evento de ativação ou definida a propriedade de usuário.
Mesmo utilizando alguma das opções acima, ainda parece haver discrepância no grupo de controle, portanto realizei outro experimento. Desta vez incluí mais um grupo, idêntico ao grupo de controle. Os resultados obtidos foram:
Neste teste os grupos A1 e A2 possuíam parâmetros idênticos. Infelizmente, o uso da propriedade de usuário (ou do evento de ativação) não foram suficientes para equilibrar os grupos A1 e A2. No entanto, dada a suspeita de que o grupo de controle não é confiável, a idéia aqui seria ignorá-lo e utilizar o segundo grupo, A2, como referência para o teste. Neste caso, o grupo B se torna o vencedor do teste.
Quando um teste é iniciado, na página de relatório a primeira informação apresentada é a seguinte:
It is still too risky to declare a leader
Em todos os testes que já executei nunca vi um vencedor ser declarado. No momento em que escrevo estou executando um teste há 3 meses com 110k usuários participando, e ainda assim um vencedor não foi encontrado. Portanto não espere isso acontecer. Decida você mesmo quando o teste pode ser finalizado. O Firebase destaca em verde quando um grupo possui pelo menos 95% de chances de superar o grupo de controle, mas mesmo assim não se prenda a isso. O que não faltam são informações para ajudar no julgamento.
O Firebase se mostra cada vez mais uma excelente ferramenta para auxiliar a evolução dos apps. Um desenvolvedor consegue, sozinho, implementar testes e analisar seus resultados. No entanto devemos ser criteriosos na forma de usar esta ferramenta. A documentação não possui respostas para todas as dúvidas e, se mal utilizada, podemos chegar a resultados equivocados. Lembre-se de que não importa o quão boa uma ferramenta seja, ela só terá valor nas mãos de quem souber utilizá-la.