Stringhe hardcoding che non cambieranno mai


39

Quindi, nei miei sforzi di scrivere un programma per coniugare i verbi (algoritmicamente, non attraverso un set di dati) per il francese, ho riscontrato un leggero problema.

L'algoritmo per coniugare i verbi è in realtà abbastanza semplice per i circa 17 casi di verbi e gira su un modello particolare per ciascun caso; quindi, i suffissi di coniugazione per queste 17 classi sono statici e (molto probabilmente) non cambieranno presto. Per esempio:

// 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"]
    };

Questi sono suffissi flessivi per la classe di verbi più comune in francese.

Esistono altre classi di verbi (irregolari), le cui coniugazioni rimarranno anche molto probabilmente statiche per il prossimo secolo o due. Poiché sono irregolari, le loro coniugazioni complete devono essere incluse staticamente, perché non possono essere coniugate in modo affidabile da un modello (ci sono anche solo [dal mio conteggio] 32 irregolari). Per esempio:

// "ê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"]
    };

Potrei mettere tutto questo in XML o persino JSON e deserializzarlo quando deve essere usato, ma c'è un punto? Queste stringhe fanno parte del linguaggio naturale, che cambia, ma a un ritmo lento.

La mia preoccupazione è che facendo le cose nel modo "giusto" e deserializzando alcune fonti di dati, non solo ho complicato il problema che non deve essere complicato, ma ho anche completamente rintracciato l'intero obiettivo del approccio algoritmico: non usare una fonte di dati! In C #, potrei semplicemente creare una classe sotto namespace Verb.Conjugation(ad esempio class Irregular) per ospitare queste stringhe in un tipo elencato o qualcosa del genere, invece di inserirle in XML e creare un class IrregularVerbDeserializer.

Quindi la domanda: è appropriato per le stringhe di hard-code che è molto improbabile che cambino durante la vita di un'applicazione? Ovviamente non posso garantire al 100% che non cambieranno, ma il rischio rispetto al costo è quasi banale da pesare ai miei occhi: l'hardcoding è l'idea migliore qui.

Modifica : il duplicato proposto chiede come archiviare un gran numero di stringhe statiche , mentre la mia domanda è quando devo codificare queste stringhe statiche .


26
Potresti utilizzare questo software in futuro in una lingua diversa dal francese?

10
Approccio algoritmico o no, è chiaro che devi semplicemente codificare queste stringhe 32 * 20 (e più quando aggiungi più lingue), e l'unica vera domanda è dove metterle. Sceglierei ovunque ti sembri più comodo per te, il che suona come se fosse in codice per il momento. Puoi sempre mescolarli in un secondo momento.
Ixrec,

1
@ChrisCirefice Mi sembra quasi ottimale. Fallo.
Ixrec,

2
@Gusdor Non credo che tu abbia letto chiaramente - Ho detto che i modelli di coniugazione probabilmente non cambieranno mai, o cambieranno così raramente che una ricompilazione ogni 100 anni circa andrebbe bene. Naturalmente il codice cambierà, ma una volta che le stringhe sono lì come le voglio, a meno che non stia eseguendo il refactoring saranno statiche per i prossimi 100 anni.
Chris Cirefice,

1
+1. Per non parlare del fatto che tra 60 e 100 anni il costo non esisterà o sarà sostituito da una versione migliore del tutto.
HarryCBurn,

Risposte:


56

è appropriato per le stringhe di codice che è molto improbabile che cambino durante la vita di un'applicazione? Ovviamente non posso garantire al 100% che non cambieranno, ma il rischio rispetto al costo è quasi banale da pesare ai miei occhi - l' hardcoding è l'idea migliore qui

Mi sembra che tu abbia risposto alla tua stessa domanda.

Una delle maggiori sfide che affrontiamo è quella di separare le cose che probabilmente cambieranno da quelle che non cambieranno. Alcune persone impazziscono e scaricano assolutamente tutto ciò che possono in un file di configurazione. Altri vanno all'estremo opposto e richiedono una ricompilazione anche per i cambiamenti più evidenti.

Andrei con l'approccio più semplice da implementare fino a quando non trovassi un motivo convincente per renderlo più complicato.


Grazie Dan, è un po 'quello che ho pensato. Scrivere uno schema XML per questo, avere un altro file di cui tenere traccia e dover scrivere un'interfaccia per deserializzare i dati sembrava un po 'eccessivo considerando che non ci sono così tante stringhe e poiché è un linguaggio naturale, è improbabile che cambi drasticamente nei prossimi 100 anni. Fortunatamente, al giorno d'oggi nei linguaggi di programmazione abbiamo modi fantasiosi per astrarre questi dati grezzi dietro un'interfaccia gradevole, ad esempio French.Verb.Irregular.Etreche conterrebbe i dati della mia domanda. Penso che
vada

