Módulo 13 - Abstração e modularidade: código que dura
Invariantes: a promessa que o código mantém
8 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 12/07/2026
O que você vai aprender
- Entender invariante como uma condição sempre verdadeira de uma estrutura ou função.
- Reconhecer invariantes em exemplos como a BST e o saldo de uma conta.
- Usar a invariante como base para testar o código.
- Ver a ligação entre invariante e a interface pública de um módulo.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: Invariantes: a promessa que o código mantém.
Os objetivos desta aula. Entender invariante como uma condição sempre verdadeira de uma estrutura ou função. Reconhecer invariantes em exemplos como a BST e o saldo de uma conta. Usar a invariante como base para testar o código. Ver a ligação entre invariante e a interface pública de um módulo.
Veja o essencial, parte por parte.
A promessa que vale sempre. Invariante é uma condição que a estrutura mantém sempre verdadeira, antes e depois de cada operação.
A invariante vira teste. A grande utilidade prática de nomear as invariantes é que elas viram testes quase de graça.
A invariante mora atrás da interface. Só há garantia se ninguém quebrar a invariante por fora: mexer direto na estrutura interna a coloca em risco.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
A promessa que vale sempre
No começo do curso você viu a árvore de busca binária. O que faz a busca dela ser rápida é uma regra que nunca pode falhar: em cada nó, tudo o que está à esquerda é menor, tudo o que está à direita é maior. Enquanto essa regra valer, a busca corta pela metade a cada passo. Essa regra que vale sempre, não importa quantas inserções e remoções aconteceram, é o que se chama de invariante. É a promessa central da estrutura. Se em algum momento um valor maior aparecer à esquerda, a árvore para de ser uma BST e a busca deixa de funcionar. A estrutura só é confiável porque a invariante é mantida a cada operação.
Invariantes estão em toda parte, não só em estruturas de dados. Uma conta bancária tem a invariante de que o saldo nunca cai abaixo do limite permitido. Uma lista de tarefas ordenada por prioridade tem a invariante de que a mais urgente está sempre na frente. Um carrinho de compras tem a invariante de que o total é sempre a soma dos itens. O ponto comum: são condições que devem ser verdadeiras antes e depois de qualquer operação. Durante uma operação, a invariante pode ser quebrada por um instante (no meio de uma inserção a árvore fica temporariamente inconsistente), mas ao fim ela precisa estar de volta. Quem garante isso é a interface, cada função dela cuida de deixar a promessa intacta.
A invariante vira teste
A grande utilidade prática de nomear as invariantes é que elas viram testes quase de graça. Se você sabe que a árvore deve manter menores à esquerda e maiores à direita, dá para escrever uma função que percorre a estrutura e confere isso, e chamá-la depois de cada inserção e remoção nos testes. Se a invariante estiver de pé, a operação preservou a promessa; se estiver quebrada, você achou um bug exatamente onde ele nasce, e não três telas depois, quando o sintoma aparece confuso. Testar contra invariantes é uma das formas mais poderosas de garantir que uma estrutura complexa continua correta enquanto ela cresce e o código muda.
// A invariante da conta: o saldo nunca fica abaixo do limite negativo.
// invariante: saldo >= -limite
funcao sacar(conta, valor)
novoSaldo <- conta.saldo - valor
se novoSaldo < (-conta.limite) então
retorne "saque negado" // protege a invariante: não deixa quebrar
fim
conta.saldo <- novoSaldo
retorne "ok"
fim
// Nos testes, depois de cada operação, cheque a promessa:
funcao invarianteVale(conta)
retorne conta.saldo >= (-conta.limite)
fim
// se invarianteVale(conta) for falso em algum ponto, há um bug.A função sacar protege a invariante recusando o que a quebraria. invarianteVale confere a promessa nos testes.
🎮 Jogo da aula
É invariante ou não?
Decida se cada afirmação sobre invariantes é verdadeira ou falsa.
A invariante mora atrás da interface
Repare como as três ideias do módulo se encaixam. A invariante é uma promessa interna do módulo. Quem a protege é a interface: as funções públicas são desenhadas para nunca deixar a promessa quebrada no fim. E por isso a implementação fica escondida: se qualquer um pudesse mexer direto na estrutura interna, sem passar pela interface, poderia quebrar a invariante à toa, e o módulo perderia sua garantia. É por isso que se esconde o interior e se obriga o uso pela interface. A parede não existe só por organização, ela existe para proteger a promessa. Quem usa o módulo, em troca, ganha uma garantia em que pode confiar sem verificar toda vez, o que simplifica todo o código que depende dele.
Teste rápido
Por que nomear a invariante de uma estrutura ajuda a encontrar bugs?
Perguntas frequentes
- O que é uma invariante, em uma frase?
- É uma condição que uma estrutura ou função mantém sempre verdadeira, antes e depois de cada operação. É a promessa central do módulo, como a BST manter os menores à esquerda ou uma conta respeitar o limite de saldo.
- A invariante pode ser quebrada em algum momento?
- Por um instante durante uma operação, sim. No meio de uma inserção, uma estrutura pode ficar temporariamente inconsistente. O que não pode é a invariante estar quebrada no fim da operação. Antes e depois de cada operação completa, a promessa precisa estar de pé.
- Como uma invariante vira um teste?
- Você escreve uma função que confere a condição (por exemplo, percorre a árvore verificando a regra dos menores e maiores) e a chama depois de cada operação nos testes. Se a função disser que a invariante foi quebrada, você achou um bug no exato ponto em que ele nasce.
- Qual a relação entre invariante e interface?
- A interface protege a invariante. Cada função pública é feita para nunca deixar a promessa quebrada no fim. Por isso a estrutura interna fica escondida: se qualquer um mexesse direto nela, sem passar pela interface, poderia quebrar a invariante sem querer e a garantia se perderia.
- Toda estrutura tem invariante?
- As estruturas com garantias fortes têm invariantes bem claras, como a BST ou uma fila de prioridade. Estruturas mais simples podem ter invariantes leves ou quase nenhuma. Mas sempre que um módulo faz uma promessa em que quem usa confia, vale nomear essa promessa como invariante e protegê-la.
- Por que confiar numa garantia simplifica o código?
- Porque quem usa o módulo não precisa verificar a condição toda vez. Se a fila de prioridade garante que o mais urgente está na frente, quem usa só pega o da frente, sem procurar o maior. A invariante economiza checagens espalhadas pelo programa, deixando o código de quem usa mais enxuto e claro.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.