¿Son las constantes de un solo carácter mejores que los literales?

127

Recientemente encontré una clase que proporciona prácticamente todos los caracteres como una constante; todo desde COMMAhasta BRACKET_OPEN. Preguntándose si esto era necesario; Leí un "artículo" que sugiere que puede ser útil convertir los literales de un solo carácter en constantes. Entonces, soy escéptico.

El principal atractivo del uso de constantes es que minimizan el mantenimiento cuando se necesita un cambio. Pero, ¿cuándo vamos a comenzar a usar un símbolo diferente a ',' para representar una coma?

La única razón por la que veo el uso de constantes en lugar de literales es para hacer que el código sea más legible. ¿Pero es city + CharacterClass.COMMA + state(por ejemplo) realmente más legible que city + ',' + state?

Para mí, las desventajas son mayores que las ventajas, principalmente porque introduces otra clase y otra importación. Y creo en menos código cuando sea posible. Entonces, me pregunto cuál es el consenso general aquí.

Dia de austin
fuente
33
Hmm ... ¿podría ser útil para diferentes lugares, tal vez? Por ejemplo, algunos idiomas utilizan guillements (comillas angulares, «y ») como las comillas en lugar de Inglés de nivel "(o de aspecto más agradable y ). Aparte de eso, solo suena como un conjunto de personajes mágicos. Suponiendo dos instancias de CharacterClassllamadas englishCharsy frenchChars, es posible que englishChars.LEFT_QUOTEsea , mientras que frenchChars.LEFT_QUOTEpodría ser «.
Justin Time
44
Hay muchas variantes diferentes en las comas: en.wikipedia.org/wiki/Comma#Comma_variants - tal vez esta no sea una idea tan tonta, especialmente si su código fuente puede codificarse como utf-8.
Aaron Hall el
21
En su caso, es como llamar a una variable "número". Su constante debería haberse llamado DELIMITADOR. O debería ser CITY_STATE = "{0}, {1}"
the_lotus el
13
Ese artículo que vinculaste es muy terrible. Las constantes nunca deben arrojarse a un cubo como ese. Póngalos en las clases donde tienen contexto: en esencia, la clase con la constante proporciona el contexto en el que se usa la constante. Por ejemplo, Java's File.separator. La clase te dice el tipo de separador. Tener una clase llamada Constso Constantsno proporciona contexto y hace que las constantes sean más difíciles de usar correctamente.

Respuestas:

183

Tautología :

Es muy claro si lees la primera oración de la pregunta que esta pregunta no se trata de usos apropiados, como la eliminación de números mágicos , sino de una consistencia tonta sin sentido, en el mejor de los casos. Que es lo que aborda esta respuesta

El sentido común le dice que const char UPPER_CASE_A = 'A';o const char A = 'A'no agrega nada más que mantenimiento y complejidad a su sistema. const char STATUS_CODE.ARRIVED = 'A'Es un caso diferente.

Se supone que las constantes representan cosas que son inmutables en tiempo de ejecución, pero que pueden necesitar modificaciones en el futuro en tiempo de compilación. ¿Cuándo equivaldría const char A =correctamente a otra cosa que no sea A?

Si ve public static final char COLON = ':'en el código Java, encuentre a quien lo escribió y rompa sus teclados. Si la representación COLONcambia para siempre :, tendrá una pesadilla de mantenimiento.

Ofuscación:

¿Qué sucede cuando alguien lo cambia COLON = '-'porque donde lo está usando necesita un -lugar en todas partes? ¿Vas a escribir pruebas unitarias que básicamente digan assertThat(':' == COLON)para cada constreferencia para asegurarte de que no se cambien? ¿Solo para que alguien arregle la prueba cuando la cambian?

Si alguien realmente argumenta que public static final String EMPTY_STRING = "";es útil y beneficioso, simplemente calificó su conocimiento e ignórelo con seguridad en todo lo demás.

Tener todos los caracteres imprimibles disponibles con una versión con nombre solo demuestra que quien lo hizo, no está calificado para escribir código sin supervisión.

Cohesión:

También reduce artificialmente la cohesión, porque aleja las cosas de las cosas que las usan y están relacionadas con ellas.

En la programación de computadoras, la cohesión se refiere al grado en que los elementos de un módulo pertenecen juntos. Por lo tanto, la cohesión mide la fuerza de la relación entre las piezas de funcionalidad dentro de un módulo dado. Por ejemplo, en sistemas altamente cohesivos, la funcionalidad está fuertemente relacionada.

Acoplamiento:

También combina muchas clases no relacionadas porque todas terminan haciendo referencia a archivos que no están realmente relacionados con lo que hacen.

El acoplamiento apretado es cuando un grupo de clases depende mucho el uno del otro. Este escenario surge cuando una clase asume demasiadas responsabilidades, o cuando una preocupación se extiende a muchas clases en lugar de tener su propia clase.

Si usara un nombre mejor como el DELIMITER = ',', todavía tendría el mismo problema, porque el nombre es genérico y no tiene semántica. La reasignación del valor no ayuda más a hacer un análisis de impacto que la búsqueda y el reemplazo del literal ','. Porque, ¿cuál es el código que lo usa y necesita ,y otros códigos que usa pero necesita ;ahora? Todavía tengo que mirar cada uso manualmente y cambiarlos.

