.MB: Wie am besten Konfigurationsparameter Übergeben?

Morgen Community,

Frage 1: ich beziehe mich auf Konfigurations variablen. Was ist besser zu handhaben?

Konfigurations Variablen...

  • über $_GLOBALS[]. Ich würde vermuten das die Gefahr besteht, dass PHP-Projkt Einbindung andere Superglobale überscheibt.
  • über Klassen Methoden xyz->getParameter(). Ist finde ich sinnvoller da es Klassen gibt di nweist gott wie benennen kann yxz = new Klasse(). (ich persönlich favourisiere die zweite vorgehensweise).
  • über eine INI-Datei dieman Ausliest mit parse_ini_file(). Ich hab hier in diesem Forum gelesen das diese Vorgehensweise unnötig ressourcen frist.

Frage 2: Gibtes noch andere Methoden die angeforderte Konfigurations Parameter übergeben?

Grüße MB

(Ich hab die Frage schon einmal gestellt, hab sich denke ich nicht ausreichen formuliert)

  1. Moin,

    was spricht gegen Konstanten (würde ich als nicht-Profi so machen)?

    Gruß
    Julius

    1. Moin Julius,

      was spricht gegen Konstanten (würde ich als nicht-Profi so machen)?

      Konstanten sind öffentlich. Zwar kann man da keine veränderungen vornehmen, aber wenn du schon einmal eine Konstante mit selbigen Namen wie eine andere mit unterschiedlicher Funktion hast, wirds knifflig. Mir fällt kein Beispil ein. Sry

      Grüße MB

      1. Tach!

        Konstanten sind öffentlich. Zwar kann man da keine veränderungen vornehmen, aber wenn du schon einmal eine Konstante mit selbigen Namen wie eine andere mit unterschiedlicher Funktion hast, wirds knifflig.

        Damit hat du schon deine Lösung. Alles was öffentlich (genauer gesagt global) ist, ist anfällig gegen Gleichbenamsung. Also fallen neben Konstanten auch andere globale Konstrukte weg. Das bedeutet auch, dass man die Konfigurationswerte nicht holen kann, weil man dafür einen globalen Namen kennen muss. Was bleibt übrig? Das Übergeben. Und das sollte man auch mit allen anderen Werten machen. Nicht holen (Don't look for things) sondern entgegennehmen und übergeben. Damit kann der Aufrufer steuern, was das aufgerufene Element für Werte bekommt, und das ist in einer Menge Lebenslagen sinnvoll (beispielsweise beim Test Driven Design).

        dedlfix.

        1. Hallo

          Das bedeutet […], dass man die Konfigurationswerte nicht holen kann, weil man dafür einen globalen Namen kennen muss. Was bleibt übrig? Das Übergeben. Und das sollte man auch mit allen anderen Werten machen. Nicht holen (Don't look for things) sondern entgegennehmen und übergeben.

          Eine Verständnisfrage: Wie übergebe ich einem Skript Konfigurationswerte, ohne dazu ein Skript, das selbst diese Werte irgendwoher holt (was ja vermieden werden soll), zu benutzen?

          Tschö, Auge

          --
          Wir hören immer wieder, dass Regierungscomputer gehackt wurden. Ich denke, man sollte die Sicherheit seiner Daten nicht Regierungen anvertrauen.
          Jan Koum, Mitgründer von WhatsApp, im Heise.de-Interview
          1. Tach!

            Das bedeutet […], dass man die Konfigurationswerte nicht holen kann, weil man dafür einen globalen Namen kennen muss. Was bleibt übrig? Das Übergeben. Und das sollte man auch mit allen anderen Werten machen. Nicht holen (Don't look for things) sondern entgegennehmen und übergeben.

            Eine Verständnisfrage: Wie übergebe ich einem Skript Konfigurationswerte, ohne dazu ein Skript, das selbst diese Werte irgendwoher holt (was ja vermieden werden soll), zu benutzen?

            Das "in einem Script" ist eigenartig formuliert. Man befindet sich doch bei PHP die ganze Zeit "in einem Script". Was genau ist denn dein Anliegen?

            In meiner Überlegung ging ich davon aus, dass du (zum Beispiel) eine Klasse hast, die etwas tun soll und dafür Konfigurationswerte braucht. Diese Klasse soll sie sich nicht holen, weil sie damit weniger universell wird und es auch nicht ihre Kernaufgabe ist. Die Klasse soll nur tun, was sie tun soll. Wenn sie dazu etwas braucht, ist es nicht ihre Aufgabe, das zu holen. Dafür gibt es Handlanger - sprich andere Klassen, die ihrerseits darauf spezialisiert sind, das spezielle Ding zu besorgen oder bereitzuhalten. Es gilt zu vermeiden, dass man sich eierlegende Wollmilchschwein-Klassen schreibt, die zwar alles können, dafür aber unhandlich groß geworden sind.

            Also, irgendwer muss die Werte holen (aus einer Konfigurationsdatei) oder sonstwie kennen (im Code drinstehen haben). Wenn man ein Framework schreibt, schreibt man sich meist eine oder mehrere (vom selben Interface abgeleitete) Klassen, die darauf spezialisiert sind, sich die Daten irgendwoher zu holen. So kann man auch einen anderen Provider schreiben, der die Daten anderweitig beschafft. Die Klasse, die was tun soll, bekommt dann vom Provider bereitgestellten Daten übergeben. Welcher Provider zum Einsatz kommt, bestimmt der Aufrufer. Das Test-Script nimmt den Testdatenprovider und das Produktivscript den mit den Produktivdaten.

            dedlfix.

            1. nabend Dedlfix,

              schön erklär :-). hab ich alles irgendwo schonmal gehört und wahrscheinlich auch ansatzweise gemacht. Nur mir sind die begrifflichkeiten nicht geläufig. Am besten verstehe ich über den konkreten ansatz. Meine Lösung, wie ich (glaube ich) schon mal gepostet habe:

              Config.cfg.php

              class Config {
                
                $farbe = 'rot';
              
                function getAttribut() {
                  return $this->farbe;
                }
              }
              

              Auto.class.php

              class Auto {
              
                $farbe;
              
                function __construct( $farbe ) {
                  $this->farbe = $farbe;
                }
              }
              

              index.php

              include( 'Config.cfg.php' );
              include( 'Auto.class.php' );
              
              $cfg = new Config();
              $auto = new Auto( $cfg->farbe );
              

              So hab ich das gelöst. Abe ich weis beim besten Willen nicht wie du was bezeichnest. Kläre mich auf. Denn genau darauf ziel meine Frage ab.

              Liebe Grüße MB

              1. Tach!

                Meine Lösung, wie ich (glaube ich) schon mal gepostet habe:

                Sieht ungefähr so aus, wie ich das beschrieben habe, nur dass man beim Programmieren sehr selten was mit Autos macht. Aber wenn du das Auto durch beispielsweise eine Datenbank-Klasse ersetzt und statt "rot" die Zugangsdaten nimmst, kommen wir schon in realistischere Programmierergefilde.

                Config ist eine Klasse, die Konfigurationsdaten bereitstellt, also ein Konfigurationsdatenprovider.

                dedlfix.

                1. jo, sehr gut! Das mit den autos habe ich nur kurz und knapp nebenbei runter programmiert mit überhaupt keiner aussage, absicht und Inhalt nur das Prinzipt.

                  Grüße und schönen Abend MB

                  PS: Ich hab die Konfigurationsdateien schematisch blabla.cfg.php und blubblub.class.php benannt. Man achte hier auf den vom ersten Punkt getrennten Namen.

              2. Moin!

                Meine Lösung, wie ich (glaube ich) schon mal gepostet habe:

                Config.cfg.php

                class Config {
                  
                  $farbe = 'rot';
                
                  function getAttribut() {
                    return $this->farbe;
                  }
                }
                

                Auto.class.php

                class Auto {
                
                  $farbe;
                
                  function __construct( $farbe ) {
                    $this->farbe = $farbe;
                  }
                }
                

                index.php

                include( 'Config.cfg.php' );
                include( 'Auto.class.php' );
                
                $cfg = new Config();
                $auto = new Auto( $cfg->farbe );
                

                Das ist Dependency Injection, und genau so sollte man es machen.

                Was man nicht machen sollte:

                • Keine globalen Variablen, keine globalen Konstanten (Klassenkonstanten lassen sich ja zum Glück nicht dynamisch definieren, außer man schreibt dynamischen Code und ruft eval() auf - igittiwürg), keine global existierenden Konfigurationsobjekte, die in die Klassen getan werden. Insbesondere kein Config-Singleton. Alle diese Varianten bedeuten, dass der Konsument der Konfigurationswerte wissen muss, wie dieser Wert heißt, bzw. wo dieser gefunden werden kann. Es bedeuten gleichzeitig, dass bei Wiederverwendung des Codes der Wert im neuen Projekt an die gleiche Stelle getan werden muss.
                • Keine Setter für Konfigurationswerte. Einen Setter muss man nicht zwingend aufrufen, zumindest nach der Codelogik nicht, man kann ihn aufrufen. Vor allem kann man ihn mehrfach aufrufen. Im Setter und im Nutzcode der Klasse müsste deshalb erstens Code sein, der meckert, wenn der Setter noch nicht aufgerufen wurde, der Wert aber gebraucht wird. Zweitens verhindert, dass ein zweiter Aufruf erfolgen kann. Diese beiden Probleme verschwinden sofort, wenn man den Parameter als Argument im Konstruktor platziert. Der Konstruktor kann nur einmal pro Instanz aufgerufen werden, und sofern kein Default-Wert angegeben ist, ist auch klar ersichtlich: Diese Klasse braucht ZWINGEND diese Parameter.
                • Ein wichtiges Argument gegen Setter (mindestens für Konfiguration) ist: Konfiguration ist "state". Eine Klasse kann als identische Instanz an mehreren Stellen referenziert werden, und mit Settern würde die Möglichkeit bestehen, diesen Zustand der gemeinsamen Instanz zu ändern, ohne dass man das mitkriegt. Nur mal kurz nachdenken: Eine DB-Instanz bekommt Servernamen und Zugangsdaten per Setter übergeben und wird als dieselbe Instanz in zwei Klassen verwendet. Eine Klasse setzt initial ihren Test-Server und dessen Zugangsdaten, die andere erwartet eine fertig konfigurierte DB-Instanz. Solange die vorkonfigurierte DB-Instanz auch den Testserver benutzt, ist alles prima. Und dann wird auf den Produktivbetrieb umgestellt, und Produktivdaten gehen auf dem Testserver verloren, bzw. Testdaten werden in Produktion sichtbar... Und die Entwickler können in der Testumgebung nichts verdächtiges finden.

                Grüße Sven

  2. hi,

    (Ich hab die Frage schon einmal gestellt, hab sich denke ich nicht ausreichen formuliert)

    Wer soll denn hier was an wen übergeben? Ist Deine Konfiguration mittlerweile im Hauptspeicher angekommen oder bist du noch bei der Dateifrage?

    Sag mal.

    1. Hi pl,

      Das projekt is schon erledigt.

      Ich solle ne DB Verbindung aufbauen, drauf zugreifen oder auslesen als Beispiel. ersteinmal ist noch garnix da. ich konzipieren nur auf Anforderung. nix programmieren.

      Grüße MB

      1. Wie ich gestern bereits gepostet habe, hat das Responseobjekt Vollzugriff auf die gesamte Konfiguration. Das ist wichtig, damit Attribute auch persistent geändert werden können (Content Management).

        Nun kommt wieder OOP ins Spiel und so haben wir: Sämtliche Konfigurationsdaten stecken in einer Instanz der Klasse Config (soweit bist Du ja auch schon). Ergo müssen wir über die Config-Instanz nur die Methode write() aufrufen und wohin die dann die Daten schreibt ist in der Methode slebst definiert.

        Verbindung zischen nicht verwandten Klassen kannst Du infolge Aggegation+Delegation herstellen (Dependency Injection). Wir haben:

        1. das Response Object als instanz der Klasse, welche die Response erzeugt
        2. das Config Object

        So injezieren wir das Config Objekt in die Unter (1) genannte Instanz als Attribut. Was zur Folge hat, oh wie schön, wir könmnen write() als eigene Methode der unter (1) erzeugten Instanz aufrufen.

        Moment mal, es gibt noch mehr zu schrieben, 3. Kommt hinzu, die Sessiondaten. Kein Problem wir machen das wie bei 1. u. 2. nur nennen wir die Methoten um damit wir die nicht verwechslen:

        1. write_config()
        2. write_session()

        Und wenn wir das so gemacht heben, sehen wir, wie kluch das alles ist, weil wir nur noch in den Destructor der Responseklasse greifen müssen um solche einfachen Sachen zu regeln.

        Die von mir vor einiger Zeit erwähnte Factory ist eine Rafinesse der hier vermittelten Grundlagen.

        1. Wie ich gestern bereits gepostet habe, hat das Responseobjekt Vollzugriff auf die gesamte Konfiguration. Das ist wichtig, damit Attribute auch persistent geändert werden können (Content Management).

          Nun kommt wieder OOP ins Spiel und so haben wir: Sämtliche Konfigurationsdaten stecken in einer Instanz der Klasse Config (soweit bist Du ja auch schon).

          Du musst hier aufpassen, dass diese Daten keine Klassenvariablen sind sondern tatsächlich nur in der Instanz vorliegen. Sonst kann es passieren, dass eine Instanz auf Daten zugreift, die während der Laufzeit von einer anderen Instanz geändert worden sind. Und genau dasselbe Problem hättest Du auchmit Globalen Variablen.

          1. Moin!

            Wie ich gestern bereits gepostet habe, hat das Responseobjekt Vollzugriff auf die gesamte Konfiguration. Das ist wichtig, damit Attribute auch persistent geändert werden können (Content Management).

            Nun kommt wieder OOP ins Spiel und so haben wir: Sämtliche Konfigurationsdaten stecken in einer Instanz der Klasse Config (soweit bist Du ja auch schon).

            Du musst hier aufpassen, dass diese Daten keine Klassenvariablen sind sondern tatsächlich nur in der Instanz vorliegen. Sonst kann es passieren, dass eine Instanz auf Daten zugreift, die während der Laufzeit von einer anderen Instanz geändert worden sind. Und genau dasselbe Problem hättest Du auchmit Globalen Variablen.

            Es gibt eine Lösung für das Problem: Immutabilität. Einfach keine Schreibzugriffe auf die Klasse programmieren, und schon können die innenliegenden Werte nicht mehr geändert werden.

            Grüße Sven

          2. Wie ich gestern bereits gepostet habe, hat das Responseobjekt Vollzugriff auf die gesamte Konfiguration. Das ist wichtig, damit Attribute auch persistent geändert werden können (Content Management).

            Nun kommt wieder OOP ins Spiel und so haben wir: Sämtliche Konfigurationsdaten stecken in einer Instanz der Klasse Config (soweit bist Du ja auch schon).

            Du musst hier aufpassen, dass diese Daten keine Klassenvariablen sind sondern tatsächlich nur in der Instanz vorliegen. Sonst kann es passieren, dass eine Instanz auf Daten zugreift, die während der Laufzeit von einer anderen Instanz geändert worden sind. Und genau dasselbe Problem hättest Du auchmit Globalen Variablen.

            Ein schönes praktisches Beispiel: Der Benutzer submittet ein Formular und löst damit einen Zustandsübergang aus. Die Instanz welche fürs Ausliefern der Response zuständig ist, liest aus der Config, welches Template für die Response zu laden ist. Eine andere Instanz hat jedoch zur Laufzeit den Dateinamen geändert. So wird für die Response das falsche Template geladen.

            Sowas kommt sicher selten vor, aber das Beispiel dient ja nur dem Verständnis. Ich habe jedoch oft genug erlebt, was passiert wenn sich mehrere Instanzen diegleiche DB-Connection teilen: Verlorene Warenkörbe und verärgerte Kunden.

        2. ff,

          Die von mir vor einiger Zeit erwähnte Factory ist eine Rafinesse der hier vermittelten Grundlagen.

          die Factory-Methode beschreibt eine Herangehensweise, die mehrere Ziele verfolgt:

          1. Auslagern von Code aus dem direkten(initial) Compile-Process, solcher Code wird erst auf Anforderung zur Laufzeit compiliert. Das wirkt sich positiv auf die Performance aus.
          2. Optimierung von Debug-Anforderungen/Qualitätssicherung
          3. Verbesserung der Wartungsfreundlichkeit
          4. Optimierung von Teamarbeit infolge Teilung
          5. Verkürzung der Entwicklerzeiten, Kostensenkung

          Wie wir sehen, sind das Ziele die sowohl technische als auch ökonomische Aspekte haben. Konkret können Letztere, um mal eine Zahl zu nennen, in einem Unternehmen Einhunderttausend € p.a. Kostensenkung bringen. Es liegt dann nur im Ermessen der Geschäftsleitung ob infolge solcher Kalkulationen Programmierer entlassen oder mehr Aufträge angenommen werden.

          1. ff,

            Die von mir vor einiger Zeit erwähnte Factory ist eine Rafinesse der hier vermittelten Grundlagen.

            die Factory-Methode beschreibt eine Herangehensweise, die mehrere Ziele verfolgt:

            1. Auslagern von Code aus dem direkten(initial) Compile-Process, solcher Code wird erst auf Anforderung zur Laufzeit compiliert. Das wirkt sich positiv auf die Performance aus.

            Als Beispiel nehmen wir die Methode write_config(). Denn die brauchen wir nur fürs Backend. Im Regelbetrieb jedoch wird die Config nur gelesen, da müssen wir die Methode zum Schreiben nicht jedesmal mit compilieren.

            Ja nach Data Access Layer gibt es weitere Dinge zu beachten wie z.B. ein LOCK_EX wenn das eine Datei ist. Bei vielen Zugriffen auf eine Seite bremsen die sich gegenseitig aus, wenn die Configdatei jedesmal exclusive gelockt wird.

        3. Moin!

          Wie ich gestern bereits gepostet habe, hat das Responseobjekt Vollzugriff auf die gesamte Konfiguration. Das ist wichtig, damit Attribute auch persistent geändert werden können (Content Management).

          Lieber nicht! Geht in einem 300-Zeilen-Miniskript vielleicht noch einigermaßen, aber der Response hat absolut nichts mit Konfiguration oder Persistierung zu tun.

          PHP: PSR-7: HTTP Message Interfaces

          Damit eng zusammenhängend das Konzept der Middleware, siehe z.B. M.W. O'Phinney: On HTTP, Middleware, and PSR-7

          Zitat:

          The basic concept of middleware can be summed up in a single method signature:
          function (request, response) { }

          Wenn aber das Responseobjekt als Parameter in die Transformationsfunktion zusammen mit dem Request hineingeht, muss es eine Schicht außerhalb geben, die sowohl diese beiden Objekte instanziiert, als auch diese Funktion hostet und aufruft.

          Nun kommt wieder OOP ins Spiel und so haben wir: Sämtliche Konfigurationsdaten stecken in einer Instanz der Klasse Config (soweit bist Du ja auch schon). Ergo müssen wir über die Config-Instanz nur die Methode write() aufrufen und wohin die dann die Daten schreibt ist in der Methode slebst definiert.

          Konfiguration wird in meiner Welt vom Admin einmalig festgelegt und gilt dann für die Lebensdauer der Applikation, bzw. bis es einen Änderungsbedarf gibt. Da die Konfiguration auf eine Serverfarm ausgerollt werden können sollte, wäre es unpraktisch, wenn man sie lokal auf einem Server geändert wegschreiben würde.

          Sprich: Das Ändern der Konfiguration ist zwar grundsätzlich ein Usecase, aber dieser ist zum einen viel seltener, und erfordert zum anderen keine schreibfähige Konfigurationsleseklasse, sondern eine schreibfähige Konfigurationsverteilungsklasse.

          Config lesen $config = include('config.php');
          Config schreiben file_put_contents('<?php return '.var_export($config, true)', 'config.php');
          ist kein Akt, aber man sollte sich über die verwendeten Datenstrukturen im Klaren sein und dies in irgendeiner Weise auch verifizieren. Deshalb sollten diese Zeilen keine fertige Konfiguration ergeben, sondern intern von der Konfigurationsklasse genutzt werden.

          Aber wie gesagt: Konfiguration lesen ist der Standard-Usecase, und ich würde einer schreibbaren Konfigurationsklasse sehr kritisch gegenüber stehen. Damit erzeugt man sich im Zweifel nur Zustandsprobleme.

          Moment mal, es gibt noch mehr zu schrieben, 3. Kommt hinzu, die Sessiondaten. Kein Problem wir machen das wie bei 1. u. 2. nur nennen wir die Methoten um damit wir die nicht verwechslen:

          1. write_config()
          2. write_session()

          Session-Daten schreiben hat NICHTS mit dem Response zu tun. Das ist Applikationslogik und gehört in die Persistenzschicht.

          Und wenn wir das so gemacht heben, sehen wir, wie kluch das alles ist, weil wir nur noch in den Destructor der Responseklasse greifen müssen um solche einfachen Sachen zu regeln.

          Das Ende des Responses bedeutet nicht zwingend das Ende der Codeausführung, und insbesondere nicht das Ende der Konfiguration. Man denke nur an asynchron aufgerufene Hintergrundtätigkeiten: Mailen, Garbage Collection, DB-Zeugs, Bildbearbeitung etc. - sowas tut man natürlich lieber in eine Queue und arbeitet unabhängig vom Webserver, aber auch dieser Code braucht ja Konfiguration, mithin ist diese im Responseobjekt eher falsch, weil es gar keinen Response gibt in diesen Fällen.

          Grüße Sven

          1. Session-Daten schreiben hat NICHTS mit dem Response zu tun. Das ist Applikationslogik und gehört in die Persistenzschicht.

            Ja sicher muss das getrennt werden. Beispielsweise über einen Data Acccess Layer wie ich bereits schrieb. Die Factory-Methode ist lediglich eine besondere Vorgehensweise die beschreibt, wo nämlich genau diese Layer eingebunden werden. In Perl nutze ich für sowas den AutoLoader und die Methoden, in dedizierten Dateien definiert, sind so aufgebaut, dass sie von einer beliebigen Instanz, also auch von einem sog. Mock (Attrappe) aufgerufen werden können.

            Welche weiteren Klassen in solchen ausgelagerten Methoden eingebunden werden und wo die dann die Daten physikalisch hinschreiben, ist der main völlig egal.

        4. Die von mir vor einiger Zeit erwähnte Factory ist eine Rafinesse der hier vermittelten Grundlagen.

          Eine auf dem Server gut aufgesetzte Factory kann über Remote Procedure Call auf die Kommandozeile eines lokalen PC verlängert werden:

          D:\>.pl RPC
          Remote CMD auf dem Host
          --attribute, -a: Zeigt Attribut+Value einer Entity in Konfiguration
          --base, -ba: Name der Datenbank für Option --sql
          --binary, -bi: Erzeuge die Konfiguration als Binary
          --cmd, -c: Freies Kommando im aktuellen Verzeichnis
          --dump, -d: Dump Response Object
          --entity, -e: Zeigt Attribute einer Entity in Konfiguration
          --files, -f: Lokale Dateien für Upload
          --head, -he: HEAD Request auf URL
          --host, -ho: rolfrost.de oder rolfrost
          --request, -r: HTTP Request auf den angegebenen URL oder auf alle URLs
          --sql, -s: SQL Anweisung oder aus Datei, erfordert --base
          --urls, -u: Listet URLs in Konfiguration
          

          Und gerade hier zeigt sich wieder der Vorteil, wenn die serverseitige Framework-Instanz auf die gesamte Configuration zugreifen kann. In meinem Fall kann die sogar SQL-Dumps einspielen. Praktisch wird die übergebene Methode über eine Instanz der an den RPC-URL gebundenen Subklasse aufgerufen.

          Ein universeller Parser, ebenfalls über die FW-Instanz aufgerufen, kann nicht nur die üblichen Enctypes parsen sondern auch XML, CSV u.a. beliebige Content-Types. RPC vollintegriert ins Framework. Diese Fusion ist echt der Hammer, umsetzen kann das wohl jeder aber die Idee muss erstmal ausgeheckt sein.

    • über eine INI-Datei dieman Ausliest mit parse_ini_file(). Ich hab hier in diesem Forum gelesen das diese Vorgehensweise unnötig ressourcen frist.

    Eine Konfiguration die als ini-Datei bearbeitet wird, muss ja nicht als ini-Datei aufgestellt sein. Es gibt nämlich 2 Aspekte zur Auswahl:

    1. Performance beim maschinellen Lesen
    2. Benutzerfreundlichkeit beim Editieren

    Was nicht heißt, dass im Deployment beide Aspekte in einer Datei verwirklicht sind. Beispielsweise dient eine ini-Datei nur dem lokalen Bearbeiter, nach dem Hochladen auf den Server jedoch wird die ini-Datei in ein anderes Dateiformat gebracht oder der ganze Hash wird in eine MySQL Tabelle eingetragen.

    Diese beiden o.g. Aspekte machen mal wieder mehr als einmal deutlich, wie wichtig es ist, sich mit bestimmten Schichtenmodellen auseinanderzusetzen. Theorie und Praxis halt.