O quê Enzo, x2, Nairobi e Enfermería tem a ver com o seu código


Todas as vezes que eu escrevo alguma coisa eu tento colocar um título interessante que consiga merecer a atenção de alguém para lê-lo e, ao mesmo tempo, passe a mensagem que eu quero. É irritante quando a gente clica num link e quando abre é outra coisa, não é?

Mas é isso mesmo que você leu. O assunto de hoje é esse: nomes. Aqui algumas dicas, histórias e porquê eu acho nomes importantes. Divirta-se e deixe/mande um feedback! :)


Confesso que fiquei pouco relutante em escrever esse texto, afinal todo mundo já sabe que dar bons nomes é bem importante. Mas será mesmo? Por quê que algo tão simples é tão importante?

Otimizando o trabalho cerebral

Talvez você já tenha escutado por aí ou percebido que passamos muito tempo lendo código, seja pra corrigir um bug ou implementar uma funcionalidade nova. Quando esse código não está legível essa tarefa acaba requerendo muito mais da nossa capacidade cognitiva, o que nos leva a demorar mais tempo na nossa tarefa e até mesmo ao cansaço mental. A legibilidade de um código pode ser determinada por vários fatores: quantidade de código duplicado, estruturas aninhadas, excesso de comentários, organização dos pacotes etc. Mas um dos fatores mais simples de resolver é a nomenclatura (ou naming). Em outras palavras: dar os nomes certos ~aos bois~.

Nomeando variáveis, métodos, classes, módulos, ou o que seja, de maneira intuitiva ajuda a quem lê o seu código a aproveitar melhor a capacidade do cérebro. O ser humano que estiver lendo não precisará fazer esforço para entender o que você quis dizer, o que aquela coisa representa ou até mesmo o próximo caminho. A leitura, que é um processo internalizado, será o guia para o ensino do que o código faz, tornando o aprendizado e o entendimento mais leves.

Tornar as coisas simples e expressivas melhora muito a qualidade do que você escreve de maneira super rápida, o que te faz atingir outros objetivos como compartilhar conhecimento acerca do código e melhorar a manutenibilidade (a arte de fazer com que o código seja mais fácil de alterar ou adicionar um comportamento).

Sintomas e dicas

Espero que a essa altura você ache que esse papo todo faz sentido. 😅 Quero te mostrar alguns sintomas de nomenclatura ruim e dicas pra ajudar a resolvê-los (e também explicar esse título esquisito).

x2

Eu não sei se isso veio da matemática ou os docentes de computação são meio sádicos mesmo mas é super comum encontrarmos por aí umas variáveis como x2 ou a. Só queria ⭐ morta quando eu tenho que descobrir o que o tal do x2 faz. Por conta de professores, exemplos na internet etc muitas vezes reproduzimos esse padrão de nomes, o que não deixa explícito em nada o que a variável representa.

O objetivo de uma variável é guardar um valor, que tem um significado dentro de um contexto (que pode ser também o mundo real). Por que não nomear com o significado dela?

Olhando para esses dois métodos, podemos ver a diferença que apenas o nome das coisas faz:

ANTES

def convert(string):
    return string.lower().replace(' ', '-')

DEPOIS

def title_to_slug(title):
    return title.lower().replace(' ', '-')

Talvez a segunda abordagem tenha sido melhor. 😄 (Tudo bem que essa coisinha maravilhosa e cheirosa chamada Python ajuda também…hehe)

Enfim, mais nomes expressivos, por favor!

Enfermería

Uma certa vez estava estagiando em uma empresa onde eu tinha um colega que morou uns tempos na Espanha. Nós estávamos mexendo no mesmo módulo quando comecei a ver uns nomes em espanhol no código… Chamei ele pra perguntar o que estava rolando e ele me falou que tinha posto aquele nome porque o nome que ele queria já estava sendo usado. 😂

Nomes expressivos mas na mesma linguagem utilizada no seu codebase. :)

Enzo

Ao utilizar alguns frameworks acabamos utilizando muitas estruturas que já vem com nomes prontos, o que torna fácil encher alguns métodos de códigos que já poderiam estar encapsulado em outros métodos menores, cada um com suas responsabilidades bem definidas. Um exemplo que acontece muito onde trabalho é a adição de algumas validações em métodos como clean ou save. Adicionar blocos e blocos de código, sem estar explícito o que está acontecendo também é ruim. A ideia é sair dos métodos Enzo, esses que são iguais por convenção, e extrair para métodos privados com nomes que mostrem o que eles fazem sem que a pessoa precise abrir a implementação para descobrir.

