Anti-patterns & Code Smells
Baixar PDFPadrões que parecem bons mas causam problemas — God Object, Spaghetti Code, Copy-Paste, Over-engineering e como identificá-los.
Anti-patterns & Code Smells
Anti-patterns são soluções tentadoras que parecem corretas mas causam problemas a longo prazo. Code smells são sinais de que algo no código não está certo — como um cheiro estranho na cozinha que indica que algo apodreceu.
Mapa de estudo
Os 7 anti-patterns mais comuns
1. God Object / God Function
Uma classe ou função que faz tudo — cresce até se tornar impossível de entender ou manter.
// ❌ God Function — 200 linhas, 15 responsabilidades
async function processOrder(req: Request, res: Response) {
// 1. Valida body
// 2. Busca usuário
// 3. Verifica estoque
// 4. Calcula frete
// 5. Aplica cupom
// 6. Calcula impostos
// 7. Cobre pagamento
// 8. Cria pedido
// 9. Atualiza estoque
// 10. Envia email
// 11. Envia WhatsApp
// 12. Atualiza analytics
// 13. Loga auditoria
// 14. Invalida cache
// 15. Retorna response
}
// ✅ Separado — cada coisa no seu lugarSintoma: Função com mais de 50 linhas, mais de 5 parâmetros, ou mais de 3 níveis de aninhamento.
2. Spaghetti Code
Código com fluxo de controle desorganizado — goto disfarçado de callbacks, promises aninhadas, lógica saltando entre arquivos sem padrão.
// ❌ Spaghetti — nested callbacks, fluxo impossível de rastrear
getUser(id, (user) => {
getOrders(user.id, (orders) => {
orders.forEach((order) => {
getItems(order.id, (items) => {
items.forEach((item) => {
getStock(item.productId, (stock) => {
if (stock > 0) {
// ... mais 5 níveis
}
});
});
});
});
});
});
// ✅ Flat — async/await, fluxo linear
const user = await getUser(id);
const orders = await getOrders(user.id);
for (const order of orders) {
const items = await getItems(order.id);
// fluxo claro, linha a linha
}3. Copy-Paste Programming
Código duplicado que "funciona porque copiei de onde funcionava". Quando uma regra muda, você precisa achar e alterar todos os copies.
Sintoma: Mesmo bloco de código aparecendo em 3+ lugares.
Solução: DRY — extraia uma função, componente ou utilitário.
4. Over-engineering
Solução complexa para um problema simples. Factory de factories, abstraction layers, design patterns onde uma função resolveria.
// ❌ Over-engineering — para formatar uma data
class DateFormatterFactory {
static create(locale: string, timezone: string, options: FormatOptions): DateFormatter {
const strategy = DateFormatStrategyFactory.create(locale);
const adapter = new TimezoneAdapter(timezone);
return new DateFormatter(strategy, adapter, options);
}
}
// ✅ Simples
function formatDate(date: Date): string {
return date.toLocaleDateString('pt-BR');
}5. Primitive Obsession
Usar tipos primitivos (string, number, boolean) para representar conceitos complexos que deveriam ter seu próprio tipo.
// ❌ Primitive obsession — o que é essa string?
function createUser(name: string, email: string, role: string, status: string) {
// role pode ser qualquer string — 'admin', 'ADMIN', 'adm', 'banana'
// status pode ser qualquer string — 'active', 'ACTIVE', 'ativo', '1'
}
// ✅ Tipos específicos — o compilador garante validade
type Role = 'admin' | 'editor' | 'viewer';
type Status = 'active' | 'inactive' | 'pending';
interface CreateUserDto {
name: string;
email: Email; // tipo refinado
role: Role;
status: Status;
}6. Boolean Trap
Funções com múltiplos booleanos onde fica impossível saber o que cada true/false significa.
// ❌ Boolean trap — o que true, false, true significam?
createUser('Kaique', '[email protected]', true, false, true);
// ✅ Objeto nomeado
createUser({
name: 'Kaique',
email: '[email protected]',
isAdmin: true,
sendWelcomeEmail: false,
isActive: true,
});7. Arrow Function Anti-pattern
// ❌ Arrow function retornando void por engano
items.forEach(item => {
processItem(item); // se processItem retorna Promise, essa promise é IGNORADA
});
// ✅ Para promises, use for...of
for (const item of items) {
await processItem(item);
}
// ✅ Para map, use o retorno
const results = items.map(item => processItem(item)); // retorna array de resultados