Cadenas de codificación que nunca cambiarán

39

Entonces, en mis esfuerzos por escribir un programa para conjugar verbos (algorítmicamente, no a través de un conjunto de datos) para el francés, me encontré con un pequeño problema.

El algoritmo para conjugar los verbos es en realidad bastante simple para los más o menos 17 casos de verbos, y se ejecuta en un patrón particular para cada caso; por lo tanto, los sufijos de conjugación para estas 17 clases son estáticos y (muy probablemente) no cambiarán en el corto plazo. Por ejemplo:

// Verbs #1 : (model: "chanter")
    terminations = {
        ind_imp: ["ais", "ais", "ait", "ions", "iez", "aient"],
        ind_pre: ["e", "es", "e", "ons", "ez", "ent"],
        ind_fut: ["erai", "eras", "era", "erons", "erez", "eront"],
        participle: ["é", "ant"]
    };

Estos son sufijos de inflexión para la clase de verbo más común en francés.

Hay otras clases de verbos (irregulares), cuyas conjugaciones probablemente también permanecerán estáticas durante el próximo siglo o dos. Como son irregulares, sus conjugaciones completas deben incluirse estáticamente, porque no pueden conjugarse de manera confiable a partir de un patrón (también hay solo [según mi recuento] 32 irregulares). Por ejemplo:

// "être":
    forms = {
        ind_imp: ["étais", "étais", "était", "étions", "étiez", "étaient"],
        ind_pre: ["suis", "es", "est", "sommes", "êtes", "sont"],
        ind_fut: ["serai", "seras", "sera", "serons", "serez", "seront"],
        participle: ["été", "étant"]
    };

Podría poner todo esto en XML o incluso JSON y deserializarlo cuando sea necesario, pero ¿hay algún punto? Estas cadenas son parte del lenguaje natural, que cambia, pero a un ritmo lento.

Mi preocupación es que al hacer las cosas de la manera "correcta" y deserializar alguna fuente de datos, no solo he complicado el problema que no tiene por qué ser complicado, sino que también he retrocedido por completo en todo el objetivo del enfoque algorítmico: ¡ no usar una fuente de datos! En C #, podría crear una clase bajo namespace Verb.Conjugation(por ejemplo class Irregular) para alojar estas cadenas en un tipo enumerado o algo así, en lugar de rellenarlas en XML y crear un class IrregularVerbDeserializer.

Entonces la pregunta: ¿ es apropiado codificar cadenas que es muy poco probable que cambien durante la vida útil de una aplicación? Por supuesto, no puedo garantizar al 100% que no cambien, pero el riesgo frente al costo es casi trivial para mí: la mejor idea aquí es la codificación dura.

Editar : El duplicado propuesto pregunta cómo almacenar una gran cantidad de cadenas estáticas , mientras que mi pregunta es cuándo debo codificar estas cadenas estáticas .

Chris Cirefice
fuente
26
¿Puede utilizar este software para un idioma diferente al francés en el futuro?
10
Enfoque algorítmico o no, está claro que simplemente tiene que codificar estas cadenas de 32 * 20 (y más cuando agrega más idiomas), y la única pregunta real es dónde colocarlas. Elegiría el lugar que le parezca más conveniente, lo que parece que estaría en código por el momento. Siempre puedes barajarlos más tarde.
Ixrec
1
@ChrisCirefice Eso me parece bastante óptimo. Ve a por ello.
Ixrec
2
@Gusdor No creo que leas con claridad: dije que los patrones de conjugación probablemente nunca cambiarán, o cambiarán con tanta frecuencia que una recompilación cada 100 años estaría bien. Por supuesto, el código cambiará, pero una vez que las cadenas estén allí como las quiero, a menos que esté refactorizando, serán estáticas durante los próximos 100 años.
Chris Cirefice
1
+1. Sin mencionar que en 60-100 años el costo no existirá o habrá sido reemplazado por una versión mejor.
HarryCBurn

Respuestas:

56

¿Es apropiado codificar cadenas que es muy poco probable que cambien durante la vida útil de una aplicación? Por supuesto, no puedo garantizar al 100% que no cambiarán, pero el riesgo frente al costo es casi trivial para mí: la mejor idea aquí es la codificación dura.

Me parece que respondiste tu propia pregunta.

Uno de los mayores desafíos que enfrentamos es separar las cosas que probablemente cambien de las que no cambiarán. Algunas personas se vuelven locas y vuelcan absolutamente todo lo que pueden en un archivo de configuración. Otros van al otro extremo y requieren una recompilación incluso para los cambios más obvios.