3
+1 Qui dal campo di Ruby, inizierei cose hardcoding e le sposterei in configurazione se necessario. Non sovraccaricare prematuramente il tuo progetto rendendo le cose configurabili. Ti rallenta e basta.
Overbryd,

2
Nota: alcuni gruppi hanno una diversa definizione di "hardcoding", quindi tieni presente che quel termine significa più cose. Esiste un modello anti-riconoscimento ben noto in cui si codificano i valori nelle istruzioni di una funzione, piuttosto che creare strutture di dati come ( if (num == 0xFFD8)). Tale esempio dovrebbe diventare qualcosa di simile if (num == JPEG_MAGIC_NUMBER)in quasi tutti i casi per motivi di leggibilità. Lo sottolineo solo perché la parola "hardcoding" spesso solleva i peli sul collo delle persone (come la mia) a causa di questo significato alternativo della parola.
Cort Ammon,

@CortAmmon JPEG ha molti numeri magici. Sicuramente JPEG_START_OF_IMAGE_MARKER?
user253751

@immibis La tua scelta di denominazione costante è probabilmente migliore della mia.
Cort Ammon,

25

Stai ragionando nel campo sbagliato.

Non hai codificato solo i singoli verbi. Hai codificato la lingua e le sue regole . Questo, a sua volta, significa che l'applicazione non può essere utilizzata per nessun'altra lingua e non può essere estesa con altre regole.

Se questo è il tuo intento (cioè usandolo solo per il francese), questo è l'approccio giusto, grazie a YAGNI. Ma ti ammetti che vuoi usarlo in seguito anche per altre lingue, il che significa che molto presto, dovrai comunque spostare tutta la parte codificata nei file di configurazione. La domanda rimanente è:

  • Con una certezza prossima al 100%, nel prossimo futuro estendere l'app ad altre lingue? In tal caso, avresti dovuto esportare cose in file JSON o XML (per parole, parti delle parole, ecc.) E linguaggi dinamici (per regole) in questo momento invece di forzarti a riscrivere la maggior parte della tua app.

  • Oppure c'è solo una probabilità minore che l'app venga estesa da qualche parte in futuro, nel qual caso YAGNI impone che l'approccio più semplice (quello che stai usando in questo momento) sia il migliore?

A titolo di esempio, utilizza il correttore ortografico di Microsoft Word. Quante cose pensi siano codificate?

Se si sta sviluppando un processore di testo, si potrebbe iniziare da un semplice motore di ortografia con le regole hardcoded e parole anche hardcoded: if word == "musik": suggestSpelling("music");. Rapidamente, inizierai a spostare le parole, quindi si governeranno al di fuori del tuo codice. Altrimenti:

  • Ogni volta che devi aggiungere una parola, devi ricompilare.
  • Se hai imparato una nuova regola, devi cambiare di nuovo il codice sorgente.
  • E, soprattutto, non è possibile adattare il motore al tedesco o al giapponese senza scrivere enormi quantità di codice.

Come hai evidenziato te stesso:

Pochissime regole dal francese potrebbero essere applicate al giapponese.

Non appena si stabiliscono le regole per una lingua, ogni altro richiederà sempre più codice, soprattutto data la complessità dei linguaggi naturali.

Un altro argomento è il modo in cui esprimi queste diverse regole, se non attraverso il codice. In definitiva, potresti scoprire che un linguaggio di programmazione è lo strumento migliore per questo. In tal caso, se è necessario estendere il motore senza ricompilarlo, le lingue dinamiche potrebbero essere una buona alternativa.


1
Beh, ovviamente non tutto è hardcoded lì: P quindi immagino che dipenda davvero dal modo in cui voglio che appaia l'interfaccia in modo da poterla applicare a più lingue. Il problema è che non conosco ancora abbastanza bene tutte le lingue, quindi è effettivamente impossibile. Penso che l'unica cosa che forse ti manca è che i modelli di coniugazione (questo è tutto ciò di cui sto parlando) sono molto statici in una lingua, ed è davvero qualcosa che è caso per caso. Esistono circa 17 modelli di coniugazione in francese per i verbi. Presto non si prolungherà ...
Chris Cirefice,

