Boas Práticas Nathan Geeksman

Como fazer code review de verdade (sem ser chato ou inútil)

Como fazer code review de verdade (sem ser chato ou inútil)

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 Estoque tem 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-except para 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 Estoque for 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 Estoque deve 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 hinting para 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 Estoque sejam 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.