Código Limpo: destaques do capítulo 2
Continuando a série de destaques da leitura do livro Código Limpo, do Robert C. Martin.
Nomes estão em todos lugares em software: variáveis, funções, argumentos, classes, pacotes, etc. Como criamos nomes o tempo inteiro, queremos criar bons nomes. Neste capítulo são apresentadas regras para isso.
Revele a Intenção no Próprio Nome
Escolher bons nomes leva tempo, mas salva mais tempo do que gasta. Não há problema em mudar um nome quando encontrar outro melhor, já que melhorar a clareza do código é uma de suas principais funções. O contexto do nome deve estar no código: não devemos ter que procurar a declaração de uma variável para entendê-la.
Um nome deve responder:
- Porque este elemento existe.
- O que este elemento faz.
- Como usar este elemento.
Se um nome requer um comentário, então o nome não revela sua intenção. Por exemplo, considere o código abaixo:
int d; // elapsed time in days
o nome d
não revela nada. Um nome infinitamente melhor seria:
int elapsedTimeInDays;
Um princípio interessante de lembrar nesse momento: é melhor ter um código claro do que um código conciso. No final das contas, escrevemos código para outras pessoas, não para máquinas.
Outros exemplos de nomes informativos são:
int daysSinceCreation;
int daysSinceModification;
int fileAgeInDays;
Uma ideia bem interessante é usar constantes, aliases ou até enum para o contexto ficar mais claro. Por exemplo, ao invés de:
if (client.type == 1) { enablePremiumFeatures()
}
Podemos usar um enum
e ter:
if (client.type == .premium) { enablePremiumFeatures()
}
Evite Desinformação
Não defina um nome que deixe uma pista falsa sobre o que ele representa. Por exemplo, não nomeie um conjunto de contas como accountList
a não ser que realmente seja uma lista.
Também tome cuidado com nomes muito similares, pois eles tendem a causar confusão. Veja o exemplo de duas classes abaixo:
XYZControllerForEfficientHandlingOfStrings
XYZControllerForEfficientStorageOfStrings
É difícil identificar a diferença entre eles. Este tipo de situação também causa problemas em IDEs onde costumamos digitar só o início da classe e recebemos um autocomplete, que pode acabar sugerindo o elemento errado.
Um exemplo interessante de desinformação é em relação à letra L minúscula ou a letra o maiúscula, que dependendo da fonte usada na IDE, pode nos fazer confundir com i maiúsculo ou com o número 0.
Faça Distinções Significativas
Programadores criam problemas para si mesmos quando escrevem código apenas para o compilador ou interpretador. Nomes como a1, a2,…, an
não provêem informação alguma ao programador. Por exemplo, ao invés de:
public static void copyChars(char a1[], char a2[]) { ... }
Podemos usar:
public static void copyChars(char source[], char destination[]) { ... }
Lembre-se: clareza é melhor que concisão.
Evite também palavras que só adicionam ruído ao nome. Por exemplo: se você tiver uma classe Product
e tiver outra chamada ProductInfo
ou ProductData
, você criou nomes diferentes mas não deixou claro a diferença em seus significados. Info
e Data
são palavras que só adicionam ruído.
Outros nomes com ruído podem ser vistos abaixo:
var aClient;
var theStudent;
var professorVariable;
var clientNameString;
Estes nomes deveriam ser:
var client;
var student;
var professor;
var clientName;
Um exemplo problemático em métodos é:
getActiveAccount();
getActiveAccounts();
getActiveAccountInfo();
Não é possível entender a distinção exata entre os métodos sem procurar sua declaração no código.
Use Nomes Pronunciáveis
Novamente, código é escrito para humanos, e não máquinas. Nomes pronunciáveis são importantes inclusive para momentos de debates sobre o código. (ninguém vai gostar de falar "aquele atributo gê ním dê aga eme éssi" para referenciar genymdhms
).
Exemplo de nomes não pronunciáveis:
class DtaRcrd102 {
private Date genymdhms;
private Date modymdhms;
private final String pszqint = "102";
/*...*/
};
Uma alternativa melhor seria:
class Customer {
private Date generationTimestamp;
private Date modificationTimestamp;
private final String recordId = "102";
/*...*/
}
Use Nomes Buscáveis
Nomes de uma única letra e constantes numéricas tem um problema particular que eles não são facilmente localizáveis em um texto.
Por exemplo, na IDE é fácil buscar uma constante MAX_CLASSES_PER_STUDENT, mas encontrar o número 7 pode ser algo complicado. Por isso é bom definir constantes pra estes casos:
var MAX_CLASSES_PER_STUDENT = 7;
Nomes de uma única letra (o famoso i dentro de um for) devem ser usados apenas como variáveis locais dentro de métodos pequenos.
O tamanho de um nome deve corresponder ao tamanho do seu escopo.
Interfaces e Implementações
Para as interfaces de Java (ou similares em outras linguagens), há um hábito de prefixar com I. Nestes casos, o autor prefere não prefixar com I, mas adicionar um sufixo Imp na implementação. Por exemplo, ao invés de:
interface IShapeFactory { ... }
class ShapeFactory: IShapeFactory { ... }
Teríamos:
interface ShapeFactory { ... }
class ShapeFactoryImp: ShapeFactory { ... }
Isso de certa forma é coerente, já que muitas vezes é a interface que será pública, enquanto a implementação concreta não será acessada diretamente.
Evite Mapas Mentais
O leitor não deve precisar traduzir mentalmente os nomes em outros nomes que ele já conhece.
Por exemplo, um loop pode conter variáveis i
, j
ou k
.Estes nomes já são tradicionais. Porém, escolher uma variável a
seria uma escolha ruim.
Não há razão pior pra escolher o nome
c
do que o fato dea
eb
já estarem sendo usados.
Uma diferença entre um programador inteligente e um programador profissional é que o profissional entende que clareza é fundamental. Profissionais usam seus poderes para uma boa escrita de código que outros entendam.
Nome de Classes
O nome de uma classe deve ser um substantivo ou uma frase que contenha um. Nunca deve ser um verbo.
Exemplo de bons nomes:
Customer
WikiPage
Account
AddressParser
Evite no nome da classe, usar palavras como Manager, Processor, Data, Info.
Nome de Métodos
Métodos devem ser ou conter um verbo no seu nome. Por exemplo:
postPayment()
deletePage()
save()
Métodos que servem pra acessar, modificar ou verificar um predicado devem ser prefixados com get, set e is (padrão javabean):
getName();
setName("Victor");
paycheck.isPosted();
Escolha uma Palavra por Conceito
Escolha uma palavra por abstração e mantenha ela. Por exemplo, é confuso ter fetch
, retrieve
e get
como métodos equivalentes em classes diferentes. Como você irá lembrar de qual nome é usado em qual classe?
Outro caso é ter um controller e um manager usados para a mesma abstração. Dado que ambos executam a mesma função, é possível dizer a diferença essencial entre DeviceManager
e um ProtocolController
? Porque não são ambos controller ou manager? Se os nomes são diferentes, esperamos que representem abstrações diferentes.
Escolha uma palavra por conceito e mantenha essa escolha através do código.
Use Nomes do Domínio da Solução
Quem lerá seu código será um programador, então não tenha medo de usar termos relacionados à ciência da computação: nomes de algoritmos, nomes de padrões, termos matemáticos, etc. Não é sábio criar um nome diferente para representar um conceito que seus colegas já conhecem por outro nome.
Por exemplo, o nome AccountVisitor
já traz informação para o programador que é familiarizado com o padrão Visitor. Outros exemplos são:
UserGraph
PlayerQueue
CustomerBinaryTree
Use Nomes do Domínio do Problema
Quando não há nomes relacionados com ciência da computação, escolha nomes baseados no domínio do problema. Assim, se quem for dar manutenção ao seu código não entendê-lo, ele pode ao menos perguntar para quem entende do domínio do problema.
Adicione Contextos Significativos
As variáveis firstName, lastName, street, houseNumber, city, state, zipCode
juntas claramente formam um endereço.
Porém, se você ver apenas state
, não fica claro sobre o que se trata. Podemos adicionar contexto à esta variável chamando-a de addressState
, por exemplo.
Não Adicione Contexto Gratuitamente
Em Objective-C, era muito comum adicionar prefixos em todas as classes. Por exemplo, se eu desenvolvesse um projeto pessoal, adicionaria o prefixo VM
(de Victor Melo) nas classes:
VMUser
VMAddress
VMDataBaseManager
...
Porém, não precisamos fazer isso na grande maioria dos casos, e isso provavelmente vai dificultar mais na busca por classes na IDE, já que digitar VM
irá exibir todas suas classes.
Por fim, algo muito importante é:
Não tenha medo de renomear algo porque outros desenvolvedores podem reclamar.
Se você acredita que renomear um elemento irá trazer mais clareza ao projeto, faça isso. Novamente, código não é escrito para máquinas, mas para pessoas.