+ sobre Refatoração [edição] de Códigos

+ sobre Refatoração [edição] de Códigos

Mostrarei agora um pouco sobre refatoração de códigos, esse nome bonitinho que talvez seja "aportuguesado", não sei, mas que em linhas gerais trata-se de editar o código.

Claro que é só um pequeno artigo, nada a se comparar a livros como : Refatoração: Aperfeiçoando o Design de Códigos Existentes - Martin Fowler, mas da pra ser um pontapé inicial.


A Refatoração de código é uma prática essencial em desenvolvimento de software, que consiste em reorganizar o código existente para torná-lo mais legível, mantível e eficiente, sem alterar seu comportamento externo. Neste artigo, exploraremos os conceitos básicos de refatoração de código, seus benefícios e algumas técnicas comuns que você pode usar em seu código Python.

Por que refatorar o código?

O código que funciona pode não ser necessariamente bom código. À medida que um projeto cresce e se desenvolve, o código pode se tornar confuso, difícil de entender e difícil de manter. Algumas razões para refatorar seu código incluem:

  • Legibilidade: Um código mais legível é mais fácil de entender e, portanto, mais fácil de manter e aprimorar. Isso também pode melhorar a colaboração em equipe.

  • Manutenção: O código bem organizado é mais fácil de manter e modificar. Isso também reduz o tempo necessário para solucionar problemas ou corrigir erros.

  • Performance: Uma refatoração bem-sucedida pode melhorar o desempenho do código, tornando-o mais rápido e eficiente.

  • Escalabilidade: O código refatorado pode tornar o aplicativo mais escalável, preparando-o para lidar com cargas de trabalho maiores ou situações mais complexas.

Técnicas de refatoração

A refatoração pode assumir muitas formas diferentes e é influenciada pela estrutura do seu código. No entanto, existem algumas técnicas comuns que podem ser usadas para melhorar a qualidade do código Python.

Extração de método

A extração de método é uma técnica usada para dividir uma função grande em funções menores, que fazem parte do mesmo processo. Isso melhora a legibilidade do código e o torna mais modular.

Por exemplo, considere a seguinte função:

def calcular_pagamento(horas_trabalhadas, taxa_hora):
    salario_bruto = horas_trabalhadas * taxa_hora
    imposto_renda = salario_bruto * 0.20
    salario_liquido = salario_bruto - imposto_renda
    return salario_liquido

Esta função realiza vários cálculos em uma única função. Podemos usar a extração de método para dividir esses cálculos em funções separadas:

def calcular_pagamento(horas_trabalhadas, taxa_hora):
    salario_bruto = calcular_salario_bruto(horas_trabalhadas, taxa_hora)
    imposto_renda = calcular_imposto_renda(salario_bruto)
    salario_liquido = calcular_salario_liquido(salario_bruto, imposto_renda)
    return salario_liquido

def calcular_salario_bruto(horas_trabalhadas, taxa_hora):
    return horas_trabalhadas * taxa_hora

def calcular_imposto_renda(salario_bruto):
    return salario_bruto * 0.20

def calcular_salario_liquido(salario_bruto, imposto_renda):
    return salario_bruto - imposto_renda

Observe que agora a função calcular_pagamento chama outras três funções, cada uma com uma responsabilidade clara. Isso torna a função principal mais fácil de ler e entender.

Eliminação de duplicação

Duplicação de código é quando há trechos de código muito semelhantes em diferentes lugares do seu projeto. Isso pode levar a erros quando o código é atualizado em apenas um lugar e não em outros. Além disso, duplicação de código pode tornar o código mais difícil de manter.

Por exemplo, imagine que você tenha duas funções que calculam a área de um retângulo e de um círculo, respectivamente:

def calcular_area_retangulo(base, altura):
    area = base * altura
    return area

def calcular_area_circulo(raio):
    area = 3.14 * raio ** 2
    return area

Observe que a variável area é calculada da mesma maneira nas duas funções. Podemos eliminar a duplicação de código criando uma função separada para calcular a área:

def calcular_area_retangulo(base, altura):
    area = calcular_area_retangulo(base, altura)
    return area

def calcular_area_circulo(raio):
    area = calcular_area_circulo(raio)
    return area

def calcular_area_forma_geometrica(base, altura=None, raio=None):
    if raio:
        area = 3.14 * raio ** 2
    else:
        area = base * altura
    return area

