(Diversão com) Feature Flags em Elixir

Bruno Cruz
Petlabs
6 min readAug 5, 2021

--

This should be fun.

Neste artigo iremos falar sobre uma biblioteca que facilita e potencializa o uso de Feature Flags em Elixir. Caso queira saber como Feature Flags podem ajudar os times de Engenharia e Produto no release de funcionalidades, testes de público e até mesmo em controle de acesso, veja nossa publicação anterior “Falando Sobre Feature Flags”.

FunWithFlags é uma poderosa biblioteca (inspirada no Flipper do ruby) que nos fornece diversas possibilidades e ferramentas para utilizar e gerenciar feature flags.

Essa biblioteca armazena as informações das flags no Redis ou no banco de dados, especificamente Postgres ou MySQL, através do Ecto para persistência e sincronização entre nós (nodes), mas também disponibiliza a opção de utilizar o ETS para manter um cache local.

Caso uma nova flag seja adicionada ou uma existente seja alterada, os outros nós serão notificados via PubSub do Redix.PubSub ou do Phoenix.PubSub (não é necessário ser uma aplicação Phoenix para utilizar este PubSub), para que possam atualizar seus respectivos caches locais.

Instalação

Neste blog post iremos utilizar a lib fun_with_flags e o Redis como persistência, no entanto existem outras opções abordadas na seção de adapters da documentação da biblioteca.

No arquivo mix.exs vamos adicionar as seguintes dependências:

mix.exs

e rodar o comando mix deps.get para instalá-las.

Configuração

A biblioteca nos permite escolher duas opções para persistir as flags: Redis e Ecto (Postgres e MySQL). Por conveniência e facilidade, vamos utilizar o Redis, já que as configurações padrão o utilizam.

Para mais informações sobre os tipos de persistencias disponíveis, a documentação do FunWithFlags é bem detalhada.

No arquivo config.exs iremos adicionar as configurações do `Redis`

config.exs

Tipos de Toggle Gates

A biblioteca nos fornece ainda algumas opções bem interessantes para lidar com os casos de uso possíveis e a principal delas é o Toggle Gate.

Dentro da biblioteca temos os seguintes gates:

  • Booleano (Boolean)
  • Ator (Actor)
  • Grupo (Group)
  • Porcentagem de tempo (Percentage of Time)
  • Porcentagem de Atores (Percentage of Actors)

Toggle gate é uma maneira de expressar o estado de uma flag. No caso, se ela está habilitada ou desabilitada. A exceção fica para os toggle gates de porcentagem, que expressam apenas o estado habilitado, pois desabilitar uma flag por uma porcentagem de tempo ou atores é logicamente equivalente a habilitá-la na porcentagem restante.

É importante salientar que, em caso de adoção de diferentes tipos de toggle, a biblioteca, por padrão, respeita a seguinte ordem de prioridade:

Actors > Groups > Boolean > Percentage

Dado esse contexto, vamos nos aprofundar um pouco em cada toggle gate:

Booleano

Este tipo de gate é bem simples, uma flag pode estar ou ser ativada/desativada globalmente.

Ator

O Actor gate nos permite ativar ou desativar uma flag para um ou mais tipos de entidades (structs, maps, String, …) dentro da aplicação.

Caso de Uso
Imagine que temos um sistema de recomendação de frequências para assinaturas de produtos pets (ex: seu pet consome a ração X a cada 2 meses) e gostaríamos de tornar essa recomendação mais precisa e personalizada para cada tipo de produto. Uma alteração desse porte sempre traz riscos e a ocorrência de algum comportamento inesperado pode acarretar a insatisfação do cliente final por conta de uma recomendação inadequada e, no pior caso, até o cancelamento de suas assinaturas.
Com o Actor gate, nós podemos fazer essa alteração gradativamente, ativando uma flag para um produto específico, analisar o comportamento e os resultados do novo sistema de recomendação de maneira que afete apenas uma parcela pequena dos clientes.

Exemplo
Primeiramente precisamos que a nossa struct, Product no exemplo, implemente o protocolo (Protocol) FunWithFlags.Actor:

Nota: o actor id precisa ser único.

