Argumentübergabestrategie - Umgebungsvariablen vs. Befehlszeile

75

Die meisten Anwendungen, die wir Entwickler schreiben, müssen beim Start extern parametrisiert werden. Wir übergeben Dateipfade, Pipe-Namen, TCP / IP-Adressen usw. Bisher habe ich die Befehlszeile verwendet , um diese an die zu startende Anwendung zu übergeben. Ich musste die Befehlszeile analysieren mainund die Argumente dorthin leiten, wo sie benötigt werden. Dies ist natürlich ein gutes Design , aber für eine große Anzahl von Argumenten schwer zu pflegen . Kürzlich habe ich mich für den Umgebungsvariablenmechanismus entschieden . Sie sind global und von überall zugänglich, was aus architektonischer Sicht weniger elegant ist , aber die Codemenge begrenzt .

Dies sind meine ersten (und möglicherweise recht flachen) Eindrücke zu beiden Strategien, aber ich würde gerne Meinungen erfahrener Entwickler hören. Was sind die Höhen und Tiefen der Verwendung von Umgebungsvariablen und Befehlszeilenargumenten, um Argumente an einen Prozess zu übergeben? Ich möchte folgende Punkte berücksichtigen:

  1. Designqualität (Flexibilität / Wartbarkeit),
  2. Speicherbeschränkungen,
  3. Portabilität der Lösung.

Bemerkungen:

Anzeige. 1. Dies ist der Hauptaspekt, der mich interessiert.

Anzeige. 2. Das ist ein bisschen pragmatisch. Ich kenne einige Einschränkungen unter Windows, die derzeit sehr groß sind (über 32 KB sowohl für die Befehlszeile als auch für den Umgebungsblock). Ich denke, dies ist jedoch kein Problem, da Sie nur eine Datei verwenden sollten, um bei Bedarf Tonnen von Argumenten zu übergeben.

Anzeige. 3. Ich weiß fast nichts über Unix, daher bin ich mir nicht sicher, ob beide Strategien genauso ähnlich sind wie unter Windows. Erläutern Sie dies bitte.

Janusz Lenar
quelle
Würden Sie mehr Einzelheiten angeben, wie in der tatsächlichen Anzahl der Parameter? und wenn es Gruppierungen gibt oder sind sie alle zufällig? und für welche Sprache ist das? Java, C ++, etc ... Der Grund, warum ich nach dieser Detailebene frage, ist, dass es zwar ein Problem in jeder Sprache geben kann, es aber möglicherweise eine sprachimplementierungsspezifische Lösung gibt, die Sie nicht kennen.
James Drinkard
Um nur die * nix-Betriebssysteme zu erwähnen, sie haben nichts wie "globale Umgebungsvariable" und jede env-Variable wird in der Gabelzeit vom übergeordneten Prozess zum untergeordneten Prozess geerbt. "Global" ist also kein Profi für env var over command line, zumindest für diese Betriebssysteme.
Shr
Hallo, @jamesDrinkard. Ich interessiere mich für den allgemeinen Ansatz. Welche Methode würden Sie verwenden, wenn Sie 20 verschiedene Argumente für Zeichenfolgen / Integrale / reelle Zahlen von einem Python-Skript, das von einem 32-Bit-Interpreter ausgeführt wird, an eine in C ++ geschriebene 64-Bit-Anwendung übergeben möchten?
Janusz Lenar
Hallo, @shr. Vielen Dank für den * nix Hinweis. Wie Raymond weiter unten betonte, ist eine solche Globalität für diese Aufgabe überhaupt kein Profi.
Janusz Lenar
1
Dies könnte relevant sein und befürwortet Umgebungsvariablen: devcenter.heroku.com/articles/config-vars
eyeApps LLC

Antworten:

76

1) Ich würde empfehlen, Umgebungsvariablen so weit wie möglich zu vermeiden.

Vorteile von Umgebungsvariablen

  • einfach zu bedienen, da sie von überall sichtbar sind. Wenn viele unabhängige Programme Informationen benötigen, ist dieser Ansatz wesentlich praktischer.

