Clean Code em JavaScript: princípios e exemplos para Node.js
Código limpo não é apenas um termo da moda, mas um princípio fundamental do desenvolvimento profissional. No mundo do JavaScript, especialmente no ecossistema Node.js, onde o código é frequentemente escrito rapidamente e em grandes volumes, seguir os princípios do Clean Code torna-se criticamente importante. Neste artigo, vamos analisar os conceitos principais que ajudarão você a escrever código que seja fácil de ler, manter e escalar.
Por que o código limpo é importante para JavaScript e Node.js?
JavaScript é uma linguagem dinâmica com tipagem flexível. Isso é ao mesmo tempo sua força e sua fraqueza. Sem regras rigorosas, é fácil criar "código espaguete" que funciona, mas que é impossível de entender depois de um mês. No Node.js, onde o código frequentemente processa requisições assíncronas e lógica de negócios complexa, a limpeza do código impacta diretamente a velocidade de depuração e o custo de manutenção do projeto.
Código limpo é um investimento no futuro do seu projeto. Ele reduz o número de bugs, simplifica a integração de novos desenvolvedores e torna a refatoração menos dolorosa.
Princípio 1: Nomeação de variáveis e funções
A regra mais simples e mais importante — dê nomes significativos. O nome deve responder às perguntas "o que é isso?" ou "o que isso faz?". Evite variáveis de uma letra (exceto índices de loops) e abreviações.
Exemplo ruim:
const d = new Date(); // o que é d?const fn = (a, b) => a + b; // o que estamos somando?Exemplo bom:
const currentDate = new Date();const sumPrices = (price1, price2) => price1 + price2;Para funções, use verbos (get, set, calculate, fetch, validate). Para variáveis, use substantivos (user, orderList, config). Para valores booleanos, use prefixos is, has, should.
const isUserActive = user.status === 'active';const hasPermission = user.role === 'admin';Princípio 2: Funções devem ser pequenas e fazer uma única coisa
O Princípio da Responsabilidade Única (Single Responsibility Principle) se aplica não apenas a classes, mas também a funções. Se uma função faz mais de uma ação — divida-a.
Exemplo ruim (função faz tudo):
function processUserData(user) { // Validação if (!user.email || !user.name) throw new Error('Invalid user'); // Formatação const formattedName = user.name.trim().toUpperCase(); // Salvamento no BD db.save({ ...user, name: formattedName }); // Envio de email emailService.sendWelcome(user.email); return true;}Exemplo bom (separação de responsabilidades):
function validateUser(user) { if (!user.email || !user.name) throw new Error('Invalid user');}
function formatUserName(name) { return name.trim().toUpperCase();}
async function saveUser(user) { await db.save(user);}
async function sendWelcomeEmail(email) { await emailService.send(email);}
async function processUserData(user) { validateUser(user); const formattedName = formatUserName(user.name); await saveUser({ ...user, name: formattedName }); await sendWelcomeEmail(user.email);}Essa estrutura permite testar facilmente cada parte separadamente e alterar a lógica sem o risco de quebrar tudo de uma vez.
Princípio 3: Evite aninhamento profundo e números mágicos
Aninhamento profundo (callback hell ou múltiplos if/else aninhados) torna o código ilegível. Use retorno antecipado (early return) e guard clauses.
Exemplo ruim (aninhamento profundo):
function getDiscount(price, user) { if (user.isLoggedIn) { if (user.isPremium) { if (price > 100) { return price * 0.8; } else { return price * 0.9; } } else { return price; } } else { return price; }}