J'ai toujours utilisé des fichiers JSON pour la configuration de mes applications. J'ai commencé à les utiliser à partir du moment où je codais beaucoup de Java. Aujourd'hui, je travaille principalement sur le développement Python côté serveur et en science des données, et je ne suis pas sûr que JSON soit la bonne solution.
J'ai vu Celery utiliser des fichiers Python réels pour la configuration. Au début, j'étais sceptique à ce sujet. Mais l'idée d'utiliser de simples structures de données Python pour la configuration commence à germer. Quelques pros:
- Les structures de données seront les mêmes que celles que je code normalement. Je n'ai donc pas besoin de changer d'état d'esprit.
- Mon IDE (PyCharm) comprend le lien entre la configuration et le code. Ctrl+ Bpermet de basculer facilement entre la configuration et le code.
- Je n'ai pas besoin de travailler avec JSON strict strict inutile IMO . Je vous regarde entre guillemets, sans virgule ni commentaire.
- Je peux écrire des configurations de test dans l'application sur laquelle je travaille, puis les transférer facilement dans un fichier de configuration sans avoir à effectuer de conversion ni d'analyse JSON.
- Il est possible de faire un script très simple dans le fichier de configuration si vraiment nécessaire. (Bien que cela devrait être très très limité.)
Ma question est donc la suivante: si je change de mode, comment puis-je me tirer une balle dans le pied?
Aucun utilisateur final non qualifié n'utilisera les fichiers de configuration. Toutes les modifications apportées aux fichiers de configuration sont actuellement validées dans Git et sont déployées sur nos serveurs dans le cadre d'un déploiement continu. Il n'y a pas de changement de configuration manuel, sauf en cas d'urgence ou de développement.
(J'ai envisagé YAML , mais quelque chose à ce sujet m'énerve. Donc, pour l'instant, c'est hors de la table américaine.)
la source
Réponses:
L' utilisation d' un langage de script en place d'un fichier de configuration ressemble beaucoup au premier coup d' œil: vous avez la pleine puissance de cette langue disponible et peut simplement
eval()
ouimport
elle. En pratique, il y a quelques pièges:c'est un langage de programmation qui doit être appris. Pour éditer la configuration, vous devez connaître suffisamment cette langue. Les fichiers de configuration ont généralement un format plus simple et plus difficile à obtenir.
c'est un langage de programmation, ce qui signifie que la configuration peut être difficile à déboguer. Avec un fichier de configuration normal, examinez-le et voyez quelles valeurs sont fournies pour chaque propriété. Avec un script, vous devez éventuellement l'exécuter pour voir les valeurs.
c'est un langage de programmation, ce qui rend difficile de maintenir une séparation claire entre la configuration et le programme réel. Parfois, vous souhaitez ce type d'extensibilité, mais à ce stade, vous recherchez probablement plutôt un véritable système de plug-in.
c'est un langage de programmation, ce qui signifie que la configuration peut faire tout ce que le langage de programmation peut faire. Donc, soit vous utilisez une solution de sandbox qui nie une grande partie de la flexibilité du langage, soit vous accordez une grande confiance à l'auteur de la configuration.
Donc, utiliser un script pour la configuration est probablement OK si le public de votre outil est constitué de développeurs, par exemple Sphinx config ou le fichier setup.py dans les projets Python. D'autres programmes avec une configuration exécutable sont des shells comme Bash et des éditeurs comme Vim.
L'utilisation d'un langage de programmation pour la configuration est nécessaire si la configuration contient de nombreuses sections conditionnelles, ou si elle fournit des rappels / plugins. Utiliser un script directement au lieu de eval () - certains champs de configuration ont tendance à être plus faciles à déboguer (pensez aux traces de pile et aux numéros de ligne!).
L'utilisation directe d'un langage de programmation peut également être une bonne idée si votre configuration est tellement répétitive que vous écrivez des scripts pour générer automatiquement la configuration. Mais peut-être qu'un meilleur modèle de données pour la configuration pourrait supprimer la nécessité d'une telle configuration explicite? Par exemple, il peut être utile que le fichier de configuration puisse contenir des espaces réservés que vous développez ultérieurement. Une autre caractéristique parfois observée est la présence de plusieurs fichiers de configuration avec une priorité différente pouvant se remplacer, bien que cela pose certains problèmes.
Dans la plupart des cas, les fichiers INI, les fichiers de propriétés Java ou les documents YAML conviennent beaucoup mieux à la configuration. Pour les modèles de données complexes, XML peut également être applicable. Comme vous l'avez noté, JSON présente certains aspects qui le rendent inutilisable en tant que fichier de configuration modifiable par l'homme, même s'il s'agit d'un format d'échange de données précis.
la source
sendmail.cf
. Cela indiquerait que l'utilisation d'un langage de script réel pourrait être bénéfique, étant donné que celui-ci a été conçu pour être complet. Cependant , la complétude de Turing et la "complétude de Tetris" sont deux choses différentes, et biensendmail.cf
qu’elles puissent calculer des fonctions arbitraires, elles ne peuvent pas vous envoyer/etc/passwd
sur le net ni formater votre disque dur, ce que Python ou Perl seraient en mesure de le faire.+1 à tout dans la réponse amon . J'aimerais ajouter ceci:
Vous regretterez d'utiliser le code Python comme langue de configuration la première fois que vous souhaitez importer la même configuration à partir d'un code écrit dans une langue différente. Par exemple, si le code faisant partie de votre projet et écrit en C ++ ou en Ruby ou si quelque chose d’autre doit extraire la configuration, vous devez créer un lien dans l’interpréteur Python en tant que bibliothèque ou analyser la configuration dans un coprocessus Python. qui sont maladroites, difficiles, ou à haute surcharge.
Tout le code qui importe cette configuration aujourd'hui peut être écrit en Python, et vous pensez peut-être que ce sera le cas demain également, mais êtes-vous certain?
Vous avez dit que vous utiliseriez avec parcimonie la logique (quelque chose d’autre que des structures de données statiques) dans votre configuration, ce qui est bien, mais si vous en rencontrez un, vous aurez du mal à le défaire à l’avenir pour peut revenir à un fichier de configuration déclaratif.
EDIT for the record: plusieurs personnes ont commenté cette réponse sur la probabilité ou l’improbabilité qu’un projet soit réécrit complètement avec succès dans une autre langue. Il est juste de dire qu’une réécriture intégrale compatible avec les versions antérieures est probablement rarement vue. Ce que je pensais réellement, c’était des morceaux d’un même projet (et qui nécessitaient un accès à la même configuration) étant écrits dans différentes langues. Par exemple, servir la pile en C ++ pour la rapidité, nettoyer la base de données par lots en Python, utiliser certains scripts shell. Alors réfléchissez bien à cette affaire aussi :)
la source
key=value
assignations pour la configuration, je ne vois pas pourquoi un programme Java / C ++ ne pourrait pas lire le fichier Python en tant que fichier texte brut et l’analyser de la même manière s’ils doivent passer à autre chose l'avenir. Je ne vois pas la nécessité d'un interprète Python à part entière.Les autres réponses sont déjà très bonnes, je vais simplement apporter mon expérience d'utilisation dans le monde réel dans quelques projets.
Avantages
Ils sont pour la plupart déjà expliqués:
eval
); cela fonctionne automatiquement même pour des types de données plus complexes (dans notre programme, nous avons des points géométriques et des transformations, qui sont déchargés / chargés juste parrepr
/eval
);Les inconvénients
repr
. C'est évidemment une mauvaise chose.Même si vous êtes en Python, la modification du fichier de configuration à partir de code est un réel problème, car ... eh bien, la modification de code n'est pas du tout triviale, en particulier le code qui a une syntaxe riche et qui n'est pas dans LISP ou similaire. Un de nos programmes contient un fichier de configuration Python, écrit à la main à l’origine, mais il est apparu qu'il serait utile de manipuler le logiciel (un paramètre particulier est une liste de choses qu'il est beaucoup plus simple de réorganiser à l'aide d'une interface graphique). C'est un gros problème, parce que:
Comparez cela avec JSON, INI ou XML (Dieu nous en préserve!), Où la représentation en mémoire peut toujours être modifiée et réécrite, sans perte de données (XML, où la plupart des analyseurs DOM peuvent conserver des espaces dans les nœuds de texte et de commentaire), ou perdez au moins un peu de formatage (JSON, où le format lui-même ne permet pas plus que les données brutes que vous lisez).
Donc, comme d'habitude, il n'y a pas de solution claire; Ma politique actuelle en la matière est la suivante:
si le fichier de configuration est:
un fichier Python peut être une idée valide;
si à la place:
un format "données uniquement" peut être une meilleure idée.
Notez qu'il n'est pas nécessaire de faire un seul choix. J'ai récemment écrit une application qui utilise les deux approches. J'ai un fichier presque jamais modifié avec les paramètres de configuration initiale, manuscrits où il y a des avantages à avoir de beaux bonus Python, et un fichier JSON pour la configuration édité à partir de l'interface utilisateur.
la source
note:
champ qui est ignoré pour la configuration.curl ... | bash
, c'est encore moins embêtant. :-PLa question principale est la suivante: voulez-vous que votre fichier de configuration soit dans un langage complet de Turing (comme Python)? Si vous le souhaitez, vous pouvez également envisager d'intégrer un autre langage de script (complet de Turing) tel que Guile ou Lua (car il pourrait être perçu comme "plus simple" à utiliser, ou à intégrer, que Python; lisez le chapitre sur Extension & Incorporation de Python ). Je ne discuterai pas de cela plus avant (car d'autres réponses, comme Amon par exemple , en ont discuté en profondeur), mais remarquez que l' intégration d'un langage de script dans votre application est un choix architectural majeur , à prendre très tôt en compte.; Je ne recommande vraiment pas de faire ce choix plus tard!
Un exemple bien connu de programme configurable via des "scripts" est l' éditeur GNU emacs (ou probablement AutoCAD dans le domaine propriétaire); Sachez donc que si vous acceptez les scripts, un utilisateur utilisera éventuellement - et peut-être même abusera, de votre point de vue - cette installation de manière intensive et créera un script de plusieurs milliers de lignes. par conséquent, le choix d'un langage de script suffisant est important.
Cependant (du moins sur les systèmes POSIX), il peut être utile d’activer le calcul dynamique du "fichier" de configuration au moment de l’initialisation (bien sûr, le fardeau d’une configuration rationnelle incombant à votre administrateur système ou à votre utilisateur; c’est en fait une configuration. texte qui provient d’un fichier ou d’une commande). Pour cela, vous pouvez simplement adopter la convention (et la documenter ) selon laquelle un chemin de fichier de configuration commençant par, par exemple, a
!
ou|
est en fait une commande shell que vous liriez comme un pipeline . Cela laisse à l'utilisateur le choix d'utiliser le "préprocesseur" ou le "langage de script" avec lequel il est le plus familier.(vous devez faire confiance à votre utilisateur pour les problèmes de sécurité si vous acceptez une configuration calculée dynamiquement)
Ainsi, dans votre code d’initialisation, vous
main
accepteriez (par exemple) des--config
argumentsconfarg
et en retirerions des argumentsFILE*configf;
. Si cet argument commence par!
(c'est-à-dire si(confarg[0]=='!')
....), vous utiliseriezconfigf = popen(confarg+1, "r");
et fermez ce tuyau avecpclose(configf);
. Sinon, vous utiliseriezconfigf=fopen(confarg, "r");
et fermeriez ce fichier avecfclose(configf);
(n'oubliez pas la vérification des erreurs). Voir pipe (7) , popen (3) , fopen (3) . Pour une application codée en Python, lisez à propos de os.popen , etc ...(document également pour l'utilisateur étrange qui souhaite passer un fichier de configuration nommé
!foo.config
à passer./!foo.config
pour contourner l'popen
astuce ci-dessus)En passant, une telle astuce n’est qu’une commodité (pour éviter d’obliger l’utilisateur avancé à coder par exemple un script shell pour générer un fichier de configuration ). Si l'utilisateur souhaite signaler un bogue, il doit vous envoyer le fichier de configuration généré ...
Notez que vous pouvez également concevoir votre application avec la possibilité d’utiliser et de charger des plugins au moment de l’initialisation, par exemple avec dlopen (3) (et vous devez faire confiance à votre utilisateur pour ce plugin). Là encore, il s’agit d’une décision très importante en matière d’architecture (et vous devez définir et fournir des API et des conventions relativement stables concernant ces plug-ins et votre application).
Pour une application codée dans un langage de script tel que Python, vous pouvez également accepter certains arguments de programme pour les primitives eval ou exec ou similaires. Encore une fois, les problèmes de sécurité sont alors la préoccupation de l'utilisateur (avancé) .
En ce qui concerne le format textuel pour votre fichier de configuration (que ce soit généré ou non), je crois que vous avez besoin surtout pour documenter bien (et le choix d' un certain format particulier est pas si important que cela, mais je vous recommande de laisser votre utilisateur soit en mesure de mettre quelques-uns commentaires commentés à l'intérieur). Vous pouvez utiliser JSON (de préférence avec un analyseur JSON acceptant et ignorant les commentaires avec les
//
lettres habituelles jusqu’à eol ou/*
...*/
...), ou YAML, ou XML, ou INI ou votre propre chose. L'analyse d'un fichier de configuration est relativement facile (et vous trouverez de nombreuses bibliothèques liées à cette tâche).la source
En ajoutant à la réponse d’ Amon , avez-vous envisagé des alternatives? JSON est peut-être plus que ce dont vous avez besoin, mais les fichiers Python vous poseront probablement des problèmes à l'avenir pour les raisons mentionnées ci-dessus.
Cependant, Python a déjà un analyseur de configuration pour un langage de configuration très simple qui pourrait répondre à tous vos besoins. Le
ConfigParser
module implémente un langage de configuration simple.la source
Je travaille depuis longtemps avec un logiciel bien connu dont les fichiers de configuration sont écrits en TCL. L'idée n'est donc pas nouvelle. Cela a très bien fonctionné, car les utilisateurs qui ne connaissaient pas la langue pouvaient toujours écrire / éditer des fichiers de configuration simples en utilisant une seule
set name value
instruction, tandis que les utilisateurs et les développeurs plus avancés pouvaient tirer des astuces sophistiquées avec cela.Je ne pense pas que "les fichiers de configuration peuvent être difficiles à déboguer" est une préoccupation valable. Tant que votre application ne force pas les utilisateurs à écrire des scripts, ceux-ci peuvent toujours utiliser des affectations simples dans leurs fichiers de configuration, ce qui n'est guère plus difficile à obtenir que le JSON ou le XML.
La réécriture de la configuration est un problème, bien que ce ne soit pas aussi grave qu'il y paraît. La mise à jour de code arbitraire est impossible, mais le chargement de la configuration à partir d'un fichier, sa modification et sa sauvegarde le sont. Fondamentalement, si vous créez des scripts dans un fichier de configuration qui n'est pas en lecture seule, vous obtiendrez une liste d'
set name value
instructions équivalente une fois qu'il aura été enregistré. Un bon indice que cela se produira est un commentaire "ne pas modifier" au début du fichier.Une chose à considérer est que vos fichiers de configuration ne seront pas lisibles de manière fiable par de simples outils basés sur regex, tels que
sed
, mais autant que je sache, ce n'est déjà pas le cas avec vos fichiers JSON actuels, il n'y a donc pas grand chose à perdre.Assurez-vous simplement d’utiliser les techniques de sandbox appropriées lors de l’exécution de vos fichiers de configuration.
la source
Outre tous les points valables d'autres bonnes réponses ici (wow, ils ont même mentionné le concept de Turing-complete), il existe en fait deux ou trois bonnes raisons pratiques de ne PAS utiliser un fichier Python comme configuration, même lorsque vous travaillez sur un fichier Python. seul projet.
Les paramètres d'un fichier source Python font techniquement partie d'un code source exécutable, plutôt que d'un fichier de données en lecture seule. Si vous choisissez cette voie, vous le ferez généralement
import config
, car ce genre de "commodité" était probablement l'une des principales raisons pour lesquelles les gens ont commencé par utiliser un fichier Python comme configuration au départ. Vous avez maintenant tendance à enregistrer ce fichier config.py dans votre référentiel, sinon l’utilisateur final rencontrerait un problème important ImportError lorsqu’il essaiera d’exécuter votre programme pour la première fois.En supposant que vous engagiez réellement ce fichier config.py dans votre référentiel, les membres de votre équipe auraient probablement des paramètres différents dans des environnements différents. Imaginez qu'un jour, un membre engage accidentellement son fichier de configuration local dans le référentiel.
Dernier point mais non le moindre, votre projet pourrait avoir des mots de passe dans le fichier de configuration. (Il s'agit d'une pratique discutable en soi, mais elle se produit quand même.) Et si votre fichier de configuration existe dans le référentiel, vous risquez de valider vos informations d'identification dans un référentiel public.
Désormais, l’utilisation d’un fichier de configuration contenant uniquement des données, tel que le format JSON universel, peut éviter les 3 problèmes ci-dessus, car vous pouvez demander à l’utilisateur de créer son propre fichier config.json et de l’alimenter dans votre programme.
PS: Il est vrai que JSON a de nombreuses restrictions. Deux des limitations mentionnées par le PO peuvent être résolues par une certaine créativité.
Et j'ai généralement un espace réservé pour contourner la règle de virgule finale. Comme ça:
la source