---
title: "Abstração Rasa"
type: "ai-smell"
slug: "shallow-abstraction"
url: "http://localhost:3000/pt-br/ai-smells/shallow-abstraction.md"
category: "Estrutura"
description: "Um assistente de IA envolve o código em funções, classes ou interfaces extras que adicionam uma camada de indireção sem esconder nenhuma complexidade nem permitir reutilização — abstrações que apenas repassam para um único ponto de chamada."
---
# Abstração Rasa

> Um assistente de IA envolve o código em funções, classes ou interfaces extras que adicionam uma camada de indireção sem esconder nenhuma complexidade nem permitir reutilização — abstrações que apenas repassam para um único ponto de chamada.

## Signs and Symptoms

Um revisor reconhece a Abstração Rasa quando uma nova função/classe/interface adiciona um _nome e uma camada_ mas nenhuma _alavancagem_: seu corpo apenas repete sua assinatura, repassa direto para uma única chamada subjacente, é invocada exatamente uma vez ou não esconde nenhuma decisão, invariante ou variação. O código _parece_ ter camadas e um ar "corporativo", mas você precisa ler todas as camadas para entender qualquer coisa — a abstração não encapsula nada.

Sinais reveladores:

* Funções/métodos de repasse cujo corpo é uma única chamada delegante sem nenhum comportamento adicional.
* Classes wrapper (`FooService` → `FooRepository` → `db`) em que cada camada apenas chama a próxima.
* Interfaces de implementação única (`IClock` apenas com `SystemClock`) introduzidas especulativamente "para testabilidade" sem uma segunda implementação ou fake.
* Funções `utils`/`helpers` usadas em exatamente um lugar.
* Aliasing/renomeação redundante que repassa um valor inalterado.

Esse é o clássico smell **Middle Man** / **Lazy Class** / **Speculative Generality**, e o outro lado da constatação de "superespecificação" da OX Security (soluções hiperespecíficas e de uso único em vez de componentes generalizáveis).

```ts
// A IA adicionou três "camadas" que apenas repassam para a próxima.
function getUserName(id: string) {
  return fetchUserName(id);            // não acrescenta nada
}
function fetchUserName(id: string) {
  return userRepository.getName(id);   // não acrescenta nada
}
class UserRepository {
  getName(id: string) {
    return db.query("SELECT name FROM users WHERE id = ?", [id]);
  }
}
// getUserName é o único ponto de chamada, usado uma vez.
// Duas das três camadas não adicionam nenhum comportamento — puro Middle Man.

```

## Reasons for the Problem

**Por que os modelos a produzem**

* **Imitar a _forma_ de uma boa arquitetura.** Os corpora de treinamento estão saturados de tutoriais e scaffolding corporativo — camadas de service/repository/factory, DI, interfaces com uma única implementação. O modelo reconhece o _cerimonial_ da abstração sem a substância, porque um auxiliar nomeado é localmente plausível e "parece profissional". A geração do próximo token otimiza para parecer código bem estruturado, não para saber se uma camada justifica sua existência.
* **Sem contexto do repositório.** Gerando localmente, o modelo não consegue ver que o auxiliar é chamado uma única vez, ou que já existe uma abstração canônica em outro lugar — então inventa novas camadas rasas em vez de reutilizá-las. Essa é exatamente a tendência medida pela GitClear: linhas refatoradas ("movidas") caíram de \~24% (2020) para menos de 10% (2024), enquanto as linhas copiadas/coladas aumentaram e os clones de código cresceram \~4x. Os modelos adicionam estrutura, mas nunca a _consolidam_.
* **Fixação no "manual" + superespecificação.** A OX Security constatou que a IA superespecifica em 80–90% do código gerado, produzindo "soluções estreitas que não podem ser reutilizadas", e evita refatorações em 80–90% dos casos ("para no suficientemente bom"). Os wrappers rasos são o resíduo visível.
* **Literalismo no prompt e bajulação.** Instruído a "adicionar uma camada de serviço" ou "deixar limpo/modular", o modelo adiciona camadas literalmente mesmo quando vale o YAGNI — a tendência de superengenharia / "god agent" que os profissionais descrevem na discussão _code-smells-for-AI-agents_.
* **Desatualização pelo corte do treinamento.** Ele envolve uma API obsoleta em um adaptador fino em vez de migrar para fora dela.

