Pular para o conteúdo

Uma boa parte do tempo de desenvolvimento de software não é gasta “escrevendo código novo”, mas lendo e entendendo código já existente. Estimativas empíricas em projetos reais apontam que a maior parte do esforço de manutenção está ligada à compreensão de código.

Nomes são a principal interface entre o código e a nossa capacidade de entendê‑lo:

  • Eles indicam o que é (variáveis, classes, módulos);
  • Eles indicam o que faz (funções, métodos);
  • Eles carregam informação de domínio (regras de negócio, conceitos da aplicação).

Em muitos sistemas grandes, análises mostram que mais da metade das linhas é composta apenas por identificadores (nomes). Uma escolha ruim nesses elementos tem efeito cascata em toda a base de código.

Um computador não se importa se a variável se chama x, d ou diasDesdeUltimaAtualizacao. Mas para uma pessoa — ou um time — essa escolha muda completamente o esforço de leitura, revisão e evolução do sistema.

Ao longo do capítulo, vamos detalhar vários princípios, mas é útil ter um “checklist mental” inicial:

Um bom nome tende a ser:

  • Descritivo: indica claramente o que representa ou o que faz.
  • Consistente: segue o mesmo padrão de outros nomes no sistema.
  • Não enganoso: não sugere um comportamento ou tipo diferente do real.
  • Pronunciável e memorizável: facilita discussão em equipe.
  • Adequado ao contexto: nível de detalhe condizente com o lugar onde é usado.

Nem sempre é possível atingir todos esses pontos de forma perfeita, mas eles servem como bússola ao revisar ou criar novos identificadores.


Em geral, estruturas que representam dados ou entidades devem ser nomeadas com substantivos ou locuções substantivas:

  • Variáveis, campos e propriedades;
  • Classes de domínio;
  • Data Transfer Objects (DTOs), entidades de banco, etc.

Exemplos:

usuario
analise_agenda
device_storage
user_profile
pedido
endereco_entrega

Esses nomes respondem à pergunta: “Que tipo de coisa é isso?”.

Funções e métodos representam comportamento; em programação imperativa e orientada a objetos, isso se traduz em ações sobre dados. Por isso, é natural que sejam nomeados com verbos ou locuções verbais:

save_user_profile
get_user_info
get_user_data
calcular_total_pedido
validar_documento

Esses nomes respondem à pergunta: “O que essa função faz?”.

Essa distinção entre substantivos (coisas) e verbos (ações) ajuda a manter um modelo mental claro da arquitetura: classes e estruturas de dados descrevem o mundo; funções e métodos descrevem o que acontece nele.


Caprile e Tonella analisaram bases de código reais e identificaram categorias comuns de nomes de funções. Entender essas categorias ajuda a padronizar padrões de verbo dentro de um código.

Nomes que representam eventos, estados ou “ganchos” (hooks):

  • error
  • on_error
  • on_error_callback
  • before_save
  • after_commit

Geralmente aparecem em frameworks orientados a eventos, middlewares e registradores de callback.

Funções com nomes verbais simples, sem objeto explícito:

  • open
  • close
  • kill
  • start
  • stop
  • reset

Nesse caso, o objeto implícito costuma ser o próprio contexto da classe ou o recurso associado:

arquivo.open()
conexao.close()
timer.reset()

Nomes que incluem o objeto alvo da operação:

  • read_line
  • write_line
  • enviar_email
  • atualizar_endereco
  • calcular_desconto

Esse padrão é muito útil quando uma mesma classe realiza operações distintas sobre múltiplos elementos.

Funções que tentam expressar duas ações diferentes:

  • search_and_replace_text
  • confirmar_e_salvar
  • validar_e_enviar

Geralmente indicam violação de responsabilidade única. Em vez disso, costuma ser melhor quebrar em duas funções menores:

def search_text(...):
# ...
def replace_text(...):
# ...
def confirmar():
# ...
def salvar():
# ...