4
Non sono d'accordo - non penso che abbia senso spostare qualcosa al di fuori del codice prima che arrivi naturalmente attraverso il refactoring. Inizia con una lingua, aggiungine altre: a un certo punto l'implementazione di ILanguageRule condividerà abbastanza codice da rendere più efficiente avere un'unica implementazione parametrizzata con un XML (o un altro file). Ma anche allora potresti finire con un giapponese che ha una struttura completamente diversa. Iniziare spingendo la tua interfaccia in modo che sia XML (o simile) è solo chiedere modifiche nell'interfaccia piuttosto che nell'implementazione.
ptyx,

2
Nota: se si desidera aggiungere più lingue, ciò non implica lo spostamento delle lingue in un file di configurazione! Potresti anche avere una LanguageProcessorclasse con più sottoclassi. (In effetti, il "file di configurazione" è in realtà una classe)
user253751

2
@MainMa: Perché ritieni che sia un problema ricompilare quando aggiungi una parola? Devi comunque ricompilare quando fai qualsiasi altra modifica al codice, e l'elenco delle parole è probabilmente la parte del codice che è meno probabile che cambi nel tempo.
JacquesB,

3
Ho il sospetto che la flessibilità di poter codificare le regole grammaticali molto specifiche di ciascuna lingua in una sottoclasse alla fine sarebbe più conveniente della possibilità di caricare le stesse regole in qualche modo da un file di configurazione (perché fondamentalmente dovresti scrivere il tuo proprio linguaggio di programmazione per interpretare le configurazioni).
David K,

15

Le stringhe dovrebbero essere estratte in un file di configurazione o in un database quando i valori potrebbero cambiare indipendentemente dalla logica del programma.

Per esempio:

  • Estrazione di testi dell'interfaccia utente in file di risorse. Ciò consente a un non programmatore di modificare e rileggere i testi e consente di aggiungere nuove lingue aggiungendo nuovi file di risorse localizzati.

  • Estrazione di stringhe di connessione, URL a servizi esterni ecc. Nei file di configurazione. Ciò consente di utilizzare diverse configurazioni in ambienti diversi e di modificare le configurazioni al volo perché potrebbero dover essere modificate per motivi esterni alla propria applicazione.

  • Un correttore ortografico che ha un dizionario di parole da controllare. È possibile aggiungere nuove parole e lingue senza modificare la logica del programma.

Ma c'è anche un sovraccarico di complessità con l'estrazione alla configurazione, e non ha sempre senso.

Le stringhe possono essere hardcoded quando la stringa effettiva non può cambiare senza cambiare la logica del programma.

Esempi:

  • Un compilatore per un linguaggio di programmazione. Le parole chiave non vengono estratte in una configurazione, poiché ogni parola chiave ha una semantica specifica che deve essere supportata dal codice nel compilatore. L'aggiunta di una nuova parola chiave richiederà sempre modifiche al codice, quindi nessun valore nell'estrazione delle stringhe in un file di configurazione.
  • Implementazione di un protocollo: ad es. un client HTTP avrà stringhe codificate come "GET", "content-type" ecc. Qui le stringhe fanno parte delle specifiche del protocollo, quindi sono le parti del codice che hanno meno probabilità di cambiare.

Nel tuo caso, penso che sia chiaro che le parole sono parte integrante della logica del programma (poiché stai costruendo un coniugatore con regole specifiche per parole specifiche), e l'estrazione di queste parole in un file esterno non ha alcun valore.

Se aggiungi una nuova lingua, dovrai aggiungere comunque un nuovo codice, poiché ogni lingua ha una logica di coniugazione specifica.


Alcuni hanno suggerito che potresti aggiungere un qualche tipo di motore di regole che ti consenta di specificare le regole di coniugazione per le lingue arbitrarie, quindi nuove lingue potrebbero essere aggiunte puramente dalla configurazione. Pensa attentamente prima di percorrere quella strada, perché le lingue umane sono meravigliosamente strane, quindi hai bisogno di un motore di regole molto espressivo. Fondamentalmente, inventeresti un nuovo linguaggio di programmazione (una coniugazione DSL) per vantaggi discutibili. Ma hai già un linguaggio di programmazione a tua disposizione che può fare tutto ciò di cui hai bisogno. In ogni caso, YAGNI.