En la naturaleza:

Hace poco refactorizado una 1,000,000+ LOCaplicación que tenía 18 años. Tenía cosas como public static final COMMA = SPACE + "," + SPACE;. De ninguna manera es mejor que simplemente alinearse " , "donde se necesita.

Si desea argumentar la legibilidad , necesita aprender a configurar su IDE para mostrar whitespacecaracteres donde pueda verlos o lo que sea, esa es solo una razón extremadamente floja para introducir la entropía en un sistema.

También se había ,definido varias veces con múltiples errores ortográficos de la palabra COMMAen múltiples paquetes y clases. Con referencias a todas las variaciones entremezcladas en código. Fue una pesadilla tratar de arreglar algo sin romper algo completamente ajeno.

Lo mismo con el alfabeto, había múltiples UPPER_CASE_A, A, UPPER_A, A_UPPERque la mayoría de las veces eran igual A , pero en algunos casos no eran . Para casi todos los personajes, pero no para todos los personajes.

Y a partir de los historiales de edición, no parecía que ninguno de estos haya sido editado o cambiado en los últimos 18 años, debido a lo que ahora debería ser una razón obvia es que rompería demasiadas cosas que no se pueden rastrear, por lo que tiene una nueva variable nombres que apuntan a la misma cosa que nunca se pueden cambiar por la misma razón.

En ninguna realidad sensata puede argumentar que esta práctica no está haciendo nada más que comenzar con la máxima entropía.

Refacté todo este desorden y subrayé todas las tautologías y las nuevas contrataciones universitarias fueron mucho más productivas porque no tenían que perseguir a través de múltiples niveles de indirección lo que estas constreferencias apuntaban realmente, porque no eran confiables en lo que se llamaban vs lo que contenían.


fuente
112
Quizás debería agregar un contraejemplo: const char DELIMITER = ':'sería realmente útil.
Bergi
115
Haría varios argumentos que EMPTY_STRINGson beneficiosos. (1) Puedo encontrar mucho más fácilmente todos los usos de EMPTY_STRINGun archivo que todos los usos de "". (2) cuando veo EMPTY_STRING, sé con certeza que el desarrollador pretendía que esa cadena estuviera vacía, y que no se trata de una edición incorrecta o un marcador de posición para que una cadena se suministre más tarde. Ahora, usted afirma que al argumentar que puede calificar mi conocimiento y que me ignora para siempre. Entonces, ¿cómo calificas mi conocimiento? ¿Y planeas ignorar mi consejo para siempre? No tengo ningún problema de ninguna manera.
Eric Lippert
39
@immibis: Podemos dejar de pensar en estas cosas como útiles en el contexto de la gestión del cambio. Son constantes No cambian Piense en ellos como útiles en el contexto de los humanos que buscan y comprenden la semántica del código . Saber que algo es un delimitador de pares valor-clave es mucho más útil que saber que es un punto y coma; eso es un hecho sobre el dominio semántico de la preocupación del programa, no su sintaxis .
Eric Lippert
15
@EricLippert: estoy viendo un poco el punto de otros aquí, que señalan que la única garantía de que una constofrece es que no va a cambiar en tiempo de ejecución (después de la compilación), aunque estoy de acuerdo con usted en que el significado semántico de la constes mucho más importante que su uso como herramienta de gestión del cambio. Dicho esto, ciertamente puedo imaginar una const EARLIEST_OS_SUPPORTEDque no solo sea semánticamente consistente, sino que también cambiará con el tiempo a medida que el programa evolucione y se elimine la vieja ruina.
Robert Harvey
16
@DanielJour: Entonces este es un tercer argumento para EMPTY_STRING; que un IDE bien diseñado mostrará herramientas que me permitan tratar esta entidad simbólicamente, en lugar de sintácticamente. Generalice esto a un cuarto argumento: que la biblioteca de herramientas de análisis de código que se encuentra debajo del IDE puede permitir un análisis programático avanzado de la corrección del código a nivel simbólico . Un desarrollador que desea aprovechar las herramientas más avanzadas que las escritas literalmente hace 40 años solo necesita hacer pequeños cambios en sus hábitos para cosechar las recompensas de las herramientas avanzadas.
Eric Lippert
145

El principal atractivo del uso de constantes es que minimizan el mantenimiento cuando se necesita un cambio.

ABSOLUTAMENTE NO. Esta no es la razón para usar constantes porque las constantes no cambian por definición . Si una constante cambia, entonces no fue una constante, ¿verdad?

El atractivo de usar constantes no tiene nada que ver con la gestión del cambio y con todo para hacer que los programas puedan ser escritos, entendidos y mantenidos por las personas . Si quiero saber en todas partes de mi programa dónde se usan dos puntos como separador de URL, entonces puedo saberlo muy fácilmente si tengo la disciplina para definir un URLSeparator constante, y no puedo saberlo fácilmente si tengo que buscar :y obtener cada lugar en el código donde :se utiliza para indicar una clase base, un ?:operador o lo que sea.

