O fundamento que o dev usa o tempo todo: proposições, operadores, tabelas-verdade, De Morgan e o custo exponencial de cada condição.
Lógica booleana é um daqueles assuntos que todo desenvolvedor usa em todas as horas de trabalho e poucos param pra estudar de verdade. Todo if, todo while, todo filtro, todo WHERE numa query é lógica booleana em ação. Justamente por ser tão onipresente, ela passa despercebida: a pessoa acha que domina porque conhece &&, || e !, e é aí que mora a diferença entre o dev que faz funcionar e o dev que entende o que está fazendo.
Este post cobre o assunto em si primeiro, e só depois mostra por que ele impacta diretamente a qualidade do código que você escreve.
O que é uma proposição
Uma proposição é qualquer afirmação que é verdadeira ou falsa, nunca as duas ao mesmo tempo. "O usuário é premium" é uma proposição. "O saldo é maior que zero" é uma proposição. No código, é qualquer expressão que resulta em true ou false:
const ehPremium = usuario.plano === "premium";
const temSaldo = saldo > 0;
Lógica proposicional é o estudo de como combinar essas afirmações e raciocinar sobre o resultado da combinação. É a gramática por baixo de toda decisão que o seu código toma.
Os operadores
Três operadores formam a base, e todo o resto se constrói a partir deles.
O NÃO (!) inverte o valor: !true é false. O E (&&) só é verdadeiro quando as duas partes são verdadeiras. O OU (||) é verdadeiro quando pelo menos uma parte é verdadeira.
Um detalhe que engana: na linguagem natural, "ou" costuma ser exclusivo ("café ou chá" significa um ou outro). Na lógica, || é inclusivo, verdadeiro até quando as duas partes são verdadeiras. Confundir os dois é uma fonte comum de erro ao traduzir uma regra de negócio pra código.
A tabela-verdade: a ferramenta que resolve qualquer dúvida
Uma tabela-verdade lista todas as combinações possíveis de entrada e o resultado de cada uma. Quando você não tem certeza se uma expressão está correta, não discute: enumera os casos e confere.
Para a && b:
| a | b | a && b |
|---|---|---|
| V | V | V |
| V | F | F |
| F | V | F |
| F | F | F |
A tabela-verdade é a forma honesta de provar que duas expressões fazem a mesma coisa. Gere a tabela das duas e compare linha a linha; se batem em todas, são equivalentes. Isso é útil na prática toda vez que você quer simplificar um condicional sem mudar o comportamento.
As equivalências: o coração do assunto
Duas expressões são equivalentes quando dão o mesmo resultado em todas as combinações. Saber transformar uma na outra é a habilidade central da lógica booleana, e é o que permite escrever a mesma decisão de forma mais legível.
As leis de De Morgan são as mais importantes. Negar um grupo inverte o operador:
!(a && b) === !a || !b // o E vira OU
!(a || b) === !a && !b // o OU vira E
Isso importa porque toda regra escrita na forma negativa ("não libera a menos que...", "bloqueia se não...") esconde um De Morgan, e traduzir errado é uma das causas mais comuns de bug em condicional. O erro clássico é achar que !(a && b) é !a && !b, o que é falso.
Outra distinção fundamental é entre implicação e recíproca. "Se A então B" não é o mesmo que "se B então A". "Se é premium, tem acesso" não quer dizer que "se tem acesso, é premium", porque a pessoa pode ter acesso por outro motivo. Confundir os dois é um erro de raciocínio, não de sintaxe, e é o que faz alguém ler uma regra como se fosse mão dupla.
E há equivalências úteis pra simplificar expressões, como a distributiva, que permite fatorar uma condição repetida:
(a && b) || (a && c) === a && (b || c)
Dominar essas transformações é o que diferencia quem escreve um condicional emaranhado de quem escreve o mesmo comportamento de forma limpa.
Como isso impacta o dev: o custo de cada condição
Estabelecido o fundamento, chega a consequência prática mais importante, e a mais subestimada. Ela aparece quando a lógica booleana se acumula dentro de um método.
Cada condição booleana que você adiciona a um método dobra o número de comportamentos possíveis. Não soma, multiplica por dois. Um método cujo resultado depende de N condições tem 2^N combinações de entrada:
for (let n = 1; n <= 10; n++) {
console.log(`${n} condições -> ${2 ** n} combinações`);
}
// 3 -> 8
// 5 -> 32
// 7 -> 128
// 10 -> 1024
Com 3 condições são 8 combinações, o que um humano segura na cabeça. Com 7 são 128. Com 10, mais de mil. O crescimento é exponencial, e o cérebro humano é ruim em sentir isso, então a quinta condição entra sem alarme e de repente o método tem centenas de caminhos que ninguém mapeou.
Esse número cobra em quatro lugares concretos:
Testar. Cobrir de verdade um método de N condições exigiria testar as 2^N combinações. Na prática, testa-se o caminho feliz e mais alguns casos. Num método de 7 condições, isso cobre talvez 4 dos 128 comportamentos; os outros vão pra produção sem nunca terem sido executados. A afirmação "está testado" perde sentido conforme as condições crescem.
Ler e entender. Pra prever o que o método faz numa combinação específica, você precisa simular aquela combinação na cabeça, e com muitas variáveis isso excede a memória de trabalho humana. O método vira uma caixa preta que funciona mas cujo comportamento ninguém consegue prever sem rodar. É daí que vem o medo de mexer em certos trechos, e o medo é racional.
Manter. Cada condição existente é uma interação potencial com qualquer mudança futura. Adicionar a nona condição a um método de oito insere uma variável que agora interage com todas as outras, e é assim que uma alteração pequena quebra um caso aparentemente sem relação.
Revisar o que a IA gera. Ferramentas de IA produzem métodos condicionais rápido e com boa aparência. Um método de 8 condições gerado assim tem 256 caminhos que ninguém testou. Revisar isso lendo linha por linha não funciona, porque o problema está na combinação, não em nenhuma linha isolada. Saber estimar o 2^N e reconhecer a explosão vira uma ferramenta de revisão.
O que o fundamento te permite fazer
É aqui que a lógica booleana deixa de ser teoria e vira vantagem prática. Quem domina o assunto responde à explosão de caminhos de três formas.
Trata cada condição como uma decisão de design, não como uma linha: antes de adicionar a próxima, reconhece que está dobrando o espaço de comportamento e pergunta se ela precisa mesmo estar ali, ou se o método está acumulando responsabilidades.
Reduz o espaço quebrando o método: dois métodos de 4 condições têm 16 + 16 comportamentos; um método de 8 tem 256. Separar a lógica em pedaços com responsabilidades claras reduz o espaço que cada pedaço precisa cobrir, e o todo volta a ser verificável.
Simplifica com equivalências e prova com tabela-verdade: usa De Morgan e a distributiva pra enxugar condições, e confirma que a versão nova é equivalente à antiga comparando as tabelas em vez de confiar no olho.
O princípio
Lógica booleana e proposicional não é um tópico acadêmico que ficou pra trás na faculdade. É o fundamento que decide quantos comportamentos um método pode ter, e esse número cresce de forma exponencial com cada condição. Dominar o assunto é o que permite manter o espaço de comportamento dentro do que um ser humano consegue verificar.
O dev que entende isso não escreve necessariamente menos condições. Ele escreve com consciência do custo: sabe quando a condição vale, quando o método precisa ser quebrado, e como provar que uma versão mais simples é equivalente. É a diferença entre um método que funciona e um método que você consegue afirmar que está correto.