1
In realtà, in un commento a MainMa, ho detto che scrivere un DSL per questo sarebbe inutile perché pochissimi linguaggi naturali sono abbastanza simili da far valere lo sforzo. Forse il francese / spagnolo / italiano sarebbe abbastanza vicino , ma non meriterebbe davvero lo sforzo extra considerando che la quantità di regole è altamente statica in una determinata lingua. Gli altri punti che menzioni sulla complessità erano le mie preoccupazioni esatte, e penso che tu abbia capito meravigliosamente quello che stavo chiedendo nella mia domanda e hai dato un'ottima risposta con esempi, quindi +1!
Chris Cirefice,

5

Sono d'accordo al 100% con la risposta di Dan Pichelman, ma vorrei aggiungere una cosa. La domanda che dovresti porre qui è "chi manterrà / estenderà / correggerà l'elenco delle parole?". Se è sempre la persona che mantiene anche le regole di una lingua specifica (il particolare sviluppatore, immagino tu), allora non ha senso usare un file di configurazione esterno se questo rende le cose più complesse - non otterrai alcun beneficio da Questo. Da questo punto di vista, sarà logico codificare tali elenchi di parole anche se è necessario modificarli di volta in volta, a condizione che sia sufficiente consegnare un nuovo elenco come parte di una nuova versione.

(D'altra parte, se c'è una leggera possibilità che qualcun altro debba essere in grado di mantenere l'elenco in futuro o se è necessario modificare gli elenchi di parole senza distribuire una nuova versione dell'applicazione, utilizzare un file separato.)


Questo è un buon punto, tuttavia, è molto probabile che sarò l'unica persona a mantenere il codice, almeno per i prossimi anni. La parte buona di questo è che anche se le stringhe saranno hardcoded, è una serie molto piccola di stringhe / regole che è improbabile che cambi presto in qualsiasi momento (dato che è un linguaggio naturale, che non si evolve troppo -anno). Detto questo, le regole di coniugazione, le stringhe di terminazione dei verbi, ecc. Con ogni probabilità saranno le stesse per tutta la nostra vita :)
Chris Cirefice,

1
@ChrisCirefice ": esattamente il mio punto.
Doc Brown

2

Anche se l'hardcoding sembra andare bene qui, e meglio del caricamento dinamico dei file di configurazione, ti consiglio comunque di separare rigorosamente i tuoi dati (il dizionario dei verbi) dall'algoritmo . Puoi compilarli direttamente nella tua applicazione nel processo di compilazione.

Questo ti farà risparmiare un sacco di problemi con la manutenzione della lista. Nel tuo VCS puoi facilmente identificare se un commit ha cambiato l'algoritmo o semplicemente correggere un bug di coniugazione. Inoltre, in futuro potrebbe essere necessario aggiungere l'elenco per i casi non considerati. In particolare, il numero dei 32 verbi irregolari che hai contato non sembra essere esatto. Mentre quelli sembrano coprire quelli comunemente usati, ho trovato riferimenti a 133 o addirittura a 350 di essi.


Bergi, avevo intenzione di separare i dati dall'algoritmo. Quello che noti sugli irregolari francesi: la definizione di irregolare è fraintesa nella migliore delle ipotesi. Ciò che intendo quando dico irregolare sono i verbi che non possono essere "calcolati" o coniugati solo dalla loro forma infinita. I verbi irregolari non hanno alcun modello particolare e quindi devono avere le loro coniugazioni esplicitamente elencate (ad esempio in French.Verb.Conjugation.Irregular`). Tecnicamente, i verbi -ir sono "irregolari", ma in realtà hanno un modello di coniugazione fisso :)
Chris Cirefice,

0

La parte importante è la separazione delle preoccupazioni. Il modo in cui lo raggiungi è meno rilevante. cioè Java va bene.

Indipendentemente da come vengono espresse le regole, è necessario aggiungere una lingua per modificare una regola: quanti codice e file è necessario modificare?

Idealmente, aggiungere una nuova lingua dovrebbe essere possibile aggiungendo un file 'english.xml' o un nuovo oggetto 'EnglishRules implementa ILanguageRules'. Un file di testo (JSON / XML) offre un vantaggio se si desidera modificarlo al di fuori del ciclo di vita della build, ma richiede una grammatica complessa, l'analisi e sarà più difficile eseguire il debug. Un file di codice (Java) consente di esprimere regole complesse in un modo più semplice, ma richiede una ricostruzione.

Vorrei iniziare con una semplice API Java dietro un'interfaccia agnostica di linguaggio pulito, come è necessario in entrambi i casi. Se lo desideri, puoi sempre aggiungere un'implementazione di quell'interfaccia supportata da un file XML in un secondo momento, ma non vedo la necessità di affrontare il problema immediatamente (o mai).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.