Ist es eine schlechte Programmierpraxis, etwas in einem Get zu erstellen, wenn es nicht existiert?

17

Ich besitze also einen Webservice, der so etwas wie einen hat, getAccountbei dem eine Kennung an das Konto zurückgegeben wird, wenn er vorhanden ist. Andernfalls wird eine Ausnahme ausgelöst. Der Client möchte immer ein Konto erstellen, wenn eine Ausnahme mit denselben Informationen ausgelöst wird, mit denen der Abruf ausgeführt wird.

Ich erstelle eine Convenience-Bibliothek für Kunden, die alle Webservice-Aufrufe verarbeiten, damit sie nicht wissen müssen, wie sie die Aufrufe selbst ausführen sollen.

Was ich mich wundere, ist in dieser Bibliothek, wenn ich ein getAccount(accountName)Konto erstellen würde , das das Konto erhält, wenn es existiert, und wenn es es dann nicht erstellt und die Informationen zurückgibt, ist das eine schlechte Sache? Sollte ich es dem Client überlassen, die Ausnahmen zu behandeln, oder es einfach so benennen wie getOrCreateAccount? Ist das wichtig?

Ist es eine schlechte Praxis, etwas in einer get-Operation zu erstellen?

Mike
quelle
9
Zumindest würde ich es nennen getOrCreateAccountoder ähnlich.
Telastyn
4
Dies scheint im Kontext einer verzögerten Initialisierung gültig zu sein. Es hängt jedoch davon ab, ob Sie dieses Muster in Ihrer Bibliothek verwenden müssen.
Chris C
1
Ich mag das Verb acquire, wie acquireAccount. Es hat in den wichtigsten Protokollen, auf die ich gestoßen bin, keine vorhandene Bedeutung, und es hat einen zwingenden Klang, der gut zu ihm passt. "Tun Sie, was immer Sie tun müssen, um eines davon für mich zu erwerben. Fordern Sie es an, bauen Sie es, fälschen Sie es, stehlen Sie es, es ist mir egal, holen Sie mir eins oder sterben Sie bei dem Versuch."
Dan Ross
2
"Der Kunde wird immer ein Konto erstellen wollen" - das scheint höchst ungewöhnlich. Wenn ich das Konto nicht erhalten kann, weil der Benutzer seinen Benutzernamen falsch eingegeben hat, möchte ich auf keinen Fall ein Konto mit dem falsch eingegebenen Namen erstellen.
gnasher729
Laut der Javabean-Spezifikation ist oracle.com/technetwork/articles/javaee/spec-136004.html getSomething() für Getter und setSomething()für Setter. Imo alles , was etwas mehr intellektuelle tut muss etwas anderes genannt werden, das heißt fetchSomething, obtainSomething, computeSomething, oder doSomethingElseusw.
ccpizza

Antworten:

31

Ja, das ist wichtig. Meiner Meinung nach ist es im Allgemeinen eine schlechte Praxis, etwas in einem Verfahren zu schaffen, das nicht als schöpferisch dokumentiert ist. Benennen Sie die Prozedur getOrCreate...oder haben Sie eine separate create...Prozedur. Wenn Sie dies wirklich möchten, getOrCreate...versuchen Sie es zuerst. get...Wenn dies fehlschlägt, rufen Sie an create...und rufen Sie dann an get....

Der Benutzer der Bibliothek erwartet wahrscheinlich nicht, dass die get...Prozedur erstellt wird, wenn der Abrufvorgang fehlschlägt. Wenn sie plötzlich feststellen, dass ihre Testaufrufe get...eine ganze Tonne Daten erzeugen, werden sie wahrscheinlich ziemlich überrascht sein. Und wie räumen sie es auf? Was ist, wenn sie Code schreiben und glauben, dass sie einen Fehler bekommen, wenn der Fehler get...fehlschlägt und sie das auf ihre Weise handhaben wollen ?