Estoy totalmente en desacuerdo con las otras respuestas que afirman que esta es una pérdida de tiempo sin sentido. Las constantes nombradas agregan significado a un programa, y ​​esa semántica puede ser utilizada tanto por humanos como por máquinas para comprender un programa más profundamente y mantenerlo de manera más efectiva.

El truco aquí no es evitar las constantes, sino nombrarlas con sus propiedades semánticas en lugar de sus propiedades sintácticas . ¿Para qué se usa la constante? No lo llame a Commamenos que el dominio comercial de su programa sea tipografía, análisis del idioma inglés o similares. Llámalo ListSeparatoro algo así, para aclarar la semántica de la cosa.

Eric Lippert
fuente
42
Si bien estoy de acuerdo con el espíritu de lo que estás diciendo aquí, tus frases segunda / tercera no son realmente correctas. Una constante puede cambiar entre versiones de un archivo. De hecho, la mayoría de los programas que escribo tienen una constante llamada algo así MY_VER, que contiene el número de versión actual del programa, que luego puede usarse en el resto del programa en lugar de una cadena mágica como "5.03.427.0038". El beneficio adicional es que usted dice que proporciona información semántica.
Monty Harder
50
Para ser justos, el punto de una constante es que no cambia durante el tiempo de ejecución después de ser inicializado, no es que no cambie entre compilaciones. Desde la perspectiva del compilador, el punto es que el compilador puede hacer suposiciones de que el programa no puede modificarlo; si el programador puede modificarlo cuando se vuelve a compilar no cambia su constancia. También puede haber casos en los que el software toma un valor de solo lectura del hardware, tal vez desreferenciando un const volatile T*puntero a una dirección predeterminada; mientras que el programa no puede cambiarlo, el hardware sí.
Justin Time
66
@MontyHarder: Buen punto. Mi opinión está informada por el hecho de que normalmente uso lenguajes que distinguen entre constantes, que deben ser invariables para siempre, y variables que pueden asignarse una vez , que pueden cambiar de una versión a otra, de una ejecución a otra, o lo que sea. Una constante y una variable son cosas diferentes; uno permanece igual y uno varía con el tiempo.
Eric Lippert
77
@SteveCox: estoy de acuerdo; la forma en que C / C ++ caracteriza "const" es extraña y de uso limitado. La propiedad que quiero de las constantes es que sus valores no cambian, no es que tenga restricciones para cambiarlas en algunas funciones pero no en otras.
Eric Lippert
15
"Esta no es la razón para usar constantes porque las constantes no cambian por definición. Si una constante cambia, entonces no fue una constante, ¿verdad?" Cambiar constantes en tiempo de compilación (obviamente no en tiempo de ejecución) es perfectamente normal. Es por eso que les hiciste una "cosa" claramente etiquetada en primer lugar. Por supuesto, las constantes de la OP son basura, pero piensa en algo parecido const VERSION='3.1.2'o const KEYSIZE=1024lo que sea.
AnoE
61

No, eso es tonto.

Lo que no es necesariamente tonto es colocar cosas como esas en etiquetas con nombre por razones de localización. Por ejemplo, el delimitador de miles es una coma en América (1,000,000), pero no una coma en otros lugares. Al colocar eso en una etiqueta con nombre (con un nombre apropiado, sin coma), el programador puede ignorar / abstraer esos detalles.

Pero hacer una constante porque "las cuerdas mágicas son malas" es solo culto de carga.

Telastyn
fuente
8
La localización suele ser más complicada que solo las constantes de cadena. Por ejemplo, algunos idiomas desean un delimitador de lista entre todos los elementos de la lista, mientras que otros excluyen el delimitador antes del último elemento. Por lo tanto, generalmente no se necesitan constantes localizadas, sino reglas localizadas .
Vlad
19
En realidad, el delimitador de miles no es necesariamente un delimitador de miles en otros lugares (China / Japón). Ni siquiera se establece después de un número constante de dígitos (India). Ah, y puede haber diferentes delimitadores dependiendo de si es un delimitador 1000 o el delimitador 1000000 (México). Pero eso es menos problemático que no usar dígitos ASCII 0-9 en algunas configuraciones regionales (farsi). ux.stackexchange.com/questions/23667/…
Peter
1
@Vlad Localization es mucho más complejo que eso, sin embargo, el separador de miles es un ejemplo bien conocido que las personas reconocen.
Depende de la estrategia de localización ... ¿cambia todas las constantes en su programa para traducirlo? ¿O debería preferir leer los valores de un archivo (u otro almacén de datos), convirtiéndolos efectivamente en variables de tiempo de ejecución?
Paŭlo Ebermann
Eso no sería útil en absoluto como una constante, entonces. El programa necesitaría recompilarse para configuraciones regionales, lo cual es una práctica horrible. Deben ser variables cargadas desde archivos de definición y buscadas según sea necesario. No es que no esté de acuerdo con el punto (voté la respuesta), pero tomaría una posición más dura sobre el asunto.
29

