Para evitar los números mágicos, a menudo escuchamos que debemos dar un nombre literal a significativo. 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;
}
Tengo un método ficticio como este:
Explique: supongo que tengo una lista de personas para servir y, de manera predeterminada, gastamos $ 5 para comprar comida solamente, pero cuando tenemos más de una persona, necesitamos comprar agua y comida, debemos gastar más dinero, tal vez $ 6. Cambiaré mi código, concéntrese en el literal 1 , mi pregunta al respecto.
public int getMoneyByPersons(){
if(persons.size() == 1){
// TODO - return money for one person
} else {
// TODO - calculate and return money for people.
}
}
Cuando le pedí a mis amigos que revisaran mi código, uno dijo que dar un nombre para el valor 1 generaría un código más limpio, y el otro dijo que no necesitamos un nombre constante aquí porque el valor es significativo en sí mismo.
Entonces, mi pregunta es ¿Debería dar un nombre para el valor literal 1? ¿Cuándo es un valor un número mágico y cuándo no? ¿Cómo puedo distinguir el contexto para elegir la mejor solución?
persons
viene y qué describe? Su código no tiene comentarios, por lo que es difícil adivinar lo que está haciendo.if(getErrorCode().equals(4095)) ...
Respuestas:
No. En ese ejemplo, 1 es perfectamente significativo.
Sin embargo, ¿qué pasa si persons.size () es cero? Parece extraño que
persons.getMoney()
funcione para 0 y 2 pero no para 1.fuente
¿Por qué un fragmento de código contiene ese valor literal en particular?
Si el valor literal tiene un significado que no está claro por el contexto, entonces sí, dar un nombre a ese valor a través de una constante o variable es útil. Más tarde, cuando se olvida el contexto original, el código con nombres de variables significativos será más fácil de mantener. Recuerde, la audiencia para su código no es principalmente el compilador (el compilador trabajará felizmente con un código horrible), sino los futuros mantenedores de ese código, que apreciarán si el código se explica por sí mismo.
En su primer ejemplo, el significado de literales tales como
34
,4
,5
no es evidente por el contexto. En cambio, algunos de estos valores tienen un significado especial en el dominio del problema. Por lo tanto, fue bueno darles nombres.En su segundo ejemplo, el significado del literal
1
es muy claro desde el contexto. Introducir un nombre no es útil.De hecho, introducir nombres para valores obvios también puede ser malo, ya que oculta el valor real.
Esto puede ocultar errores si el valor nombrado se modifica o es incorrecto, especialmente si la misma variable se reutiliza en partes de código no relacionadas.
Un código también puede funcionar bien para un valor específico, pero puede ser incorrecto en el caso general. Al introducir abstracciones innecesarias, el código ya no es obviamente correcto.
No hay límite de tamaño en literales "obvios" porque esto depende totalmente del contexto. Por ejemplo, el literal
1024
puede ser totalmente obvio en el contexto del cálculo del tamaño del archivo, o el literal31
en el contexto de una función hash, o el literalpadding: 0.5em
en el contexto de una hoja de estilo CSS.fuente
Hay varios problemas con este código que, por cierto, se pueden acortar así:
No está claro por qué una persona es un caso especial. Supongo que hay una regla comercial específica que dice que obtener dinero de una persona es radicalmente diferente de obtener dinero de varias personas. Sin embargo, tengo que ir y mirar dentro de ambos
getMoneyIfHasOnePerson
ygetMoney
, con la esperanza de entender por qué hay casos distintos.El nombre
getMoneyIfHasOnePerson
no se ve bien. Por el nombre, esperaría el método para verificar si hay una sola persona y, si este es el caso, obtener dinero de él; de lo contrario, no hagas nada. Desde su código, esto no es lo que está sucediendo (o está haciendo la condición dos veces).¿Hay alguna razón para devolver
List<Money>
una colección en lugar de una colección?Volviendo a su pregunta, dado que no está claro por qué hay un tratamiento especial para una persona, el dígito debe reemplazarse por una constante, a menos que haya otra forma de hacer explícitas las reglas. Aquí, uno no es muy diferente de cualquier otro número mágico. Podría tener reglas comerciales que indiquen que el tratamiento especial se aplica a una, dos o tres personas, o solo a más de doce personas.
Haces lo que haga que tu código sea más explícito.
Ejemplo 1
Imagine la siguiente pieza de código:
¿Es cero aquí un valor mágico? El código es bastante claro: si no hay elementos en la secuencia, no lo procesemos y devolveremos un valor especial. Pero este código también se puede reescribir así:
Aquí, no más constante, y el código es aún más claro.
Ejemplo 2
Toma otra pieza de código:
No toma mucho tiempo entender lo que hace en lenguajes como JavaScript que no tienen
round(value, precision)
sobrecarga.Ahora, si quieres introducir una constante, ¿cómo se llamaría? El término más cercano que puede obtener es
Precision
. Entonces:¿Mejora la legibilidad? Puede ser. Aquí, el valor de una constante es bastante limitado, y puede preguntarse si realmente necesita realizar la refactorización. Lo bueno aquí es que ahora, la precisión se declara solo una vez, por lo que si cambia, no corre el riesgo de cometer un error como:
cambiando el valor en una ubicación y olvidando hacerlo en la otra.
Ejemplo 3
A partir de esos ejemplos, puede tener la impresión de que los números deben reemplazarse por constantes en todos los casos . Esto no es verdad. En algunas situaciones, tener una constante no conduce a la mejora del código.
Tome el siguiente código:
Si intenta reemplazar ceros por una variable, la dificultad sería encontrar un nombre significativo. ¿Cómo lo nombrarías?
ZeroPosition
?Base
?Default
? Introducir una constante aquí no mejoraría el código de ninguna manera. Lo haría un poco más largo, y solo eso.Tales casos son, sin embargo, raros. Por lo tanto, cada vez que encuentre un número en el código, intente encontrar cómo se puede refactorizar el código. Pregúntese si hay un significado comercial para el número. En caso afirmativo, una constante es obligatoria. Si no, ¿cómo nombrarías el número? Si encuentra un nombre significativo, eso es genial. Si no, es probable que encuentre un caso en el que la constante sea innecesaria.
fuente
Podría hacer una función que tome un solo parámetro y devuelva cuatro veces dividido por cinco que ofrezca un alias limpio de lo que hace mientras sigue usando el primer ejemplo.
Solo estoy ofreciendo mi propia estrategia habitual, pero quizás también aprenda algo.
Lo que estoy pensando es.
Lo siento si no estoy en la base pero solo soy un desarrollador de JavaScript. No estoy seguro de qué composición justifiqué esto, supongo que no todo tiene que estar en una matriz o lista, pero .length tendría mucho sentido. Y el * 4 haría que el bien sea constante ya que su origen es nebuloso.
fuente
Ese número 1, ¿podría ser un número diferente? ¿Podría ser 2 o 3, o hay razones lógicas por las que debe ser 1? Si debe ser 1, entonces usar 1 está bien. De lo contrario, puede definir una constante. No llames a eso constante UNO. (Lo he visto hecho).
60 segundos en un minuto: ¿necesitas una constante? Bueno, son 60 segundos, no 50 o 70. Y todos lo saben. Entonces eso puede seguir siendo un número.
60 elementos impresos por página: ese número podría haber sido fácilmente 59 o 55 o 70. En realidad, si cambia el tamaño de la fuente, podría convertirse en 55 o 70. Entonces, aquí se pide más una constante significativa.
También es una cuestión de qué tan claro es el significado. Si escribe "minutos = segundos / 60", está claro. Si escribe "x = y / 60", eso no está claro. Debe haber algunos nombres significativos en alguna parte.
Hay una regla absoluta: no hay reglas absolutas. Con la práctica, descubrirá cuándo usar números y cuándo usar constantes con nombre. No lo hagas porque un libro lo dice, hasta que entiendas por qué dice eso.
fuente
minutes*60
, a veces inclusohours*3600
cuando lo necesito sin declarar constantes adicionales. Durante días probablemente escribiríad*24*3600
od*24*60*60
porque86400
está cerca del borde donde alguien no reconocerá ese número mágico de un vistazo.He visto una buena cantidad de código como en el OP (modificado) en las recuperaciones de DB. La consulta devuelve una lista, pero las reglas de negocio dicen que solo puede haber un elemento. Y luego, por supuesto, algo cambió para 'solo este caso' a una lista con más de un elemento. (Sí, dije bastantes veces. Es casi como si ... nm)
Entonces, en lugar de crear una constante, crearía (en un método de código limpio) un método para dar un nombre o aclarar lo que el condicional pretende detectar (y encapsular cómo lo detecta):
fuente