---
title: "Excesso de Defensividade"
type: "ai-smell"
slug: "defensive-overkill"
url: "http://localhost:3000/pt-br/ai-smells/defensive-overkill.md"
category: "Manutenção"
description: "Assistentes de IA se protegem contra falhas que não podem acontecer, embrulhando código já seguro em verificações de null redundantes, cláusulas de guarda mortas e blocos try/except pega-tudo que adicionam complexidade sem adicionar segurança."
---
# Excesso de Defensividade

> Assistentes de IA se protegem contra falhas que não podem acontecer, embrulhando código já seguro em verificações de null redundantes, cláusulas de guarda mortas e blocos try/except pega-tudo que adicionam complexidade sem adicionar segurança.

## Signs and Symptoms

Um revisor identifica Excesso de Defensividade quando uma função gasta mais linhas se protegendo contra estados impossíveis do que fazendo trabalho de fato. Sinais reveladores:

* **Guardas para condições que o sistema de tipos já garante** — verificações de null/undefined em um parâmetro tipado não anulável, `typeof x === "string"` em um `string`.
* **Guardas duplicadas ou subsumidas** — `if (!user) return` imediatamente seguido por `if (user === null || user === undefined) return`.
* **Pega-tudo `try/catch` em torno de código que não pode lançar**, muitas vezes engolindo o erro ou apenas relançando-o ("só por precaução").
* **Lógica para casos extremos "fantasmas"** — ramos que tratam entradas que nenhum chamador pode produzir. A OX Security descobriu que a IA rotineiramente adiciona "lógica para casos extremos imaginários".
* **Blocos defensivos copiados e colados** em vez de extraídos, de modo que a mesma guarda aparece em cinco lugares.

```ts
// User é um tipo NÃO anulável: { profile: { name: string } }
function getDisplayName(user: User): string {
  if (!user) return "Unknown";                         // morto: user é não anulável
  if (user === null || user === undefined) return "?"; // duplicado, também morto
  try {
    if (user.profile && typeof user.profile.name === "string") { // o tipo já garante isto
      const name = user.profile.name;
      if (name.length > 0) {
        return name.trim() !== "" ? name.trim() : "Unknown";
      }
    }
    return "Unknown";
  } catch (e) {
    console.error("could not get name", e); // este bloco não pode lançar
    return "Unknown";
  }
}

```

Nove linhas de proteção embrulham uma linha de intenção. A contradição notada pelos revisores é que o _mesmo_ modelo muitas vezes omite a única verificação que importa (por exemplo, validar entrada externa não confiável) enquanto protege excessivamente chamadas internas — defensividade espalhada por vibe, não por modelo de ameaças.

## Reasons for the Problem

### Por que os modelos o produzem

* **Aversão a risco do próximo token / "prestatividade" do RLHF.** Os modelos são ajustados para parecer minuciosos e evitar estar "errados". Emitir uma guarda extra ou um `try/catch` é de baixo risco para o objetivo de próximo token e lê como consciencioso, então é superamostrado. Um revisor em escala observou que cadeias repetidas de `if (array && array.length > 0)` são "um sinal de que o modelo não está totalmente confiante no fluxo do código" — a guarda é uma proteção contra a própria incerteza do modelo.
* **Sem contexto de dataflow de todo o repositório.** O modelo não consegue ver que um chamador já validou o argumento, ou que um tipo TypeScript torna um ramo inalcançável. O arXiv 2509.20491 (_Code Smells Específicos de IA_) mostra que os LLMs "têm dificuldade com code smells que dependem de fluxo ou são sensíveis a valor" — quando não conseguem raciocinar sobre o fluxo, recorrem a proteger tudo localmente.
* **Cargo-cult de prompt de segurança.** Pesquisas sobre prompting de código seguro descobriram que, quando solicitados a "torná-lo seguro", os LLMs "adicionam blocos try-catch como medida de segurança isolada, sem outros aprimoramentos de segurança... tipicamente quando não conseguem identificar vulnerabilidades específicas". A defensividade substitui a compreensão.
* **Viés dos dados de treinamento em direção a código verboso, estilo tutorial** que demonstra cada verificação por pedagogia, somado a uma recusa em refatorar: a OX Security encontrou **evitação de refatorações em 80–90%** do código de IA e **sobre-especificação em 80–90%** — o modelo adiciona, ele raramente remove.

### Por que isso prejudica

