Code review em JavaScript: o que verificar e como dar feedback
Code review (revisão de código) não é apenas uma verificação formal antes do merge de um pull request. É uma ferramenta poderosa para melhorar a qualidade do código, compartilhar conhecimento na equipe e prevenir bugs nas fases iniciais. No mundo do JavaScript e Node.js, onde a assincronicidade e a tipagem dinâmica criam muitas armadilhas ocultas, uma revisão competente se torna criticamente importante.
Neste artigo, vamos analisar exatamente o que observar ao revisar código JavaScript e como dar feedback para que ele seja útil, e não ofensivo.
1. Lógica, arquitetura e segurança
A primeira coisa a verificar é se o código resolve o problema proposto. Não se aprofunde imediatamente na formatação. Faça a si mesmo estas perguntas:
- A lógica funciona corretamente? Existem casos extremos (edge cases)? O que acontece se vier
null,undefinedou um array vazio? - Não há vulnerabilidades? Em Node.js, isso é especialmente relevante. Verifique se dados brutos da requisição não estão sendo passados diretamente para uma consulta SQL (SQL injection) ou para
eval(). Sanitizadores para HTML estão sendo usados? - A arquitetura está sendo respeitada? O código viola os princípios SOLID? Por exemplo, uma função não está fazendo demais? A lógica de negócio foi separada dos handlers de rotas?
// RUIM: Mistura de lógica e camada HTTP
app.get('/user/:id', async (req, res) => {
const user = await db.query(`SELECT * FROM users WHERE id = ${req.params.id}`); // SQL Injection!
res.json(user);
});
// BOM: Separação de responsabilidades
const getUserById = async (id) => {
if (!id || typeof id !== 'string') throw new Error('ID inválido');
return await db.query('SELECT * FROM users WHERE id = $1', [id]);
};
app.get('/user/:id', async (req, res) => {
const user = await getUserById(req.params.id);
res.json(user);
});
2. Assincronicidade e trabalho com Promises
Este é o calcanhar de Aquiles de muitos desenvolvedores JavaScript. Ao revisar código Node.js, verifique obrigatoriamente:
- Tratamento de erros. Todas as funções assíncronas estão envolvidas em try/catch? O
.catch()das Promises não foi esquecido? Existem Promises "órfãs" (unhandled promise rejections)? - Uso correto de async/await. Não há
awaitdesnecessário onde as Promises poderiam ser executadas em paralelo comPromise.all? - Condições de corrida (race conditions). O código pode ser executado incorretamente com requisições paralelas ao mesmo recurso (por exemplo, um arquivo ou variável global)?
// RUIM: Execução sequencial de requisições independentes
const user = await getUser(id);
const posts = await getPosts(id);
// BOM: Execução paralela
const [user, posts] = await Promise.all([getUser(id), getPosts(id)]);
// RUIM: Tratamento de erros esquecido
router.get('/data', async (req, res) => {
const data = await fetchData(); // Se fetchData falhar, o servidor "cairá" também
res.json(data);
});
// BOM
router.get('/data', async (req, res, next) => {
try {
const data = await fetchData();
res.json(data);
} catch (error) {
next(error); // Passa o erro para o handler global
}
});
3. Qualidade do código, estilo e nomenclatura
O código deve ser legível, como um bom livro. Mesmo que a lógica esteja correta, um estilo ruim tornará o desenvolvimento mais lento no futuro.
- Nomes de variáveis e funções. Os nomes devem responder "o que é isso?" e "o que faz?". Evite variáveis de uma letra (exceto contadores de loop) e abreviações como
getUsrInf. - Números e strings mágicas. Eles são extraídos para constantes?
const MAX_RETRIES = 3;é muito mais compreensível do que