Hay algunos caracteres que pueden ser ambiguos o que se usan para varios propósitos diferentes. Por ejemplo, lo usamos '-'como un guión, un signo menos o incluso un guión. Puedes hacer nombres separados como:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '-';
static const wchar_t EM_DASH = '-';

Más tarde, puede elegir modificar su código para desambiguar redefiniéndolos como:

static const wchar_t HYPHEN = '-';
static const wchar_t MINUS = '\u2122';
static const wchar_t EM_DASH = '\u2014';

Esa podría ser una razón por la que consideraría definir constantes para ciertos caracteres individuales. Sin embargo , el número de caracteres que son ambiguos de esta manera es pequeño. A lo sumo, parece que lo harías solo por esos. También argumentaría que podría esperar hasta que realmente necesite distinguir los caracteres ambiguos antes de factorizar el código de esta manera.

Como las convenciones tipográficas pueden variar según el idioma y la región, probablemente sea mejor cargar una puntuación tan ambigua de una tabla de traducción.

Adrian McCarthy
fuente
Para mí, esta es la única razón válida por la que uno podría crear constantes de caracteres
FP
2
Usarlo -como un guión em es bastante engañoso ... es demasiado corto para eso en la mayoría de las fuentes. (Es incluso más corto que un guión.)
Paŭlo Ebermann
OK, no es el mejor ejemplo. Comencé con strings en lugar de wchar_ts y usé la convención estándar de manuscritos "--"para el tablero. Pero el ejemplo original estaba usando caracteres individuales, así que cambié para permanecer fiel a la pregunta. Hay personas que -escriben guiones, especialmente cuando trabajan en una fuente de tono fijo.
Adrian McCarthy
1
@ PaŭloEbermann No, tradicionalmente un guión largo es el ancho del carácter 'm' de una tipografía y un guión largo es el ancho de un carácter 'n'.
Dizzley
@Dizzley sí, y ancho de guión <n-ancho <m-ancho.
Paŭlo Ebermann
22

Una constante debe agregar significado.

Definir COMMA como una coma no agrega significado, porque sabemos que una coma es una coma. En cambio, destruimos el significado, porque ahora COMMA podría no ser una coma.

Si usa una coma para un propósito y desea usar una constante con nombre, asígnele el nombre después de su propósito. Ejemplo:

  • city + CharacterClass.COMMA + state = malo
  • city + CITY_STATE_DELIMITER + state = bueno

Usar funciones para formatear

Personalmente prefiero FormatCityState(city, state)y no me importa cómo se ve el cuerpo de esa función siempre que sea breve y pase los casos de prueba.

Peter
fuente
1
Ah, pero una coma no es siempre la misma coma. Podría definir COMMA = '\ u0559' o '\ u060C' etc. (ver Unicode) o incluso convertirlo en una variable más tarde y leerlo desde un archivo de configuración. De esa manera, seguirá teniendo el mismo significado , pero solo un valor diferente. Qué hay sobre eso.
Sr. Lister el
2
@ MrLister: YAGNI. Si tienes esa necesidad: ¡genial! Tienes una buena solución. Pero si no lo hace, no desordene su código porque posiblemente quizás algún día lo haga. Además, en mi experiencia, si intentas introducir abstracciones sin función en tu base de código, las personas no son excelentes para ser consistentes. Entonces, incluso si definió COMMA con la intención de usar algún otro punto de código, en un programa de tamaño y edad suficientes para que la elección sea importante, es probable que descubra que la constante no se usó en todas partes estado (y por el contrario, puede haber sido utilizado de manera inapropiada también).
Eamon Nerbonne
17

La idea de que un COMMA constante es mejor ','o ","más fácil de desacreditar. Claro que hay casos en los que tiene sentido, por ejemplo, final String QUOTE = "\"";ahorrar mucho en la lectura sin todas las barras, pero salvo los caracteres de control de idioma como \ 'y "no he encontrado que sean muy útiles.

Usar final String COMMA = ","no solo es una mala forma, ¡es peligroso! Cuando alguien quiere cambiar el separador de ","a ";", puede cambiar el archivo de constantes COMMA = ";"porque es más rápido para ellos y simplemente funciona. Excepto, ya sabes, todas las otras cosas que usaban COMMA ahora también son punto y coma, incluidas las cosas enviadas a consumidores externos. Por lo tanto, pasa todas sus pruebas (porque todo el código de clasificación y desorganización también estaba usando COMMA) pero las pruebas externas fallarán.

Lo que es útil es darles nombres útiles. Y sí, a veces las constantes múltiples tendrán el mismo contenido pero nombres diferentes. Por ejemplo final String LIST_SEPARATOR = ",".

Entonces su pregunta es "son constantes de un solo carácter mejores que literales" y la respuesta es inequívocamente no, no lo son. Pero incluso mejor que ambos es un nombre de variable de alcance limitado que dice explícitamente cuál es su propósito. Claro, gastará algunos bytes adicionales en esas referencias adicionales (suponiendo que no se compilen en usted, lo que probablemente lo harán) pero en el mantenimiento a largo plazo, que es donde está la mayor parte del costo de una aplicación, Vale la pena el tiempo para hacer.

