No post anterior, a ideia central era simples: mudar schema com segurança depende de compatibilidade.
Agora entra a pergunta que costuma confundir muita gente:
compatível para quem, exatamente?
É aqui que entram os modos BACKWARD, FORWARD e FULL.
Eles não são nomes genéricos para "mudança segura".
Cada um protege uma direção diferente entre schema antigo e schema novo. E, na prática, isso muda a ordem segura de rollout entre produtores e consumidores.
O que esses modos realmente validam
Quando um registry verifica compatibilidade, ele não está perguntando se "o payload continua parecido".
Ele está perguntando se uma versão de schema ainda consegue ler dados escritos pela outra.
Em outras palavras, a pergunta correta não é só "houve quebra?".
A pergunta correta é:
- o schema novo consegue ler dados antigos?
- o schema antigo consegue ler dados novos?
Essas duas direções parecem parecidas, mas têm impacto operacional bem diferente.
BACKWARD: o schema novo lê dados antigos
BACKWARD significa que o novo schema consegue ler dados produzidos com o schema anterior.
Na prática, isso protege o lado de quem vai consumir histórico.
Se um consumer for atualizado para a versão nova, ele continua conseguindo ler eventos antigos que já estavam no tópico.
Isso importa bastante em Kafka porque tópico tem retenção, replay e reprocessamento.
Não é raro um consumer voltar offsets, reler backlog ou subir uma instância nova que ainda vai encontrar mensagens antigas no log.
Nesse modo, o rollout mais seguro costuma ser:
- atualizar consumidores
- depois atualizar produtores
O raciocínio é simples: o consumer novo entende o passado. O contrário não está necessariamente garantido.
Por isso BACKWARD costuma ser o modo mais natural quando a preocupação principal é preservar leitura de histórico sem obrigar sincronização perfeita entre serviços.
Em registries como o da Confluent, esse também é o modo padrão.
FORWARD: o schema antigo lê dados novos
FORWARD significa que o schema anterior consegue ler dados produzidos com o schema novo.
Aqui a proteção aponta para o outro lado.
O produtor pode evoluir primeiro, e os consumidores antigos continuam conseguindo ler os eventos novos, ainda que talvez não aproveitem toda a informação adicional.
Nesse modo, o rollout mais seguro costuma ser:
- atualizar produtores
- depois atualizar consumidores
Esse cenário faz sentido quando existe uma necessidade real de o produtor sair na frente sem derrubar quem ainda está consumindo com a versão anterior.
O cuidado é que FORWARD não garante a leitura confortável do passado pelo schema novo.
Se o sistema depende bastante de replay, reconstrução de estado ou leitura de eventos antigos, essa escolha costuma ser menos natural do que parece.
FULL: compatibilidade nos dois sentidos
FULL significa que o schema novo lê dados antigos e o schema antigo lê dados novos.
Ou seja: ele combina BACKWARD e FORWARD.
Na prática, isso dá mais liberdade de rollout porque:
- consumidores novos continuam lendo o histórico
- consumidores antigos continuam entendendo eventos novos
Esse é o modo que mais se aproxima da ideia de convivência segura entre versões.
Mas ele também é mais restritivo.
Nem toda mudança que passa em BACKWARD ou FORWARD vai passar em FULL, porque agora a evolução precisa funcionar bem nas duas direções.
Em geral, mudanças aditivas bem planejadas tendem a se encaixar melhor aqui. Mudanças destrutivas, troca de tipo e renomeação costumam ficar bem mais arriscadas.
Um jeito simples de não inverter o significado
Se você costuma se confundir com os nomes, pense assim:
BACKWARD: o sistema novo olha para trás e ainda entende o que já foi escritoFORWARD: o sistema antigo olha para frente e ainda entende o que começou a ser escritoFULL: os dois lados convivem
Essa leitura é mais útil do que decorar definição abstrata.
Ela ajuda a tomar decisão de rollout.
O que muda na prática para producer e consumer
Essa é a parte mais importante:
BACKWARDfavorece upgrade de consumer antes do producerFORWARDfavorece upgrade de producer antes do consumerFULLreduz acoplamento entre as duas pontas, mas exige mudanças mais conservadoras
Isso conecta diretamente com o problema do post sobre evento como contrato: integração distribuída não pode depender de um deploy coreografado toda vez que o payload muda.
Compatibilidade é justamente a regra que define qual margem de desencontro entre versões o sistema consegue absorver.
Então qual modo escolher?
Na maior parte dos cenários de Kafka orientado a eventos, BACKWARD costuma ser a escolha mais natural.
O motivo é operacional:
- consumidores frequentemente precisam ler histórico
- replay e reprocessamento são comuns
- atualizar consumers antes costuma ser mais seguro do que exigir que consumidores antigos entendam tudo que o producer novo passou a publicar
FORWARD faz mais sentido quando o producer precisa evoluir primeiro e o ecossistema ao redor ainda vai levar algum tempo para acompanhar.
FULL faz sentido quando o contrato precisa sustentar convivência forte entre versões e quando o time aceita impor mais disciplina às mudanças do schema.
Não existe modo "mais avançado" por si só.
Existe o modo que combina melhor com a direção de rollout e com o tipo de segurança que o sistema precisa.
Um cuidado importante: compatibilidade não é semântica
Mesmo quando o registry aprova o schema, o trabalho não acabou.
Compatibilidade estrutural não garante compatibilidade de significado.
Você pode manter campos, defaults e tipos de forma tecnicamente válida e, ainda assim, mudar a interpretação do evento de um jeito perigoso para o domínio.
Foi exatamente esse tipo de risco que apareceu no post sobre schema como contrato: contrato não é apenas formato, mas também significado compartilhado.
Ou seja: BACKWARD, FORWARD e FULL ajudam muito, mas não substituem critério de modelagem.
Vale ainda um detalhe prático: em registries como o da Confluent, esses modos normalmente comparam o schema novo com a última versão registrada, não com todo o histórico. Quando a compatibilidade precisa valer para todas as versões anteriores, entram os modos transitive.
O ponto que vale fixar
BACKWARD, FORWARD e FULL não são três jeitos equivalentes de dizer "compatível".
Eles respondem a perguntas diferentes sobre quem precisa continuar lendo o que.
Se você entende a direção protegida por cada modo, fica muito mais fácil decidir:
- quem pode subir primeiro
- qual risco de quebra ainda existe
- qual nível de convívio entre versões o contrato precisa suportar
Em Kafka, compatibilidade de schema não é detalhe de tooling.
Ela define o quanto sua arquitetura realmente tolera evolução sem deploy coordenado.
