Wird es als Anti-Pattern angesehen, aus einer Bibliothek aus STDIN zu lesen?

39

Beim Schreiben einer Bibliothek für ein großes Projekt, an dem ich gerade arbeite, ist ein Problem aufgetreten, bei dem ein Token an eine E-Mail-Adresse gesendet und dann an den Code zurückgegeben werden musste, wo es für die weitere Verwendung verwendet werden kann.

Mein Kollege sagt, er solle nur aus STDIN lesen (mit Python:) code = input("Enter code: ")und dann von einem Benutzer weiterleiten lassen. Dies scheint mir jedoch eine schlechte Praxis zu sein, da die Bibliothek möglicherweise (in diesem Fall definitiv) in einer Hintergrundaufgabe auf einem Server verwendet wird .

Ich fragte mich, ob dies als Anti-Muster angesehen wurde oder nicht.

Paradoxis
quelle
45
Nicht alles Schlechte ist ein "Anti-Muster", obwohl dies sicherlich schlecht ist.
Phoshi
4
"Muster" bedeutet etwas, was Programmierer häufig tun. Es ist nur dann ein Anti-Pattern, wenn es sowohl (A) eine schlechte Idee als auch (B) etwas ist, was Entwickler die ganze Zeit tun.
Solomon Slow
20
Dies ist viel zu dumm, um ein Anti-Muster zu sein. Ein Anti-Pattern ist etwas, das natürlich und vernünftig erscheint, sich jedoch als schlecht herausstellt, wenn man sich damit befasst. Was Sie hier beschreiben, ist offensichtlich grausam.
Evan Harper
Ich verstehe den Sinn keiner der Antworten. Der Zweck der Benutzer-Token-Übung muss sein, zu beweisen, dass die E-Mail-Adresse des Benutzers funktioniert. Wenn das nicht der Punkt wäre, wäre es viel einfacher, das Token einfach zu speichern.
Emory
2
Das ist ziemlich schrecklich. Wenn die Übergabe eines solchen Tokens unbedingt erforderlich ist, können Sie mithilfe der Bibliothek eine separate ausführbare Datei erstellen und Ihr Token an die Standard-ID übergeben. Aber den Standard der aufrufenden ausführbaren Datei zu entführen, ist ein Nein-Nein.
GroßmeisterB

Antworten:

78

Als allgemeine Richtlinie sollten Bibliotheken vollständig von der Umgebung getrennt sein. Das bedeutet, dass sie keine Vorgänge für Standard-Streams oder für bestimmte Dateien ausführen oder Erwartungen an die Umgebung oder den Kontext haben sollten, in dem sie verwendet werden.

Natürlich gibt es Ausnahmen von dieser Regel, aber es muss einen sehr guten Grund dafür geben. Im Falle der Verwendung stdinkann ich keinen Grund finden (es sei denn, Ihre Bibliothek bietet tatsächlich Routinen zum Lesen von stdin, wie std::cinaus C ++). Darüber hinaus bietet das Abrufen der E / A-Datenströme von einem Parameter, anstatt sie fest zu codieren, so viel Flexibilität, dass es sich nicht lohnt, dies nicht zu tun.

Paul92
quelle
36
Die Ausnahme ist eine Bibliothek, deren spezifisches Ziel die Interaktion mit einer Umgebung ist. Auch dann sollten Details der Umgebung weg abstrahiert werden. Beispielsweise muss ein Grafiktreiber mit dem PCIe-Bus kommunizieren, die Bus-ID sollte jedoch über die Konfiguration bereitgestellt werden.
Dies ist die Art von Ausnahme, die ich dachte: Meine Idee war näher an ncurses - im Allgemeinen eine Benutzeroberflächenbibliothek für Textumgebungen. Wenn der Zweck darin besteht, Benutzereingaben zu lesen und Benutzereingaben bereitzustellen, ist dies ein guter Grund.
SF.
5
@SF. Sogar eine Bibliothek wie ncurses sollte ein Paar Dateideskriptoren als Argumente verwenden, anstatt die Verwendung von 0 und 1 fest zu codieren. Sie möchten möglicherweise ein Programm schreiben, in dem stdin und stdout umgeleitet werden können, und Sie möchten stattdessen öffnen /dev/tty, um mit dem zu kommunizieren Benutzer. Das Programm kann sogar ohne Terminal gestartet werden und mit ein eigenes Terminal öffnen xterm -S.
Kasperd
3
@kasperd: Der beste Ansatz besteht darin, vernünftige Standardeinstellungen bereitzustellen und diese zu überschreiben.
SF.
1
In diesem speziellen Fall sehe ich keinen Grund, einen Stream als Eingabe anzufordern. Warum nicht einfach den Token als Parameter akzeptieren ?
jpmc26
16

