Hey dedlfix,
ich kann mich wieder einmal nur herzlich für Deine aufschlussreiche Antwort bedanken!
Eine zum jetzigen, frühen Zeitpunkt durchdachte Wahl erspart später sicherlich viel Arbeit.
Durchdacht für welche konkreten Einsatzzwecke?
Da hab ich mich wieder sehr schwammig ausgedrückt. Das Framework sollte natürlich insgesamt durchdacht sein. An dieser Stelle soll es jedoch erstmal darum gehen, welcher Stil allgemein verwendet werden soll - natürlich nur, wenn es sinnvoll ist.
Als Beispiel: Ein Konfigurationsobjekt ist vergleichbar mit einer Registry. Damit nachher auch "vernünftig" damit gearbeitet werden kann, sollen jetzt zum Beispiel Config und Registry auf gleichem Wege zugänglich sein. Also beispielsweise über eine Factory-Method und nicht eins über Factory und das andere über DI und noch ein anderes kann vielleicht nur über die Unterklasse angesprochen werden.
Das meinten wir hier mit "Konsistenz".
Die Aufgabenstellung ist ja recht allgemein formuliert,
Ja, leider.
also kann man auch nur eine allgemeine Regel wie zum Beispiel die 80/20 heranziehen.
Das ist schon mal super. So haben wir jetzt mal eine "ungefähre Hausnummer".
[...] Besser ist, 80% abzudecken und für den Rest erweiterbar bleiben - also Plugins vorsehen, "final" und andere abschließenden Dinge sehr gut bedenken. [...]
Das ist tatsächlich ein Problem. Einer bei uns im Team verwendet fast nur "private" und "final", ein anderer ausschließlich "public". Ich persönlich verwende oft "protected". Gut, dass Du das ansprichst: Da müssen wir mal klare Regeln finden.
[dedlfix' Beschreibung möglicher Datenhaltung und Verschachtelungen in Konfigurations-Objekten, siehe vorheriges Posting]
Darüber haben wir uns auch schon Gedanken gemacht und versuchen, das auch umzusetzen. Bei der Ini-Variante werden wir wohl das von Dir beschriebene Verfahren mit dem Punkt als Trennzeichen für Verschachtelungen verwenden.
- Einzelne Klasse [...]
Quick and dirty. Lässt sich eigentlich nur über Code-Hinzufügen erweitern. Erben und neue Quellen-Methode hinzufügen geht auch, aber dazu muss der Aufruf der Quellen-Methode per Hand erfolgen oder deren Name konfigurierbar sein. Sicherlich effektiv, aber künstlerisch nicht besonders wertvoll.
Das kam auch bei unseren Gesprächen heraus. Danke für die Bestätigung!
Scheitert, wenn der Original-Code wegen OpCode-Compilern [...] nicht geändert werden kann.
Das verstehe ich leider nicht. Wie meinst Du das mit den OpCode-Compilern? In welcher Form spielen die eine Rolle für die Erweiterung des Original-Codes?
- Vererbung [...]
Schon besser im Hinblick auf Erweiterbarkeit und Trennung nach einzelnen Speicherarten. Welche der Unterklassen verwendet werden soll, muss fest im Code stehen oder durch Instantiierung über Stringvariable statt Klassennamen erfolgen (falls man konfigurieren können muss, welche Konfigurationsklasse verwendet werden soll).
Das sollte man auf jeden Fall können. Also wohl auch nicht gerade die beste Wahl, was die Erweiterbarkeit angeht.
Für die Instantiierung über Stringvariable scheint sich kein Begriff etabliert zu haben, wie bei variable Variablen. Variable Klassen könnte man das nennen.
Jetzt hat sich, zumindest bei uns, der Begriff "Variable Klasse" etabliert. Super!
- "Helper"-Klasse [...]
Sieht fast nach DI aus. Nur dass du wohl daran denkst, dem Konstruktor einen Wert zu übergeben, über den man die Quellen-Klasse instantiieren kann, statt eines Objekts einer Quellenklasse selbst.
Genau das war die Idee, auch wenn ich mich wieder etwas schwierig ausgedrückt habe.
Wenn nicht mit variablen Klassen gearbeitet werden soll, ist man hier auch auf einen vordefinierten Vorrat beschränkt.
Stimmt, die vorgegebenen Möglichkeiten sind wohl auch hier das Problem. "Variable Klassen" sollten nicht verwendet werden.
- Factory Method [...]
Das ist eher eine Ergänzung zu 2 oder 3. ie Factory legt fest, was verwendet wird. Ob das nun eine Helper- oder eine geerbte Klasse ist, ist dabei nebensächlich. Jedenfalls ist das nicht wirklich testbar - falls das notwendig sein sollte.
Das mit der Testbarkeit ist ein guter Punkt! Den haben wir im Moment etwas aus den Augen verloren, wäre aber sehr wichtig. Warum erschwert eine Factory das Testen?
- Dependency Injection [...]
Nach meinem Wissen über DI bekommt der Konstruktor bereits eine Instanz der Helperklasse übergeben. Config kann diese dann "melken". Zur Not kann es einen Default-Fall geben, wenn kein Helper-Objekt übergeben wird, erstellt sich der Config-Konstruktor eins selbst. Der Name der physikalischen Konfig-Datenhaltung müsste dann über eine Konvention ermittelt werden.
Also haben wir uns, wie zuvor beschrieben, sozusagen eine "Anti-DI" ausgedacht?
Anti-DI: Oberklasse übergibt sich selbst an Helferklasse
DI: Oberklasse erhält Helferklasse
Dann würde DI ja richtig Sinn machen :-) und erscheint mir vorerst als "beste Wahl" für solche Anwendungszwecke.
So wie du das beschreibst, ist (mir) das zu sehr ineinander verzahnt.
Mir auch... Deshalb ja die Frage.
Dein Konstruktor sieht wie eine Factory aus. Und statt dass Config einfach die Quellen-Objekt-Methoden verwendet, um sich zu füllen, muss sich Config dem von ihm selbst erstellten Quellen-Objekt regelrecht aufdrängen, auf dass es es befülle. Damit machst du nur das Testen von Config- und Quellen-Klassen schwer, weil stets ein (Mock-)Objekt der jeweils anderen Klasse benötigt wird.
Du bringst es auf den Punkt, worüber wir uns schon Stunden unterhalten haben.
Muss das ganze TDD-fähig sein? [...]
Ich wusste bis gerade nicht, was TDD bedeutet (für alle Unwissenden wie mich: Testgetriebene Entwicklung). Ja, so wollen wir es machen! Und jetzt haben wir auch endlich einen Namen dafür :-)
Das sind verschiedene Möglichkeiten, die wir uns überlegt haben, an die Sache ranzugehen. Alle haben sicherlich Vor- und Nachteile und es gibt sicher auch noch andere Möglichkeiten. Wir sind etwas verwirrt!
Wenn du noch mehr Möglichkeiten kennenlernst, wird das Bild nicht unbedingt klarer.
Das nicht. Aber vielleicht ist ja die ultimative Umsetzung dabei ;-)
Also nun meine Frage an Euch: Welche Möglichkeiten haltet Ihr noch für denkbar?
Mit parse_ini_file() und SimpleXML kommt man auch an Konfigurationsdaten ran, aber so einfach und unflexibel willst du es ja nicht haben :-)
Wenn ich das so abgebe, bekomm ich bestimmt einen "auf den Sack" :-)
Komplexer und komplizierter geht immer. Zum Beispiel könnte man statt eines (verschachtelten) Arrays in der Config-Klasse weiteren Klassen vorsehen, die im einfachsten Fall einen Wert aber auch andere individuelle Strukturen enthalten können.
Wenn ich Dich richtig verstehe, versuchen wir das bereits. Ich hab mal eine Zip-Datei mit einer anfänglichen und unfertigen (was für ein tolles Wort...) Version einer möglichen Config-Implementierung hochgeladen. Wenn Du Lust hast, kannst Du es Dir ja mal ansehen (Vorschläge natürlich sehr erwünscht): http://fsac.de/dat/selfhtml/library.zip
Was würdet Ihr ganz persönlich bevorzugen, wenn Ihr mit einem Framework arbeitet?
Zu allgemein gefragt kann ich da nur zu allgemein antworten. Meine aktuellen Bedürfnisse muss es erfüllen können, notfalls durch individuelle Erweiterbarkeit.
Ok, war ne doofe Frage.
Wir freuen uns über alle Meinungen, Anmerkungen, Vorschläge oder was-auch-immer, was uns bei unserer Entscheidungsfindung behilflich sein könnte.
Schamlos bei anderen abschauen, wie die es gelöst haben, ausprobieren, Erfahrungen sammeln, aus deren Fehlern lernen, was bei anderen zu komplex geraten ist, auf einfache(re) Weise nachbauen, dann selbst um so viel benötigte Funktionalität erweitern, biss es mindestens genauso komplex und unüberschaubar geworden ist, ...
So wird's wahrscheinlich laufen...
Ps: Sorry, dass das wieder so ein langer Text geworden ist.
Nö, ich kann auch "lang".
Dann bin ich beruhigt :-)
Gruß und nochmal danke,
Dennis