(Diversão com) Feature Flags em Elixir
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:
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`
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
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
e rodar novamente o comando mix deps.get
Configuração
No módulo Router
da 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
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!