¿Es este el uso de una exageración simbólica constante?

34

Soy bastante nuevo en ingeniería de software y, como ejercicio de aprendizaje, escribí un juego de ajedrez. Mi amigo lo miró y señaló que mi código parecía

for (int i = 0; i < 8; i++){
    for (int j = 0; j < 8; j++){

mientras él insistía en que debería ser

for (int i = 0; i < CHESS_CONST; i++){
    for (int j = 0; j < CHESS_CONST; j++){

con un mejor nombre de símbolo que no me puedo molestar en pensar en este momento.

Ahora, por supuesto, sé que generalmente evito usar números mágicos, pero siento que desde

  1. este número nunca cambiará;
  2. el nombre no podría ser tan descriptivo de todos modos ya que el número se usa en muchos lugares en todo el código; y
  3. cualquiera que esté pasando por el código fuente de un programa de ajedrez debe saber lo suficiente sobre el ajedrez como para saber para qué sirve el 8,

Realmente no hay necesidad de una constante simbólica.

Entonces, ¿qué piensan ustedes? ¿Es esto exagerado, o debería seguir la convención y usar un símbolo?

chocolatedevil
fuente
46
CHESS_CONST es mucho peor que simplemente usar el número 8, pero una constante con un nombre descriptivo sería una mejora. Dices que cualquiera debería saber qué significa 8 en el código, pero esto no es cierto. Un literal entero sin contexto podría significar cualquier cantidad de cosas, como un número de movimientos, número de piezas en el tablero, etc. Un nombre descriptivo para la constante aclararía la intención y, por lo tanto, el código sería más fácil de entender.
JacquesB
43
Personalmente, lo que encuentro mucho más discordante que el número mágico son los nombres iy jlas variables de bucle. Por mi vida no puedo determinar cuál se supone que representa el rango y cuál se supone que representa el archivo. Los rangos van desde 1..8 y archivos van desde a..h, pero en su caso, tanto iy jrango de 0..7, por lo que no ayuda a ver cuál es cuál. ¿Hay alguna crisis internacional de cartas de escasez no sé sobre, o lo que es malo con el cambio de nombre a ranky file?
Jörg W Mittag
44
Juega abogado del diablo por un segundo; Imagina leer el código de ajedrez de alguien donde ha usado un número mágico 8. ¿Puedes suponer que sabes para qué se usa? ¿Cómo puedes estar 100% seguro? ¿Hay alguna posibilidad de que pueda significar algo más? ¿No habría sido un poco mejor si ni siquiera tuvieras que hacer una suposición? ¿Cuánto tiempo podría pasar rastreando el código para determinar si su suposición es correcta? ¿Pasaría menos tiempo si el código hubiera sido más autodocumentado utilizando un nombre significativo y perspicaz?
Ben Cottrell
16
@JacquesB: De hecho. Hay 8 rangos, 8 archivos, 8 peones. Algunos motores de ajedrez usan un sistema de puntos donde ciertas piezas, ciertos campos y ciertos movimientos tienen puntos adjuntos y el motor elige el movimiento con la puntuación más alta. 8 podría ser tal puntaje. 8 podría ser una profundidad de búsqueda predeterminada. Puede ser casi cualquier cosa.
Jörg W Mittag
99
Consideraría usar un bucle foreach, por ejemplo foreach(var rank in Ranks). También consideraría fusionar ambos bucles en uno donde cada elemento es una tupla (rango, archivo).
CodesInChaos

Respuestas:

101

En mi humilde opinión, tu amigo tiene razón al usar un nombre simbólico, aunque creo que el nombre definitivamente debería ser más descriptivo (como en BOARD_WIDTHlugar de CHESS_CONST).

Incluso cuando el número nunca cambie a lo largo de la vida útil del programa, puede haber otros lugares en su programa donde el número 8 ocurrirá con un significado diferente. Reemplazar "8" por BOARD_WIDTHel ancho del tablero, y usar otro nombre simbólico cuando se trata de algo diferente hace que estos significados diferentes sean explícitos, obvios y que su programa general sea más legible y fácil de mantener. También le permite realizar una búsqueda global en su programa (o una búsqueda de símbolo inverso, si su entorno lo proporciona) en caso de que necesite identificar rápidamente todos los lugares en el código que dependen del ancho del tablero.

Vea también esta publicación anterior de SE.SE para una discusión sobre cómo (o cómo no) elegir nombres para los números.

Como nota al margen, ya que se discutió aquí en los comentarios : si, en el código de su programa real, importa si la variable se irefiere a filas y jcolumnas del tablero, o viceversa, entonces es recomendable elegir nombres de variables que haga la distinción clara, como rowy col. El beneficio de tales nombres es que hacen que el código incorrecto parezca incorrecto.

Doc Brown
fuente
22
Me gustaría agregar, si el OP había escrito un motor de ajedrez realmente grandioso y luego deseaba expandirlo para incluir ajedrez en 3D u otras variantes, entonces qué 8s necesitan cambiar será un desafío.
Steve Barnes
32
@SteveBarnes: trato de evitar tales argumentos, ya que conduce demasiado fácilmente a un argumento revertido como "Creo que es extremadamente diferente a hacer de este programa un tipo diferente de juego, así que puedo dejar el número mágico 8 donde está. "
Doc Brown
44
@IllusiveBrian Ese es un argumento clásico de "hombre de paja" por dos razones: (1) solo definir una constante no significa que el programador todavía no pueda escribir "8" (¡ya sea por accidente, diseño o malicia!) Y (2) solo porque hay una constante BOARD_WIDTH = 8 no hace que BOARD_WIDTH sea la constante correcta para usar en un lugar particular del programa.
alephzero
3
@Blrfl ... o conducirá a una ingeniería excesiva del código. Es responsabilidad del desarrollador darse cuenta de lo que puede cambiar en el futuro y codificar en consecuencia. La codificación como requisitos no cambiará causa problemas, pero el otro extremo no es mejor.
Malcolm
44
@corsiKa Cuando las variables de bucle corresponden a ejes físicos, deben llamarse x, y o fila, col o, para ajedrez, archivo, rango.
user949300
11

Ok, aquí hay algunos comentarios que tengo:

Deshacerse de los números mágicos es una gran idea. Existe un concepto conocido como DRY, que a menudo se tergiversa, pero la idea es que no duplique el conocimiento de los conceptos en su proyecto. Entonces, si tiene una clase llamada ChessBoard, puede mantener una constante llamada BOARD_SIZE o ChessBoard.SIZE adjunta. De esta manera, hay una única fuente para esta información. Además, esto ayuda a la legibilidad más adelante:

for (int i = 0; i < ChessBoard.SIZE; i++){
  for (int j = 0; j < ChessBoard.SIZE; j++){

Incluso si el número nunca cambia, su programa es posiblemente mejor. Cualquier persona que lo lea sabe más información sobre lo que está haciendo el código.

Un mal nombre es peor que ningún nombre, pero eso no significa que algo no deba nombrarse. Solo cambia el nombre. No tire al bebé con el agua del baño. : p El nombre puede ser descriptivo siempre que comprenda bien lo que está describiendo. Entonces, ese concepto puede usarse para múltiples cosas diferentes.

se despliega
fuente
8
esto parece simplemente repetir los puntos ya hechos y explicados en la respuesta principal
mosquito
-7

Lo que realmente desea es eliminar las referencias ad nauseum a las constantes, ya sea que estén nombradas o desnudas:

for_each_chess_square (row, col) {
  /*...*/
}

Si realmente va a proliferar la constante repitiendo tales bucles y otras cosas, es mejor quedarse 8.

8es autodescriptivo; No es una macro que representa otra cosa.

You Are't Don't Gonna (TM) lo convertirá en un programa de ajedrez de 9x9 y si alguna vez lo hace, la proliferación de 8 no será la mayor dificultad.

Podemos buscar una base de código de línea de 150,000 para el token 8, y clasificar qué ocurrencias significan qué en segundos.

Mucho más importante es modularizar el código para que el conocimiento del ajedrez se concentre en la menor cantidad de lugares posible. Es mejor tener uno, dos, quizás tres módulos específicos de ajedrez en los que se produce un 8 literal, que treinta y siete módulos unidos con responsabilidad específica de ajedrez, que se refieren al 8 a través de un nombre simbólico.

Cuando o 8 esta constante se convierte en una fuente de tensión en su programa, puede solucionarlo fácilmente en ese momento. Solucione problemas reales que están sucediendo ahora. Si no siente que se ve obstaculizado por ese 8 en particular, vaya con ese instinto.

Suponga que en el futuro desea admitir dimensiones de placa alternativas. En ese caso, esos bucles tendrán que cambiar si usan una constante con nombre o 8, porque las dimensiones serán recuperadas por alguna expresión como board.widthy board.height. Si tiene en BOARD_SIZElugar de 8, estos lugares serán más fáciles de encontrar. Entonces eso es menos esfuerzo. Sin embargo, no hay que olvidar el esfuerzo de reemplazar 8con BOARD_SIZEen el primer lugar. El esfuerzo general no es menor. Haciendo un paso sobre el código para el cambio 8a BOARD_SIZE, y luego otro para apoyar dimensiones alternativas, no es más barato que sólo ir de 8a apoyo dimensión alternativa.

También podemos ver esto desde un análisis de riesgo / beneficio puramente frío y objetivo. El programa tiene constantes desnudas ahora. Si estos son reemplazados por una constante, no hay beneficio; El programa es idéntico. Con cualquier cambio, existe un riesgo distinto de cero. En este caso, es pequeño. Aún así, no se debe correr ningún riesgo sin un beneficio. Para "vender" el cambio frente a este razonamiento, tenemos la hipótesis de un beneficio: un beneficio futuro que ayudará con un programa diferente: una versión futura del programa que no existe ahora. Si se está planificando tal programa, esta hipótesis y su razonamiento asociado son de buena fe y deben tomarse en serio.

Por ejemplo, si le faltan días para agregar más código que prolifere aún más estas constantes, es posible que desee eliminarlas. Si esas instancias de las constantes son aproximadamente todas las instancias que existirán, ¿por qué molestarse?

Si alguna vez trabaja en software comercial, los argumentos de ROI también se aplicarán. Si un programa no se vende, y cambiar algunos números codificados a constantes no mejorará las ventas, no se le compensará el esfuerzo. El cambio tiene cero retorno de la inversión de tiempo. Los argumentos del ROI se generalizan más allá del dinero. Usted escribió un programa, invirtiendo tiempo y esfuerzo, y obtuvo algo de él: ese es su retorno, su "R". Si al hacer ese cambio solo, obtienes más de esa "R", sea lo que sea, entonces por todos los medios. Si tiene algún plan para un mayor desarrollo y ese cambio mejora su "R", lo mismo. Si el cambio no tiene una "R" inmediata o previsible para usted, olvídalo.

Kaz
fuente
13
8NO es tan autodescriptivo, es un número que podría significar cualquier cosa. Y tal vez quieran hacer un juego de ajedrez de 9x9, ¿por qué no? Si tiene 150,000 líneas de código, no hay forma de que pueda memorizar lo que cada una 8significa en el código, e incluso si pudiera, ¿por qué lo haría? Eso es solo un montón de problemas adicionales. En cuanto a la modularización, reemplazar 8con algo así NUM_RANKSno daña la modularidad, de hecho, ayuda porque hace que el código sea más fácil de manipular.
Jerfov2
44
@Kaz Yo también hago eso. Y luego introduzco errores extraños significativos porque un puñado de usos no eran lo que pensaba que eran, porque es difícil prestar tanta atención a una gran cantidad de reemplazos y también ser correctos cada vez. Por esa razón, evito entrar en este escenario en primer lugar, por lo que no puedo apoyar los consejos que lo toleran.
doppelgreener
1
"Sin embargo, no hay que olvidar el esfuerzo de reemplazar 8con BOARD_SIZEen el primer lugar" - El tiempo que había pasado más de escrutar su código tratando de averiguar lo que cada uno 8hace en sus meses de programa a partir de ahora muy probablemente superaría el tiempo dedicado a reemplazar 8con Una constante significativa a nivel de módulo.
Christian Dean
1
@doppelganger Ese escenario ya está aquí. No estoy diciendo, tome un programa de ajedrez que use constantes y reemplácelos con 8. Tampoco estoy diciendo, "planee no usar constantes en un programa de ajedrez aún no escrito"
Kaz
1
@Kaz ¿Por qué querrías tener que leer todo el código alrededor del 8, y tal vez a veces te equivocas de contexto cuando solo puedes pasar 3 segundos adicionales dando un nombre significativo? En cuanto a conocer el valor real de la constante, es mucho más fácil buscar el valor exacto de una variable que tratar de diseñar al revés lo que significa un número entero mágico en el código
Jerfov2