Nachteile von Umgebungsvariablen

  • schwer richtig zu verwenden, da sie von überall sichtbar (löschbar, einstellbar) sind. Wenn ich ein neues Programm installiere, das auf Umgebungsvariablen basiert, werden diese dann auf meine vorhandenen stampfen? Habe ich versehentlich meine Umgebungsvariablen vermasselt, als ich gestern herumgespielt habe?

Meine Meinung

  • Verwenden Sie Befehlszeilenargumente für diejenigen Argumente, die bei jedem einzelnen Aufruf des Programms am wahrscheinlichsten unterschiedlich sind (dh n für ein Programm, das n berechnet!).
  • Verwenden Sie Konfigurationsdateien für Argumente, die ein Benutzer möglicherweise vernünftigerweise ändern möchte, jedoch nicht sehr häufig (dh Anzeigegröße, wenn das Fenster angezeigt wird).
  • Verwenden Sie Umgebungsvariablen sparsam - vorzugsweise nur für Argumente, von denen erwartet wird, dass sie sich nicht ändern (dh die Position des Python-Interpreters).
  • Ihr Punkt They are global and accessible from anywhere, which is less elegant from architectural point of view, but limits the amount of codeerinnert mich an Rechtfertigungen für die Verwendung globaler Variablen;)

Meine Narben, weil ich die Schrecken der Überbeanspruchung durch Umgebungsvariablen aus erster Hand erlebt habe

  • Zwei Programme, die wir bei der Arbeit benötigen und die aufgrund von Umweltkonflikten nicht gleichzeitig auf demselben Computer ausgeführt werden können
  • Mehrere Versionen von Programmen mit demselben Namen, aber unterschiedlichen Fehlern - brachten einen ganzen Workshop stundenlang in die Knie, weil der Speicherort des Programms aus der Umgebung entfernt wurde und (lautlos, subtil) falsch war.

2) Grenzen

Wenn ich die Grenzen dessen verschieben würde, was die Befehlszeile enthalten kann oder was die Umgebung verarbeiten kann, würde ich sofort umgestalten.

Ich habe JSON in der Vergangenheit für eine Befehlszeilenanwendung verwendet, die viele Parameter benötigte. Es war sehr praktisch, Wörterbücher und Listen zusammen mit Zeichenfolgen und Zahlen verwenden zu können. Die Anwendung benötigte nur einige Befehlszeilenargumente, von denen eines der Speicherort der JSON-Datei war.

Vorteile dieses Ansatzes

  • Es musste nicht viel (schmerzhafter) Code geschrieben werden, um mit einer CLI-Bibliothek zu interagieren. Es kann schwierig sein, viele der gängigen Bibliotheken dazu zu bringen, komplizierte Einschränkungen durchzusetzen (mit "kompliziert" meine ich komplexer als das Suchen nach a spezifischer Schlüssel oder Wechsel zwischen einem Schlüsselsatz)
  • Sie müssen sich nicht um die Anforderungen der CLI-Bibliotheken für die Reihenfolge der Argumente kümmern - verwenden Sie einfach ein JSON-Objekt!
  • einfach, komplizierte Daten (Antworten What won't fit into command line parameters?) wie Listen darzustellen
  • Einfache Verwendung der Daten aus anderen Anwendungen - sowohl zum Erstellen als auch zum programmgesteuerten Parsen
  • einfach, zukünftige Erweiterungen unterzubringen

Hinweis : Ich möchte dies vom Ansatz der .config-Datei unterscheiden - dies dient nicht zum Speichern der Benutzerkonfiguration. Vielleicht sollte ich dies den Ansatz der 'Befehlszeilen-Parameterdatei' nennen, weil ich ihn für ein Programm verwende, das viele Werte benötigt, die nicht gut in die Befehlszeile passen.


3) Portabilität der Lösung: Ich weiß nicht viel über die Unterschiede zwischen Mac, PC und Linux in Bezug auf Umgebungsvariablen und Befehlszeilenargumente, aber ich kann Ihnen sagen:

  • Alle drei unterstützen Umgebungsvariablen
  • Sie alle unterstützen Befehlszeilenargumente