corsiKa
fuente
¿Qué hay de definir condicionalmente DISP_APOSTROPHE como un ASCII 0x27 o un carácter de comilla simple a la derecha de Unicode (que es una representación más apropiada tipográficamente de un apóstrofe), dependiendo de la plataforma de destino?
supercat
3
En realidad, el QUOTEejemplo demuestra que también es una mala idea, ya que lo está asignando a lo que generalmente se conoce popularmente como DOUBLE QUOTEe e QUOTEimplica SINGLE_QUOTEque se conoce más correctamente APOSTROPHE.
3
@JarrodRoberson No creo que una cita implique una sola cita, personalmente, ¡pero esa es otra buena razón para eliminar la ambigüedad donde puedas!
corsiKa
2
No me gusta el QUOTEejemplo por una razón adicional: hace que leer cadenas construidas con él sea aún más difícil, "Hello, my name is " + QUOTE + "My Name" + QUOTEeste es un ejemplo trivial y, sin embargo, todavía se ve mal. Oh, claro, en lugar de concatenación puedes usar tokens de reemplazo, también "Hello, my name is %sMy Name%s".format(QUOTE, QUOTE)puede ser peor. Pero, oye, intentemos tokens indexados "Hello, my name is {0}My Name{0}".format(QUOTE)ugh, no mucho mejor. Cualquier cadena no trivial generada con comillas sería aún peor.
VLAZ
2
@corsiKa: viviré con las citas reales escapadas. Si extraño escapar de uno, el IDE que uso se quejaría inmediatamente. El código probablemente tampoco se compilará. Es bastante fácil de detectar. Qué fácil es cometer un error al hacerlo "My name is" + QUOTE + "My Name" + QUOTE. Realmente cometí el mismo error tres veces escribiendo el comentario anterior. ¿Puedes distinguirlo? Si le toma un poco, es el espacio que falta después es . ¿Formatea la cadena? En ese caso, una cadena con múltiples tokens para reemplazar será aún peor de resolver. ¿Cómo voy a usarlo para que sea más legible?
VLAZ
3

He trabajado un poco escribiendo lexers y analizadores y he usado constantes enteras para representar terminales. Los terminales de un solo carácter tenían el código ASCII como su valor numérico por simplicidad, pero el código podría haber sido algo completamente diferente. Entonces, tendría un T_COMMA al que se le asignó el código ASCII para ',' como su valor constante. Sin embargo, también hubo constantes para los no terminales a los que se asignaron enteros por encima del conjunto ASCII. Al mirar generadores de analizadores sintácticos como yacc o bison, o analizadores escritos usando estas herramientas, tuve la impresión de que básicamente así fue como lo hicieron todos.

Entonces, aunque, como todos los demás, creo que no tiene sentido definir constantes con el propósito expreso de usar las constantes en lugar de los literales en todo el código, creo que hay casos extremos (analizadores, por ejemplo) en los que puede encontrar código plagado de constantes como las que usted describe. Tenga en cuenta que en el caso del analizador sintáctico, las constantes no solo están allí para representar literales de caracteres; que representan las entidades que sólo podría pasan a ser literales de caracteres.

Puedo pensar en algunos casos más aislados en los que podría tener sentido usar constantes en lugar de los literales correspondientes. Por ejemplo, puede definir NEWLINE como el literal '\ n' en un cuadro de Unix, pero '\ r \ n' o '\ n \ r' si está en un cuadro de Windows o Mac. Lo mismo ocurre con el análisis de archivos que representan datos tabulares; puede definir constantes FIELDSEPARATOR y RECORDSEPARATOR. En estos casos, en realidad estás definiendo una constante para representar un personaje que cumple una determinada función. Aún así, si fueras un programador novato, tal vez nombrarías a tu separador de campo como COMMA constante, sin darte cuenta de que deberías haberlo llamado FIELDSEPARATOR, y para cuando te hayas dado cuenta, el código estaría en producción y estarías en el próximo proyecto,

Finalmente, la práctica que describe puede tener sentido en algunos casos en los que escribe código para manejar datos codificados en una codificación de caracteres específica, por ejemplo iso-8859-1, pero espera que la codificación cambie más adelante. Por supuesto, en tal caso, tendría mucho más sentido usar bibliotecas de localización o codificación y decodificación para manejarlo, pero si por alguna razón no pudieras usar dicha biblioteca para manejar problemas de codificación por ti, usando constantes solo usarías tener que redefinir en un solo archivo en lugar de literales codificados en todo su código fuente podría ser un camino a seguir.

En cuanto al artículo al que se vinculó: No creo que intente justificar el reemplazo de literales de caracteres por constantes. Creo que está tratando de ilustrar un método para usar interfaces para extraer constantes en otras partes de su base de código. Las constantes de ejemplo utilizadas para ilustrar esto se eligen muy mal, pero no creo que importen de ninguna manera.

Pascal
fuente
2
Creo que está tratando de ilustrar un método para usar interfaces para extraer constantes en otras partes de su base de código. que es un antipatrón aún peor y que también está estrechamente acoplado y tiene poca cohesión, tampoco hay una razón válida para hacerlo.
3

