Hardcoding-Zeichenfolgen, die sich nie ändern

39

Bei meinen Bemühungen, ein Programm zur Konjugation von Verben (algorithmisch, nicht über einen Datensatz) für Französisch zu schreiben, bin ich auf ein kleines Problem gestoßen.

Der Algorithmus zur Konjugation der Verben ist für die etwa 17 Fälle von Verben eigentlich recht einfach und wird für jeden Fall nach einem bestimmten Muster ausgeführt. Daher sind die Konjugationssuffixe für diese 17 Klassen statisch und werden sich (sehr wahrscheinlich) in Kürze nicht mehr ändern. Zum Beispiel:

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

Dies sind Beugungssuffixe für die häufigste Verbklasse in Französisch.

Es gibt andere Klassen von Verben (Unregelmäßigkeiten), deren Konjugationen höchstwahrscheinlich auch für die nächsten ein oder zwei Jahrhunderte statisch bleiben werden. Da sie unregelmäßig sind, müssen ihre vollständigen Konjugationen statisch eingeschlossen werden, da sie nicht zuverlässig aus einem Muster konjugiert werden können (es gibt auch nur [nach meiner Zählung] 32 Unregelmäßigkeiten). Zum Beispiel:

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

Ich könnte das alles in XML oder sogar JSON einfügen und es deserialisieren, wenn es verwendet werden muss, aber gibt es einen Punkt? Diese Saiten sind Teil der natürlichen Sprache, die sich zwar ändert, jedoch nur langsam.

Meine Sorge ist , dass durch die Dinge , die „richtige“ Art und Weise und Deserialisieren einige Datenquelle zu machen, ich habe nicht nur das Problem kompliziert , die nicht brauchen kompliziert zu sein, aber ich habe auch ganz zurück Abwege auf das gesamte Ziel der algorithmischer Ansatz: nicht eine Datenquelle verwenden! In C # könnte ich einfach eine Klasse unter namespace Verb.Conjugation(z. B. class Irregular) erstellen , um diese Zeichenfolgen in einem Aufzählungstyp oder etwas anderem unterzubringen, anstatt sie in XML einzufügen und eine zu erstellen class IrregularVerbDeserializer.

Also die Frage: ist es zu hart Codefolgen angemessen , dass es sehr unwahrscheinlich , dass Änderung während der Lebensdauer einer Anwendung? Natürlich kann ich nicht 100% ig garantieren, dass sie sich nicht ändern, aber das Risiko gegenüber den Kosten ist in meinen Augen fast trivial - Hardcoding ist hier die bessere Idee.

Bearbeiten : In dem vorgeschlagenen Duplikat wird gefragt, wie eine große Anzahl statischer Zeichenfolgen gespeichert werden soll. Meine Frage lautet jedoch, wann ich diese statischen Zeichenfolgen fest codieren soll .

Chris Cirefice
quelle
26
Möchten Sie diese Software in Zukunft möglicherweise für eine andere Sprache als Französisch verwenden?
10
Algorithmischer Ansatz oder nicht, es ist klar, dass Sie diese 32 * 20 Zeichenfolgen (und mehr, wenn Sie mehr Sprachen hinzufügen) einfach fest codieren müssen, und die einzige wirkliche Frage ist, wo Sie sie ablegen müssen. Ich würde auswählen, wo es für Sie am bequemsten ist, was so klingt, als ob es vorerst im Code wäre. Sie können sie später immer noch mischen.
Ixrec
1
@ ChrisCirefice Das klingt für mich ziemlich optimal. Tue es.
Ixrec
2
@Gusdor Ich glaube nicht, dass Sie klar lesen - ich sagte, dass sich die Konjugationsmuster wahrscheinlich nie oder so selten ändern werden, dass eine Neukompilierung alle 100 Jahre oder so in Ordnung wäre. Natürlich wird sich der Code ändern, aber sobald die Zeichenfolgen da sind, wie ich sie haben möchte, sind sie für die nächsten 100 Jahre statisch, sofern ich sie nicht überarbeite.
Chris Cirefice
1
+1. Ganz zu schweigen davon, dass die Kosten in 60-100 Jahren entweder nicht existieren werden oder durch eine bessere Version insgesamt ersetzt wurden.
HarryCBurn

Antworten:

56

Ist es angebracht, Zeichenfolgen mit festem Code zu verwenden, die sich während der Lebensdauer einer Anwendung wahrscheinlich nicht ändern? Natürlich kann ich nicht 100% ig garantieren, dass sie sich nicht ändern, aber das Risiko gegenüber den Kosten ist in meinen Augen fast trivial - Hardcoding ist hier die bessere Idee

