Clean Code em JavaScript: princípios e exemplos na prática
\n\nCódigo limpo (Clean Code) não é apenas um termo da moda, mas uma filosofia de desenvolvimento que transforma um conjunto caótico de instruções em um sistema organizado, legível e sustentável. No mundo do JavaScript e Node.js, onde os projetos crescem e se tornam mais complexos rapidamente, a habilidade de escrever código limpo torna-se uma competência criticamente importante. Neste artigo, vamos analisar os princípios-chave do Clean Code com exemplos concretos usando Node.js.
\n\nPor que o código limpo é importante para o desenvolvedor JavaScript?
\n\nJavaScript é uma linguagem com tipagem dinâmica e alta flexibilidade, o que é ao mesmo tempo seu ponto forte e uma fonte de problemas. Sem seguir as disciplinas do código limpo, o projeto rapidamente se transforma em um "pântano", onde qualquer alteração pode quebrar partes inesperadas do sistema. O Clean Code ajuda a:
\n- \n
- Reduzir a quantidade de bugs e o tempo para encontrá-los. \n
- Acelerar a integração de novos desenvolvedores no projeto. \n
- Facilitar a refatoração e a escalabilidade da base de código. \n
- Aumentar a qualidade das revisões de código (code review). \n
Princípio 1: Nomes significativos — a base da compreensão
\n\nO primeiro e mais importante princípio do Clean Code é a nomeação correta de variáveis, funções, classes e arquivos. O nome deve responder às perguntas "o que é isso?" e "para que serve?". Evite variáveis de uma letra (exceto contadores de loop) e nomes abstratos.
\n\nExemplo ruim (Node.js):
\n// O que esta função faz? Não está claro.\nfunction d(a, b) {\n let r = [];\n for (let i = 0; i < a.length; i++) {\n if (b.includes(a[i])) {\n r.push(a[i]);\n }\n }\n return r;\n}\n\n// Uso\nconst arr1 = [1, 2, 3, 4, 5];\nconst arr2 = [3, 4, 5, 6, 7];\nconst result = d(arr1, arr2);\nconsole.log(result); // [3, 4, 5]\n\nExemplo bom (Clean Code):
\n// O nome da função e dos parâmetros falam por si\nfunction findCommonElements(array1, array2) {\n const commonElements = [];\n for (const element of array1) {\n if (array2.includes(element)) {\n commonElements.push(element);\n }\n }\n return commonElements;\n}\n\n// Uso\nconst firstList = [1, 2, 3, 4, 5];\nconst secondList = [3, 4, 5, 6, 7];\nconst intersection = findCommonElements(firstList, secondList);\nconsole.log(intersection); // [3, 4, 5]\n\nRecomendações adicionais para nomeação:
\n- \n
- Variáveis booleanas: use prefixos
is,has,can(por exemplo,isActive,hasPermission). \n - Funções: use verbos (
getUserData,validateEmail,sendNotification). \n - Constantes: escreva em UPPER_SNAKE_CASE (
MAX_RETRY_COUNT,DEFAULT_TIMEOUT_MS). \n
Princípio 2: Funções pequenas com uma única responsabilidade
\n\nCada função deve fazer apenas uma coisa e fazê-la bem. Se uma função realiza várias ações (por exemplo, valida dados, faz uma consulta ao banco de dados e envia um e-mail), ela deve ser dividida em várias funções pequenas. Isso melhora a testabilidade e a reutilização do código.
\n\nExemplo ruim (Node.js Express):
\napp.post('/api/users', async (req, res) => {\n const { name, email, password } = req.body;\n\n // Validação\n if (!name || !email || !password) {\n return res.status(400).json({ error: 'Missing fields' });\n }\n if (password.length < 8) {\n return res.status(400).json({ error: 'Password too short' });\n }\n\n // Trabalho com BD\n const existingUser = await db.findUserByEmail(email);\n if (existingUser) {\n return res.status(409).json({ error: 'User exists' });\n }\n\n const hashedPassword = await bcrypt.hash(password, 10);\n const newUser = await db.createUser({ name, email, password: hashedPassword });\n\n //