Lendo uma
isEnabled e useFlag são síncronos e devolvem um booleano puro. Isso é o
contrato, não um detalhe de implementação. Um hook que começasse em undefined
renderizaria a ausência de toda funcionalidade protegida por um quadro e a
funcionalidade no seguinte — e “ainda não sabemos” e “desligado” são idênticos para
a pessoa, enquanto só um dos dois é seguro. Uma flag que pisca ligada é pior que
uma simplesmente desligada.
Uma chave desconhecida é false. Uma flag que ninguém definiu é uma funcionalidade
que ninguém entregou, e uma página que nunca chamou boot() vê false para tudo,
que é a resposta honesta: ninguém decidiu a audiência dessa pessoa.
Do que uma flag é feita
null e 0 serem diferentes é o tipo de distinção que esta API mantém em vez de
colapsar: “sem rampa” e “com rampa, no zero” são estados diferentes de um release,
e guardar 100 para o primeiro perderia o segundo.
Uma flag mira um segmento e nunca um filtro próprio. É a regra que impede
audiências de serem reconstruídas módulo a módulo — tudo o que você consegue dizer
sobre quem vê uma funcionalidade, você diz uma vez, num
segmento, e todo outro módulo lê o mesmo.
A porcentagem, e qual string ela hasheia
Uma rampa faz bucket pelo id do contato assim que a pessoa está identificada, e pelo id anônimo do dispositivo enquanto ela é uma visitante. Os dois são estáveis enquanto o que eles nomeiam for. Cada flag carrega o próprio sal, então estar no décimo azarado de uma rampa não diz nada sobre a próxima — um sal compartilhado faria toda rampa de 10% acertar o mesmo décimo dos seus usuários, que passariam a experimentar seu produto como permanentemente quebrado enquanto ninguém mais conseguiria reproduzir nada do que eles relatassem. Um flicker é real e está dito em vez de escondido. Uma visitante anônima faz bucket pelo dispositivo; no momento em que assina, o mesmo humano faz bucket por um id de contato — string diferente, portanto possivelmente bucket diferente, portanto uma rampa em que ela estava pode deixá-la de fora um carregamento depois. Isso é aceito porque as alternativas são piores. Fazer bucket de todo mundo pelo id do contato não evitaria (uma visitante anônima tem uma linha de contato, e assinar faz o merge dela, então o id muda de qualquer jeito). Carregar o id anônimo para sempre faria a audiência de uma rampa depender de um cookie que a pessoa pode limpar, o que transforma “10% dos usuários” em “10% dos navegadores, re-amostrados sempre que alguém limpa o histórico” — uma porcentagem que deriva em silêncio é pior que uma que muda uma vez, num momento em que a pessoa já está vendo a página mudar. O que decorre disso para você é uma frase e não um mecanismo: não coloque um checkout atrás de uma flag de porcentagem para tráfego deslogado.O kill switch, e o atraso honesto dele
O valor da flag para esta pessoa — segmento, porcentagem, tudo — é decidido peloboot(), na mesma ida e volta que a sessão já custou. Depois disso, o cliente faz
poll de um documento público:
- desligar uma flag alcança uma página aberta em cerca de quinze segundos, sem nenhum refresh de sessão envolvido;
- alargar uma rampa, ou re-mirar um segmento, vale a partir do próximo boot.
version é opaca — compare por igualdade para saber que nada
se moveu, nunca por ordem.
O que acontece quando a rede não está lá
Um refresh que falha mantém o último documento. Ele nunca esvazia as flags. Um kill switch que abre sempre que a rede cai é o oposto do que ele existe para fazer, e degradar para “sem flags” durante um minuto ruim faria seu produto voltar ao estado pré-flag para todo mundo — nossa indisponibilidade virando a sua, por causa de uma funcionalidade que você ligou semana passada e não pensa mais nela. O documento levastale-if-error ao lado do max-age pelo mesmo motivo. O poll roda
apenas enquanto a página está visível; uma aba em segundo plano não é uma página
onde alguém está prestes a ser surpreendido.
Uma flag arquivada some do documento, e uma chave que não está nele é false.
Arquivar é como você encerra uma rampa da qual desistiu — para quem lê, é
indistinguível de um delete, que é o que se quer.
No servidor
Não há intervalo nem visibilidade para se apoiar, entãorefreshFlags() é a leitura
explícita — para um servidor, para um teste, ou para o momento logo depois de um ato
que você sabe ter mudado algo.
@userkit/nextjs o mesmo documento é
buscado pela sua própria origem, então a publishable key fica fora do bundle.
No painel
Engagement → Flags, atrás deflags:manage — owner e admin por padrão. Uma
permissão cobre a superfície inteira aqui, diferente de segmentos, onde ler é
customers:read porque a leitura de um segmento é uma lista filtrada de contatos.
A leitura de uma flag não é a vista de nada que outra permissão já mostre: é o estado
de release do seu produto, então ela não tem outra casa.
Ela é uma permissão separada de segments:manage justamente porque as duas são
vizinhas. Definir uma audiência é descrever pessoas; virar uma flag é entregar ou
desentregar uma funcionalidade no minuto em que ela é virada, para quem estiver com
a página aberta. Uma organização que quer seu analista de growth construindo
audiências sem poder desligar o checkout diz isso concedendo uma e não a outra.
Virar uma flag publica flag.updated no barramento interno, e esse fato
deliberadamente não sai do prédio como webhook: ele nomeia o estado de release de
um ambiente, e o documento já é a forma suportada de saber de uma mudança.
O sal do bucket nunca é devolvido pela API. É o único valor que permitiria a
alguém calcular em que bucket está e então escolher um identificador que caia dentro
de uma rampa.