Es scheint mir, dass Sie Ihre eigene Frage beantwortet haben.

Eine der größten Herausforderungen besteht darin, die Dinge, die sich wahrscheinlich ändern, von den Dingen zu trennen, die sich nicht ändern werden. Manche Leute sind verrückt und geben absolut alles, was sie können, in eine Konfigurationsdatei. Andere gehen zum anderen Extrem und erfordern eine Neukompilierung, um selbst die offensichtlichsten Änderungen zu erzielen.

Ich würde den einfachsten Implementierungsansatz wählen, bis ich einen überzeugenden Grund gefunden habe, es komplizierter zu machen.

Dan Pichelman
quelle
Danke Dan, das habe ich mir gedacht. Ein XML-Schema dafür zu schreiben, eine andere Datei zu haben und eine Schnittstelle zu schreiben, um die Daten zu deserialisieren, schien einfach übertrieben, wenn man bedenkt, dass es nicht so viele Zeichenfolgen gibt und weil es sich um eine natürliche Sprache handelt, ist es unwahrscheinlich, dass sie sich drastisch ändert in den nächsten 100 Jahren. Glücklicherweise haben wir heutzutage in Programmiersprachen ausgefallene Möglichkeiten, diese Rohdaten hinter einer gut aussehenden Oberfläche zu abstrahieren, die beispielsweise French.Verb.Irregular.Etredie Daten aus meiner Frage enthalten würde. Ich denke, es funktioniert in Ordnung;)
Chris Cirefice
3
+1 Hier aus dem Ruby-Camp würde ich anfangen, Sachen fest zu codieren und sie nach Bedarf in die Konfiguration zu verschieben. Übersteuern Sie Ihr Projekt nicht vorzeitig, indem Sie es konfigurierbar machen. Es verlangsamt dich nur.
Overbryd
2
Hinweis: Einige Gruppen haben eine andere Definition von "Hardcoding". Beachten Sie daher, dass dieser Begriff mehrere Bedeutungen hat. Es gibt ein gut bekanntes Anti-Pattern, bei dem Sie Werte in die Anweisungen einer Funktion einprogrammieren, anstatt wie bei Ihnen Datenstrukturen zu erstellen ( if (num == 0xFFD8)). Dieses Beispiel sollte if (num == JPEG_MAGIC_NUMBER)aus Gründen der Lesbarkeit in fast allen Fällen so aussehen . Ich weise nur darauf hin, weil das Wort "Hardcoding" aufgrund dieser alternativen Bedeutung des Wortes häufig Haare im Nacken der Menschen aufwirft (wie meines).
Cort Ammon
@ CortAmmon JPEG hat viele magische Zahlen. Sicher JPEG_START_OF_IMAGE_MARKER?
user253751
@immibis Deine Wahl der konstanten Benennung ist wahrscheinlich besser als meine.
Cort Ammon
25

Sie argumentieren im falschen Rahmen.

Sie haben nicht nur einzelne Verben fest codiert. Sie haben die Sprache und ihre Regeln fest programmiert . Dies bedeutet wiederum, dass Ihre Anwendung nicht für eine andere Sprache verwendet und nicht mit anderen Regeln erweitert werden kann.

Wenn Sie dies beabsichtigen (dh nur für Französisch verwenden), ist dies aufgrund von YAGNI der richtige Ansatz. Aber Sie geben selbst zu, dass Sie es später auch für andere Sprachen verwenden möchten, was bedeutet, dass Sie sehr bald den gesamten fest codierten Teil in die Konfigurationsdateien verschieben müssen. Die verbleibende Frage ist:

  • Werden Sie die App in naher Zukunft mit einer Sicherheit von nahezu 100% auf andere Sprachen ausweiten? In diesem Fall hätten Sie Dinge in JSON- oder XML-Dateien (für Wörter, Wortteile usw.) und dynamische Sprachen (für Regeln) exportieren müssen, anstatt sich zu zwingen, den größten Teil Ihrer App neu zu schreiben.

  • Oder besteht nur eine geringe Wahrscheinlichkeit, dass die App in Zukunft erweitert wird. In diesem Fall schreibt YAGNI vor, dass der einfachste Ansatz (der, den Sie gerade verwenden) der bessere ist.

Nehmen Sie zur Veranschaulichung die Rechtschreibprüfung von Microsoft Word. Wie viele Dinge sind Ihrer Meinung nach fest codiert?