FrustratedWithFormsDesigner
quelle
Danke, das create gibt tatsächlich die ID zurück, die der get auch zurückgeben würde, so dass ich nicht get... create... get...nur die ersten beiden machen müsste . Ich werde mit dem Kunden darüber sprechen, ob er jemals die Möglichkeit haben muss, einfach anzurufen, getohne etwas erstellen zu wollen
Mike
6
@Mike: Ich denke immer noch, dass es createim Namen stehen sollte, nur um 100% klar zu sein, was passiert.
FrustratedWithFormsDesigner
Ja, ich stimme zu, ich hatte vor, etwas in der Art von getOrCreate zu machen, weil mein ursprünglicher Gedanke darin bestand, etwas zu machen, aber mir wurde klar, dass es nicht sofort klar ist, dass es auch etwas im Hintergrund schafft
Mike
1
Dies ist sehr spät, getOrCreatehat aber Vorrang in einem beliebten Webframework: docs.djangoproject.com/en/1.10/ref/models/querysets/…
tex
18

Nein, es ist keine „schlechte Praxis“. Solange Sie und die anderen Entwickler sich einig sind, dass es so funktionieren soll, ist es in Ordnung. Immerhin würde es ein Konto zurückgeben, was Sie wollen. Dass das Konto "unter der Haube" erstellt wird, ist für den Anrufer unerheblich.

GroßmeisterB
quelle
10
Einzige Ausnahme ist, wenn es sich um eine öffentlich verfügbare API handelt. Die größere Gemeinschaft hat bereits zugestimmt, dass GET entschädigungs- und nullpotent ist. Mit anderen Worten, es wird jedes Mal dieselbe Aktion ausgeführt, und es ist eine sichere Methode, die den Status des Servers nicht ändert. Dies befindet sich im REST-Wiki . Abgesehen davon, wenn die API nur in Ihrer eigenen kleinen Welt existiert, tun Sie, was auch immer von Ihrer Gruppe akzeptiert wird.
jmort253
9
Ich bin damit nicht einverstanden, auch wenn eine öffentliche API in Ordnung ist - solange dies im Kontext dessen, was die API tun soll, sinnvoll ist. Es hat wenig Sinn, mehrere Einträge in der API zu erstellen, wenn ein einzelner den Trick ausführen würde.
GroßmeisterB
Für die Aufzeichnung ist es eine vollständig interne Bibliothek und ich habe die Möglichkeit, dem Team einfach mitzuteilen, wie es funktioniert
Mike
1
@ jmort253: Ein Dienst ist nullpotent, wenn für den Client keine Nebenwirkungen sichtbar sind . Der Server kann tun, was ihm gefällt.
Kevin Cline
1
@ Kevincline, ich denke, ich dachte darüber nach, sagen wir mal, meine Kreditkarte zu belasten. Wenn der Server meine Karte auf der Grundlage einer GET-Anfrage auflädt, mir aber bei jeder Ausführung ein Ergebnis wie "Abgelehnt" anzeigt, ist dies ein Verstoß gegen den Geist von GET. Vor diesem Hintergrund verstehe ich Ihren Standpunkt. Der Server konnte die Anzahl der GET-Anfragen zählen und mich nach 3 Abfragen aussperren, wodurch die Rate mich einschränkte, ohne jedoch Details meines Kontos zu ändern. Ich denke, das ist ein wichtiger Unterschied, wenn man sagt, dass der Serverstatus nicht geändert wird. Vielleicht sollte ich stattdessen "Client-Status auf Server" sagen
jmort253
10

Wenn getAccount()ein Konto immer zurückgegeben werden kann, ist das Konto aus Sicht des Anrufers vorhanden und hat es immer gegeben. Es ist nicht nötig getAccount(), irgendetwas zu "erschaffen". Das Konto muss erst gespeichert werden, wenn es sich vom Standardkonto unterscheidet.