Seguiría el enfoque más fácil de implementar hasta que encontrara una razón convincente para hacerlo más complicado.

Dan Pichelman
fuente
Gracias Dan, eso es lo que pensé. Escribir un esquema XML para esto, tener otro archivo para realizar un seguimiento y tener que escribir una interfaz para deserializar los datos parecía excesivo teniendo en cuenta que simplemente no hay tantas cadenas, y debido a que es un lenguaje natural, es poco probable que cambie drásticamente en los próximos 100 años Afortunadamente, hoy en día en lenguajes de programación tenemos formas elegantes de abstraer estos datos en bruto detrás de una interfaz de aspecto agradable, por ejemplo, French.Verb.Irregular.Etreque contendría los datos de mi pregunta. Creo que funciona bien;)
Chris Cirefice
3
+1 Aquí, desde el campamento de Ruby, comenzaría a codificar y moverlo a la configuración según sea necesario. No sobre-ingenie prematuramente su proyecto haciendo las cosas configurables. Simplemente te ralentiza.
Overbryd
2
Nota: algunos grupos tienen una definición diferente de "codificación rígida", así que tenga en cuenta que ese término significa varias cosas. Hay un anti-patrón bien reconocido en el que codifica los valores en las declaraciones de una función, en lugar de crear estructuras de datos como lo ha hecho ( if (num == 0xFFD8)). Ese ejemplo debería convertirse en algo parecido if (num == JPEG_MAGIC_NUMBER)en casi todos los casos por razones de legibilidad. Solo lo señalo porque la palabra "codificación" a menudo levanta pelos en el cuello de las personas (como la mía) debido a este significado alternativo de la palabra.
Cort Ammon
@CortAmmon JPEG tiene muchos números mágicos. JPEG_START_OF_IMAGE_MARKER¿ Seguro ?
user253751
@immibis Su elección de nombres constantes es probablemente mejor que la mía.
Cort Ammon
25

Estás razonando en el ámbito equivocado.

No ha codificado solo verbos individuales. Has codificado el idioma y sus reglas . Esto, a su vez, significa que su aplicación no se puede usar para ningún otro idioma y no se puede extender con otras reglas.

Si esta es su intención (es decir, usarla solo para francés), este es el enfoque correcto, debido a YAGNI. Pero admite que desea usarlo más tarde también para otros idiomas, lo que significa que muy pronto, tendrá que mover toda la parte codificada a los archivos de configuración de todos modos. La pregunta restante es:

  • ¿Podrá, con una certeza cercana al 100%, en un futuro próximo, extender la aplicación a otros idiomas? Si es así, debería haber estado exportando cosas a archivos JSON o XML (para palabras, partes de las palabras, etc.) e idiomas dinámicos (para reglas) en este momento en lugar de obligarse a reescribir la mayor parte de su aplicación.

  • ¿O solo hay una pequeña probabilidad de que la aplicación se extienda en algún lugar en el futuro, en cuyo caso YAGNI dicta que el enfoque más simple (el que está utilizando en este momento) es el mejor?

Como ilustración, tome el corrector ortográfico de Microsoft Word. ¿Cuántas cosas crees que están codificadas?

Si está desarrollando un procesador de texto, se puede empezar por un motor de ortografía sencilla con las normas Hardcoded y palabras, incluso Hardcoded: if word == "musik": suggestSpelling("music");. Rápidamente, comenzará a mover palabras, luego se regirá a sí mismas fuera de su código. De otra manera:

  • Cada vez que tiene que agregar una palabra, tiene que volver a compilar.
  • Si aprendió una nueva regla, debe cambiar el código fuente una vez más.
  • Y lo que es más importante, no hay forma de adaptar el motor al alemán o japonés sin escribir enormes cantidades de código.

Como te destacaste a ti mismo:

Muy pocas reglas del francés podrían aplicarse al japonés.

Tan pronto como codifique las reglas de un idioma, cada uno requerirá más y más código, especialmente dada la complejidad de los lenguajes naturales.

Otro tema es cómo expresa esas diferentes reglas, si no a través del código. En última instancia, puede encontrar que un lenguaje de programación es la mejor herramienta para eso. En ese caso, si necesita extender el motor sin volver a compilarlo, los lenguajes dinámicos pueden ser una buena alternativa.