**Por que isso prejudica**

* **Manutenibilidade e carga de revisão.** Toda mudança precisa atravessar camadas mortas; quem lê precisa percorrer Middle Men inline. O argumento do "Exército de Juniores" da OX: os revisores não conseguem acompanhar código que _parece_ estruturado mas não tem costuras reais.
* **Correção e segurança.** O arXiv 2509.20491 e a SonarSource observam que o aliasing e os wrappers "obscurecem os pontos de chamada decisivos", degradando a análise de fluxo de dados/controle e de taint — um wrapper pode engolir silenciosamente um erro ou esconder um sink de um scanner.
* **Acúmulo de dívida técnica.** Interfaces especulativas de uma única implementação se ossificam; e como cada abstração rasa é de uso único, a _próxima_ variação é copiada e colada em vez de parametrizada — alimentando diretamente o crescimento de clones que a GitClear mediu. Você paga pela indireção sem nunca colher a reutilização que ela prometia.

## Treatment

**Táticas de revisão e de prompting**

* Aplique a **Regra de Três**: "Não adicione uma função/classe/interface a menos que ela seja usada em ≥2 lugares _ou_ esconda uma decisão/invariante real. Faça inline dos auxiliares de uso único (YAGNI)."
* Force a reutilização: "Antes de adicionar um auxiliar/serviço/interface, procure no repositório por um já existente e reutilize-o." Aponte o modelo para o módulo canônico.
* Faça-o justificar cada camada: "Liste cada nova função/classe e diga qual variação ou invariante ela esconde; remova as que apenas repassam."
* Exija que ele **execute o linter** (`no-useless-constructor`, `no-useless-rename`) e uma **varredura de duplicação** (`jscpd`) e corrija o que for sinalizado.

**Refatorações (nomeie-as):** **Inline Function**, **Inline Class**, **Remove Middle Man** para repasses; **Collapse Hierarchy** / descarte a interface no caso de interfaces de implementação única. Quando a duplicação é o motivo _real_, faça **Extract Function uma vez** para um auxiliar genuinamente compartilhado e parametrizado — não um wrapper por ponto de chamada.

Antes — Middle Man:

```ts
function getUserName(id: string) { return fetchUserName(id); }
function fetchUserName(id: string) { return userRepository.getName(id); }

```

Depois — Inline Function / Remove Middle Man (um ponto de chamada, sem comportamento adicional):

```ts
const name = userRepository.getName(id);

```

Antes — interface especulativa de implementação única:

```ts
interface IClock { now(): number; }
class SystemClock implements IClock { now() { return Date.now(); } }

```

Depois — Collapse Hierarchy (use o tipo concreto; reintroduza a interface apenas quando uma segunda implementação, por exemplo um fake de teste, realmente existir):

```ts
class SystemClock { now() { return Date.now(); } }

```

## Detected by

- **ESLint** `no-useless-constructor` — Construtor de repasse que apenas delega para super ou está vazio (https://eslint.org/docs/latest/rules/no-useless-constructor)
- **ESLint** `no-useless-rename` — Aliasing redundante de import/export/desestruturação que repassa um nome inalterado (https://eslint.org/docs/latest/rules/no-useless-rename)
- **PMD (Java)** `UselessOverridingMethod` — Método sobrescrito que apenas chama super com os mesmos argumentos (https://pmd.github.io/pmd/pmd_rules_java_design.html)
- **SonarSource (Sonar S4144)** `Functions/methods should not have identical implementations` — Sinaliza abstrações de uso único duplicadas com corpos idênticos (https://rules.sonarsource.com/java/RSPEC-4144/)
- **jscpd** `duplication threshold` — Detecta os auxiliares de uso único quase duplicados que as abstrações rasas não conseguem consolidar (https://github.com/kucherenko/jscpd)