Grupo

O Group gate é bem similar ao Actor gate, porém nos permite ativar ou desativar uma flag para um grupo ou mais de entidades dentro da aplicação.

Caso de Uso
Imagine que temos sistema de chamadas online com diferentes tipos de usuários:

  • Os de contas gratuitas, que só possuem acesso a funcionalidades básicas, como ligar para uma ou mais pessoas e algumas limitações, como limite de duração de chamadas;
  • Os de contas pagas que, além de não possuírem nenhum tipo de limitação, ainda têm acesso a funcionalidades a mais, como gravar chamadas.

Para esse cenário o group gate funciona perfeitamente, já que podemos dividir os usuário nas categorias standard e premium e disponibilizar ou limitar funcionalidades com base no status da flag para determinado tipo ou categoria de usuário.

Exemplo de uso de Group Gate para dois tipos de conta: Standard e Premium

Exemplo
Também precisamos que a User struct implemente um protocolo, mas nesse caso o FunWithFlags.Group

Porcentagem de tempo

O tipo %-of-time gate é semelhante ao tipo boolean, entretanto nos permite definir uma porcentagem de tempo em que determinada flag estará habilitada, ou seja, uma porcentagem das verificações de status da flag que irá retornar verdadeiro.

Na prática, nós definimos uma porcentagem (ex: 0.50) para o gate e quando a função FunWithFlags.enabled?/2 é chamada, um número randômico é chamado. Esse número é comparado com a porcentagem definida; caso seja menor, a flag estará habilitada, caso contrário, desabilitada.

Porcentagem de Atores

Já o tipo %-of-actors gate é bem parecido com o %-of-time, mas ao invés gerar um número randômico, é usado uma função determinística, consistente e repetível que leva em consideração o nome da bandeira para calcular uma pontuação para determinados atores.

Web dashboard

Dado que temos essa variedade de opções que a biblioteca FunWithFlags nos traz, seria muito burocrático e nada ágil ter que entrar no terminal da aplicação em produção para adicionar, excluir ou alterar uma flag.

Dessa maneira um painel de controle em que possamos gerenciar as flags do sistema seria muito importante, pois não apenas as pessoas desenvolvedoras teriam acesso, mas também as pessoas de produto — como Product Owner e Product Manager, assim ganhando flexibilidade e praticidade no gerenciamento de flags.

Uma pessoa de produto ter acesso a esse tipo de funcionalidade é muito benéfico, porque ela teria total autonomia de alterar o estado de uma flag ou a porcentagem de pessoas que teriam acesso a determinada parte do sistema de maneira simples e rápida, sem a necessidade de solicitar alguém da área de desenvolvimento de software.

Com esse contexto em mente nós temos a biblioteca FunWithFlags.UI, que é uma extensão da biblioteca FunWithFlags, no caso, um painel de controle que nos permite gerenciar facilmente as flags da nossa aplicação através de uma interface gráfica.

Instalação

No arquivo mix.exs iremos adicionar a dependência fun_with_flags_ui

mix.exs

e rodar novamente o comando mix deps.get

Configuração

No módulo Routerda sua aplicação iremos adicionar:

Depois destes pequenos passos, ao acessar o caminho configurado no navegador, a interface web já deve estar disponível para uso!

Listagem de Flags

Tela de listagem de flags

Edição de uma flag

Tela de edição de uma flag

Concluindo…

A biblioteca FunWithFlags traz uma gama alta de funcionalidades, tornando a implementação de feature flags algo simples e prático para diversos casos de uso.

Agradecimentos

Gostaria de agradecer ao Gustavo Chapim, Henrique Dalvi, Jhonatan Martins, Michelle Galindo e Guest Singleton pelas sugestões e comentários que ajudaram a melhorar o conteúdo deste texto.

Petlove&Co

Quer ajudar a criar produtos de qualidade com a gente? Veja a página de carreiras da Matilha!

--

--

Bruno Cruz
Petlabs

Gosto de gatos e cachorros, ler, ouvir podcasts, jogar video game, sou especialista em desenhar palitito e torcedor do Borussia Dortmund 💛 ❤