Ich habe immer JSON- Dateien für die Konfiguration meiner Anwendungen verwendet. Ich habe angefangen, sie zu verwenden, als ich viel Java codiert habe, und jetzt arbeite ich hauptsächlich an der serverseitigen und datentechnischen Python-Entwicklung und bin mir nicht sicher, ob JSON der richtige Weg ist.
Ich habe gesehen, wie Sellerie aktuelle Python-Dateien für die Konfiguration verwendet. Anfangs war ich skeptisch. Die Idee, einfache Python-Datenstrukturen für die Konfiguration zu verwenden, wächst jedoch langsam. Einige Profis:
- Die Datenstrukturen stimmen mit denen überein, in die ich normalerweise programmiere. Daher muss ich die Einstellung nicht ändern.
- Meine IDE (PyCharm) versteht den Zusammenhang zwischen Konfiguration und Code. Ctrl+ Bermöglicht das einfache Wechseln zwischen Konfiguration und Code.
- Ich brauche nicht mit IMO unnötig strengen JSON zu arbeiten . Ich betrachte Sie doppelte Anführungszeichen, keine nachgestellten Kommas und keine Kommentare.
- Ich kann Testkonfigurationen in die Anwendung schreiben, an der ich arbeite, und sie dann einfach in eine Konfigurationsdatei portieren, ohne Konvertierung und JSON-Analyse durchführen zu müssen.
- Bei Bedarf können sehr einfache Skripte in der Konfigurationsdatei erstellt werden. (Obwohl dies sehr, sehr begrenzt sein sollte.)
Meine Frage lautet also: Wenn ich wechsle, wie schieße ich mir in den Fuß?
Kein ungelernter Endbenutzer verwendet die Konfigurationsdateien. Alle Änderungen an den Konfigurationsdateien werden derzeit für Git festgeschrieben und im Rahmen einer kontinuierlichen Bereitstellung auf unseren Servern bereitgestellt. Es gibt keine manuellen Konfigurationsänderungen, es sei denn, es liegt ein Notfall vor oder es befindet sich in der Entwicklung.
(Ich habe über YAML nachgedacht , aber etwas daran ärgert mich. Im Moment ist es also vom amerikanischen Tisch verschwunden.)
quelle
Antworten:
Die Verwendung einer Skriptsprache anstelle einer Konfigurationsdatei sieht auf den ersten Blick großartig aus: Sie haben die volle Leistungsfähigkeit dieser Sprache zur Verfügung und können einfach
eval()
oderimport
es. In der Praxis gibt es einige Fallstricke:Es ist eine Programmiersprache, die gelernt werden muss. Um die Konfiguration zu bearbeiten, müssen Sie diese Sprache ausreichend gut beherrschen. Konfigurationsdateien haben normalerweise ein einfacheres Format, bei dem es schwieriger ist, einen Fehler zu machen.
Es ist eine Programmiersprache, was bedeutet, dass die Konfiguration schwierig zu debuggen sein kann. Mit einer normalen Konfigurationsdatei sehen Sie sich diese an und sehen, welche Werte für jede Eigenschaft bereitgestellt werden. Bei einem Skript müssen Sie es möglicherweise zuerst ausführen, um die Werte anzuzeigen.
Es ist eine Programmiersprache, die es schwierig macht, eine klare Trennung zwischen der Konfiguration und dem eigentlichen Programm aufrechtzuerhalten. Manchmal möchten Sie diese Art von Erweiterbarkeit, aber an diesem Punkt suchen Sie wahrscheinlich eher ein echtes Pluginsystem.
Es ist eine Programmiersprache, was bedeutet, dass die Konfiguration alles kann, was die Programmiersprache kann. Entweder verwenden Sie eine Sandbox-Lösung, die einen Großteil der Flexibilität der Sprache zunichte macht, oder Sie setzen großes Vertrauen in den Konfigurationsautor.
Die Verwendung eines Skripts für die Konfiguration ist also wahrscheinlich in Ordnung, wenn die Zielgruppe Ihres Tools Entwickler sind, z. B. Sphinx config oder die Datei setup.py in Python-Projekten. Andere Programme mit ausführbarer Konfiguration sind Shells wie Bash und Editoren wie Vim.
Die Verwendung einer Programmiersprache zur Konfiguration ist erforderlich, wenn die Konfiguration viele bedingte Abschnitte enthält oder Callbacks / Plugins bereitstellt. Die direkte Verwendung eines Skripts anstelle von eval () - einige Konfigurationsfelder sind in der Regel leichter zu debuggen (denken Sie an die Stack-Traces und Zeilennummern!).
Die direkte Verwendung einer Programmiersprache kann auch eine gute Idee sein, wenn sich Ihre Konfiguration so wiederholt, dass Sie Skripte schreiben, um die Konfiguration automatisch zu generieren. Aber vielleicht könnte ein besseres Datenmodell für die Konfiguration die Notwendigkeit einer solchen expliziten Konfiguration beseitigen? Beispielsweise kann es hilfreich sein, wenn die Konfigurationsdatei Platzhalter enthält, die Sie später erweitern. Eine andere Eigenschaft, die manchmal auftritt, sind mehrere Konfigurationsdateien mit unterschiedlicher Priorität, die sich gegenseitig überschreiben können, die jedoch einige eigene Probleme mit sich bringen.
In den meisten Fällen eignen sich INI-Dateien, Java-Eigenschaftendateien oder YAML-Dokumente besser für die Konfiguration. Für komplexe Datenmodelle kann auch XML anwendbar sein. Wie Sie bereits bemerkt haben, weist JSON einige Aspekte auf, die es als von Menschen bearbeitbare Konfigurationsdatei ungeeignet machen, obwohl es ein gutes Datenaustauschformat ist.
quelle
sendmail.cf
. Dies würde darauf hinweisen, dass die Verwendung einer tatsächlichen Skriptsprache von Vorteil sein könnte, da diese tatsächlich so konzipiert wurde , dass sie vollständig ist. Allerdings , Turing-Vollständigkeit und „Tetris-Vollständigkeit“ sind zwei verschiedene Dinge, und währendsendmail.cf
beliebige Funktionen berechnen kann, kann es nicht Ihre senden/etc/passwd
über das Netz oder formatieren Sie Ihre Festplatte, der Python oder Perl Lage wäre.+1 für alles in Amons Antwort . Ich möchte folgendes hinzufügen:
Sie werden es bereuen, Python-Code als Konfigurationssprache verwendet zu haben, wenn Sie zum ersten Mal dieselbe Konfiguration aus Code importieren möchten, der in einer anderen Sprache geschrieben ist. Wenn beispielsweise Code, der Teil Ihres Projekts ist und in C ++ oder Ruby geschrieben wurde, oder etwas anderes in die Konfiguration geladen werden muss, müssen Sie den Python-Interpreter als Bibliothek verknüpfen oder die Konfiguration in einem Python-Coprozess analysieren die umständlich, schwierig oder hoch über dem Kopf sind.
Der gesamte Code, der diese Konfiguration heute importiert, ist möglicherweise in Python geschrieben, und Sie denken möglicherweise, dass dies auch morgen der Fall sein wird, aber wissen Sie es mit Sicherheit?
Sie sagten, Sie würden Logik (alles andere als statische Datenstrukturen) in Ihrer Konfiguration sparsam verwenden, wenn überhaupt, was gut ist, aber wenn etwas davon überhaupt vorhanden ist, werden Sie es in Zukunft schwierig finden, es rückgängig zu machen, damit Sie kann zu einer deklarativen Konfigurationsdatei zurückkehren.
EDIT for the record: Mehrere Personen haben diese Antwort dahingehend kommentiert, wie wahrscheinlich oder unwahrscheinlich es ist, dass ein Projekt jemals vollständig in einer anderen Sprache neu geschrieben werden kann. Es ist fair zu sagen, dass ein vollständiges abwärtskompatibles Umschreiben wahrscheinlich selten zu sehen ist. Was ich eigentlich im Sinn hatte, waren Teile desselben Projekts (und die Notwendigkeit, auf dieselbe Konfiguration zuzugreifen), die in verschiedenen Sprachen geschrieben waren. Beispiel: Bereitstellen des Stacks in C ++ für Geschwindigkeit, Bereinigen der Batch-Datenbank in Python und einige Shell-Skripte als Klebstoff. Also überleg auch für diesen Fall :)
quelle
key=value
ich nicht verstehen, warum ein Java / C ++ - Programm die Python-Datei nicht als reine Textdatei lesen und gleich analysieren konnte, wenn sie zu etwas anderem in wechseln mussten , wenn sie die Python-Seite auf Zuweisungen für config beschränkten die Zukunft. Ich sehe keinen Bedarf für einen vollwertigen Python-Interpreter.Die anderen Antworten sind bereits sehr gut, ich werde nur meine Erfahrungen mit der praktischen Anwendung in ein paar Projekten einbringen.
Vorteile
Sie sind meistens schon buchstabiert:
eval
). es funktioniert auch bei komplexeren Datentypen automatisch (in unserem Programm haben wir geometrische Punkte und Transformationen, die einfach durchrepr
/ ausgegeben / geladen werdeneval
);Nachteile
repr
. Das ist offensichtlich eine schlechte Sache.Selbst wenn Sie sich in Python befinden, ist das Ändern der Konfigurationsdatei in Code ein echtes Problem, da ... das Ändern von Code überhaupt nicht trivial ist, insbesondere von Code, der eine umfangreiche Syntax aufweist und nicht in LISP oder ähnlichem vorliegt. Ein Programm von uns hat eine Konfigurationsdatei , die Python ist, die ursprünglich von Hand geschrieben, aber das stellte sich später heraus , es wäre nützlich , über Software zu manipulieren (eine bestimmte Einstellung ist eine Liste der Dinge , die ist Art und Weise einfacher mit Hilfe eines GUI neu zu ordnen). Das ist ein großes Problem, weil:
Vergleichen Sie dies mit JSON, INI oder (Gott bewahre!) XML, wo die In-Memory-Darstellung immer bearbeitet und zurückgeschrieben werden kann, entweder ohne Datenverlust (XML, wo die meisten DOM-Parser Leerzeichen in Textknoten und Kommentarknoten belassen können) oder Mindestens einige Formatierungen gehen verloren (JSON, bei dem das Format selbst nicht viel mehr zulässt als die Rohdaten, die Sie lesen).
Es gibt also wie üblich keine eindeutige Lösung. Meine derzeitige Politik zu diesem Thema lautet:
wenn die Konfigurationsdatei ist:
Eine Python-Datei kann eine gültige Idee sein.
wenn stattdessen:
Ein "Nur-Daten" -Format ist möglicherweise eine bessere Idee.
Beachten Sie, dass es nicht erforderlich ist, eine einzige Auswahl zu treffen - ich habe kürzlich eine Anwendung geschrieben, die beide Ansätze verwendet. Ich habe eine fast nie geänderte Datei mit ersten Einstellungen, handschriftlichen Einstellungen, bei denen es Vorteile gibt, nette Python-Boni zu haben, und eine JSON-Datei für die Konfiguration, die über die Benutzeroberfläche bearbeitet wird.
quelle
note:
Feld ein, das für die Konfiguration ignoriert wird.curl ... | bash
, was noch weniger problematisch ist. :-PDie Hauptfrage ist: Soll Ihre Konfigurationsdatei in einer vollständigen Turing-Sprache vorliegen (wie Python)? Wenn Sie dies wünschen, können Sie auch eine andere Skriptsprache (Turing complete) wie Guile oder Lua einbetten (da diese als "einfacher" zu verwenden oder einzubetten ist als Python). Lesen Sie das Kapitel zu Erweitern und Python einbinden ). Ich werde darauf nicht weiter eingehen (da andere Antworten - z. B. von Amon - ausführlich darauf eingegangen sind), aber beachten Sie, dass das Einbetten einer Skriptsprache in Ihre Anwendung eine wichtige architektonische Wahl ist , die Sie sehr früh in Betracht ziehen sollten; Ich empfehle wirklich nicht, diese Wahl später zu treffen!
Ein bekanntes Beispiel für ein durch "Skripte" konfigurierbares Programm ist der GNU-Emacs- Editor (oder wahrscheinlich AutoCAD im proprietären Bereich). Beachten Sie daher, dass einige Benutzer, wenn Sie Skripte akzeptieren, diese Funktion möglicherweise ausgiebig verwenden und ein Skript mit mehreren tausend Zeilen erstellen würden. Daher ist die Auswahl einer ausreichend guten Skriptsprache wichtig.
(Zumindest auf POSIX-Systemen) können Sie es jedoch als zweckmäßig erachten, die Konfigurationsdatei zum Zeitpunkt der Initialisierung dynamisch berechnen zu lassen Text, der aus einer Datei oder einem Befehl stammt). Dazu können Sie einfach die Konvention übernehmen (und dokumentieren ), dass ein Konfigurationsdateipfad, der mit a
!
oder a beginnt,|
tatsächlich ein Shell- Befehl ist , den Sie als Pipeline lesen würden . Dadurch hat der Benutzer die Wahl, welche "Präprozessor" - oder "Skriptsprache" er am besten kennt.(Sie müssen Ihrem Benutzer in Bezug auf Sicherheitsprobleme vertrauen, wenn Sie eine dynamisch berechnete Konfiguration akzeptieren.)
In Ihrem Initialisierungscode
main
würde Ihr (zum Beispiel) ein--config
Argument akzeptierenconfarg
und einigesFILE*configf;
daraus abrufen. Wenn dieses Argument mit!
(dh wenn(confarg[0]=='!')
....) beginnt , würden Sieconfigf = popen(confarg+1, "r");
diese Pipe mit verwenden und schließenpclose(configf);
. Andernfalls würden Sieconfigf=fopen(confarg, "r");
diese Datei verwenden und mit schließenfclose(configf);
(Fehlerprüfung nicht vergessen). Siehe Pipe (7) , Popen (3) , Fopen (3) . Eine in Python codierte Anwendung enthält Informationen zu os.popen usw.(Dokument auch für den seltsamen Benutzer, der eine Konfigurationsdatei mit dem Namen
!foo.config
pass übergeben möchte./!foo.config
, um denpopen
obigen Trick zu umgehen )BTW, wie ein Trick ist nur eine Bequemlichkeit (zu vermeiden , dass die erweiterte Benutzer zB Code erfordern einige Shell - Skript zu generieren eine Konfigurationsdatei ). Wenn der Benutzer einen Fehler melden möchte, sollte er Ihnen die generierte Konfigurationsdatei senden ...
Beachten Sie, dass Sie Ihre Anwendung auch so gestalten können, dass Sie Plugins zum Zeitpunkt der Initialisierung verwenden und laden können , z. B. mit dlopen (3) (und Sie müssen Ihrem Benutzer in Bezug auf dieses Plugin vertrauen). Auch dies ist eine sehr wichtige architektonische Entscheidung (und Sie müssen einige recht stabile APIs und Konventionen für diese Plugins und Ihre Anwendung definieren und bereitstellen ).
Für eine Anwendung, die in einer Skriptsprache wie Python codiert ist, können Sie auch ein Programmargument für eval oder exec oder ähnliche Grundelemente akzeptieren . Wiederum sind die Sicherheitsprobleme das Anliegen des (fortgeschrittenen) Benutzers.
In Bezug auf das Textformat für Ihre Konfigurationsdatei (ob generiert oder nicht) glaube ich, dass Sie es meistens gut dokumentieren müssen (und die Wahl eines bestimmten Formats ist nicht so wichtig, ich empfehle jedoch, dass Ihr Benutzer es setzen kann einige übersprungene Kommentare drin). Sie könnten JSON (vorzugsweise mit einem JSON-Parser, der Kommentare mit der üblichen
//
bis-eol-Methode oder/*
...*/
... akzeptiert und überspringt ) oder YAML oder XML oder INI oder Ihr eigenes Ding verwenden. Das Parsen einer Konfigurationsdatei ist relativ einfach (und Sie werden viele Bibliotheken finden, die sich auf diese Aufgabe beziehen).quelle
Haben Sie zur Antwort von amon noch Alternativen in Betracht gezogen? JSON ist vielleicht mehr als Sie brauchen, aber Python-Dateien werden Ihnen wahrscheinlich aus den oben genannten Gründen in Zukunft Probleme bereiten.
Python verfügt jedoch bereits über einen Konfigurationsparser für eine sehr einfache Konfigurationssprache, die alle Ihre Anforderungen erfüllen kann. Das
ConfigParser
Modul implementiert eine einfache Konfigurationssprache.quelle
Ich habe lange mit einer bekannten Software gearbeitet , deren Konfigurationsdateien in TCL geschrieben sind. Die Idee ist also nicht neu. Dies funktionierte recht gut, da Benutzer, die die Sprache nicht kannten, einfache Konfigurationsdateien mit einer einzigen
set name value
Anweisung schreiben / bearbeiten konnten , während fortgeschrittenere Benutzer und Entwickler mit dieser Anweisung ausgefeilte Tricks anwenden konnten.Ich denke nicht, dass "das Debuggen der Konfigurationsdateien schwierig werden kann" ein berechtigtes Anliegen ist. Solange Ihre Anwendung Benutzer nicht zum Schreiben von Skripten zwingt, können Ihre Benutzer immer einfache Zuweisungen in ihren Konfigurationsdateien verwenden, was im Vergleich zu JSON oder XML kaum schwieriger zu erreichen ist.
Das Umschreiben der Konfiguration ist ein Problem, obwohl es nicht so schlimm ist, wie es scheint. Das Aktualisieren von beliebigem Code ist nicht möglich, aber das Laden der Konfiguration aus einer Datei, das Ändern und Zurückspeichern ist möglich. Wenn Sie Skripte in einer Konfigurationsdatei ausführen, die nicht schreibgeschützt ist, erhalten Sie nach dem Speichern nur eine entsprechende Liste von
set name value
Anweisungen. Ein guter Hinweis, dass dies passieren wird, ist ein "Nicht bearbeiten" -Kommentar am Anfang der Datei.Zu beachten ist, dass Ihre Konfigurationsdateien von einfachen, auf Regex basierenden Tools wie z. B. nicht zuverlässig gelesen werden können.
sed
Soweit ich weiß, ist dies bei Ihren aktuellen JSON-Dateien bereits nicht der Fall, sodass Sie nicht viel verlieren können.Stellen Sie einfach sicher, dass Sie beim Ausführen Ihrer Konfigurationsdateien die entsprechenden Sandbox- Techniken verwenden.
quelle
Neben all den gültigen Punkten anderer guter Antworten (wow, sie haben sogar das Turing-complete-Konzept erwähnt) gibt es tatsächlich ein paar gute praktische Gründe, eine Python-Datei NICHT als Konfiguration zu verwenden, selbst wenn Sie an einer Python-Datei arbeiten. nur projekt.
Die Einstellungen in einer Python-Quelldatei sind technisch gesehen Teil des ausführbaren Quellcodes und keine schreibgeschützten Datendateien. Wenn Sie diesen Weg gehen, tun Sie dies in der Regel
import config
, da diese Art von "Bequemlichkeit" vermutlich einer der Hauptgründe war, warum die Leute anfingen, eine Python-Datei als Konfiguration zu verwenden. Jetzt neigen Sie dazu, diese config.py in Ihr Repo zu übernehmen, da Ihr Endbenutzer sonst auf einen verwirrenden ImportError stoßen würde, wenn er versucht, Ihr Programm zum ersten Mal auszuführen.Unter der Annahme, dass Sie die Datei config.py tatsächlich in Ihr Repo übernehmen, hätten Ihre Teammitglieder jetzt wahrscheinlich unterschiedliche Einstellungen in unterschiedlichen Umgebungen. Stellen Sie sich vor, eines Tages schreibt ein Mitglied versehentlich seine lokale Konfigurationsdatei in das Repo.
Last but not least könnte Ihr Projekt Passwörter in der Konfigurationsdatei haben. (Dies ist eine strittige Praxis, aber sie passiert trotzdem.) Wenn Ihre Konfigurationsdatei in repo vorhanden ist, besteht das Risiko, dass Sie Ihren Berechtigungsnachweis für ein öffentliches Repo festlegen.
Mit einer reinen Datenkonfigurationsdatei wie dem universellen JSON-Format können Sie nun alle drei oben genannten Probleme vermeiden, da Sie den Benutzer auffordern können, eine eigene config.json-Datei zu erstellen und diese in Ihr Programm einzufügen.
PS: Es ist wahr, dass JSON viele Einschränkungen hat. 2 der vom OP genannten Einschränkungen können durch etwas Kreativität gelöst werden.
Und ich habe normalerweise einen Platzhalter, um die nachstehende Komma-Regel zu umgehen. So was:
quelle