Para evitar números mágicos, geralmente ouvimos que devemos dar um nome significativo a um literal. Tal como:
//THIS CODE COMES FROM THE CLEAN CODE BOOK
for (int j = 0; j < 34; j++) {
s += (t[j] * 4) / 5;
}
-------------------- Change to --------------------
int realDaysPerIdealDay = 4;
const int WORK_DAYS_PER_WEEK = 5;
int sum = 0;
for (int j = 0; j < NUMBER_OF_TASKS; j++) {
int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
sum += realTaskWeeks;
}
Eu tenho um método fictício como este:
Explique: Suponho que tenho uma lista de pessoas para servir e, por padrão, gastamos US $ 5 para comprar apenas comida, mas quando temos mais de uma pessoa, precisamos comprar água e comida, precisamos gastar mais dinheiro, talvez US $ 6. Vou mudar meu código, por favor , foque no literal 1 , minha pergunta sobre isso.
public int getMoneyByPersons(){
if(persons.size() == 1){
// TODO - return money for one person
} else {
// TODO - calculate and return money for people.
}
}
Quando pedi a meus amigos que revisassem meu código, um disse que dar um nome ao valor 1 produziria um código mais limpo e o outro disse que não precisamos de um nome constante aqui porque o valor é significativo por si só.
Então, minha pergunta é Devo dar um nome para o valor literal 1? Quando um valor é um número mágico e quando não é? Como posso distinguir o contexto para escolher a melhor solução?
persons
vem e o que descreve? Seu código não possui comentários, portanto é difícil adivinhar o que está fazendo.if(getErrorCode().equals(4095)) ...
Respostas:
Não. Nesse exemplo, 1 é perfeitamente significativo.
No entanto, e se persons.size () for zero? Parece estranho que
persons.getMoney()
funciona para 0 e 2, mas não para 1.fonte
Por que um pedaço de código contém esse valor literal específico?
Se o valor literal tiver um significado que não esteja claro no contexto, será útil dar um nome a esse valor por meio de uma constante ou variável. Mais tarde, quando o contexto original for esquecido, o código com nomes de variáveis significativos será mais sustentável. Lembre-se de que o público do seu código não é primariamente o compilador (o compilador funcionará alegremente com código horrível), mas os futuros mantenedores desse código - que apreciarão se o código é um pouco autoexplicativo.
Em seu primeiro exemplo, o significado de literais, como
34
,4
,5
não é aparente a partir do contexto. Em vez disso, alguns desses valores têm um significado especial no domínio do problema. Portanto, era bom dar nomes a eles.No seu segundo exemplo, o significado do literal
1
é muito claro a partir do contexto. Introduzir um nome não é útil.De fato, a introdução de nomes para valores óbvios também pode ser ruim, pois oculta o valor real.
Isso pode ocultar bugs se o valor nomeado for alterado ou estiver incorreto, especialmente se a mesma variável for reutilizada em partes de código não relacionadas.
Um pedaço de código também pode funcionar bem para um valor específico, mas pode estar incorreto no caso geral. Ao introduzir abstração desnecessária, o código não está mais obviamente correto.
Não há limite de tamanho para literais "óbvios" porque isso depende totalmente do contexto. Por exemplo, o literal
1024
pode ser totalmente óbvio no contexto do cálculo do tamanho do arquivo, ou o literal31
no contexto de uma função hash, ou o literalpadding: 0.5em
no contexto de uma folha de estilo CSS.fonte
Existem vários problemas com esse trecho de código, que, a propósito, podem ser abreviados assim:
Não está claro por que uma pessoa é um caso especial. Suponho que exista uma regra comercial específica que indique que receber dinheiro de uma pessoa é radicalmente diferente de receber dinheiro de várias pessoas. No entanto, eu tenho que ir e olhar dentro de ambos
getMoneyIfHasOnePerson
egetMoney
, na esperança de entender por que existem casos distintos.O nome
getMoneyIfHasOnePerson
não parece certo. Pelo nome, eu esperaria que o método verifique se existe uma única pessoa e, se for esse o caso, receba dinheiro dele; caso contrário, não faça nada. No seu código, não é isso que está acontecendo (ou você está fazendo a condição duas vezes).Existe algum motivo para retornar um
List<Money>
uma coleção em vez de uma coleção?Voltando à sua pergunta, porque não está claro por que existe um tratamento especial para uma pessoa, o dígito um deve ser substituído por uma constante, a menos que exista outra maneira de tornar as regras explícitas. Aqui, um não é muito diferente de qualquer outro número mágico. Você pode ter regras comerciais informando que o tratamento especial se aplica a uma, duas ou três pessoas ou apenas a mais de doze pessoas.
Você faz o que torna seu código mais explícito.
Exemplo 1
Imagine o seguinte pedaço de código:
Aqui zero é um valor mágico? O código é bastante claro: se não houver elementos na sequência, não vamos processá-lo e retornar um valor especial. Mas esse código também pode ser reescrito assim:
Aqui, não mais constante, e o código é ainda mais claro.
Exemplo 2
Pegue outro pedaço de código:
Não leva muito tempo para entender o que ele faz em linguagens como JavaScript que não possuem
round(value, precision)
sobrecarga.Agora, se você deseja introduzir uma constante, como seria chamada? O termo mais próximo que você pode obter é
Precision
. Então:Melhora a legibilidade? Pode ser. Aqui, o valor de uma constante é bastante limitado, e você pode se perguntar se realmente precisa executar a refatoração. O bom aqui é que agora, a precisão é declarada apenas uma vez; portanto, se ela mudar, você não corre o risco de cometer um erro como:
alterando o valor em um local e esquecendo de fazê-lo no outro.
Exemplo 3
A partir desses exemplos, você pode ter a impressão de que os números devem ser substituídos por constantes em todos os casos . Isso não é verdade. Em algumas situações, ter uma constante não leva à melhoria do código.
Pegue o seguinte pedaço de código:
Se você tentar substituir zeros por uma variável, a dificuldade seria encontrar um nome significativo. Como você o nomearia?
ZeroPosition
?Base
?Default
? A introdução de uma constante aqui não aprimora o código de forma alguma. Isso tornaria um pouco mais longo, e exatamente isso.Tais casos são contudo raros. Portanto, sempre que encontrar um número no código, faça um esforço para descobrir como o código pode ser refatorado. Pergunte a si mesmo se existe um significado comercial para o número. Se sim, uma constante é obrigatória. Se não, como você nomearia o número? Se você encontrar um nome significativo, isso é ótimo. Caso contrário, é provável que você encontre um caso em que a constante seja desnecessária.
fonte
Você pode criar uma função que use um único parâmetro e retorne quatro vezes dividido por cinco que ofereça um alias limpo ao que faz enquanto ainda estiver usando o primeiro exemplo.
Estou apenas oferecendo minha própria estratégia usual, mas talvez eu também aprenda algo.
O que estou pensando é.
Desculpe se estou fora da base, mas sou apenas um desenvolvedor de javascript. Não tenho certeza de qual composição justifiquei isso, acho que nem tudo precisa estar em uma matriz ou lista, mas .length faria muito sentido. E o * 4 tornaria o bem constante, pois sua origem é nebulosa.
fonte
Esse número 1, poderia ser um número diferente? Poderia ser 2 ou 3, ou existem razões lógicas pelas quais deve ser 1? Se precisar ser 1, usar 1 é bom. Caso contrário, você pode definir uma constante. Não chame isso de constante. (Eu já vi isso).
60 segundos em um minuto - você precisa de uma constante? Bem, são 60 segundos, não 50 ou 70. E todo mundo sabe disso. Então isso pode permanecer um número.
60 itens impressos por página - esse número poderia ter sido facilmente 59 ou 55 ou 70. Na verdade, se você alterar o tamanho da fonte, ele pode se tornar 55 ou 70. Portanto, aqui é necessária uma constante significativa.
Também é uma questão de quão claro é o significado. Se você escrever "minutos = segundos / 60", está claro. Se você escrever "x = y / 60", isso não está claro. Deve haver alguns nomes significativos em algum lugar.
Há uma regra absoluta: não há regras absolutas. Com a prática, você descobrirá quando usar números e quando usar constantes nomeadas. Não faça isso porque um livro diz isso - até você entender por que diz isso.
fonte
minutes*60
, às vezes atéhours*3600
quando preciso, sem declarar constantes adicionais. Por dias, eu provavelmente escreveriad*24*3600
oud*24*60*60
porque86400
está perto do limite, onde alguém não reconhecerá esse número mágico de relance.Eu já vi uma quantidade razoável de código, como no OP (modificado) nas recuperações de banco de dados. A consulta retorna uma lista, mas as regras de negócios dizem que pode haver apenas um elemento. E então, é claro, algo mudou para 'apenas este caso' para uma lista com mais de um item. (Sim, eu disse várias vezes. É quase como se eles ... nm)
Então, em vez de criar uma constante, eu (no método de código limpo) criaria um método para dar um nome ou esclarecer o que o condicional se destina a detectar (e encapsular como ele o detecta):
fonte