Wenn Sie ein Textverarbeitungsprogramm entwickeln, könnten Sie durch eine einfache Rechtschreibprüfung mit fest einprogrammierten Regeln und sogar fest einprogrammierter Worten beginnen: if word == "musik": suggestSpelling("music");. Schnell werden Sie anfangen, Wörter zu bewegen, und sich dann außerhalb Ihres Codes anordnen. Andernfalls:

  • Jedes Mal, wenn Sie ein Wort hinzufügen müssen, müssen Sie neu kompilieren.
  • Wenn Sie eine neue Regel gelernt haben, müssen Sie den Quellcode noch einmal ändern.
  • Und was noch wichtiger ist, es gibt keine Möglichkeit, die Engine auf Deutsch oder Japanisch anzupassen, ohne ungeheure Mengen an Code zu schreiben.

Wie Sie sich selbst hervorgehoben haben:

Sehr wenige Regeln aus dem Französischen konnten auf Japanisch angewendet werden.

Sobald Sie die Regeln für eine Sprache fest programmieren, benötigt jede andere Sprache immer mehr Code, insbesondere angesichts der Komplexität natürlicher Sprachen.

Ein weiteres Thema ist, wie Sie diese unterschiedlichen Regeln ausdrücken, wenn nicht durch Code. Letztlich können Sie feststellen , dass eine Programmiersprache ist das beste Werkzeug dafür. In diesem Fall können dynamische Sprachen eine gute Alternative sein , wenn Sie die Engine erweitern müssen, ohne sie neu zu kompilieren .

Arseni Mourzenko
quelle
1
Natürlich ist dort nicht alles fest programmiert: P Ich denke, es kommt darauf an, wie die Benutzeroberfläche aussehen soll, damit ich sie auf mehrere Sprachen anwenden kann. Das Problem ist, dass ich noch nicht alle Sprachen gut genug kenne, was praktisch unmöglich ist. Ich denke, das eine, was Sie vielleicht vermissen, ist, dass Konjugationsmuster (das ist alles, worüber ich spreche) in einer Sprache sehr statisch sind, und es ist wirklich etwas, das von Fall zu Fall ist. Es gibt ungefähr 17 Konjugationsmuster in Französisch für Verben. Es wird nicht mehr lange
dauern
4
Ich bin anderer Meinung - ich denke nicht, dass es Sinn macht, irgendetwas außerhalb des Codes zu verschieben, bevor es auf natürliche Weise durch Refactoring zustande kommt. Fangen Sie mit einer Sprache an und fügen Sie andere hinzu. Irgendwann wird die Implementierung von ILanguageRule so viel Code gemeinsam nutzen, dass es nur effizienter ist, eine einzelne Implementierung mit einem XML-Code (oder einer anderen Datei) zu parametrisieren. Aber selbst dann könnten Sie Japaner haben, die eine völlig andere Struktur haben. Wenn Sie Ihre Benutzeroberfläche auf XML (oder ähnliches) umstellen, müssen Sie lediglich Änderungen an der Benutzeroberfläche und nicht an der Implementierung vornehmen.
Ptyx
2
Hinweis: Wenn Sie weitere Sprachen hinzufügen möchten, bedeutet dies nicht, dass die Sprachen in eine Konfigurationsdatei verschoben werden! Sie können auch eine LanguageProcessorKlasse mit mehreren Unterklassen haben. (Eigentlich ist die "Konfigurationsdatei" eine Klasse)
user253751
2
@MainMa: Warum ist es für Sie ein Problem, beim Hinzufügen eines Wortes neu zu kompilieren? Sie müssen ohnehin neu kompilieren, wenn Sie eine andere Änderung am Code vornehmen, und die Liste der Wörter ist wahrscheinlich der Teil des Codes, der sich mit der Zeit mit der geringsten Wahrscheinlichkeit ändert.
JacquesB
3
Ich vermute, dass die Flexibilität, die sehr spezifischen grammatikalischen Regeln jeder Sprache in einer Unterklasse codieren zu können, am Ende praktischer wäre als die Möglichkeit, dieselben Regeln irgendwie aus einer Konfigurationsdatei zu laden (weil Sie im Grunde genommen Ihre Regeln schreiben würden) eigene Programmiersprache zur Interpretation der Konfigurationen).
David K
15

Zeichenfolgen sollten in eine Konfigurationsdatei oder Datenbank extrahiert werden, wenn sich die Werte unabhängig von der Programmlogik ändern könnten .