Además de todas las buenas respuestas aquí, me gustaría agregar como alimento para pensar, que una buena programación se trata de proporcionar abstracciones apropiadas que puedan ser construidas por usted y tal vez por otros, sin tener que repetir el mismo código una y otra vez.

Las buenas abstracciones hacen que el código sea fácil de usar, por un lado, y fácil de mantener, por otro lado.

Estoy totalmente de acuerdo DELIMITER=':'en que, en sí mismo, es una mala abstracción, y solo mejor que COLON=':'(ya que este último está totalmente empobrecido).

Una buena abstracción que incluya cadenas y separadores incluiría una forma de empaquetar uno o más elementos de contenido individuales en la cadena y también desempaquetarlos de la cadena empaquetada, antes que nada, antes de decirle cuál es el delimitador. Tal abstracción se incluiría como un concepto, en la mayoría de los idiomas como una clase; por ejemplo, para que su uso sea prácticamente autodocumentado, ya que puede buscar todos los lugares donde se usa esta clase y tener confianza en cuál es la intención del programador con respecto al formato de las cadenas empaquetadas en cada caso donde se usa alguna abstracción.

Una vez que se proporcione dicha abstracción, sería fácil de usar sin tener que consultar cuál es el valor de DELIMITERo COLON, y, cambiar los detalles de implementación generalmente se limitaría a la implementación. En resumen, estas constantes realmente deberían ser detalles de implementación ocultos dentro de una abstracción apropiada.

El principal atractivo del uso de constantes es que minimizan el mantenimiento cuando se necesita un cambio.

Las buenas abstracciones, que generalmente son composiciones de varias capacidades relacionadas, son mejores para minimizar el mantenimiento. Primero, claramente separan al proveedor de los consumidores. En segundo lugar, ocultan los detalles de implementación y, en cambio, proporcionan una funcionalidad directamente útil. En tercer lugar, documentan a un alto nivel cuándo y dónde se están utilizando.

Erik Eidt
fuente
2

La única vez que he visto que esas constantes se usan de manera efectiva es hacer coincidir una API o documento existente. He visto símbolos como el que se COMMAusa porque una pieza de software en particular estaba directamente conectada a un analizador sintáctico que se usaba COMMAcomo etiqueta en un árbol de sintaxis abstracta. También he visto que solía coincidir con una especificación formal. En las especificaciones formales, a veces verá símbolos como en COMMAlugar de ','porque quieren ser lo más claros posible.

En ambos casos, el uso de un símbolo con nombre como COMMAayuda a proporcionar cohesión a un producto que de otro modo sería disjunto. Ese valor a menudo puede superar el costo de las anotaciones excesivamente detalladas.

Cort Ammon
fuente
2

Observe que está tratando de hacer una lista.

Entonces, refactorizarlo como: String makeList(String[] items)

En otras palabras, factorice la lógica en lugar de los datos .
Los idiomas pueden ser diferentes en la forma en que representan las listas, pero las comas siempre son comas (eso es una tautología). Entonces, si el idioma cambia, cambiar el carácter de coma no lo ayudará, pero esto sí.

Mehrdad
fuente
0

Si esta fue una clase escrita como parte de una aplicación por su compañero desarrollador, es casi seguro que sea una mala idea. Como ya señalaron otros, tiene sentido definir constantes, como SEPARATOR = ','dónde puede cambiar el valor y la constante todavía tiene sentido, pero mucho menos las constantes cuyo nombre describe solo su valor.

Sin embargo, hay al menos dos casos en los que tiene sentido declarar constantes cuyo nombre describe exactamente su contenido y en los que no puede cambiar el valor sin cambiar adecuadamente el nombre de la constante:

  • Constantes matemáticas o físicas, por ej PI = 3.14159. Aquí, el papel de la constante es actuar como un mnemotécnico ya que el nombre simbólico PIes mucho más corto y más legible que el valor que representa.
  • Exhaustivas listas de símbolos en un analizador o teclas en un teclado. Incluso podría tener sentido tener una lista de constantes con la mayoría o todos los caracteres Unicode y aquí es donde puede caer su caso. Algunos personajes como Ason obvios y claramente reconocibles. Pero se puede decir fácilmente Аy Aaparte? El primero de ellos es el cirílico carta А mientras que el último es letra latina A . Son letras diferentes, representadas por diferentes puntos de código Unicode, aunque gráficamente son casi idénticas. Prefiero tener constantes CYRILLIC_CAPITAL_AyLATIN_CAPITAL_Aen mi código que dos personajes de aspecto casi idéntico. Por supuesto, esto no tiene sentido si sabe que solo trabajará con caracteres ASCII que no contengan cirílico. Del mismo modo: uso el alfabeto latino día a día, así que si estuviera escribiendo un programa que necesitara un carácter chino, probablemente preferiría usar una constante en lugar de insertar un carácter que no entiendo. Para alguien que usa caracteres chinos día a día, un carácter chino puede ser obvio, pero uno latino puede ser más fácil de representar como una constante con nombre. Entonces, como ves, depende del contexto. Aún así, una biblioteca puede contener constantes simbólicas para todos los caracteres, ya que los autores no pueden saber de antemano cómo se utilizará la biblioteca y qué caracteres pueden necesitar constantes para mejorar la legibilidad en una aplicación específica.