Arseni Mourzenko
fuente
1
Bueno, por supuesto, no todo está codificado allí: P, así que supongo que realmente se reduce a determinar cómo quiero que se vea la interfaz para poder aplicarla a varios idiomas. El problema es que todavía no conozco todos los idiomas, así que eso es efectivamente imposible. Creo que lo único que tal vez te estás perdiendo es que los patrones de conjugación (esto es de lo que estoy hablando) son muy estáticos en un lenguaje, y realmente es algo que es caso por caso. Hay alrededor de 17 patrones de conjugación en francés para los verbos. No se extenderá en el
corto
44
No estoy de acuerdo: no creo que tenga sentido mover nada fuera del código antes de que ocurra naturalmente a través de la refactorización. Comience con un idioma, agregue otros: en algún momento, la implementación de ILanguageRule compartirá suficiente código para que sea más eficiente tener una única implementación parametrizada con un XML (u otro archivo). Pero incluso entonces puede terminar con japonés que tiene una estructura completamente diferente. Comenzar presionando su interfaz para que sea XML (o similar) es solo pedir cambios en la interfaz en lugar de la implementación.
ptyx
2
Nota: si desea agregar más idiomas, ¡eso no implica mover los idiomas a un archivo de configuración! Igualmente podría tener una LanguageProcessorclase con múltiples subclases. (Efectivamente, el "archivo de configuración" es en realidad una clase)
user253751
2
@MainMa: ¿Por qué considera que es un problema volver a compilar al agregar una palabra? De todos modos, debe volver a compilar al hacer cualquier otro cambio en el código, y la lista de palabras es probablemente la parte del código que es menos probable que cambie con el tiempo.
JacquesB
3
Sospecho que la flexibilidad de poder codificar las reglas gramaticales muy específicas de cada idioma en una subclase sería más conveniente al final que la capacidad de cargar esas mismas reglas de alguna manera desde un archivo de configuración (porque básicamente estarías escribiendo tu lenguaje de programación propio para interpretar las configuraciones).
David K
15

Las cadenas deben extraerse a un archivo de configuración o base de datos cuando los valores puedan cambiar independientemente de la lógica del programa.

Por ejemplo:

  • Extracción de textos de IU a archivos de recursos. Esto permite que un no programador edite y corrija los textos, y permite agregar nuevos idiomas al agregar nuevos archivos de recursos localizados.

  • Extracción de cadenas de conexión, direcciones URL a servicios externos, etc. a archivos de configuración. Esto le permite usar diferentes configuraciones en diferentes entornos y cambiar las configuraciones sobre la marcha porque pueden necesitar cambiar por razones externas a su aplicación.

  • Un corrector ortográfico que tiene un diccionario de palabras para verificar. Puede agregar nuevas palabras e idiomas sin modificar la lógica del programa.

Pero también hay una sobrecarga de complejidad con la extracción a la configuración, y no siempre tiene sentido.

Las cadenas se pueden codificar cuando la cadena real no puede cambiar sin cambiar la lógica del programa.

Ejemplos:

  • Un compilador para un lenguaje de programación. Las palabras clave no se extraen a una configuración, ya que cada palabra clave tiene una semántica específica que debe ser soportada por el código en el compilador. Agregar una nueva palabra clave siempre requerirá cambios en el código, por lo que no tiene valor extraer las cadenas a un archivo de configuración.
  • Implementando un protocolo: Ej. un cliente HTTP tendrá cadenas codificadas como "GET", "tipo de contenido", etc. Aquí las cadenas son parte de la especificación del protocolo, por lo que son las partes del código con menos probabilidades de cambiar.

En su caso, creo que está claro que las palabras son una parte integrada de la lógica del programa (ya que está construyendo un conjugador con reglas específicas para palabras específicas), y extraer estas palabras a un archivo externo no tiene ningún valor.

Si agrega un nuevo idioma, deberá agregar un nuevo código de todos modos, ya que cada idioma tiene una lógica de conjugación específica.


Algunos han sugerido que podría agregar algún tipo de motor de reglas que le permita especificar reglas de conjugación para lenguajes arbitrarios, de modo que los nuevos lenguajes puedan agregarse únicamente por configuración. Piensa con mucho cuidado antes de seguir ese camino, porque los lenguajes humanos son maravillosamente extraños, por lo que necesitas un motor de reglas muy expresivo. Básicamente, estaría inventando un nuevo lenguaje de programación (un DSL de conjugación) para dudoso beneficio. Pero ya tiene un lenguaje de programación a su disposición que puede hacer todo lo que necesite. En cualquier caso, YAGNI.

