Como fazer code review de verdade (sem ser chato ou inútil)
Introdução
O desenvolvimento de software é um processo contínuo que envolve a criação, manutenção e evolução de aplicações para atender às necessidades dos usuários. Neste contexto, a code review desempenha um papel fundamental na garantia da qualidade do código-fonte, no controle do fluxo de trabalho e na melhoria contínua das práticas de desenvolvimento.
A code review é uma atividade crucial que envolve a revisão do código-fonte por outros membros da equipe com o objetivo de identificar erros, melhorias e padrões de design não adotados. Embora seja uma ferramenta poderosa para garantir a qualidade do código e evitar defeitos, muitas equipes enfrentam desafios em sua implementação eficaz.
Neste artigo, exploraremos as melhores práticas para realizar uma code review de verdade, sem torná-la um processo chato ou inútil. Ao final desta leitura, você estará capacitado a conduzir avaliações do código mais eficazes e produtivas, contribuindo assim para o melhoramento contínuo da qualidade dos seus projetos de desenvolvimento de software.
O que é e por que importa
A code review é um processo de revisão sistemática do código-fonte de uma aplicação, realizado por outros desenvolvedores ou especialistas em qualidade. O objetivo principal é garantir a consistência e a qualidade do código, identificando erros, melhorias e padrões de design não adotados que possam afetar a estabilidade, escalabilidade e manutenibilidade da aplicação.
A code review visa prevenir defeitos, melhorar a legibilidade do código e garantir que os padrões de desenvolvimento estejam sendo seguidos. Ela também é uma oportunidade para compartilhar conhecimentos e experiências entre os membros da equipe, promovendo a inovação e a melhoria contínua dos processos.
Ao realizar uma code review eficaz, você pode identificar problemas como:
- Erros de lógica ou de sintaxe
- Padrões de design não adotados ou inconsistentes
- Possíveis seguranças e vulnerabilidades
- Complexidade excessiva ou duplicação de código
- Falhas em manutenção e escalabilidade
Ao abordar essas questões, a code review ajuda a evitar problemas que poderiam afetar a qualidade do produto final.
Como funciona na prática
1. Preparação
Antes de iniciar a code review, é fundamental que você tenha acesso ao código-fonte e às informações necessárias sobre o projeto, incluindo:
- Documentação do design arquitetural
- Padrões de desenvolvimento adotados
- Regras de qualidade e segurança
2. Definição dos critérios
Estabeleça claramente os critérios de avaliação para a code review, incluindo:
- Padrões de design adotados
- Requisitos de legibilidade e manutenibilidade
- Regras de segurança
- Critérios de qualidade
3. Leitura do código
- Lembre-se de que a leitura é mais importante do que a escrita. Não se preocupe com a velocidade, mas sim com a qualidade da avaliação.
- Leia o código linha por linha, analisando a lógica e a estrutura.
4. Identificação de problemas
- Liste os problemas encontrados, incluindo:
- Erros de lógica ou sintaxe
- Padrões de design não adotados ou inconsistentes
- Possíveis seguranças e vulnerabilidades
- Complexidade excessiva ou duplicação de código
5. Comunicação com o autor
- Comunique-se com o autor dos códigos encontrando, fornecendo feedback claro e específico.
- Forneça sugestões de melhoria e justifique as razões.
6. Revisão do feedback
- O autor dos códigos deve revisar o feedback recebido e responder às questões ou sugestões feitas.
- Certifique-se de que todas as solicitações de mudança sejam registradas e acompanhadas.
7. Integração do feedback
- Integre o feedback nos processos de desenvolvimento, garantindo que todas as melhorias sejam implementadas corretamente.
- Ajuste os critérios de avaliação conforme necessário para refletir melhorias implementadas.
Exemplo real
Vamos considerar um exemplo de código para uma aplicação de gerenciamento de estoque, desenvolvida em Python:
import sqlite3
class Estoque:
def __init__(self):
self.conn = sqlite3.connect('estoque.db')
self.cursor = self.conn.cursor()
def inserir_produto(self, nome, quantidade):
# Inserir produto no banco de dados
sql = "INSERT INTO produtos (nome, quantidade) VALUES (?, ?)"
self.cursor.execute(sql, (nome, quantidade))
self.conn.commit()
return True
def consultar_produto(self, nome):
# Consultar produto no banco de dados
sql = "SELECT * FROM produtos WHERE nome = ?"
self.cursor.execute(sql, (nome,))
produto = self.cursor.fetchone()
return produto
estoque = Estoque()
produto_nome = 'Produto 1'
quantidade = 10
inserido = estoque.inserir_produto(produto_nome, quantidade)
print(inserido) # Deveria retornar True se o produto foi inserido com sucesso
produto_consultado = estoque.consultar_produto(produto_nome)
if produto_consultado:
print(f'Produto encontrado: {produto_consultado[1]}')
else:
print('Produto não encontrado')
Nesse exemplo, há alguns problemas que podem ser identificados durante uma code review:
- Falta de tratamento de exceções. Se houver um problema com a conexão ao banco de dados ou durante a execução da consulta SQL, o programa pode crashar sem fornecer informações úteis.
- A classe
Estoquetem métodos que modificam o estado interno do objeto (conexão e cursor do banco de dados). Isso pode causar problemas se o objeto for compartilhado entre diferentes partes da aplicação ou se forem feitas chamadas simultâneas ao método. - A classe não implementa a regra do Single Responsibility Principle, pois além de gerenciar o estoque, ela também executa operações de banco de dados.
Boas práticas
Use exceções para lidar com falhas de conexão e execução SQL
- Em vez de simplesmente tentar executar uma consulta, use
try-exceptpara capturar possíveis erros e fornecer informações úteis sobre o que aconteceu. Por exemplo:
try:
self.cursor.execute(sql, (nome,))
except Exception as e:
print(f"Erro ao executar SQL: {e}")
return False
Utilize o padrão de projeto Repository para encapsular a lógica de banco de dados
- Em vez de ter métodos de classe que acessam diretamente o banco de dados, crie uma classe separada (
ProdutoRepository) responsável por encapsular essa lógica. Isso facilita a testagem e refatoração do código.
Inclua tratamento de exceções para lidar com problemas de compartilhamento de objetos
- Se a classe
Estoquefor compartilhada entre diferentes partes da aplicação, é importante incluir tratamento de exceções para lidar com possíveis problemas de corrida ou estado inconsistente.
Segue o Single Responsibility Principle (SRP) e separa as responsabilidades
- A classe
Estoquedeve apenas gerenciar o estoque, sem realizar operações de banco de dados. Crie classes separadas para cada responsabilidade para facilitar a manutenção e escalabilidade do código.
Utilize tipo-hype (type hinting) para melhorar a legibilidade e testabilidade
- Use
type hintingpara indicar o tipo esperado das variáveis e argumentos dos métodos. Isso melhora a legibilidade do código e facilita a escritura de testes.
Armadilhas comuns
Evite usar conexões ao banco de dados como atributos de classe
- Em vez disso, considere usar injecção de dependência para fornecer uma instância da conexão ao banco de dados. Isso torna o código mais modular e facilita a testagem.
Fique atento ao escopo das variáveis e não compartilhe instâncias entre métodos
- Assegure-se de que as instâncias da classe
Estoquesejam criadas apenas quando necessário e não compartilhadas entre métodos ou threads. Isso evita problemas de estado inconsistente.
Evite realizar operações de banco de dados em métodos de classe com comportamento imutável
- Em vez disso, considere criar métodos estáticos que realizam as operações necessárias e retornam os resultados desejados. Isso facilita a testagem e torna o código mais previsível.
Não use SQL inline e preferir consultas parametrizadas
- Em vez de usar SQL inline, considere criar consultas parametrizadas para evitar problemas de segurança relacionados a injeção SQL.
Conclusão
Ao realizar um código review de verdade, é crucial focar na estrutura e organização do código, garantindo que ele seja fácil de entender e manter. Isso inclui separar responsabilidades em classes distintas, utilizar tipo-hype para melhorar legibilidade e testabilidade, e evitar armadilhas comuns como compartilhar instâncias entre métodos ou usar SQL inline.
Além disso, é importante considerar a escalabilidade do código e adotar boas práticas de desenvolvimento, como injecção de dependência e uso de consultas parametrizadas. Ao aplicar esses princípios, você pode criar um código mais modular, fácil de testar e menos propenso a erros.
Se você está procurando melhorar suas habilidades em code review ou deseja aprofundar seu conhecimento em técnicas de desenvolvimento sólido, considere explorar recursos como:
- Aprender com os principais princípios da programação orientada a objetos (POO) e padrões de projeto.
- Estudar sobre injecção de dependência e uso eficaz do tipo-hype para melhorar a legibilidade e testabilidade do código.
- Praticar code review em projetos reais, focando em identificar problemas estruturais e sugerir mudanças que melhorem o código.
Ao continuar se desenvolvendo como profissional de tecnologia, você estará melhor equipado para criar soluções robustas e escaláveis, alinhadas com as melhores práticas do setor.
Referências
- Fowler, M. Refatoração. Disponível em: <https://martinfowler.com/books/refactoring.html>. Acesso: 2024.
- Krutch, J. W. Code Complete. Disponível em: <https://www.amazon.com/Code-Complete-Practices-Development-2nd/dp/B001GE230S/>. Acesso: 2024.
- Martin, K. Clean Code. Disponível em: <https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882/>. Acesso: 2024.
- OWASP. Guidelines for Secure Coding. Disponível em: <https://owasp.org/www-community/downloads/guideline_for_secure_coding.pdf>. Acesso: 2024.
- Kent Beck. Test-Driven Development: By Example. Addison-Wesley Professional, 2002.