Sin embargo, estos casos generalmente son manejados por clases de sistema o bibliotecas de propósito especial y su aparición en código escrito por desarrolladores de aplicaciones debería ser muy rara a menos que esté trabajando en un proyecto muy especial.

Michał Kosmulski
fuente
-1

Tal vez.

Las constantes de un solo carácter son relativamente difíciles de distinguir. Por lo tanto, puede ser bastante fácil pasar por alto el hecho de que está agregando un punto en lugar de una coma

city + '.' + state

mientras que es un error relativamente difícil de hacer con

city + Const.PERIOD + state

Dependiendo de su entorno de internacionalización y globalización, la diferencia entre un apóstrofe ASCII y el apóstrofo de apertura y cierre de Windows-1252 (o la comilla doble ASCII y la comilla doble de apertura y cierre de Windows-1252) puede ser significativa y es muy difícil de visualizar. en el código

Ahora, presumiblemente, si poner un punto en lugar de una coma por error fue un problema funcional significativo, tendría una prueba automatizada que encontraría el error tipográfico. Si su software está generando archivos CSV, esperaría que su conjunto de pruebas descubriera con bastante rapidez que tuvo un período entre la ciudad y el estado. Si se supone que su software se ejecuta para clientes con una variedad de configuraciones de internacionalización, presumiblemente su conjunto de pruebas se ejecutará en cada entorno y se recuperará si tiene una cotización abierta de Microsoft si desea tener un apóstrofe.

Podría imaginar un proyecto en el que tuviera más sentido optar por un código más detallado que pudiera evitar estos problemas, especialmente cuando tienes un código más antiguo que no tiene un conjunto de pruebas completo, aunque probablemente no codifique de esta manera en Un proyecto de desarrollo de campo verde. Y agregar una constante para cada carácter de puntuación en lugar de solo aquellos que son potencialmente problemáticos en su aplicación particular es probablemente una exageración.

Justin Cave
fuente
2
¿Qué sucede cuando un imbécil cambia Const.PERIODpara ser igual a ~? No hay justificación para una tautología de caracteres con nombre, solo agrega mantenimiento y complejidad que no se necesita en los entornos de programación modernos. ¿Vas a escribir un conjunto de pruebas unitarias que básicamente digan assert(Const.PERIOD == '.')?
3
@JarrodRoberson - Eso apestaría, claro. Pero estaría en los mismos problemas si alguien agregara una constante Unicode que se vea casi exactamente como una coma en lugar de una coma real. Como dije, este no es el tipo de cosas que haría en un proyecto de desarrollo greenfield. Pero si tiene una base de código heredada con un conjunto de pruebas irregular donde se tropezó con los problemas de apóstrofes de abominación de coma / punto o apóstrofe / Microsoft un par de veces, crear algunas constantes y decirle a la gente que las use puede ser una forma razonable de hacer el código mejor sin pasar un año escribiendo pruebas.
Justin Cave
3
su ejemplo heredado es pobre, acabo de refactorizar una base de código LOC de más de 1,000,000 que tiene 18 años. Tenía todos los caracteres imprimibles definidos así varias veces, incluso con diferentes nombres en conflicto. Y muchas veces las cosas nombradas COMMAse establecieron realmente = SPACE + "," + SPACE. Sí, un idiota tenía una SPACEconstante. Los refactoré TODOS y el código era mucho más legible y las contrataciones universitarias eran mucho más capaces de rastrear las cosas y arreglarlas sin tener 6 niveles de indirección para descubrir a qué se había configurado realmente algo.
-1

¿Son las constantes de un solo carácter mejores que los literales?

Hay muchas combinaciones flotando por aquí. Déjame ver si puedo separarlos.

Las constantes proporcionan:

  • semántica
  • cambio, durante el desarrollo
  • indirección

Bajar a un solo nombre de personaje solo afecta la semántica. Un nombre debe ser útil como comentario y claro en su contexto. Debe expresar significado, no el valor. Si puede hacer todo eso con un solo personaje bien. Si no puede, no lo hagas.

Un literal y una constante pueden cambiar durante el desarrollo. Esto es lo que plantea el problema del número mágico. Las cadenas también pueden ser números mágicos.

Si existe un significado semántico, y dado que ambos son constantes, si la constante tiene más valor que un literal se reduce a la indirección.

La indirección puede resolver cualquier problema, aparte de mucha indirección.

La indirecta puede resolver el problema del número mágico porque le permite decidir el valor de una idea en un solo lugar. Semánticamente, para que eso valga la pena, el nombre debe dejar clara esa idea. El nombre debe ser sobre la idea, no sobre el valor.

La indirecta puede ser exagerada. Algunos prefieren buscar y reemplazar literales para hacer sus cambios. Eso está bien siempre que 42 sea claramente el significado de la vida y no se mezcle con 42, el número atómico de molibdeno.

