Konfigurationsdateien in Softwareanwendungen

Wieso benötigen wir überhaupt die Möglichkeit Konfigurationen einer Anwendung in Textdateien zu speichern? Genügt nicht einfach eine Datenbank für diesen Zweck? Die Anwort auf diese Frage ist recht trivial. Denn die Information wie sich eine Anwendung mit einer Datenbank verbinden kann lässt sich ja schlecht in der Datenbank selbst speichern.

Jetzt könnte man sicher argumentieren das man solche Dinge mit einer integrierten Datenbank (embedded) wie beispielsweise SQLlite hinbekommt. Das mag auch grundsätzlich korrekt sein. Leider ist diese Lösung für hoch skalierbare Anwendungen nicht wirklich praktikabel. Zudem muss man nicht immer gleich mit Kanonen auf Spatzen schießen. Das Speichern wichtiger Konfigurationsparameter in Textdateien hat bereits eine lange Tradition in der Softwareentwicklung. Mittlerweile haben sich aber auch verschiedene Textformate wie INI, XML, JSON und YAML für diesen Anwendungsfall etabliert. Aus diesem Grund stellt sich die Frage auf welches Format man am besten für das eigene Projekt zurück greifen sollte.

INI Dateien

Eines der ältesten Formate sind die bekannten INI Dateien. Sie speichern Informationen nach dem Schlüssel = Wert Prinzip. Wenn ein Schlüssel in solch einer INI Datei mehrfach vorkommt wird der finale Wert immer durch den zuletzt in der Datei vorkommenden Wert überschrieben.

; Example of an INI File
[Section-name]
key=value ; inline

text="text configuration with spaces and \' quotas"
string='can be also like this'
char=passwort

# numbers & digets
number=123
hexa=0x123
octa=0123
binary=0b1111
float=123.12

# boolean values
value-1=true
value-0=false
INI

Wie wir in dem kleinen Beispiel sehen können ist die Syntax in INI Dateien sehr einfach gehalten. Der Sektionsname [section] dient vor allem der Gruppierung einzelner Parameter und verbessert die Lesbarkeit. Kommentare können entweder durch ; oder # gekennzeichnet werden. Ansonsten gibt es die Möglichkeit verschiedene Text- und Zahlen-Formate, sowie Boolean-Wert zu definieren.

Web Entwickler kennen INI Files vor allem von der PHP Konfiguration, der php.ini in der wichtige Eingenschaften wie die Größe des Datei-Uploads festgelegt werden kann. Auch unter Windows sind INI Dateien noch immer verbreitet, obwohl seit Windows 95 für diesen Zweck die Registry eingeführt wurde.

Properties

Eine andere sehr bewährte Lösung sind sogenannte property Files. Besonders verbreitet ist diese Lösung in Java Programmen, da Java bereits eine einfache Klasse mitbringt die mit Properties umgehen kann. Das Format key=value ist den INI Dateien entlehnt. Kommentare werden ebenfalls mit # eingeleitet.

# PostgreSQL
hibernate.dialect.database = org.hibernate.dialect.PostgreSQLDialect
jdbc.driverClassName = org.postgresql.Driver
jdbc.url = jdbc:postgresql://127.0.0.1:5432/together-test
Plaintext

Um in Java Programmen beim Einlesen der .propreties auch die Typsicherheit zu gewährleisten hat die Bibliothek TP-CORE eine erweiterte Implementierung. Trotz das die Properties als Strings eingelesen werden kann auf die Werte mittels Typisierung zugegriffen werden. Eine ausführliche Beschreibung wie die Klasse PropertyReader verwendet werden kann findet sich in der Dokumentation.

Auch im Maven Build Prozess können .property Dateien als Filter für Substitutionen genutzt werden. Selbstredend sind Properties nicht nur auf Maven und Java beschränkt. Auch in Sprachen wie Dart, nodeJS, Python und Ruby ist diese Konzept nutzbar. Um eine größtmögliche Kopatibilität der Dateien zwischen den verschiedene Sprachen zu gewährleisten, sollten exotische Optionen zur Notation vermieden werden.

XML

XML ist seit vielen Jahren auch eine weit verbreitete Option Konfigurationen in einer Anwendung veränderlich zu speichern. Gegenüber INI und Property Dateien bietet XML mehr Flexibilität in der Definition der Daten. Ein sehr wichtiger Aspekt ist die Möglichkeit fixe Strukturen über eine Grammatik zu definieren. Dies erlaubt eine Validierung auch für sehr komplexe Daten. Dank der beiden Prüfmechanismen Wohlgeformtheit und Datenvalidierung gegen eine Grammatik lassen sich mögliche Konfigurationsfehler erheblich reduzieren.

Bekannte Einsatzszenarien für XML finden sich beispielsweise in Java Enterprise Projekten (J EE) mit der web.xml oder der Spring Framework und Hibernate Konfiguration. Die Mächtigkeit von XML gestattet sogar die Nutzung als Domain Specific Language (DSL) wie es bei dem Build Werkzeug Apache Maven zum Einsatz kommt.

