Code Review em Java: o que verificar e como dar feedback na prática
\n\nCode Review (revisão de código) é uma verificação sistemática do código alheio com o objetivo de identificar erros, melhorar a qualidade e compartilhar conhecimento. No desenvolvimento Java, isso é especialmente importante devido à tipagem forte, particularidades de concorrência e requisitos de desempenho. No entanto, muitos desenvolvedores reduzem a revisão a uma simples verificação de estilo ou, ao contrário, transformam-na em crítica tóxica. Neste artigo, vamos analisar exatamente o que verificar no código Java e como dar feedback para que ele traga benefícios, e não dor.
\n\n1. O que verificar no código Java: checklist para o revisor
\n\nPara que a revisão seja eficaz, é preciso olhar não apenas para a sintaxe, mas também para a arquitetura, segurança e desempenho. Aqui estão as principais categorias a serem verificadas.
\n\n1.1 Arquitetura e design
\n- \n
- Princípios SOLID: a classe viola o princípio da responsabilidade única? A interface está se transformando em um "objeto divino"? \n
- Acoplamento e coesão: as classes devem ter baixo acoplamento (loose coupling) e alta coesão interna (high cohesion). \n
- Uso de padrões: o uso de padrões complexos é justificado? Às vezes, um simples if-else é melhor do que uma fábrica com uma dúzia de classes. \n
// Ruim: classe faz tudo de uma vez\npublic class ReportService {\n public void generateReport() { /* geração */ }\n public void sendEmail() { /* envio */ }\n public void saveToDatabase() { /* salvamento */ }\n}\n\n// Bom: separação de responsabilidades\npublic class ReportGenerator { ... }\npublic class EmailSender { ... }\npublic class ReportRepository { ... }\n\n\n1.2 Tratamento de exceções e erros
\n- \n
- Supressão de exceções: não se deve escrever um
catch (Exception e)vazio — isso esconde erros. \n - Especificidade: capture exceções específicas, não
ExceptionouThrowable. \n - Registro em log: as exceções devem ser registradas com contexto suficiente (stack trace, dados de entrada). \n
// Ruim: engolir a exceção\ntry {\n processFile(file);\n} catch (Exception e) {\n // não fazemos nada\n}\n\n// Bom: registro em log e relançamento\ntry {\n processFile(file);\n} catch (IOException e) {\n log.error("Erro ao processar o arquivo: {}", file, e);\n throw new ProcessingException("Não foi possível processar o arquivo", e);\n}\n\n\n1.3 Desempenho e memória
\n- \n
- Operações redundantes: criação de objetos em loops, cópias desnecessárias de strings com
new String(). \n - Uso de coleções: o tipo está correto (ArrayList vs LinkedList)? Há sincronizações desnecessárias? \n
- Stream API: o stream prejudica a legibilidade? Às vezes, um loop comum é mais claro. \n
// Ruim: criação de string em loop\nString result = "";\nfor (String s : list) {\n result += s; // uma nova string a cada vez\n}\n\n// Bom: StringBuilder\nStringBuilder sb = new StringBuilder();\nfor (String s : list) {\n sb.append(s);\n}\n\n\n1.4 Concorrência e sincronização
\n- \n
- Uso correto de synchronized: uma seção muito grande de código está bloqueada? \n
- Coleções concorrentes: está usando
ConcurrentHashMapem vez de uma tabela hash com sincronização externa? \n - Risco de deadlock: os recursos estão sendo bloqueados em ordem diferente? \n
// Risco de deadlock\nsynchronized (lockA) {\n synchronized (lockB) { ... }\n}\n// Em outra thread:\nsynchronized (lockB) {\n synchronized (lockA) { ... }\n}\n\n\n2. Como escrever código para uma revisão fácil
\n\nUma boa revisão começa com um bom código. E