Zum Beispiel:

  • Extrahieren von UI-Texten in Ressourcendateien. Dies ermöglicht es einem Nicht-Programmierer, die Texte zu bearbeiten und Korrektur zu lesen, und es ermöglicht das Hinzufügen neuer Sprachen durch Hinzufügen neuer lokalisierter Ressourcendateien.

  • Extrahieren von Verbindungszeichenfolgen, URLs zu externen Diensten usw. in Konfigurationsdateien. Auf diese Weise können Sie verschiedene Konfigurationen in verschiedenen Umgebungen verwenden und die Konfigurationen im laufenden Betrieb ändern, da sie möglicherweise aus Gründen außerhalb Ihrer Anwendung geändert werden müssen.

  • Eine Rechtschreibprüfung, die ein Wörterbuch mit zu überprüfenden Wörtern enthält. Sie können neue Wörter und Sprachen hinzufügen, ohne die Programmlogik zu ändern.

Das Extrahieren in die Konfiguration ist jedoch mit einem hohen Aufwand verbunden und nicht immer sinnvoll.

Zeichenfolgen können fest codiert sein, wenn sich die tatsächliche Zeichenfolge nicht ändern kann, ohne die Programmlogik zu ändern.

Beispiele:

  • Ein Compiler für eine Programmiersprache. Die Schlüsselwörter werden nicht in eine Konfiguration extrahiert, da jedes Schlüsselwort eine bestimmte Semantik hat, die vom Code im Compiler unterstützt werden muss. Das Hinzufügen eines neuen Schlüsselworts erfordert immer Codeänderungen, sodass das Extrahieren der Zeichenfolgen in eine Konfigurationsdatei keinen Wert hat.
  • Implementieren eines Protokolls: z. Ein HTTP-Client verfügt über fest codierte Zeichenfolgen wie "GET", "content-type" usw. Hier sind die Zeichenfolgen Teil der Spezifikation des Protokolls, sodass sie die Teile des Codes sind, die sich mit der geringsten Wahrscheinlichkeit ändern.

In Ihrem Fall denke ich, dass es klar ist, dass die Wörter ein integraler Bestandteil der Programmlogik sind (da Sie einen Konjugator mit bestimmten Regeln für bestimmte Wörter erstellen) und das Extrahieren dieser Wörter in eine externe Datei keinen Wert hat.

Wenn Sie eine neue Sprache hinzufügen, müssen Sie trotzdem neuen Code hinzufügen, da jede Sprache eine spezifische Konjugationslogik hat.


Einige haben vorgeschlagen , dass Sie irgendeine Art von hinzufügen könnte Regel - Engine , die Sie Konjugationsregeln für beliebige Sprachen angeben können, so neue Sprachen rein durch Konfiguration hinzugefügt werden könnten. Überlegen Sie genau, bevor Sie diesen Weg gehen, denn die menschlichen Sprachen sind wunderbar seltsam. Sie benötigen daher eine sehr ausdrucksstarke Regel-Engine. Sie würden im Grunde genommen eine neue Programmiersprache (eine Konjugations-DSL) erfinden, um zweifelhaften Nutzen daraus zu ziehen. Sie haben aber bereits eine Programmiersprache zur Verfügung, die alles kann, was Sie brauchen. Auf jeden Fall YAGNI.

JacquesB
quelle
1
Tatsächlich habe ich in einem Kommentar an MainMa erwähnt, dass es sinnlos wäre, ein DSL dafür zu schreiben, da nur sehr wenige natürliche Sprachen ähnlich genug sind, um die Mühe wert zu machen. Vielleicht wäre Französisch / Spanisch / Italienisch nah genug , aber der zusätzliche Aufwand lohnt sich nicht, wenn man bedenkt, dass die Anzahl der Regeln in einer bestimmten Sprache sehr statisch ist. Die anderen Punkte, die Sie in Bezug auf die Komplexität erwähnen, waren meine genauen Sorgen, und ich denke, Sie haben wunderbar verstanden, was ich in meiner Frage fragte, und haben eine großartige Antwort mit Beispielen gegeben, also +1!
Chris Cirefice
5

Ich stimme der Antwort von Dan Pichelman zu 100% zu, möchte aber eines hinzufügen. Die Frage, die Sie sich hier stellen sollten, lautet: "Wer wird die Wortliste pflegen / erweitern / korrigieren?". Wenn es immer die Person ist, die auch die Regeln einer bestimmten Sprache einhält (der bestimmte Entwickler, denke ich, Sie), dann macht es keinen Sinn, eine externe Konfigurationsdatei zu verwenden, wenn dies die Dinge komplexer macht - Sie werden keinen Nutzen daraus ziehen diese. Aus dieser Sicht wird es sinnvoll macht solche Wortlisten selbst zu codieren , wenn Sie haben sie von Zeit zu Zeit zu ändern, solange es ausreichend ist , um eine neue Liste als Teil einer neuen Version zu liefern.