Donde puede hacer distinciones útiles como esa con una sola letra depende en gran medida del contexto. Pero no lo haría un hábito.

naranja confitada
fuente
1
La semántica es la clave. Si y "A" tiene más semántica que simplemente ser una "A", entonces vale la pena vincular la misma semántica a la misma "referencia". No importa si es una constante o no. Estoy totalmente de acuerdo.
oopexpert
-1

Como contrapunto filosófico a la opinión de la mayoría, debo decir que hay algunos de nosotros, que apreciamos al poco sofisticado programador campesino francés del siglo XIX y

Recordaba su lucidez monótona y eterna, sus opiniones asombrosamente sensatas de todo, su colosal satisfacción con las obviedades simplemente porque eran ciertas. "¡Confundirlo todo!" gritó Turnbull para sí mismo, "si está en el manicomio, no puede haber nadie afuera".

GK Chesterton, La pelota y la cruz

No hay nada de malo en apreciar la verdad y no hay nada de malo en decir la verdad, especialmente cuando se habla con una computadora.

Si mientes a la computadora, te atrapará

Perry Farrar - Germantown, Maryland (de más perlas de programación)


Pero, en su mayor parte, estoy de acuerdo con las personas que dicen que es tonto. Soy demasiado joven para haber aprendido a programar FORTRAN, pero he oído decir que puedes redefinir 'A' = 'Q'y crear todo tipo de criptogramas maravillosos. No estas haciendo esto.

Más allá de los problemas de i18n mencionados anteriormente (que no redefinen el glifo "COMMA", sino que realmente redefinen el glifo de un DECIMAL_POINT). La construcción de citas francesas de zanahoria o citas simples británicas para transmitir significado a los humanos está en juego y esas realmente deberían ser variables, no constantes. La constante sería AMERICAN_COMMA := ','y elcomma := AMERICAN_COMMA

Y, si estuviera usando un patrón de construcción para construir una consulta SQL, preferiría ver

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(" ( ")
 .append(val_1)
 .append(",")
 .append(val_2)
 .append(" ); ")

que cualquier otra cosa, pero si fuera a agregar constantes, sería

INSERT_VALUES_START = " ( "
INSERT_VALUES_END = " ) "
INSERT_VALUES_SEPARATOR = " , "
QUERY_TERMINATOR = ";"

sb.append("insert into ")
 .append(table_name)
 .append(" values ")
 .append(INSERT_VALUES_START)
 .append(val_1)
 .append(INSERT_VALUES_SEPARATOR)
 .append(val_2)
 .append(INSERT_VALUES_END)
 .append(QUERY_TERMINATOR)

Sin embargo, si alguna vez has visto el programa (o tipo) de otra persona, podrías notar algunas peculiaridades interesantes. No todos somos mecanógrafos estelares. Muchos de nosotros llegamos a la programación tarde o fuimos criados con teclados soviéticos (donde las teclas teclean) y nos gusta cortar y pegar letras individuales en lugar de tratar de encontrarlas en el teclado y / o confiar en el autocompletado.

Nada va a completar automáticamente una cadena para usted, así que si puedo obtener una coma presionando 'con', alt-space, down, down, down, enter y obtenga una cotización presionando 'con', alt-space, down, abajo, entra. Podría hacer eso.


Otra cosa para recordar acerca de los literales de cadena es la forma en que se compilan. Al menos en Delphi, (que es el único lenguaje con el que me he obsesionado), terminarás tus literales en la pila de cada función. Entonces, muchos literales = mucha sobrecarga de funciones; "," en la función_A no es el mismo bit de memoria que un "," en la función_B ". Para combatir esto, hay una" cadena de recursos "que se puede construir y vincular lateralmente, y así es como lo hacen. dos pájaros con un arbusto) .En Python todos los literales de cadena son objetos, y en realidad puede parecer agradable de usar utils.constants.COMMA.join(["some","happy","array","strings"]), pero no es una idea estelar para los puntos repetidos una y otra vez en esta página.

Peter Turner
fuente
-4

Pero, ¿cuándo vamos a comenzar a usar un símbolo diferente a ',' para representar una coma?

Para localización

En los países de habla inglesa, el símbolo que separa las partes enteras y fraccionarias de un decimal es ".", Que llamamos "punto decimal". En muchos otros países, el símbolo es "," y generalmente se llama el equivalente de "coma" en el idioma local. Del mismo modo, cuando los países de habla inglesa usan "," para separar grupos de tres dígitos en grandes números (como 1,000,000 por un millón), los países que usan una coma como punto decimal usan un punto (1,000,000).

Entonces, hay un caso para hacer constantes DECIMAL_POINT y COMMA si está haciendo la globalización.

Paul G
fuente
2
Pero entonces COMMA y DECIMAL_POINT no son los nombres correctos para las entidades (lo cual es probablemente la razón por la que se le ha rechazado).
Kyle Strand
Necesitaría compilar versiones localizadas específicas. Las constantes literales no son adecuadas para eso; ese caso de uso requeriría archivos de definición y búsquedas en ellos (lo que podría implicar constantes, pero constantes de búsqueda, no caracteres constantes).