NEWS
Test: Objektvorlagen und Hilfsfunktionen für Objektbäume
-
Ich bin mir gerade nicht sicher ob ein eigenes Objekt pro State zu haben wirklich Dinge so arg vereinfacht ... aber ja wäre so möglich.
Die andere Variante (also States mit ". getrennten Pfaden) frei zu nutzen wäre dennoch weiter sinnvoll, weil sonst eine pot. Migration von Bestandsadaptern um einiges aufwändiger
-
Schön, dass sich hier nun eine Diskussion entwickelt
@UncleSam: Zum Thema "Klassen" sollte besser @AlCalzone was sagen, ich persönlich liebe Klassen
Während ich über den Text hier überlege, fällt mir aber doch noch was ein: Ich mache ja auch etwas C# beruflich. Grad bei Klassen und dahinterliegenden "Datenbanken" denkt man ja eher an eine direkte Schnittstelle zur DB, so wie Du vermutlich bei deiner Idee.
Die Idee mit dem dynamischen Objektbaum in der Klasse finde ich etwas zu komplex. Klassen sind halt in der Regel recht fix definiert, z.B. Klasse "Mitarbeiter", "Aufträge" oder so. Dann müsste ich als Entwickler immer überlegen und selbst den Baum vor Augen haben.
Mit dem bisherigen Vorschlag schreibe ich meine Objekte und beim Speichern bekomme ich ggf. einen Fehler wenn z.B. ein Folder fehlt. Finde das auch einfacher.
Also obwohl ich Klassen ja sehr mag, ist es meines Erachtens für die Entwickler einfacher und übersichtlicher hierfür keine Klasse zu verwenden. Sonst würde wir ja über die Klasse quasi einen komplett getrennten, dafür mehr objektorientierten Zugang zu den Objekten und States aus ioBroker aufbauen. Das wäre ja dann auch keine "einfache Hilfsfunktion für Objektbäume" mehr, sondern eine fast vollständige objektorientierte Schnittstelle zu den Objekten und States, analog wie man es z.B. in anderen Programmiersprachen mit Datenbanken und Klassen realisiert.
Die Idee vereinfachte Funktionsaufrufe verfügbar zu machen finde ich überlegenswert. Vorteil wäre, man sieht schneller im Code was man da grad macht. Der Aufruf hierfür wäre z.B. für Channel oder Folder auch simpler. Auf der anderen Seite hast dann ggf. viele Aufrufe mit unterschiedlichen Parametern, dass macht es nicht einfacher bzgl. Lernkurve.
Was mir bei deinem Ansatz aber grundsätzlich sehr gefällt ist die bessere Lesbarkeit. Bin da grad so hin und her gerissen ehrlich gesagt.
Aktuell musst eine Funktion anschauen und deren Parameter. Damit kannst es befüllen. Dann noch eine weitere Funktion zum Speichern. Fertig. Auch wenn wir öfters "this" übergeben und es sich nicht schon durch den Namen der Funktion erklärt was dort passiert.
Ich habe immer noch die Warnung von @apollon77 bei der ursprünglichen Diskussion in Discord als stetige Mahnung im Kopf: Nicht zu kompliziert, keine "Eierlegende Wollmilchsau", daran sind schon andere gescheitert
Daher sehe ich es auch bei der "onChange"-Sache wie @AlCalzone : Der Helper soll es für einfache Dinge noch einfacher machen, der Hintergrund waren ja auch z.B. einfache API-Adapter. Die unendlichen Weiten der komplexen Sonderfälle soll und kann der Helper vermutlich nicht abdecken.
-
@AggroRalf Ja, ich komme auch von C# (man merkt's ).
TypeScript erlaubt leider auch etwas wahnsinniges Verhalten mit Methodenparametern. Ich bevorzuge Methodennamen, die mir schon helfen, was ich machen soll und nicht unbedingt die TypeScript Variante von "wenn das erste Argument x ist, dann kann das zweite Argument nur noch a oder b sein und wenn du dann b im zweiten Argument hast, gibt die Methode Z zurück". Ich weiss es ist machbar (und absolut cool), aber verständlicher sind einfach Methodensignaturen, die von Code Completion unterstützt werden und nicht eine Methodensignatur die nur mit Code Completion verstanden werden kann.
Zur Verteidigung meines Ansatzes: wer nicht will, muss die zurückgegebenen Objekte nicht beachten und kann (wie @apollon77 vorgeschlagen hat) fast gleich arbeiten wie bis jetzt. Der Vorteil mit den zurückgegebenen Objekten ist, dass wir darauf eine "neue" API aufbauen können - über Zeit und Schritt für Schritt.
Schlussendlich schreiben wir in etwas komplexeren Adaptern immer wieder denselben Code und haben häufig "komische" Abhängigkeiten (jedes Objekt muss den Adapter kennen), die wir so vereinfachen könnten. Benutzen müssen es ja nur die, die wollen.
Gerade wenn wir den "Helper" in die adapter-core einbauen wollen (was super wäre), würde es IMHO eben Sinn machen, dass wir eine gute API zur Verfügung stellen (die auch "vorwärtskompatibel" ist - sprich: erweitert werden kann). Da wurde in der Vergangenheit oft einfach etwas rumgebastelt.
-
@AggroRalf sagte in Test: Objektvorlagen und Hilfsfunktionen für Objektbäume:
Zum Thema "Klassen" sollte besser @AlCalzone was sagen, ich persönlich liebe Klassen
Ich habe erst mal nichts gegen Klassen, sehe sie von .NET-Entwicklern, die mit JS anfangen, aber gerne überbenutzt.
Bei unserem ursprünglichen Design fand ich es Overkill, alles in Klassen zu kapseln, die nachher nur Daten enthalten. Für die vorgeschlagene API, insbesondere mit den lokalen Change Handlern macht es durchaus Sinn.@UncleSam sagte in Test: Objektvorlagen und Hilfsfunktionen für Objektbäume:
wahnsinniges Verhalten mit Methodenparametern. Ich bevorzuge Methodennamen, die mir schon helfen, was ich machen soll und nicht unbedingt die TypeScript Variante von "wenn das erste Argument x ist, dann kann das zweite Argument nur noch a oder b sein und wenn du dann b im zweiten Argument hast, gibt die Methode Z zurück"
Daher sind wir beim Modell "Bag of Options" gelandet. Du übergibst ein Objekt (was dann zwar recht komplex werden kann, was die möglichen Zusammenhänge betrifft), aber jede Eigenschaft wird auch an sich verstanden, weil sie einen Namen hat. Für ein ausführliches Beispiel siehe folgende PR-Beschreibung: https://github.com/gaudes/iobroker-object-helper/pull/4
Kurz:buildObject({ id: "bla", name: "blub", description: "abc", value: 1, objectType: "info", role: "switch", /* oops, this one is too much: */ "bla" }); // statt buildObject("bla", "blub", "abc", 1, "info", "switch", "bla"); // ???
Meiner Ansicht nach können wir versuchen, beide Welten zu verbinden. Für manche macht es sicher Sinn, wie derzeit implementiert eine Liste von Objekten dynamisch zu erstellen. Da bei jedem zu prüfen, welches Ober-Objekt genutzt werden muss, macht es unnötig kompliziert.
Bei klarer definierten Strukturen sehe ich den Vorschlag durchaus als Vorteil an. -
@AlCalzone Danke für dein differenziertes Feedback!
Daher sind wir beim Modell "Bag of Options" gelandet.
Bag of Options sehe ich als gute Lösung für genau das: Optionen. Zwingende Argumente bevorzuge ich als Parameter, aber ich weiss, dass das bei vielen JavaScript APIs anders gemacht wird - oder zumindest beides angeboten wird. Ich bin auch ganz klar gegen Methoden Overloads, da die in JavaScript keinen und in TypeScript nur bedingt Sinn machen.
Wenn du meinen Vorschlag anschaust, sollte das genau dem entsprechen: jede Methode hat ein paar zwingende Argumente und dann einen Bag of Options. Es gibt keine Overloads. Verschiedene Funktionalitäten werden durch unterschiedlich benannte Methoden zur Verfügung gestellt. Und etwas, was ich bei C# gelernt habe: async Methoden heissen xxxAsync - das vermindert das Risiko von floating Promises.
-
@UncleSam sagte in Test: Objektvorlagen und Hilfsfunktionen für Objektbäume:
Und etwas, was ich bei C# gelernt habe: async Methoden heissen xxxAsync - das vermindert das Risiko von floating Promises.
Wenn ich das so machen würde, würden 90% meiner Funktionen xxxAsync heißen
-
@UncleSam sagte in Test: Objektvorlagen und Hilfsfunktionen für Objektbäume:
Gerade wenn wir den "Helper" in die adapter-core einbauen wollen (was super wäre), würde es IMHO eben Sinn machen, dass wir eine gute API zur Verfügung stellen (die auch "vorwärtskompatibel" ist - sprich: erweitert werden kann). Da wurde in der Vergangenheit oft einfach etwas rumgebastelt.
Adapter-Core? Extra Library? Direkt in den controller?
-
@apollon77 Mein Plan wäre adapter-core. Direkt mit dem Controller hat das IMO nichts zu tun - es ist schließlich eine Abstraktion zur Hilfe. Eine weitere Library, die dann jeder braucht, ist aber auch wieder blöd.
-
@AlCalzone jeder braucht? jeder der die convenient methoden nutzen will weil SIe ja "On top of adapter.js" existieren ... Vorteil von eigener lib wäre flexiblere versionierung ... Adapter Core hat auch immer eine js-controller dependency (2.3.1 braucht controller 1.5.8+, 2.4.0 brauche js.controller 2.0+)
Ich hab Angst das es zu undurchsichtig wird wenn adapter-core jetzt noch mehr "features" bekommt und damit aktiver neue Versionen ....
-
Also nochmal zur Grundidee: Wir wollten ja die Entwicklung vereinfachen, z.B. gerade für simple API-Adapter.
Ich denke, dass wir das Ziel mit dem aktuellen Entwurf erreicht haben. Es sind einfach zwei Funktionen, mehr nicht. Klar haben die ein paar Parameter, aber das kriegt auch ein Anfänger per Cut+Paste hin. Durch die Vorlagen erreichen außerdem wir eine bessere Validität der Objekte.
@UncleSam 's Idee finde ich als "Ein-bischen-C#-Entwickler" auch sehr elegant, denke aber das würde ja das ganze Modell verändern. Es wäre eine komplett neue, objektorientierte Schnittstelle. Hätte diese Lösung für einfache API-Adapter einen Vorteil hinsichtlich Einfachheit und schnellere Entwicklung ?
@apollon77 Das mit dem Core war ja die Idee, da es ja (aktuell) nur zwei "einfache" Funktionen sind. Diese wären dann einfach vorhanden, gerade auch für Einsteiger bei der Entwicklung. Wenn man wieder eine Abhängigkeit einbauen muss, diese dann noch ggf. updaten muss, .... dann schreckt das doch eher ab für den Ein- und Umsteiger. So wäre es direkt vorhanden und man könnte es nutzen.
-
@AggroRalf sagte in Test: Objektvorlagen und Hilfsfunktionen für Objektbäume:
Hätte diese Lösung für einfache API-Adapter einen Vorteil hinsichtlich Einfachheit und schnellere Entwicklung ?
Für Adapter, die nicht nur Werte erhalten macht das schon Sinn. Meine drei Adapter (Loxone, i2c und Luxtronik2) bräuchten alle dasselbe. Nun kann ich auch noch einen Helper schreiben, oder @apollon77 's Modul nehmen oder wir bauen es einfach gleich mit eurer Lösung zusammen ein.
Die Idee ist ja: nicht 500 Lösungen für dasselbe Problem zu haben. Und für die ganz einfachen Adapter spielen wie gesagt die zurück gegebenen Objekte keine Rolle. Wer die nicht verwenden will, muss sie nicht verwenden. Für alle anderen (mit @apollon77 zusammen sind das ja schon fünf!) ist es eine massive Vereinfachung.