* **Manutenibilidade & carga de revisão.** Uma taxonomia de ineficiências de LLM-Python (arXiv 2503.06327) cataloga _validação redundante de entrada_, _tratamento de erros excessivamente defensivo_ e _condições de guarda desnecessárias_, concluindo que esses "padrões defensivos adicionam complexidade sem benefício proporcional de segurança". Os revisores precisam ler cada ramo morto para confirmar que ele _está_ morto.
* **Correção, não apenas entulho.** Blocos pega-tudo que engolem ou tratam erros genericamente escondem falhas reais; um `try/catch` que retorna um valor padrão transforma um bug em comportamento errado silencioso. As guardas também criam ramos mortos que os testes cobrem diligentemente, inflando a cobertura com testes sem sentido (outra constatação da OX).
* **Acúmulo de dívida técnica.** A análise de 2025 da GitClear descobriu que a participação da refatoração nas linhas alteradas caiu de **25% (2021) para menos de 10% (2024)** enquanto as linhas copiadas/coladas subiram para **12,3%** e os blocos duplicados cresceram \~8x. O boilerplate defensivo é exatamente o tipo de código que é clonado em vez de extraído, e blocos clonados correlacionam-se com **15–50% mais defeitos**.
* **Maior complexidade cognitiva** por função torna a lógica real mais difícil de encontrar, atrasando cada mudança futura.

## Treatment

### Táticas de revisão & prompting

* **Torne o contrato explícito para que as guardas se tornem comprovadamente desnecessárias.** Diga ao modelo: _"`user` é não anulável e já validado pelo chamador — não o reverifique."_ Apoie-se nos tipos: com `strictNullChecks` ativado, `@typescript-eslint/no-unnecessary-condition` vai sinalizar guardas mortas para você.
* **Faça prompt por defesa proporcional, não defesa generalizada.** Peça: _"Só trate erros para os quais você consiga descrever um gatilho concreto. Valide entrada não confiável/externa na fronteira; confie em chamadas internas."_ Isso separa a validação de entrada real (mantenha-a) dos casos extremos fantasmas (apague-os).
* **Exija que o modelo rode o linter/verificador de tipos e remova o que ele sinalizar** antes de retornar o código — feche o loop da forma que os praticantes de agentes recomendam (linters, verificadores de tipos, testes como sinais de feedback automatizados).
* **Peça que ele apague, não apenas adicione:** _"Refatore para o código mínimo que satisfaz a especificação; remova ramos inalcançáveis e blocos catch que não podem disparar."_ Isso combate o viés documentado de "evitação de refatorações".

### A refatoração

Nomeie os movimentos clássicos: **Remover Código Morto**, **Consolidar Expressão Condicional**, **Substituir Condicional Aninhado por Cláusulas de Guarda** e (para entrada que _de fato_ precisa de verificação) **Introduzir Asserção / validar uma vez na fronteira** em vez de repetidamente. Onde a mesma guarda foi copiada e colada, **Extrair Função**.

```ts
// DEPOIS — o tipo garante não-null; valide uma vez, sem catch fantasma
function getDisplayName(user: User): string {
  const name = user.profile.name.trim();
  return name || "Unknown";
}

```

Se um valor genuinamente _é_ não confiável, valide-o **uma vez** na borda e deixe o resto do código confiar no tipo agora restringido:

```ts
// fronteira: faça parse/validação da entrada não confiável uma única vez
const user = UserSchema.parse(rawInput); // lança em dados ruins, aqui, de propósito
// ...tudo a jusante recebe um `User` validado e não precisa de re-proteção

```

Regra prática para revisores: cada guarda e cada `catch` precisa responder _"qual chamador ou entrada concreta dispara isto?"_ Se a resposta for "nada — só por precaução", apague-o.

## Detected by

- **typescript-eslint** `@typescript-eslint/no-unnecessary-condition` — no-unnecessary-condition (https://typescript-eslint.io/rules/no-unnecessary-condition/)
- **ESLint** `no-useless-catch` — no-useless-catch (https://eslint.org/docs/latest/rules/no-useless-catch)
- **SonarSource (SonarQube / eslint-plugin-sonarjs)** `RSPEC-2589 — Boolean expressions should not be gratuitous (always-true/false conditions)` — no-gratuitous-expressions (https://rules.sonarsource.com/javascript/RSPEC-2589/)
- **SonarSource (SonarQube / eslint-plugin-sonarjs)** `RSPEC-3776 — Cognitive Complexity (nested defensive guards inflate it; proxy detector)` — cognitive-complexity (https://rules.sonarsource.com/javascript/RSPEC-3776/)