Funções que retornam tipicamente um valor booleano, muitas vezes usadas em condicionais:

  • is_valid
  • is_empty
  • tem_estoque
  • possui_acesso
  • is_valid_email

Esse padrão torna o código de chamada bastante natural:

if usuario.possui_acesso(recurso):
# ...

Funções que convertem de um formato/representação para outro:

  • convert_to_hex
  • converter_para_binario
  • to_json
  • from_dto
  • parse_date

Exemplo:

def convert_to_hex(number: int) -> str:
return hex(number)

É importante que o nome deixe claro a direção da conversão (to_ / from_) para evitar ambiguidades.


4. Nomes com significado (em vez de letras soltas)

Seção intitulada “4. Nomes com significado (em vez de letras soltas)”

Considere:

d = 50 # tempo decorrido em dias
print(d)

Sem o comentário, o que significa d? Dias? Distância? Desconto? Karen Carpenter?

O fato de precisarmos de um comentário para explicar já indica que o nome é fraco. Melhor escrever:

# en
days_since_modification = 50
print(days_since_modification)
# pt-br
dias_desde_modificacao = 50
print(dias_desde_modificacao)

Vantagens:

  • O próprio nome carrega o contexto.
  • Se o comentário ficar desatualizado, o nome ainda é autoexplicativo.
  • Ferramentas de busca e refatoração funcionam melhor (é fácil encontrar todos os usos de dias_desde_modificacao).

Compare:

#en
def user(user_id):
return db.get_user(user_id)
#pt-br
def usuario(id_usuario):
return db.get_user(id_usuario)

O nome user/usuario não indica ação. Pelo contexto, poderia tanto:

  • Criar um usuário;
  • Atualizar um usuário;
  • Buscar um usuário;
  • Validar um usuário.

Uma opção muito mais clara:

#en
def get_user_by_id(user_id):
return db.get_user(user_id)
#pt-br
def retorna_usuario_por_id(id_usuario):
return db.get_user(id_usuario)

Agora, antes de ler a implementação, sabemos exatamente a intenção da função.

def c(x, y):
return x * y + 10
a = 5
b = 3
print(c(a, b))

Descrever esse código para um colega exige explicar o que é c, o que são a e b, o que significa o + 10 etc.

Uma escrita mais alinhada com código limpo seria:

def calcular_preco_total(preco_unitario, quantidade):
taxa_fixa = 10
return preco_unitario * quantidade + taxa_fixa
preco = 5
quantidade = 3
print(calcular_preco_total(preco, quantidade))

Agora:

  • calcular_preco_total indica a intenção;
  • preco_unitario, quantidade e taxa_fixa comunicam o papel de cada valor;
  • O leitor consegue antecipar o resultado antes de executar.

Um nome pode ser pior do que não dizer nada quando sugere algo diferente do que realmente faz ou representa.

#en
accountList = Account()
#pt-br
lista_de_contas = Conta()

Aqui, o nome sugere uma coleção (List, lista_de_contas), mas o objeto é apenas uma instância (Account, Conta). Isso induce erros de leitura e de uso.

Versão mais adequada:

#en
account = Account()
#pt-br
conta = Conta()

O mesmo vale para:

#en
students = Student()
#pt-br
alunos = Aluno()

Corrigindo:

#en
student = Student()
#pt-br
aluno = Aluno()

Regra prática: variáveis com um único elemento não devem estar no plural.

5.2. “Primeiro número” que na verdade é o menor

Seção intitulada “5.2. “Primeiro número” que na verdade é o menor”
#en
def get_first_number(numbers):
return min(numbers)
#pt-br
def get_primeiro_numero(numeros):
return max(numeros)

first/primeiro sugere ordem, não necessariamente valor mínimo ou máximo. Uma leitura rápida poderia supor “primeiro elemento da lista”.

Melhor:

#en
def get_lower_number(numbers):
return min(numbers)
#pt-br
def get_menor_numero(numeros):
return min(numeros)

Agora o nome comunica claramente que estamos tratando de valor mínimo.