Lista de chamada com 7 Enzos Fonte: Lista de chamada com sete ‘Enzos’ viraliza e vira meme na internet

Fazer exemplos pequenos é complicado mas vamos tentar. Digamos que você tem um form Django que é a matrícula de um aluno em um curso qualquer. Para esse form ser válido, você precisa verificar se o estudante já está matriculado naquele curso e se ele tem a disponibilidade adequada. Qualquer similaridade com um código real é mera coincidência. 😅

Um dos jeitos de fazer isso é adicionar a validação no método clean.

def clean(self):
    if self.student.is_enrolled:
        raise forms.ValidationError('Already enrolled')

    if (hasattr(self.student, 'availability') and
            self.student.availability):

        availability = self.student.availability
        if availability.status in [
            availability.STATUSES.online,
            availability.STATUSES.evenings,
            availability.STATUSES.on_weekdays,
        ]:
            raise forms.ValidationError("Your availability doesn't match with your preferences")

Repare que informações importantes para o negócio estão dentro da validação de um formulário. Caso você precise implementar um outro formulário que precise saber se o estudante já está matriculado no curso que ele está tentando modificar ou a disponibilidade dele, terá que repetir código, correndo o risco de deixar o seu sistema inconsistente ainda por cima.

Vamos reescrever de forma que as informações de negócio fiquem encapsuladas nos models:

def clean(self):
    if self.student.is_enrolled:
        raise forms.ValidationError('Already enrolled')

    if self.student.is_available_on_weekdays_evening():
        error_message = "Your availability doesn't match your preferences"
        raise forms.ValidationError(error_message)

O código ficou menor e melhor para ler. Certamente não precisa ter nomes gigaaantes, o ideal é encontrar o meio do caminho. :)

Nairóbi

Certo dia eu estava muito empolgada porque tinha conseguido reduzir um teste de 1 minuto e alguns segundos para menos de 2 segundos. Nada mal, não? Até que o revisor do meu pull request me disse que não daria para mergear. Eu fui logo questionar, afinal essa melhora no tempo era o suficiente pra mim. Até que ele me explicou que a versão lenta era legível, a minha não. (Pois é, você está lendo um texto dessa pessoa aí). Por fim pareamos e refatoramos, chegando a um consenso. Deu certo!

Mas eu ainda acho que estava legível… Hahaha Falando sério, o meu colega tinha razão. Em La Casa de Papel o Professor colocou os apelidos dos atracadores nomes de cidades pra que ninguém se identificasse. Nosso código não precisa ser assim.

Alguns assaltantes da série La Casa de Papel Fonte: “La Casa de Papel”: série da Netflix que conquistou legião de fãs ganha novos episódios

Dar bons nomes e, por consequência, deixar o código mais legível é um exercício constante. Receber feedback é importante, afinal a pessoa que estiver lendo o seu código vai ser o seu primeiro usuário. Auto crítica também faz parte. Depois que estamos envolvidos com o código e com o que ele faz, às vezes é difícil ter um olhar crítico. Mas não custa fazer um esforço!

Legibilidade e as responsabilidades de um código

Não é diretamente o tópico desse texto mas gostaria de finalizar falando sobre algo super importante: a responsabilidade que um código tem. Pode ser em uma linha, como em uma variável, um método ou classe. Os princípios S.O.L.I.D. são um conjunto de princípios para design de software orientado a objetos. A letra S é de Single Responsibility e diz:

A class should have one, and only one, reason to change.

Trazendo para as demais estruturas além de classes, a ideia é que a estrutura que você está escrevendo deve ter apenas uma responsabilidade. Isso mesmo, só UMA. Você consegue validar se o método, função, classe, que você está escrevendo está acumulando diferentes responsabilidades se ao tentar colocar um nome esse nome não consegue resumir bem o que essa estrutura faz.

def parser_data_and_save(raw_data):
  pass

O mesmo princípio também é aplicado aos testes. Escrever testes com nomes test_ok ou test_error não explica o que o teste faz. Muito menos se você vai mudando o objeto ao longo do caminho e enchendo o teste de asserts. Cada teste deve ter uma única responsabilidade e essa responsabilidade deve estar refletida no nome. Dessa forma, os testes serão uma documentação viva do código, com casos de uso que serão representados pelos testes.


Como já diria o zen do python explícito é melhor que implícito. As dicas são simples mas podem trazer benefícios imediatos se aplicadas no dia a dia!

Fique a vontade para deixar feedbacks ou compartilhar práticas que você também usa.

Até mais!


Links legais:

The flat success path

Clean Code


comments powered by Disqus