Ja, ich weiß - es war nicht sehr hilfreich. Es tut mir Leid. Der entscheidende Punkt ist jedoch, dass Sie erwarten können, dass eine vernünftige Lösung portabel ist, obwohl Sie dies auf jeden Fall für Ihre Programme überprüfen möchten (z. B. wird bei Befehlszeilenargumenten auf allen Plattformen zwischen Groß- und Kleinschreibung unterschieden - auf allen Plattformen - ich weiß es nicht ).


Ein letzter Punkt:

Wie Tomasz erwähnte, sollte es für die meisten Anwendungen, aus denen die Parameter stammen, keine Rolle spielen.

Matt Fenwick
quelle
Danke, Matt. Dies ist eine Art Meinung, nach der ich gesucht habe. Der wichtigste Ratschlag von Ihnen ist die Verwendung von Umgebungsvariablen für die Beschreibung der Ausführungsumgebung, die sich kaum ändert, und der cmd-Datei für die Übergabe einfacher / komplexer Argumente für die tatsächliche Ausführung. Sehr rational, danke. Beachten Sie jedoch, dass Sie 'lokale' Umgebungsvariablen verwenden können, die nur untergeordnete Prozesse durcheinander bringen können. Es ist den übergebenen Befehlszeilenargumenten sehr ähnlich, mit Ausnahme dessen, worauf Raymond unter Tomasz 'Antwort hingewiesen hat.
Janusz Lenar
1
Sehr schöne Antwort! In Bezug auf den Nachteil, dass Umgebungsvariablen von überall geändert werden können: Es besteht auch die Möglichkeit, Umgebungsvariablen lokal über ein Startskript (z. B. Bash- oder Batch-Skript) für die Anwendung festzulegen. In diesem Fall kann es einen systemweiten Standardwert geben, eine Anwendung kann jedoch bei Bedarf den Standardwert in einen benutzerdefinierten Wert ändern. Was denkst du darüber?
Lii
Gibt es Vor- und Nachteile bei der Überlegung, wie Geheimnisse / Anmeldeinformationen weitergegeben werden sollen?
iamyojimbo
Ich stimme für Desktop- und CLI-Anwendungen zu. Für Cloud-Systeme mit vielen Bereitstellungen sind env-Variablen eine gute Alternative und werden beispielsweise im 12factor-Handbuch empfohlen: 12factor.net/config
Lars Grammel
7

Sie sollten Leseparameter mithilfe des Strategiemusters abstrahieren . Erstellen eine Abstraktion benannt ConfigurationSourcemit readConfig(key) -> valueVerfahren (oder eine wiederkehrenden ConfigurationObjekt / Struktur) mit folgenden Implementierungen:

  • CommandLineConfigurationSource
  • EnvironmentVariableConfigurationSource
  • WindowsFileConfigurationSource - Laden aus einer Konfigurationsdatei von C:/Document and settings...
  • WindowsRegistryConfigurationSource
  • NetworkConfigrationSource
  • UnixFileConfigurationSource - - Laden aus einer Konfigurationsdatei von /home/user/...
  • DefaultConfigurationSource - Standardeinstellungen
  • ...

Sie können das Muster der Verantwortungskette auch verwenden , um Quellen in verschiedenen Konfigurationen zu verketten, z. B.: Wenn kein Befehlszeilenargument angegeben wird, versuchen Sie es mit der Umgebungsvariablen. Wenn alles andere fehlschlägt, geben Sie die Standardwerte zurück.

Anzeige 1. Mit diesem Ansatz können Sie nicht nur die Lesekonfiguration abstrahieren, sondern auch den zugrunde liegenden Mechanismus problemlos ändern, ohne den Clientcode zu beeinträchtigen. Sie können auch mehrere Quellen gleichzeitig verwenden, zurückgreifen oder Konfigurationen aus verschiedenen Quellen erfassen.

Anzeige 2. Wählen Sie einfach die geeignete Implementierung aus. Natürlich passen einige Konfigurationseinträge beispielsweise nicht in Befehlszeilenargumente.