Kevin Cline
quelle
+1 Ist im Allgemeinen GetOrCreatedie falsche Semantik, aber es ist in Ordnung , ein Objekt zu erhalten, das "logisch" existieren kann, unabhängig davon, ob es physisch existiert oder nicht. Beispielsweise kann einem spärlichen Array von veränderlichen Elementen kein Speicher für das Element 1.841.533 zugewiesen werden, es kann jedoch dennoch "abgerufen" werden, indem ein neues Objekt erstellt, gespeichert und ein Verweis zurückgegeben wird.
Supercat
4

Am sinnvollsten ist es, drei Methoden zu erstellen:

getAccount -> Das bekommt gerade den Account.

createAccount -> Erstellt ein Konto.

getAccountAndCreateIfNeeded -> Wählen Sie Ihre eigene Benennung;)

Warum Trennung: Sie haben eine einfache Methode zum Abrufen und Erstellen. Das ist für beide eine eindeutig überprüfbare Methode. Für getAccount ist es keine Ausnahme, das Konto nicht zu finden. Also einfach false oder so was zurückgeben, das wird erwartet.

Dann können Sie diesen Rückgabewert in Ihrer gruppierten Funktion verwenden: getAccountAndCreateIfNeeded, die jetzt auch testbar ist, sollte immer ein Konto zurückgeben. Was auch immer du fragst.

Alle diese 3 Methoden sind klar, es ist genau klar, was sie tun und was sie zurückgeben. Sie können jetzt Vereinbarungen mit Ihrem Team treffen, aber diese Art von Ausnahmen sind auf lange Sicht schrecklich. Machen Sie sie einfach sehr klar und Sie werden keine Probleme haben.

Luc Franken
quelle
Außerdem aus Clean Code: "Wenn Ihre Methode nicht das kann, was der Name impliziert, dann werfen Sie eine Ausnahme." Ich würde einen Try / Catch-Block in 'GetOrCreateIfneeded' haben, der ein fehlgeschlagenes GET auslöst und dann das 'createAccount' im Throw für jeden Ausnahmetyp hat, der für das fehlgeschlagene Get zurückkommt.
Graham
Ich könnte eine vierte Methode vorschlagen getAccountIfExists, die entweder ein Konto erhält oder anzeigt, dass es nicht existiert, ohne ein neues zu erstellen. Die getAccountMethode selbst sollte voraussetzen, dass das Konto vorhanden ist, und andernfalls eine Ausnahme auslösen.
Supercat
2

Das hängt von den Umständen ab.

Sie können es beispielsweise zum verzögerten Laden / Instanziieren verwenden, um das Laden von Daten oder das Erstellen einer Instanz zu verzögern, bis sie tatsächlich benötigt wird. Dies ist normalerweise sinnvoll, da Ressourcen gespart werden, die Sie möglicherweise nicht benötigen (wenn die Klasse / Daten niemals benötigt werden, werden sie niemals geladen).

In diesem speziellen Fall würde ich jedoch sagen, dass eine Methode namens getAccount, mit der ein neues Konto erstellt wird, wenn es nicht vorhanden ist, keine gute Vorgehensweise ist. Wenn der Benutzer einige Anmeldeinformationen zur Identifizierung eines bestimmten Kontos eingegeben hat und dieses Konto nicht gefunden werden konnte, bedeutet dies, dass der Benutzer noch kein Kunde ist und ein Konto für ihn erstellt werden sollte, oder bedeutet dies, dass die Anmeldeinformationen falsch eingegeben wurden und der Benutzer muss aufgefordert werden, zu bestätigen, dass er eingegeben hat, was er eingeben wollte?

Wenn Sie über eine getAccount-Methode verfügen, mit der ein neues Konto erstellt wird, ohne dass ein Konto identifiziert werden konnte, haben Sie in dieser Angelegenheit keine andere Wahl. Wenn Sie die Kontoerstellung und die Kontoeröffnung in getrennte Methoden aufteilen, können Sie flexibler entscheiden, was zu tun ist, wenn der Versuch, ein Konto zu erhalten, fehlschlägt.

GordonM
quelle