Quando quebrar as regras da base de dados:3 exceções
Quando quebrar as regras da base de dados: as três exceções que resistem ao escrutínio, JSONB flexível, contadores desnormalizados e dinheiro em cêntimos.
Quando quebrar as regras da base de dados? Apenas quando tens uma razão específica e documentada — e, na prática, só três razões resistem ao escrutínio. Dados genuinamente flexíveis podem viver em JSONB em vez de tabelas rígidas. Contadores que seriam demasiado caros de calcular em tempo real podem ser guardados. E o dinheiro é sempre guardado em cêntimos inteiros. Tudo o resto fica estritamente estruturado.
Já gastei muitas palavras a pregar estrutura: cada facto num só sítio, tudo ligado por referências, sem atalhos. Essa regra — a disciplina dos 90%+ explicada em normalização de bases de dados explicada — construiu uma plataforma onde centenas de tabelas se mantêm sincronizadas sem um único dado duplicado. Este artigo é sobre o outro lado: os 10% em que quebrar as regras não é um atalho, mas a decisão de engenharia correta.
Quando quebrar as regras da base de dados: a regra primeiro
Primeiro, o enquadramento. Na minha plataforma, provavelmente 95% dos dados são relacionais — tabelas a sério, referências a sério, estrutura a sério. As exceções são exatamente isso: exceções, cada uma com uma razão escrita. Essa ordem importa, porque a IA vai oferecer-te quebras de regras constantemente, e “é mais simples” nunca é a razão. O perigo não é a exceção; é a exceção não documentada, que mais tarde ninguém consegue distinguir de um erro.
Dito isto: aqui estão as três quebras de regras que uso de propósito.
Exceção 1: JSONB para dados realmente flexíveis
O PostgreSQL — o motor de base de dados por baixo da maioria dos produtos SaaS modernos — tem um superpoder chamado JSONB. Permite que uma coluna guarde um documento inteiro de forma livre: quaisquer campos, qualquer forma, diferente em cada linha. É a saída de emergência do mundo estruturado.
Pensa na tua base de dados como um móvel com gavetas etiquetadas. O JSONB é a gaveta com a etiqueta “diversos” — e uma gaveta de diversos é genuinamente útil, desde que nunca se torne o sítio onde guardas o passaporte. O conteúdo legítimo: coisas cuja forma não podes conhecer de antemão. Se os teus utilizadores constroem formulários personalizados, cada submissão tem campos diferentes — não podes desenhar de antemão uma gaveta para campos que ainda não existem. O mesmo vale para campos personalizados definidos pelo utilizador, preferências e definições por utilizador, dados que chegam dos sistemas de outras empresas, metadados soltos e os instantâneos de antes/depois dentro dos registos de auditoria.
A regra de uma frase que sigo:
Se precisas de o ligar a outros dados, de o consultar com frequência ou de impor relações — torna-o relacional. Se é flexível, definido pelo utilizador ou raramente consultado — o JSONB serve.
| O JSONB é certo para | O JSONB é um erro para |
|---|---|
| Respostas a formulários (cada formulário é diferente) | Entidades centrais do negócio: utilizadores, organizações, projetos |
| Campos personalizados definidos pelo utilizador | Tudo o que consultas ou filtras constantemente |
| Preferências e configuração | Dados com relações a outros registos |
| Dados recebidos de sistemas externos | Dados cuja correção o esquema deve garantir |
| Instantâneos de antes/depois dos registos de auditoria | Tudo o que alimenta relatórios e análises |
O sinal de que o JSONB é seguro: os dados pertencem a uma única linha e nunca são consultados independentemente dela. É exatamente a situação em que os problemas de atualização que a estrutura existe para evitar não podem ocorrer. O sinal de que é um erro: apanhas-te a querer fazer perguntas através do JSONB — “todas as tarefas marcadas como urgentes”, “todas as encomendas deste cliente”. Isso são relações, e as relações pertencem a tabelas.
12 semanasA tua carreira corporativa nunca foi o planoCandidata-te ao Solopreneur Accelerator.Candidatar-me →Exceção 2: contadores que não te podes dar ao luxo de calcular em tempo real
A estrutura estrita diz: nunca guardes o que podes calcular. O número de membros de um canal, a avaliação média de um anúncio, o número de candidaturas a uma oferta de emprego — tudo isto pode ser calculado a pedido contando os registos subjacentes, e em pequena escala é exatamente isso que deves fazer.
Depois chega a escala. Uma comunidade em que os canais têm 100 mil publicações não pode recontá-las em cada carregamento de página. Um marketplace com 500 mil anúncios não pode recalcular avaliações médias dentro de cada resultado de pesquisa. Um portal de emprego em que as empresas recebem 50 mil candidaturas não pode contá-las em tempo real em cada visualização de perfil. Nesse ponto guardas o número — uma coluna de contador pré-calculada — e lê-lo não custa nada.
Esta é a disciplina que impede que isto apodreça: cada contador guardado precisa de um mecanismo de manutenção — um trigger ou função da base de dados que o atualiza no instante em que os dados subjacentes mudam. Um contador sem esse mecanismo não é uma otimização; é uma mentira à espera de ser acreditada. No meu esquema, cada coluna de contador tem um mecanismo documentado que a mantém sincronizada, e as notas de design registam qual é e quando dispara.
Um refinamento que vale a pena copiar: as contagens de visualizações são a exceção dentro da exceção. São atualizadas de forma assíncrona — disparadas pela página depois de carregar — em vez de por um trigger, para que contar visualizações nunca torne uma página mais lenta, os bots possam ser filtrados e as visualizações repetidas possam ser deduplicadas. Os contadores exatos (membros, votos, candidaturas) têm triggers; os contadores de vaidade têm um tratamento mais descontraído.
Exceção 3: o dinheiro é sempre em cêntimos inteiros
Esta é menos “quebrar uma regra” e mais recusar um padrão que parece natural e é silenciosamente perigoso. Guardar 12,99 € como o número decimal 12.99 convida a aritmética de vírgula flutuante do computador a entrar nas tuas finanças — e a matemática de vírgula flutuante produz pequenos erros de arredondamento que num gráfico são apenas feios e numa fatura são inaceitáveis.
A solução: guarda cada montante monetário como um número inteiro de cêntimos. 12,99 € é guardado como 1299. Os números inteiros não têm erros de arredondamento, nunca. Todo o sistema de pagamentos da Stripe fala esta convenção — montantes na unidade monetária mais pequena — por isso a tua base de dados coincide nativamente com o teu fornecedor de pagamentos. A divisão por 100 acontece só no último momento, na camada de apresentação, onde um erro custa um bug cosmético em vez de dinheiro.
No meu esquema isto é absoluto: cada preço, taxa, gorjeta e total está em cêntimos inteiros. Nada de decimais para dinheiro, em lado nenhum, nunca.
A meta-regra: as exceções ficam escritas
Repara no que as três exceções têm em comum. Cada uma tem um gatilho estreito (forma impossível de conhecer; custo medido do cálculo em tempo real; a natureza do dinheiro). Cada uma tem um mecanismo compensatório (o teste do JOIN; triggers de sincronização; conversão na camada de apresentação). E cada uma está documentada — a minha plataforma mantém um ficheiro de decisões de design que lista cada desvio intencional, precisamente para que auditorias futuras (humanas ou de IA) consigam distinguir engenharia deliberada de desleixo acumulado.
Essa é a verdadeira diferença entre uma quebra de regra profissional e dívida técnica: uma vem com uma razão escrita, a outra vem com um encolher de ombros.
O livroThe Solopreneur RevolutionLuis Gonçalves sobre como construir um negócio de EUpreendedor com IA sem deixar o emprego.Quero o livro →Perguntas frequentes
O JSONB é má prática?
Não — o JSONB mal usado é que é má prática. Para dados genuinamente flexíveis e pertencentes a uma linha, é a ferramenta certa e evita complexidade inútil. O modo de falha é usá-lo para fugir ao design da base de dados: enfiar etiquetas, responsáveis ou relações num bloco JSON porque desenhar as tabelas certas parecia dar trabalho. Aplica o teste do JOIN e o JSONB continua a ser uma ferramenta em vez de uma armadilha.
Como sei quando um contador deve ser guardado?
Quando a contagem em tempo real prejudica de forma mensurável — uma página que reconta grandes conjuntos de registos em cada carregamento — e não antes. Começa por calcular as contagens a pedido; guarda um contador só quando a escala o obrigar, e nunca sem o trigger ou função que o mantém exato. Contadores prematuros são complexidade não merecida.
Porque não usar simplesmente uma coluna decimal para o dinheiro?
Porque os cêntimos inteiros tornam impossível, e não apenas improvável, toda uma classe de bugs financeiros, e porque o teu fornecedor de pagamentos já pensa em unidades monetárias mínimas. Duas representações do dinheiro — cêntimos na Stripe, decimais na tua base de dados — significam conversões por todo o lado, e cada conversão é um sítio onde te podes enganar na fatura de alguém.
O que acontece se usar JSONB para tudo?
Ficas com uma base de dados que não consegue responder a perguntas. Sem relações, sem garantia de integridade, sem filtragem eficiente, com relatórios penosos — reconstruíste uma pilha de documentos com passos a mais. Flexibilidade de que não precisavas, comprada com a capacidade de consulta de que o teu negócio vive. Mantém a estrutura para os 95% e gasta JSONB onde a forma é genuinamente impossível de conhecer.
Quão preso estás, a sério?
Faz o Índice de Sufocamento Corporativo, a avaliação gratuita para saberes se estás pronto para ser um EUpreendedor.