JacquesB
fuente
1
En realidad, en un comentario a MainMa, mencioné que escribir un DSL para esto no tendría sentido porque muy pocos lenguajes naturales son lo suficientemente similares como para que valga la pena el esfuerzo. Tal vez el francés / español / italiano sería lo suficientemente cercano , pero realmente no vale la pena el esfuerzo adicional, teniendo en cuenta que la cantidad de reglas es muy estática en cualquier idioma. Los otros puntos que mencionó sobre la complejidad fueron mis preocupaciones exactas, y creo que entendió maravillosamente lo que estaba preguntando en mi pregunta y dio una gran respuesta con ejemplos, ¡así que +1!
Chris Cirefice
5

Estoy 100% de acuerdo con la respuesta de Dan Pichelman, pero me gustaría agregar algo. La pregunta que debe hacerse aquí es "¿quién va a mantener / ampliar / corregir la lista de palabras?". Si siempre es la persona quien también mantiene las reglas de un lenguaje específico (el desarrollador particular, supongo que usted), entonces no tiene sentido usar un archivo de configuración externo si esto hace las cosas más complejas; no obtendrá ningún beneficio de esta. Desde este punto de vista, tendrá sentido codificar tales listas de palabras incluso si tiene que cambiarlas de vez en cuando, siempre que sea suficiente para entregar una nueva lista como parte de una nueva versión.

(Por otro lado, si hay una pequeña posibilidad de que alguien más pueda mantener la lista en el futuro, o si necesita cambiar las listas de palabras sin implementar una nueva versión de su aplicación, use un archivo separado).

Doc Brown
fuente
Este es un buen punto; sin embargo, es muy probable que sea la única persona que realmente mantenga el código, al menos durante los próximos años. Lo bueno de esto es que, aunque las cadenas estarán codificadas, es un conjunto muy pequeño de cadenas / reglas que es poco probable que cambien pronto (ya que es un lenguaje natural, que no evoluciona demasiado de un año a otro). -año). Dicho esto, las reglas de conjugación, las cadenas de terminación de verbos, etc., con toda probabilidad serán las mismas para toda nuestra vida :)
Chris Cirefice
1
@ChrisCirefice ": exactamente mi punto.
Doc Brown
2

Incluso aunque la codificación parece correcta aquí, y mejor que cargar dinámicamente los archivos de configuración, todavía recomendaría que separe estrictamente sus datos (el diccionario de verbos) del algoritmo . Puede compilarlos directamente en su aplicación en el proceso de compilación.

Esto le ahorrará muchos problemas con el mantenimiento de la lista. En su VCS puede identificar fácilmente si una confirmación cambió el algoritmo o simplemente solucionó un error de conjugación. Además, es posible que la lista deba agregarse en el futuro para casos que no consideró. Especialmente, el número de los 32 verbos irregulares que contó no parece ser exacto. Si bien estos parecen cubrir los de uso común, encontré referencias a 133 o incluso 350 de ellos.

Bergi
fuente
Bergi, planeé separar los datos del algoritmo. Lo que observa sobre los irregulares franceses: la definición de irregular es mal entendida en el mejor de los casos. Lo que quiero decir cuando digo irregular son los verbos que no se pueden "calcular" o conjugar solo desde su forma infinitiva. Los verbos irregulares no tienen ningún patrón en particular y, por lo tanto, deben tener sus conjugaciones enumeradas explícitamente (en francés.Verb.Conjugation.Irregular` por ejemplo). Técnicamente, los verbos -ir son 'irregulares', pero en realidad tienen un patrón de conjugación fijo :)
Chris Cirefice
0

La parte importante es la separación de la preocupación. Cómo lograr eso es menos relevante. es decir, Java está bien.

Independientemente de cómo se expresan las reglas, ¿debe agregar un idioma para cambiar una regla: cuántos códigos y archivos tiene que editar?

Idealmente, debería ser posible agregar un nuevo idioma agregando un archivo 'english.xml' o un nuevo objeto 'EnglishRules implementa ILanguageRules'. Un archivo de texto (JSON / XML) le brinda una ventaja si desea cambiarlo fuera de su ciclo de vida de compilación, pero requiere una gramática compleja, análisis y será más difícil de depurar. Un archivo de código (Java) le permite expresar reglas complejas de una manera más simple, pero requiere una reconstrucción.

Comenzaría con una API Java simple detrás de una interfaz independiente de lenguaje limpio, ya que lo necesita en ambos casos. Siempre puede agregar una implementación de esa interfaz respaldada por un archivo XML más adelante si lo desea, pero no veo la necesidad de abordar ese problema de inmediato (o nunca).

ptyx
fuente