Dank vieler frei verfügbarer Bibliotheken existiert für nahezu jede Programmiersprache eine Implementierung um XML Dateien einzulesen und gezielt auf Daten zuzugreifen. Die bei Web Entwicklern beliebte Sprache PHP hat zum Beispiel mit der Simple XML Erweiterung einen sehr einfache und intuitive Lösung um mit XML umzugehen.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1"
         xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/assembly/ApplicationContext.xml</param-value>
    </context-param>
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>${jsf.project.stage}</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>
XML

JSON

JavaScript Object Notation oder kurz JSON ist eine vergleichsweise neue Technik, obwohl diese mittlerweile auch schon einige Jahre existiert. Auch JSON hat für nahezu jede Programmiersprache eine entsprechende Implementierung. Das häufigste Einsatzszenario für JSON ist der Datentausch in Microservices. Der Grund liegt in der Kompaktheit von JSON. Gegenüber XML ist der zu übertragene Datenstrom in Webservices wie XML RPC oder SOAP mit JSON auf Grund der Notation wesentlich geringer.

Ein signifikanter Unterschied zwischen JSON und XML besteht aber auch im Bereich der Validierung. Grundsätzlich findet sich auf der offiziellen Homepage [1] zu JSON keine Möglichkeit eine Grammatik wie in XML mit DTD oder Schema zu definieren. Auf GitHub existiert zwar ein Proposal zu einer JSON Grammatik [2] hierzu fehlen aber entsprechende Implementierungen um diese Technologie auch in Projekten einsetzen zu können.

Eine Weiterentwicklung zu JSON ist JSON5 [3] das bereits 2012 begonnen wurde und als Spezifikation in der Version 1.0.0 [4] seit dem Jahr 2018 offiziell veröffentlicht ist. Zweck dieser Entwicklung war es die Lesbarkeit von JSON für Menschen erheblich zu verbessern. Hier wurden wichtige Funktionen wie beispielsweise die Möglichkeit Kommentare zu schreiben hinzugefügt. JSON5 ist als Erweiterung vollständig zu JSON kompatibel. Um einen kurzen Eindruck zu JSON5 zu gewinnen hier ein kleines Beispiel:

{
  // comments
  unquoted: 'and you can quote me on that',
  singleQuotes: 'I can use "double quotes" here',
  lineBreaks: "Look, Mom! \
No \\n's!",
  hexadecimal: 0xdecaf,
  leadingDecimalPoint: .8675309, andTrailing: 8675309.,
  positiveSign: +1,
  trailingComma: 'in objects', andIn: ['arrays',],
  "backwardsCompatible": "with JSON",
}
JSON5

YAML

Viele moderne Anwendungen wie zum Beispiel das Open Source Metrik Werkzeug Prometheus nutzen YAML zur Konfiguration. Die sehr kompakte Notation erinnert stark an die Programmiersprache Python. Aktuell ist YAML in der Version 1.2 veröffentlicht.

Der Vorteil von YAML gegenüber anderen Spezifikationen ist die extreme Kompaktheit. Gleichzeitig besitzt die Version 1.2 eine Grammatik zu Validierung. Trotz der Kompaktheit liegt der Fokus von YAML 1.2 in einer guten Lesbarkeit für Maschinen als auch Menschen. Ob YAML diese Ziel erreicht hat überlasse ich jedem selbst zu entscheiden. Auf der offiziellen Homepage findet man alle Ressourcen die für eine Verwendung im eigenen Projekt benötigt werden. Dazu zählt auch eine Übersicht zu den vorhandenen Implementierungen. Das Design der YAML Homepage gibt auch schon eine guten Vorgeschmack auf die Übersichtlichkeit von YAML Dateien. Anbei noch ein sehr kompaktes Beispiel einer Prometheus Konfiguration in YAML:

global:
  scrape_interval:     15s
  evaluation_interval: 15s

rule_files:
  # - "first.rules"
  # - "second.rules"

#IP: 127.0.0.1
scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ['127.0.0.1:8080']

  # SPRING BOOT WEB APP
  - job_name: spring-boot-sample 
    scrape_interval: 60s
    scrape_timeout: 50s
    scheme: "http"
    metrics_path: '/actuator/prometheus' 
    static_configs:
     - targets: ['127.0.0.1:8888']
    tls_config:
     insecure_skip_verify: true
YAML

Resumee

Alle hier vorgestellten Techniken sind im paktischen Einsatz in vielen Projekten erprobt. Sicher mag es für spezielle Anwendungen wie REST Services einige Präferenzen geben. Für meinen persönlichen Geschmack bevorzuge ich für Konfigurationsdateien das XML Format. Dies ist leicht im Programm zu verarbeiten, extrem flexibel und bei geschickter Modellierung auch kompakt und hervorragend für Menschen lesbar.

Referenzen

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert