Angenommen, wir haben eine Methode foo(String bar)
, die nur Zeichenfolgen verarbeitet, die bestimmte Kriterien erfüllen. Es muss beispielsweise klein geschrieben sein, darf nicht leer sein oder nur Leerzeichen enthalten und muss mit dem Muster übereinstimmen [a-z0-9-_./@]+
. In der Dokumentation der Methode sind diese Kriterien aufgeführt.
Sollte die Methode alle Abweichungen von diesem Kriterium ablehnen, oder sollte die Methode einige Kriterien eher verzeihen? Zum Beispiel, wenn die anfängliche Methode ist
public void foo(String bar) {
if (bar == null) {
throw new IllegalArgumentException("bar must not be null");
}
if (!bar.matches(BAR_PATTERN_STRING)) {
throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
}
this.bar = bar;
}
Und die zweite Vergebungsmethode ist
public void foo(String bar) {
if (bar == null) {
throw new IllegalArgumentException("bar must not be null");
}
if (!bar.matches(BAR_PATTERN_STRING)) {
bar = bar.toLowerCase().trim().replaceAll(" ", "_");
if (!bar.matches(BAR_PATTERN_STRING) {
throw new IllegalArgumentException("bar must match pattern: " + BAR_PATTERN_STRING);
}
}
this.bar = bar;
}
Sollte die Dokumentation dahingehend geändert werden, dass sie transformiert und wenn möglich auf den transformierten Wert gesetzt wird, oder sollte die Methode so einfach wie möglich gehalten werden und alle Abweichungen verworfen werden? In diesem Fall bar
könnte vom Benutzer eine Anwendung eingestellt werden.
Der primäre Anwendungsfall hierfür wären Benutzer, die über eine bestimmte Zeichenfolgen-ID von einem Repository aus auf Objekte zugreifen. Jedes Objekt im Repository sollte eine eindeutige Zeichenfolge haben, um es zu identifizieren. In diesen Repositorys konnten die Objekte auf verschiedene Arten gespeichert werden (SQL Server, JSON, XML, Binary usw.). Daher habe ich versucht, den kleinsten gemeinsamen Nenner zu identifizieren, der den meisten Namenskonventionen entspricht.
quelle
foo
Funktion haben sollten, die genau festlegt, welche Argumente akzeptiert werden, und eine zweite Hilfsfunktion, die versuchen kann, ein Argument zu "bereinigen", mit dem es verwendet werden sollfoo
. Auf diese Weise hat jede Methode für sich weniger zu tun und kann sauberer verwaltet und integriert werden. Wenn Sie diesen Weg gehen, wäre es wahrscheinlich auch hilfreich, sich von einem außergewöhnlichen Design zu entfernen. Sie könnenOptional
stattdessen so etwas wie verwenden und dann die Funktionen verwenden, diefoo
bei Bedarf Ausnahmen auslösen.Antworten:
Ihre Methode sollte das tun, was sie sagt.
Auf diese Weise wird verhindert, dass Fehler verwendet werden und das Verhalten von Betreuern später geändert wird. Das spart Zeit, da die Betreuer nicht so viel Zeit aufwenden müssen, um herauszufinden, was los ist.
Das heißt, wenn die definierte Logik nicht benutzerfreundlich ist, sollte sie möglicherweise verbessert werden.
quelle
foo
undfooForUncleanString
Methoden, bei denen letzterer die Korrekturen vornimmt, bevor er sie an ersterenEs gibt ein paar Punkte:
Denken Sie daran, dass es Debug-Assertions für die Diagnose von Logikfehlern im Debug-Modus gibt, mit denen Leistungsprobleme meistens behoben werden.
Wenn Sie eine Benutzeroberfläche implementieren, sind benutzerfreundliche Fehlermeldungen (einschließlich Vorschläge und andere Hilfe) Teil eines guten Designs.
Denken Sie jedoch daran, dass APIs für Programmierer und nicht für Endbenutzer bestimmt sind.
Ein echtes Experiment, um unscharf und tolerant mit Eingaben umzugehen, ist HTML.
Was dazu führte, dass jeder etwas anders vorging und die Spezifikation, die jetzt dokumentiert ist, ein Mammutbuch voller Sonderfälle war.
Siehe Postels Gesetz (" Sei konservativ in dem, was du tust, sei liberal in dem, was du von anderen akzeptierst. ") Und einen Kritiker, der das berührt ( oder einen viel besseren, auf den mich MichaelT aufmerksam gemacht hat ).
quelle
Das Verhalten einer Methode sollte klar, intuitiv, vorhersehbar und einfach sein. Im Allgemeinen sollten wir sehr zögern, die Eingaben eines Anrufers zusätzlich zu verarbeiten. Solche Vermutungen darüber, was der Anrufer beabsichtigt hat, haben ausnahmslos viele Randfälle, die unerwünschtes Verhalten hervorrufen. Betrachten Sie eine Operation so einfach wie das Verbinden von Dateipfaden. Viele (oder vielleicht sogar die meisten) Dateipfadverknüpfungsfunktionen verwerfen im Hintergrund alle vorhergehenden Pfade, wenn einer der Pfade, die verknüpft werden, verwurzelt zu sein scheint! Wenn Sie zum Beispiel
/abc/xyz
mit verbinden/evil
, erhalten Sie nur/evil
. Das ist fast nie das, was ich vorhabe, wenn ich Dateipfade verbinde, aber da es keine Schnittstelle gibt, die sich nicht so verhält, muss ich entweder Fehler haben oder zusätzlichen Code schreiben, der diese Fälle abdeckt.Trotzdem gibt es seltene Fälle, in denen es sinnvoll ist, dass eine Methode "verzeiht", aber es sollte immer im Ermessen des Anrufers liegen, zu entscheiden, wann und ob diese Verarbeitungsschritte auf seine Situation zutreffen. Wenn Sie also einen allgemeinen Vorverarbeitungsschritt gefunden haben, den Sie in verschiedenen Situationen auf Argumente anwenden möchten, sollten Sie Schnittstellen für Folgendes bereitstellen:
Der letzte ist optional; Sie sollten es nur bereitstellen, wenn eine große Anzahl von Anrufen es verwenden wird.
Durch die Bereitstellung der Raw-Funktionalität kann der Aufrufer diese bei Bedarf ohne Vorverarbeitungsschritt verwenden. Wenn der Präprozessor-Schritt allein verfügbar ist, kann er vom Aufrufer in Situationen verwendet werden, in denen er die Funktion nicht einmal aufruft oder Eingaben vor dem Aufrufen der Funktion vorverarbeiten möchte (z. B. wenn er sie zuerst an eine andere Funktion übergeben möchte). Durch das Bereitstellen der Kombination können Anrufer beide Funktionen problemlos aufrufen. Dies ist vor allem dann hilfreich, wenn die meisten Anrufer dies auf diese Weise tun.
quelle
Wie andere bereits gesagt haben, bedeutet das "Vergeben" der Zeichenfolgenübereinstimmung, dass zusätzliche Komplexität eingeführt wird. Das bedeutet mehr Arbeit bei der Implementierung des Matchings. Sie haben zum Beispiel jetzt viel mehr Testfälle. Sie müssen zusätzliche Arbeit leisten, um sicherzustellen, dass der Namespace keine semantisch gleichen Namen enthält. Mehr Komplexität bedeutet auch, dass in Zukunft mehr schief gehen muss. Ein einfacher Mechanismus wie ein Fahrrad erfordert weniger Wartung als ein komplexerer Mechanismus wie ein Auto.
Ist der milde String-Matching all diese zusätzlichen Kosten wert? Es hängt vom Anwendungsfall ab, wie andere angemerkt haben. Wenn es sich bei den Zeichenfolgen um eine externe Eingabe handelt, über die Sie keine Kontrolle haben, und wenn ein milder Abgleich einen eindeutigen Vorteil hat, kann sich dies lohnen. Möglicherweise kommt der Input von Endbenutzern, die in Bezug auf Leerzeichen und Großschreibung möglicherweise nicht sehr gewissenhaft sind, und Sie haben einen starken Anreiz, die Verwendung Ihres Produkts zu vereinfachen.
Wenn die Eingabe jedoch beispielsweise aus Eigenschaftendateien stammen würde, die von Technikern zusammengestellt wurden und die dies verstehen sollten
"Fred Mertz" != "FredMertz"
, wäre ich eher geneigt, die Übereinstimmung zu verschärfen und die Entwicklungskosten zu senken.Ich denke auf jeden Fall, dass es sinnvoll ist, führende und nachfolgende Leerzeichen zu kürzen und nicht zu berücksichtigen - ich habe zu viele Stunden damit verbracht, solche Probleme zu beheben.
quelle
Sie erwähnen einen Teil des Kontextes, aus dem diese Frage stammt.
Angesichts dessen würde ich die Methode nur eine Sache tun lassen, sie stellt die Anforderungen an den String, lässt ihn basierend darauf ausführen - ich würde nicht versuchen, ihn hier umzuwandeln. Halte es einfach und halte es klar; Dokumentieren Sie es und bemühen Sie sich, die Dokumentation und den Code miteinander zu synchronisieren.
Wenn Sie die aus der Benutzerdatenbank stammenden Daten noch fehlerverzeihender transformieren möchten, stellen Sie diese Funktionalität in eine separate Transformationsmethode und dokumentieren Sie die damit verbundene Funktionalität .
Irgendwann müssen die Anforderungen der Funktion erfasst, klar dokumentiert und die Ausführung fortgesetzt werden. Die "Vergebung" ist seiner Meinung nach ein wenig stumm, es ist eine Designentscheidung und ich würde argumentieren, dass die Funktion ihr Argument nicht mutiert. Wenn die Funktion die Eingabe mutiert, wird ein Teil der Validierung ausgeblendet, die für den Client erforderlich wäre. Eine Funktion, die die Mutation ausführt, hilft dem Client, sie richtig zu machen.
Das Hauptaugenmerk liegt hier auf Klarheit und der Dokumentation der Code-Funktionen .
quelle
quelle