Ich würde dies nicht unbedingt als Anti-Pattern betrachten, sondern als eine schlecht gestaltete Bibliothek. Es sollte trivial sein, nach einem String als Methodenparameter zu fragen, in den die Eingabe direkt übergeben werden kann.

Wenn dies nicht zu dieser Verwendung passt, kann ein Methodenparameter ein Stream sein, wobei STDIN an die Methode übergeben wird.

Wenn dies nicht zu dieser Verwendung passt, ist die Bibliothek nicht flexibel genug.

Bryan Boettcher
quelle
4

Erwägen Sie möglicherweise, in Ihrer Bibliothek die Möglichkeit zu haben, einen Rückruf für eine vom Benutzer bereitgestellte Funktion festzulegen, die Eingaben von überall liest , und dann den entsprechenden Wert an den Teil der Bibliothek zurückzugeben, der diese Funktion verwendet.

FrustratedWithFormsDesigner
quelle
1

Wenn es von stdin liest, bedeutet dies, dass es den Besitz von stdin auf Programmebene übernehmen möchte. Es ist wahrscheinlich nicht kompatibel mit anderen Bibliotheken, die aus dem weniger spezifischen Standardprotokoll für die gemeinsame Nutzung lesen. Zumindest in meinem persönlichen Glossar würde dies die Bibliothek zu einem Framework machen , was einen teuren Kompromiss darstellt.

In diesem Fall sollte die Bibliothek wahrscheinlich nur einen Eingabedateideskriptor verwenden.

djechlin
quelle
0

Die Antwort von @ Paul92 ist eine gute allgemeine Diskussion, aber ich möchte eine mögliche saubere (ish) Lösung dafür anbieten :

Als Bibliothek muss dieser Code an jede Laufzeitumgebung anpassbar sein, sodass Sie nicht wirklich STDINnach wichtigen Daten fragen können. Zum einen haben Benutzer Ihrer Bibliothek aus einer Reihe von Gründen möglicherweise kein stdin verfügbar. Stattdessen möchten Sie möglicherweise eine Art Strategiemuster verwenden , um anzupassen, wie das Token abgerufen werden soll.

In Python ist es wahrscheinlich die beste Option, die Token-Abrufstrategie als Funktionsparameter zu übergeben. Sowas in der Art:

def stdin_prompt():
    return input("Enter code: ")

def my_library_function(arg1, arg2, ... argn, token_provider = stdin_prompt):
    ...
    token = token_provider()
    ...
    return stuff

# somewhere in the user code
stuff = my_library_function(a1, a2, ... an, lambda: "123456")

Stellen Sie es sich so vor. Das von Ihnen benötigte Token ist ein Argument für die Bibliotheksfunktion. Da der Wert für das Token an der Aufrufstelle möglicherweise nicht statisch bekannt ist, können Sie den Wert nicht wirklich als Argument anfordern. Stattdessen muss der Aufrufer eine Funktion bereitstellen, die für die Bereitstellung des Tokens beim Aufruf verantwortlich ist.

Die gesamte Verantwortung für die Bereitstellung der genauen Mechanik des Tokens wird jetzt aus der Bibliotheksfunktion ausgelagert. Der Verbraucher der Funktion ist nun dafür verantwortlich, das Token mit allen zur Laufzeit verfügbaren Mitteln zu erfassen. Es kann STDIN fragen, aber auch als Mail-Gateway fungieren, warten, bis die Nachricht im Posteingang eingeht, gelesen, das Token extrahiert und den Vorgang vollständig automatisiert. Es kann sich um ein GUI-Dialogfeld oder ein webbasiertes Formular handeln. Eigentlich alles - alle Optionen liegen jetzt in den Händen des Bibliotheksverbrauchers.

Roland Tepp
quelle