Anzeige 3. Wenn einige Implementierungen nicht portierbar sind, lassen Sie zwei, eine wird stillschweigend ignoriert / übersprungen, wenn sie für ein bestimmtes System nicht geeignet ist.

Tomasz Nurkiewicz
quelle
Vielen Dank, dies ist im Allgemeinen eine gute Idee. Es hilft jedoch nicht bei der Entscheidung, ob die Umgebung oder die Befehlszeile verwendet werden soll. Die Ausarbeitung von Ad.2s "Einige Konfigurationseinträge passen beispielsweise nicht in Befehlszeilenargumente" wäre hilfreich. Was passt nicht in eine Saite? Wenn es nicht passt, sollte es wahrscheinlich indirekt in einer Art Datei übergeben werden, nicht wahr?
Janusz Lenar
Mein Punkt ist: Zwingen Sie den Benutzer nicht, Befehlszeilenparameter oder Umgebungsvariablen zu verwenden. Seien Sie flexibel (und behalten Sie den wartbaren Code bei). Ich glaube, dass die Konfigurationsdatei der beste Ort zum Speichern der Konfiguration ist (sie kann beliebig lang sein, Kommentare enthalten usw.), aber manchmal ist es nützlich, die Dateikonfiguration mithilfe von Befehlszeilenparametern zu überschreiben. Was passt nicht in Befehlszeilenparameter? Wenn Sie mehrere Dateipfade übergeben müssen, wird es wahrscheinlich funktionieren, aber niemand mag übermäßig lange Befehlszeilen.
Tomasz Nurkiewicz
Die Konfigurationsdatei eignet sich am besten für Argumente - dies ist eine wertvolle Meinung, und die Unterstützung von Kommentaren ist ein guter Grund, sie zu verwenden. Vielen Dank. Wenn Sie beim Starten einer App über ein Batch-Skript Umgebungsvariablen verwenden, können Sie mit remund ein gut lesbares Formular erstellen set. Wenn Sie einen Prozess erzeugen, haben Sie genau das, setenvwas Sie möchten, bevor Sie beginnen spawnl. Es ist bequem, lesbar und flexibel. Warum sollten Sie .config anstelle der Umgebung verwenden? Das ist hier die Frage.
Janusz Lenar
3
Beachten Sie, dass Umgebungsvariablen vererbt werden. Angenommen, Ihr Programm hat zwei Parameter ACTIONund einen optionalen NOTIFY. Programm A setzt Ihr Programm ACTION=if owner=nobody set owner=bobund führt es NOTIFY=senddann aus. Ihr Programm aktualisiert ein Element, sieht dann, dass NOTIFYes festgelegt ist und ausgeführt wird send. Das sendProgramm sendet eine E-Mail an Bob und führt dann Ihr Programm erneut aus ACTION=set last_send = today. Es möchte keine Benachrichtigung, daher wird es nicht festgelegt NOTIFY. Es wurde jedoch von Programm A geerbt NOTIFY , sodass Ihr Programm den letzten Lauf auf heute aktualisiert und dann ausgeführt wird send. Endlosschleife.
Raymond Chen
1
Vielen Dank, @Raymond. Der Umfang der Umgebungsvariablen ist gefährlich groß. Guter Punkt.
Janusz Lenar
4

Ich denke, diese Frage wurde bereits ziemlich gut beantwortet, aber ich denke, sie verdient ein Update für 2018. Ich bin der Meinung, dass ein nicht erwähnter Vorteil von Umgebungsvariablen darin besteht, dass sie im Allgemeinen weniger Kesselplattencode erfordern, um damit zu arbeiten. Dies sorgt für saubereren, besser lesbaren Code. Ein großer Nachteil ist jedoch, dass sie eine Isolationsschicht von verschiedenen Anwendungen entfernen, die auf demselben Computer ausgeführt werden. Ich denke, hier strahlt Docker wirklich. Mein bevorzugtes Entwurfsmuster besteht darin, ausschließlich Umgebungsvariablen zu verwenden und die Anwendung in einem Docker-Container auszuführen. Dies beseitigt das Isolationsproblem.

mdornfe1
quelle