Agora, ambas as funções calcular_area_retangulo e calcular_area_circulo chamam a função calcular_area_forma_geometrica, que realiza o cálculo da área com base nos parâmetros fornecidos. Isso reduz a duplicação de código e torna o código mais fácil de manter.

Substituição condicional por polimorfismo

Substituição condicional por polimorfismo é uma técnica que envolve a criação de uma hierarquia de classes para lidar com situações em que um código é executado de maneiras diferentes com base em uma condição. Em vez de usar várias declarações if-else, o polimorfismo usa a substituição dinâmica de métodos para lidar com diferentes casos.

Por exemplo, considere a seguinte função que verifica se um número é positivo, negativo ou zero:

def verificar_sinal_numero(numero):
    if numero > 0:
        return 'positivo'
    elif numero < 0:
        return 'negativo'
    else:
        return 'zero'

Essa função usa uma declaração if-else para determinar o sinal do número. Em vez disso, podemos criar uma hierarquia de classes, uma para cada caso (positivo, negativo e zero), que contém um método para retornar a mensagem de texto:

class NumeroPositivo:
    @staticmethod
    def mensagem():
        return 'positivo'

class NumeroNegativo:
    @staticmethod
    def mensagem():
        return 'negativo'

class NumeroZero:
    @staticmethod
    def mensagem():
        return 'zero'

def verificar_sinal_numero(numero):
    if numero > 0:
        return NumeroPositivo().mensagem()
    elif numero < 0:
        return NumeroNegativo().mensagem()
    else:
        return NumeroZero().mensagem()

Agora, a função verificar_sinal_numero cria uma instância da classe correspondente com base no sinal do número e chama o método mensagem. Isso permite que o código seja mais modular e fácil de estender. Se precisarmos adicionar suporte para números complexos, por exemplo, podemos criar uma nova classe e adicionar um novo caso à função verificar_sinal_numero sem precisar modificar o código existente.

Simplificação de expressões booleanas

Expressões booleanas complexas podem ser difíceis de entender e de depurar. Ao simplificar essas expressões, tornamos o código mais legível e menos suscetível a erros.

Por exemplo, considere a seguinte expressão booleana:

if a and (b or not c) and (not b or d):
    # faça alguma coisa

Podemos simplificar essa expressão usando identidades booleanas:

if a and (not c or d):
    # faça alguma coisa

Isso torna a expressão mais fácil de ler e entender.

Extração de métodos

Quando um método de uma classe começa a ficar muito grande ou complexo, é uma boa prática extrair partes dele em novos métodos separados. Isso torna o código mais fácil de ler e entender.

Por exemplo, considere a seguinte classe que converte uma data em uma string no formato "dd/mm/aaaa":

class ConversorData:
    def __init__(self, dia, mes, ano):
        self.dia = dia
        self.mes = mes
        self.ano = ano

    def converter_para_string(self):
        resultado = str(self.dia) + '/'
        if self.mes < 10:
            resultado += '0'
        resultado += str(self.mes) + '/'
        resultado += str(self.ano)
        return resultado

Podemos extrair o código que formata o mês em um método separado:

class ConversorData:
    def __init__(self, dia, mes, ano):
        self.dia = dia
        self.mes = mes
        self.ano = ano

    def converter_para_string(self):
        resultado = str(self.dia) + '/'
        resultado += self.formatar_mes() + '/'
        resultado += str(self.ano)
        return resultado

    def formatar_mes(self):
        if self.mes < 10:
            return '0' + str(self.mes)
        else:
            return str(self.mes)

Agora, o código que formata o mês está em um método separado, tornando a classe mais fácil de ler e entender.

Conclusão

No entanto, é importante lembrar que a refatoração deve ser usada com moderação. Refatorar um código que está funcionando pode introduzir novos bugs e consumir tempo e recursos desnecessários. A refatoração deve ser usada principalmente para melhorar a qualidade do código quando novos recursos precisam ser adicionados, ou quando o código se torna difícil de manter.

Além disso, é importante ter testes automatizados para garantir que as mudanças feitas durante a refatoração não afetem o comportamento do sistema. Esses testes devem ser executados regularmente durante o processo de refatoração para garantir que o código ainda está funcionando corretamente.

Em resumo, a refatoração é uma prática importante no desenvolvimento de software que nos permite melhorar a qualidade do código e reduzir a probabilidade de erros. Com as técnicas certas em mãos e com uma abordagem cuidadosa, podemos refatorar nossos códigos de maneira segura e eficaz.