Zuerst ein bisschen Hintergrund. Ich codiere eine Suche von Alter -> Rate. Es gibt 7 Altersklammern, daher besteht die Nachschlagetabelle aus 3 Spalten (Von | Bis | Rate) mit 7 Zeilen. Die Werte ändern sich selten - es handelt sich um gesetzlich vorgeschriebene Sätze (erste und dritte Spalte), die seit 3 Jahren gleich bleiben. Ich dachte mir, dass der einfachste Weg, diese Tabelle zu speichern, ohne sie fest zu codieren, in der Datenbank in einer globalen Konfigurationstabelle als einzelner Textwert mit einer CSV besteht (also "65,69,0,05,70,74,0,06" ist, wie die Ebenen 65-69 und 70-74 würden gespeichert). Relativ einfach zu analysieren und dann zu verwenden.
Dann wurde mir klar, dass ich zur Implementierung eine neue Tabelle erstellen, ein Repository zum Umschließen, Datenschichttests für das Repo, Komponententests für den Code, der die CSV in der Tabelle nicht flach macht, und Tests für die Suche selbst erstellen müsste. Der einzige Vorteil all dieser Arbeit besteht darin, dass die Nachschlagetabelle nicht fest codiert wird.
Wenn Sie mit den Benutzern sprechen (die derzeit die Nachschlagetabelle direkt verwenden - indem Sie sich eine Hardcopy ansehen), ist die Meinung so ziemlich, dass "die Preise sich nie ändern". Offensichtlich ist das nicht richtig - die Raten wurden erst vor drei Jahren erstellt und in der Vergangenheit hatten Dinge, die sich "nie ändern", die Angewohnheit, sich zu ändern. Um dies defensiv zu programmieren, sollte ich die Nachschlagetabelle definitiv nicht speichern die Anwendung.
Außer wenn ich an YAGNI denke . Die von mir implementierte Funktion gibt nicht an, dass sich die Raten ändern. Wenn sich die Raten ändern, ändern sie sich immer noch so selten, dass die Wartung nicht einmal in Betracht gezogen wird, und die Funktion ist nicht kritisch genug, dass bei einer Verzögerung zwischen der Ratenänderung und der aktualisierten Anwendung alles beeinträchtigt würde.
Ich habe so ziemlich entschieden, dass nichts von Wert verloren geht, wenn ich die Suche hart codiere, und ich bin nicht allzu besorgt über meine Herangehensweise an diese spezielle Funktion. Meine Frage ist, habe ich als Fachmann diese Entscheidung richtig begründet? Das Hardcodieren von Werten ist ein schlechtes Design, aber die Mühe, die Werte aus der Anwendung zu entfernen, scheint gegen das YAGNI-Prinzip zu verstoßen.
BEARBEITEN Um die Frage zu klären, bin ich nicht besorgt über die tatsächliche Implementierung. Ich mache mir Sorgen, dass ich entweder schnell etwas Schlechtes tun und es mit YAGNI rechtfertigen kann, oder dass ich einen defensiveren Ansatz mit hohem Aufwand wählen kann, der selbst im besten Fall letztendlich nur geringe Vorteile hat. Kommt meine Entscheidung, ein Design zu implementieren, von dem ich weiß, dass es fehlerhaft ist, als professioneller Programmierer einfach auf eine Kosten-Nutzen-Analyse?
BEARBEITEN Obwohl alle Antworten sehr interessant waren, da ich denke, dass dies auf die Designentscheidungen einer Person zurückzuführen ist, denke ich, dass die besten Antworten @ Corbins und @EZ Harts waren, da sie Dinge ansprechen , die ich in der Frage nicht berücksichtigt hatte:
- Die falsche Zweiteilung zwischen "korrektes Entfernen fest codierter Werte" durch Verschieben in die Datenbank und "effizientes Anwenden von YAGNI" durch Verwendung von fester Codierung. Es gab eine dritte Möglichkeit, die Nachschlagetabelle in die App-Konfiguration einzufügen, die nicht den richtigen Aufwand verursacht, und zwar ohne die Effizienz von YAGNI. Wir sind im Allgemeinen nicht auf Entscheidungen beschränkt, und es kommt dann auf eine Kosten-Nutzen-Entscheidung an.
- Durch die Codegenerierung kann der Aufwand für das Verschieben der fest codierten Werte in die Datenbank verringert werden, und dies beseitigt auch meine überentwickelte Entscheidung, eine CSV in die Tabelle zu verarbeiten. Möglicherweise führt dies auch zu einem langfristigen Wartungsproblem mit dem generierten Code, wenn sich die grundlegenden Anforderungen für die Suchmethode ändern. Dies alles wirkt sich nur auf die Kosten-Nutzen-Analyse aus, und es ist wahrscheinlich, dass ich, wenn ich diese Automatisierung zur Verfügung gehabt hätte, nicht einmal daran gedacht hätte, so etwas hart zu codieren.
Ich markiere die Antwort von @ Corbin als richtig, da sie meine Annahmen zu den Entwicklungskosten ändert, und ich werde wahrscheinlich in naher Zukunft einige Tools zur Codegenerierung in mein Arsenal aufnehmen.
Antworten:
Sie haben einen Fehler in Ihrem Entwicklungsprozess gefunden. Wenn es schwierig ist, das Richtige zu tun (Tabelle erstellen, Repo, Repo-Tests, Abflachungstests ...), werden Entwickler einen Weg finden, dies zu umgehen. Dies beinhaltet normalerweise das Falsche. In diesem Fall ist es verlockend, Anwendungsdaten als Anwendungslogik zu behandeln. Tu es nicht. Fügen Sie stattdessen Ihrem Entwicklungsprozess nützliche Automatisierungen hinzu. Wir verwenden CodeSmith , um den langweiligen Code zu generieren, den niemand schreiben möchte. Nachdem wir eine Tabelle erstellt haben, führen wir CodeSmith aus und es werden die DAOs, DTOs und Stubs-Out-Unit-Tests für jede Tabelle generiert.
Abhängig von den von Ihnen verwendeten Technologien sollten Sie ähnliche Optionen haben. Viele ORM-Tools generieren Modelle aus einem vorhandenen Schema. Schienenmigrationen funktionieren in die entgegengesetzte Richtung - Tabellen aus Modellen. Die Metaprogrammierung in dynamischen Sprachen ist besonders stark bei der Eliminierung von Boilerplate-Code. Wenn Sie eine komplexe mehrschichtige Anwendung haben, müssen Sie etwas härter arbeiten, um alles zu generieren, was Sie benötigen, aber es lohnt sich. Lassen Sie sich nicht vom Gefühl "Wow, das ist ein Schmerz im Nacken" davon abhalten, das Richtige zu tun.
Oh, und speichern Sie Ihre Daten nicht in einem Format, das zusätzliche Verarbeitung (CSV) erfordert. Das fügt nur zusätzliche Schritte hinzu, die Ihre Aufmerksamkeit und Tests erfordern.
quelle
Antwort von @ Thorbjørn Ravn Andersen: Die Berechnung / Suche an einem Ort zu halten, ist ein guter Anfang.
Ihr Denkprozess von Defensive vs. YAGNI ist ein häufiges Problem. In diesem Fall würde ich vorschlagen, dass es durch zwei weitere Dinge informiert wird.
Erstens - wie wurde die Benutzeranforderung dargestellt? Haben sie die Bearbeitbarkeit von Tarifen angegeben? Wenn nicht, ist die zusätzliche Komplexität Teil von etwas, das Sie in Rechnung stellen können oder nicht? (oder wenn Sie Mitarbeiter sind, können Sie Ihre Zeit stattdessen mit anderen Arbeiten verbringen?) Wenn ja, dann machen Sie auf jeden Fall weiter und liefern Sie, was vernünftigerweise verlangt wurde.
Zweitens, und vielleicht noch wichtiger, ist es unwahrscheinlich, dass die bloße Bearbeitbarkeit eine tatsächliche Anforderung angesichts einer Gesetzesänderung erfüllt. Wenn sich die Preise ändern, ist mit einem Stichtag und einer Vorher-Nachher-Verarbeitung zu rechnen. Wenn dieselbe Schnittstelle dann eine rückwirkende Bearbeitung von Ansprüchen durchführen muss, muss der korrekte Tarif möglicherweise auf der Grundlage des Datums des Inkrafttretens der Eingabe und nicht des tatsächlichen Datums ermittelt werden.
Kurz gesagt, ich stelle fest, dass eine tatsächlich bearbeitbare Anforderung durchaus recht komplex sein kann. Wenn sie also nicht oder bis sie konkretisiert wird, ist die einfache wahrscheinlich besser.
Viel Glück
quelle
Machen Sie die eigentliche Suche zu einer Bibliotheksfunktion. Sie können dann den gesamten Code mithilfe dieser Suche in Ihrem Quell-Repository anzeigen, sodass Sie wissen, welche Programme aktualisiert werden müssen, wenn sich die Raten ändern.
quelle
PensionRateLookup
Klasse), die dann global verwendet wird. Ich würde das tun, unabhängig davon, ob es außerhalb der App gespeichert oder fest codiert ist. Auf diese Weise muss nur die Implementierung derPensionRateLookup
Klasse beibehalten werden. Mein Problem ist, wie ich YAGNI verwendet habe, um zu dem Schluss zu kommen, dass eine Hardcodierung der Nachschlagetabelle akzeptabel ist.Lassen Sie mich sehen, ob ich Ihre Frage richtig gestellt habe. Sie haben zwei Möglichkeiten, eine Funktion zu implementieren: Entweder Sie codieren einen Wert fest und Ihre Funktion ist einfach zu implementieren (obwohl Ihnen der Hardcode-Teil nicht gefällt), oder Sie haben große Anstrengungen unternommen, um viele Dinge, die getan werden, zu "wiederholen" So können Sie Ihre Funktion auf saubere Weise entwickeln. Ist das korrekt?
Das erste, was mir in den Sinn kommt, ist: "Das Wichtigste an der Kenntnis der guten Praktiken ist, zu wissen, wann es Ihnen ohne sie besser geht."
In diesem Fall ist der Aufwand sehr hoch, sodass Sie dies auf saubere Weise tun können. Die Wahrscheinlichkeit eines Nebeneffekts dieser Änderung ist groß und die Rendite, die Sie erzielen würden, ist gering (wie Sie erklärt haben, ist dies wahrscheinlich nicht der Fall Veränderung).
Ich würde den Hardcode-Ansatz verwenden (aber darauf vorbereiten, in Zukunft flexibel zu sein) und im Falle einer zukünftigen Änderung dieser Rate die Gelegenheit nutzen, all diesen schlechten Designabschnitt des Codes umzugestalten. Die Zeit und die Kosten könnten also richtig geschätzt werden und die Kosten für die Änderung Ihres fest codierten Werts wären minimal.
Das wäre mein Ansatz :)
quelle
Dies ist ein Element, das sich "nicht ändert", bis es dies tut. Es ist unvermeidlich, dass es sich ändern wird, aber diese Zeit kann ein bisschen weit weg sein.
Ihre Begründung ist richtig. Zu diesem Zeitpunkt fragte der Kunde nicht nach der Möglichkeit, diese Preise einfach zu ändern. Als solches YAGNI.
Was Sie jedoch nicht möchten, ist der Code, der auf Ihre Raten zugreift und die in der Codebasis verteilten Ergebnisse interpretiert. Bei einem guten OO-Design müssen Sie die interne Darstellung Ihrer Raten in einer Klasse zusammenfassen und nur die eine oder zwei Methoden offenlegen, die zur Verwendung der Daten erforderlich sind.
Sie benötigen diese Kapselung, um Fehler beim Kopieren und Einfügen zu vermeiden, oder um ein Refactoring für den gesamten Code durchzuführen, der die Raten verwendet, wenn Sie eine Änderung an der internen Darstellung vornehmen müssen. Wenn Sie diese anfängliche Vorsichtsmaßnahme treffen, kann der kompliziertere Ansatz ein einfacher Austausch und ein Ersatz für die Version mit mehr Funktionen sein.
Rufen Sie dem Client außerdem die Einschränkung des aktuellen Designs auf. Sagen Sie ihnen, dass Sie im Interesse der Einhaltung des Zeitplans die Werte hart codiert haben - was eine Codierungsänderung erfordert, um sie zu aktualisieren. Auf diese Weise können sie, wenn sie aufgrund neuer Gesetze auf ausstehende Ratenänderungen aufmerksam werden, einfach die Nachschlagetabelle aktualisieren oder die zu diesem Zeitpunkt kompliziertere Änderung durchführen. Aber legen Sie diese Entscheidung in ihren Schoß.
quelle
Teilen Sie die Differenz auf und fügen Sie die Tarifdaten in eine Konfigurationseinstellung ein. Sie können das CSV-Format verwenden, das Sie bereits haben, Sie vermeiden den unnötigen Datenbankaufwand, und falls die Änderung jemals erforderlich sein sollte, sollte dies eine Änderung sein, die der Kunde vornehmen sollte, ohne sie neu kompilieren / neu installieren zu müssen und ohne Probleme zu verursachen in der Datenbank - sie können einfach die Konfigurationsdatei bearbeiten.
Normalerweise liegt die beste Antwort irgendwo in der Mitte, wenn Sie zwischen zwei Extremen wählen (YAGNI im Vergleich zu fest codierenden dynamischen Daten verletzen). Vorsicht vor falschen Dichotomien.
Dies setzt voraus, dass sich Ihre gesamte Konfiguration in Dateien befindet. Wenn es an einem schwierigen Ort wie der Registrierung ist, sollten Sie diesen Rat wahrscheinlich ignorieren :)
quelle
Ich habe gerade eine DB-Tabelle erstellt. (Du hast darüber nachgedacht, einen ganzen Tisch in einem Archiv zu speichern, bist du verrückt geworden?)
Die Tabelle benötigt 2 Felder NICHT 3. Alter und Rate. Diese nächste Zeile enthält den oberen Wert! Sie normalisieren sich, ohne es zu wissen!
Hier ist die SQL, um die Rate für jemanden im Alter zu erhalten, der 67 Jahre alt ist.
Machen Sie sich nicht die Mühe, einen Wartungsbildschirm zu erstellen, da dieser außerhalb des Gültigkeitsbereichs liegt. Wenn sie später danach fragen, stellen Sie eine Änderungsanforderung und tun Sie es.
EDIT: Wie andere gesagt haben , den Code halten die die Rate, falls die ganze zentralisiert wird Rate Struktur chages.
quelle
Ich stimme den meisten Antworten zu. Ich möchte auch hinzufügen, dass die Konsistenz mit dem Rest der Anwendung wichtig ist. Wenn dies der einzige Ort im Code ist, der fest codierte Werte enthält, wird dies wahrscheinlich die Betreuer überraschen. Dies gilt insbesondere dann, wenn es sich um eine große, stabile Codebasis handelt. Wenn es sich um ein kleines Programm handelt, das von Ihnen verwaltet wird, ist die Entscheidung weniger wichtig.
Ich habe eine ferne Erinnerung daran, wie ich einen bekannten agilen / OOP-Typen (wie Dave Thomas oder Kent Beck oder jemanden) gelesen habe, der sagte, dass seine Faustregel für die Codeduplizierung zweimal und nur zweimal war: Refactor nicht, wenn Sie zum ersten Mal etwas seitdem duplizieren Sie könnten es immer nur zweimal in Ihrem Leben schreiben. Aber das dritte Mal ...
Damit ist die Frage nicht genau beantwortet, da Sie YAGNI befragen, aber ich denke, dies spricht für die allgemeine Flexibilität der agilen Regeln. Der Punkt der Agilität besteht darin, sich an die Situation anzupassen und voranzukommen.
quelle
Harter Code in einer Funktion.
quelle