(Wenn die Wahrscheinlichkeit gering ist, dass jemand anderes die Liste in Zukunft verwalten kann, oder wenn Sie die Wortlisten ändern müssen, ohne eine neue Version Ihrer Anwendung bereitzustellen, verwenden Sie eine separate Datei.)

Doc Brown
quelle
Dies ist ein guter Punkt - ich bin jedoch sehr wahrscheinlich der einzige, der den Code tatsächlich verwaltet, zumindest für die nächsten Jahre. Das Gute daran ist, dass die Zeichenfolgen zwar hart codiert sind, es sich jedoch um einen sehr kleinen Satz von Zeichenfolgen / Regeln handelt, die sich wahrscheinlich nicht so schnell ändern werden (da es sich um eine natürliche Sprache handelt, die sich von Jahr zu Jahr nicht allzu sehr entwickelt) -Jahr). Das heißt, die Konjugationsregeln,
Verbterminierungszeichenfolgen
1
@ ChrisCirefice ": genau mein Punkt.
Doc Brown
2

Auch wenn die Hardcodierung hier in Ordnung zu sein scheint und besser als das dynamische Laden von Konfigurationsdateien, würde ich dennoch empfehlen, dass Sie Ihre Daten (das Wörterbuch der Verben) strikt vom Algorithmus trennen . Sie können diese während des Erstellungsprozesses direkt in Ihre Anwendung kompilieren.

Dies erspart Ihnen viel Aufsehen bei der Pflege der Liste. In Ihrem VCS können Sie leicht feststellen, ob ein Commit den Algorithmus geändert oder nur einen Konjugationsfehler behoben hat. Außerdem muss die Liste möglicherweise in Zukunft für Fälle angehängt werden, die Sie nicht berücksichtigt haben. Insbesondere die Anzahl der 32 unregelmäßigen Verben, die Sie gezählt haben, scheint nicht genau zu sein. Während diese scheinen, die allgemein verwendeten abzudecken, fand ich Hinweise auf 133 oder sogar 350 von ihnen.

Bergi
quelle
Bergi, ich hatte vor, die Daten vom Algorithmus zu trennen. Was Sie über die französischen Unregelmäßigkeiten bemerken - die Definition von Unregelmäßigkeiten wird bestenfalls missverstanden. Was ich meine, wenn ich unregelmäßig sage, sind die Verben, die nicht allein aus ihrer Infinitivform 'berechnet' oder konjugiert werden können. Die unregelmäßigen Verben haben überhaupt kein bestimmtes Muster und müssen daher explizit konjugiert werden (z. B. unter French.Verb.Conjugation.Irregular`). Technisch gesehen sind -ir Verben 'unregelmäßig', aber sie haben tatsächlich ein festes Konjugationsmuster :)
Chris Cirefice
0

Der wichtige Teil ist die Trennung von Bedenken. Wie Sie das erreichen, ist weniger relevant. dh Java ist in Ordnung.

Unabhängig davon, wie die Regeln ausgedrückt werden, müssen Sie eine Änderungssprache für eine Regel hinzufügen: Wie viele Codes und Dateien müssen Sie bearbeiten?

Im Idealfall sollte das Hinzufügen einer neuen Sprache entweder durch Hinzufügen einer 'english.xml'-Datei oder eines neuen' EnglishRules implementiert ILanguageRules'-Objekts möglich sein. Eine Textdatei (JSON / XML) bietet Ihnen einen Vorteil, wenn Sie sie außerhalb Ihres Build-Lebenszyklus ändern möchten, jedoch eine komplexe Grammatik und Analyse benötigen und das Debuggen schwieriger ist. Mit einer Codedatei (Java) können Sie komplexe Regeln auf einfachere Weise ausdrücken, müssen jedoch neu erstellt werden.

Ich würde mit einer einfachen Java-API hinter einer sauberen sprachunabhängigen Oberfläche beginnen - wie Sie das in beiden Fällen brauchen. Sie können später jederzeit eine Implementierung dieser Schnittstelle hinzufügen, die durch eine XML-Datei unterstützt wird, aber ich sehe keine Notwendigkeit, dieses Problem sofort (oder überhaupt) anzugehen.

ptyx
quelle