Config Datei sauber implementieren



  • Hallo zusammen,

    ich habe in bei meinem Projekt eine externe Datei für Einstellungen. Also besser gesagt eine config.cfg^^. Ich überlege gerade, wie ich das ganze jetzt sauber in mein Projekt einbinde. Es werden dadurch Variablen in unterschiedlichen .cpp Dateien beeinflusst. Nun wäre es aber Blödsinn diese jedes mal neu einzulesen für jede .cpp. Ebenfalls unsinnig wäre es das Objekt indem die ganzen Einstellungen landen (bei mir ein JSON) durch alle Funktionen oder Klassen via Übergabeparameter durchzuschleifen. Globale Variablen soll man aber ja eher vermeiden. Wie könnte also eine saubere Lösung für das Problem aussehen?



  • Wir haben einen Config Cache, ein Singleton.
    Ich hab noch nie drüber nachgedacht, ob das jetzt 100% sauber ist, unsere Software ist sehr groß und über 30 Jahre gewachsen. Jedenfalls funktionerts "ganz gut".



  • Naja, einen Tod muss man sterben.
    Vielleicht lohnt es sich, nicht alle Einstellungen in ein Config Objekt zu packen, sondern mehrere zu verwenden. Dann sind die jeweils gekapselt und jede Klasse / Funktion bekommt nur die Einstellungen die sie benötigt. Das kann auch das Erstellen von Unit Tests vereinfachen.
    Ansonsten gibt es auch schon mal Gründe für ein Singleton. Bin ich persönlich nicht der größte Freund von, aber das muss ja nichts heißen (in dem Projekt an dem ich grade arbeite gibt es auch ein Singleton für bestimmte Einstellungen...)



  • @zhavok sagte in Config Datei sauber implementieren:

    Ebenfalls unsinnig wäre es das Objekt indem die ganzen Einstellungen landen (bei mir ein JSON) durch alle Funktionen oder Klassen via Übergabeparameter durchzuschleifen.

    Wieso wäre das blödsinnig? Also das JSON überall rumzureichen: ja. Aber die geparste Version davon...? Bzw. noch besser: Klassen bekommen das was sie brauchen/was sie etwas angeht übergeben, z.B. einfach als Konstruktorparameter. Damit das ganze nicht unübersichtlich wird in ein "settings" oder "config" struct eingewickelt.

    Dabei muss man dann an einigen Stellen Werte von struct A nach struct B "umschaufeln". Ich finde das aber nicht gerade unsinnig oder gar schlecht. Bzw. es hat sogar einen klaren Vorteil, nämlich dass keine Zentrale Stelle entsteht auf die irgendwie alles in der Applikation ne Dependency hat. Gerade bei grossen Projekten ist das wichtig.



  • Bzw., ausgehend von den anderen Antworten, bin ich von was anderem ausgegangen.
    Wir haben tatsächlich einen Cache für Config-Dateien. Weil das bei uns historische Hintergründe hat und mit dem restlichen Aufbau zusammenpasst.

    Und ich dachte, dir gehts auch um was ähnliches. Aber das ist grundsätzlich eigentlich keine gute Lösung. Ich könnte mir eher vorstellen

    • Dependency Injection. Wenn ich neue Komponenten schreibe, die keine komischen globalen Abhängigkeiten haben, dann kriegen sie alles was sie brauchen über den Konstruktor übergeben.
    • Wenn man sowieso ein "GUI" Framework drumherum hat, z.B. Qt, hat man meist eine Möglichkeit, an ein globales Application Objekt zu kommen. Und an dem könnte etwas für ein Einstellungen dranhängen. Das wäre z.B. sinnvoll, wenn sich die Einstellungen zur Laufzeit ändern können.


  • So ähnlich funktioniert es auch schon @hustbaer . Zwar nicht als struct, aber ich kann bei dem JSON Object auch direkt den Parameter weitergeben, den ich möchte. Also zum Beispiel:

    doSomething(config["Port"]) {
    }
    

    Das würde funktionieren und er unterscheidet auch, ob das Element ein String, Integer oder sonst etwas ist.

    @Mechanics Nein. Ein GUI Framework habe ich nicht drum herum^^. Du gibst es also auch einfach Stück für Stück weiter.



    • Das als struct weiterzugeben, wäre aber besser. Den String "Port" muss man kennen, der kann sich ändern., usw. -> schlecht wartbar.
    • Wir haben bei uns mindestens alle drei Varianten, die ich genannt habe. Für möglichst neue und möglichst unabhängige Komponenten bevorzuge ich aber das Übergeben über den Konstruktor. Evtl. aber auch über zusätzliche Setter, weil grad wenn man eine Option über mehrere andere Komponenten durchreichen will, ist die für eine der Zwichenkomponenten vielleicht nicht so zentral, dass ich die im Konstruktor haben will. Und ja, das kann unschön werden, wenn man eine Option über viele Schichten durchreichen will.
    • Wenn du kein GUI Framework hast, kannst du immer noch einen Singleton "Application" oder ähnliches erstellen. Grundsätzlich sind Singletons keine tolle Idee, aber eine Application wäre tatsächlich ein Singleton. Und sowas wie Einstellungen kann man als Unterobjekt von Application sehen. Das wäre jetzt im Normalfall aber nicht meine favorisierte Lösung.
      Was bei uns früher ständig passiert ist... Man legt eine Komponente an, die liest ihre Einstellungen selber aus einer Config Datei, vielleicht gibts auch GUI Einstellungen dafür, oder es wird zumindest dokumentiert, wie das zu konfigurieren ist... Und dann kommt paar Monate/Jahre später ein anderer und sagt, aber ich brauch die Komponente jetzt in einem anderen Kontext. Und da ist die globale Config natürlich sehr kontraproduktiv.


  • p.s. Auch wegen der Wiederverwendbarkeit ist es nicht gut, Json Objekte zu übergeben. Wenn du ein klares Config Objekt hast, z.B. MyComponentConfig mit einer port Eigenschaft, kann das jeder anlegen und befüllen. Wenn du ein Json Objekt hast, muss der nächste, der die Komponente verwenden will, aber nicht deine globale Config will, erstmal schauen, wie er ein gültiges Json Config Objekt zusammenbaut.



  • Da hast du natürlich vollkommen Recht. Ich werde das Ganze gleich morgen anpassen. Vielen Dank für eure Antworten 👍🏻


Log in to reply