#en
def delete_user(user_id):
# ...
def remove_user(user_id):
# ...
# pt-br
def deletar_usuario(id_usuario):
# ...
def remover_usuario(id_usuario):
# ...

Aqui, delete/remove (ou deletar/remover) são praticamente sinônimos. Isso gera confusão:

  • Qual deleta permanentemente?
  • Qual marca como inativo?
  • Ambos fazem a mesma coisa?

É melhor reservar verbos distintos para diferenças reais de comportamento:

#en
def delete_user(user_id):
# remove permanentemente do banco
def disable_user(user_id):
# marca usuário como inativo
# pt-br
def deletar_usuario(id_usuario):
# remove permanentemente
def desabilitar_usuario(id_usuario):
# inativa usuário sem removê-lo do banco
#en
def login(user_id, password):
# ...
def cancel(user_id):
# ...
#pt-br
def logar(id_usuario, senha):
# ...
def cancelar(id_usuario):
# ...

O par natural de login é logout, não cancel. cancel é vago: cancelar o quê? a sessão? a conta? o pedido?

Versão mais clara:

#en
def login(user_id, password):
# ...
def logout(user_id):
# ...
# pt-br
def logar(id_usuario, senha):
# ...
def deslogar(id_usuario):
# ...

Consistência em pares opostos ajuda a identificar rapidamente fluxos completos.


#en
ymdhms = datetime.datetime.now()
#pt-br
amdhms = datetime.datetime.now()

Esses nomes tentam codificar o formato da data (year-month-day-hour-minute-second / ano-mes-dia-hora-minuto-segundo), mas são difíceis de ler e pronunciar.

Melhor usar algo simples e semânticamente claro:

#en
timestamp = datetime.datetime.now() # YYYY-MM-DD HH:MM:SS.mmmmmm
#pt-br
timestamp = datetime.datetime.now() # AAAA-MM-DD HH:MM:SS.mmmmmm

Se for relevante, o formato pode ser descrito em um comentário, não no nome.

temp_55834 = 55834

O nome temp_55834 não diz nada sobre o significado do número. Se for população:

population = 55834

Agora, qualquer leitor entende o contexto sem precisar de documentação adicional.


8. Abreviações: quando atrapalham mais do que ajudam

Seção intitulada “8. Abreviações: quando atrapalham mais do que ajudam”

Abreviações tendem a:

  • Ser difíceis de pronunciar;
  • Ser interpretadas de formas diferentes por pessoas diferentes;
  • Perder significado fora do contexto imediato.
#en
def get_df_user()
#pt-br
def recebe_usuario_pd()

Aqui df e pd podem significar “data frame”, “default”, “padrao”, “pandas”, entre outras coisas.

Versão mais clara:

#en
def get_default_user()
#pt-br
def recebe_usuario_padrao()

Regra prática: prefira nomes completos, exceto em casos em que a abreviação seja extremamente estabelecida no domínio (id, url, http, etc.).


Nomes muito curtos são mais difíceis de localizar em buscas:

x = 3
y = 20

x e y aparecem em muitos contextos — inclusive em dependências externas, bibliotecas padrão e exemplos de testes.

Quando o contexto permite, use nomes um pouco mais específicos:

x_axis = 3
y_axis = 20

Nem sempre isso é necessário (em operações matemáticas pequenas, x e y são aceitáveis), mas em código de domínio de negócio ou em trechos longos, nomes específicos ajudam tanto a busca quanto o entendimento.


10. Prefixos e sufixos (e quando ainda fazem sentido)

Seção intitulada “10. Prefixos e sufixos (e quando ainda fazem sentido)”

10.1. Tipos no nome da variável: prática ultrapassada

Seção intitulada “10.1. Tipos no nome da variável: prática ultrapassada”

Em várias linguagens antigas, era comum indicar o tipo da variável no nome:

#en
s_name = "John"
#pt-br
s_nome = "John"

Nesse caso, s_ indicaria string.

Com ferramentas modernas (IDEs, tipagem estática, inspeção de tipo em tempo de desenvolvimento), esse padrão de “Hungarian Notation” deixa de ser útil e apenas polui o nome.

Versão mais limpa:

#en
name = "John"
#pt-br
nome = "John"

Há contextos em que prefixos ou sufixos ainda trazem clareza de papel, não de tipo. Por exemplo, distinção entre interface e implementação:

public interface IUserRepository {
void save(User user);
}
public class UserRepositoryImpl implements IUserRepository {}

Aqui, o prefixo I e o sufixo Impl comunicam design estrutural, não tipo primitivo. Equipes podem adotar padrões semelhantes, desde que sejam consistentes em todo o projeto.


Nem todo nome precisa ser longo. Em casos simples e locais, nomes curtos são aceitáveis:

for i in range(10):
print(i)

Dentro de um for pequeno, i é uma convenção bem estabelecida para índice.

Considere:

class Usuario:
def __init__(self, nome, idade, email, x, y, z, a, b):
self.nome = nome
self.idade = idade
self.email = email
self.x = x
self.y = y
self.z = z
self.a = a
self.b = b

Aqui, um leitor precisa constantemente voltar para a definição da classe para lembrar o que é x, y, z, a, b. Isso aumenta a carga cognitiva sem necessidade.

Idealmente, cada atributo deveria ter um nome que indicasse claramente seu papel (endereco, cpf, telefone, etc.).

11.3. Nomes grandes demais indicam responsabilidades grandes demais

Seção intitulada “11.3. Nomes grandes demais indicam responsabilidades grandes demais”
#en
def findArticlesWithoutTitlesThenApplyDefaultStyles ()
#pt-br
def encontrar_artigos_sem_titulos_então_aplicar_estilos_padrão ()

Essa função provavelmente está fazendo mais de uma coisa: localizar artigos e aplicar estilos. O nome longo tenta descrever todas essas ações.

Melhor extrair funções menores:

#en
def find_articles_without_titles():
# ...
def apply_default_styles(articles):
# ...
#pt-br
def encontrar_artigos_sem_titulos():
# ...
def aplicar_estilos_padrao(artigos):
# ...

Além de reduzir a complexidade da função, isso aproxima o design do Princípio da Responsabilidade Única (SRP).


Classes de domínio, em geral, são substantivos:

  • User, Product, Account, Order, AddressAnalysis.
  • Usuario, Produto, Conta, Pedido, AnaliseEndereco.

Evite nomes genéricos como:

  • Manager, Processor, Data, Info, Helper, Util.

Esses termos frequentemente escondem falta de clareza de responsabilidade. Em vez de UserManager, pense se não é possível ter:

  • UserService, com responsabilidades bem definidas;
  • Ou separar em serviços mais específicos (UserRegistrationService, PasswordResetService), dependendo do tamanho do domínio.

12.2. Métodos: verbos que descrevem comportamento

Seção intitulada “12.2. Métodos: verbos que descrevem comportamento”

Métodos geralmente são verbos:

  • post_tweet
  • delete_user
  • calculate_total
  • register_new_order

Isso vale tanto para métodos de instância quanto para funções estáticas ou livres.


Nomes cheios de piadas internas, gírias locais ou referências culturais obscuras podem parecer divertidos no momento, mas:

  • Dificultam a compreensão por pessoas de outras regiões/países;
  • Ficam rapidamente datados;
  • Prejudicam a comunicação profissional (documentação, artigos, apresentações).

Exemplo:

def jogar_granada_de_mao(usuario_id):
# deleta usuário do sistema
...

Esse tipo de nome pode ser engraçado em uma conversa, mas é inapropriado no código de produção. Prefira:

def deletar_usuario(usuario_id):
...

Às vezes, o melhor nome não é aquele que replica a linguagem de negócio, mas sim a abstração técnica que o código está de fato modelando.

Exemplo:

  • Do ponto de vista do problema: “sala de espera”.
  • Do ponto de vista da solução: isso pode ser melhor representado como uma fila de elementos (queue), com operações de enfileirar e desenfileirar.

Em vez de chamar a classe de SalaDeEspera, pode ser mais útil nomeá‑la como:

  • FilaDeEspera
  • FilaDeAtendimento

Esse nome comunica tanto o contexto de domínio (espera, atendimento) quanto a estrutura de dados subjacente (fila), facilitando o entendimento do comportamento.

Em outros casos, o mais importante é manter a linguagem ubíqua do domínio, especialmente quando:

  • O código é lido por especialistas de negócio;
  • A lógica implementa regras complexas e específicas;
  • O vocabulário técnico é menos esclarecedor do que a terminologia de domínio.

Exemplo:

  • Nome interno estranho como IndividuoPreterido.
  • Melhor: JogadorReserva, que expressa diretamente o papel em um time esportivo.

Adicionar sufixos ou prefixos redundantes também prejudica a clareza.

Exemplo: em um sistema chamado “Gerenciador de Estudantes (GE)”, nomear cada classe com sufixo GE:

  • ProfessorGE
  • AlunoGE
  • CursoGE

Esse sufixo não adiciona informação relevante, apenas aumenta o tamanho dos nomes. Em geral, o contexto do pacote/módulo já identifica a que sistema aquele código pertence.

Prefira:

  • Professor
  • Aluno
  • Curso

16. Resumo dos principais problemas de nomenclatura

Seção intitulada “16. Resumo dos principais problemas de nomenclatura”

De forma geral, um nome ruim costuma cair em uma (ou mais) das seguintes categorias:

  1. Muito específico de forma inadequada

    • Faltam informações importantes (set, doIt, handle sem contexto);
    • Ou é longo demais, misturando várias responsabilidades (get_all_users_with_permission_to_edit_article).
  2. Muito ambíguo

    • Expressa um conceito genérico demais (inteiro, string, dados);
    • Tem múltiplos significados possíveis (file, data, info);
    • Não é óbvio (blowfish para uma função de criptografia, por exemplo, sem contexto).
  3. Incorreto

    • Não condiz com o que a variável representa ou a função faz (nome sugere uma coisa, implementação faz outra).
  4. Inconsistente

    • Usa padrões diferentes para coisas semelhantes (getUser, fetch_usuario, load_user_data);
    • Usa sinônimos para funções com papéis próximos (como delete vs remove sem distinção clara).

  • Use dicionários e tesauros para encontrar termos mais precisos:
  • Reaproveite verbos e substantivos já usados no projeto para o mesmo conceito:
    • Se em um lugar você usa delete, evite remove para a mesma operação.
  • Padronize naming conventions com o time:
    • Documente em um guia de estilo interno;
    • Automatize o que for possível com linters e ferramentas de análise.
  • Não tenha medo de refatorar nomes:
    • Renomear variáveis, funções e classes é uma das refatorações mais seguras e com maior retorno em legibilidade;
    • Ferramentas modernas (IDEs, LSPs) tornam essa operação trivial.

Nesta unidade, você viu que:

  • Nomenclatura é um dos fatores centrais de legibilidade em código;
  • Bons nomes ajudam a reduzir a carga cognitiva, facilitar o onboarding e evitar bugs;
  • Existem padrões típicos de nomes para funções, variáveis e classes, que podem ser aplicados de forma consistente;
  • É preciso evitar nomes enganosos, abreviações obscuras, piadas internas e ruído desnecessário;
  • A escolha entre termos do domínio da solução e do domínio do problema depende do contexto e do público do código;
  • Refatorar nomes é uma prática essencial em código limpo.

Ao longo da disciplina, procure aplicar esses princípios sempre que escrever ou revisar código. Em particular, ao encontrar um trecho difícil de entender, pergunte‑se:

“Esse código está complicado porque a lógica é complexa, ou porque os nomes estão ruins?”

Muitas vezes, melhorar apenas a escolha de nomes já torna o código significativamente mais limpo, antes mesmo de qualquer grande refatoração estrutural.