OOP Programm Struktur



  • Was mich im Moment beschäftigt ist die Frage wie man größere Projekte am besten Strukturieren sollte und was se hier so an Möglichkeinte/Lösungen/Patterns gibt.

    Wie organisiert ihr eure Projekte? Daten/UI/Funktionalität.

    Über event system. Entety/Component. Dependency Injection. Singletons... 🙂 What ever. Wie greift Ihr aus der UI auf eure Datenschicht zu?

    Hab Ihr eventuell links zu diesen(m) Thema?



  • Das Programm sollte so weit wie moeglich als Baum aufgebaut sein, s.d. jeder Knoten auf seine Kinder zugreifen kann, aber nicht zwangslaeufig auf seine Geschwisterknoten. RAII draengt einen praktischerweise automatisch in die richtige Richtung. Man muss es nur noch sinnvoll umsetzen.

    EDIT: Bei mir wird UI erst als letztes aufgebaut und greift nur noch auf fertige Algorithmen zu. Oft ist es auch angenehmer, das grafische Interface in einer anderen Sprache zu schreiben und damit nur ein Commandline-Tool zu steuern.



  • Marthog schrieb:

    Das Programm sollte so weit wie moeglich als Baum aufgebaut sein, s.d. jeder Knoten auf seine Kinder zugreifen kann, aber nicht zwangslaeufig auf seine Geschwisterknoten. RAII draengt einen praktischerweise automatisch in die richtige Richtung. Man muss es nur noch sinnvoll umsetzen.

    EDIT: Bei mir wird UI erst als letztes aufgebaut und greift nur noch auf fertige Algorithmen zu. Oft ist es auch angenehmer, das grafische Interface in einer anderen Sprache zu schreiben und damit nur ein Commandline-Tool zu steuern.

    Um Gottes willen. Warum sollte man die GUI mit einer anderen Sprache erstellen? Das erschwert die Wartung ganz erheblich. Und ein Commandlinetool als Interface ist fehleranfällig, langsam und schwer wartbar 😮 .



  • Ok das kann aber dann bei Komplexem recht schnell unordentlich wird.
    Ich hatte überlegt eine app klasse zu erstellen eine für Daten und Logik . Die beiden letzteren in der app als hat ein zu registrieren und dann die app durch die UI zu schleifen. So kann ich auf Singletons verzichten habe nur ein Objekt das ich durchgeben muss und von überall Zugriff auf die Daten und die Logik.
    Den Zugriff der UI auf die Daten dann per MVC implementiert.

    Das mit dem UI in anderer Sprache schreiben ist manchmal gar nicht schlecht. Ein Bekannter nutzt die crome engine in cpp für UI. Aber nicht als CMD sondern direkt im cpp Programm.

    Mich interessiert halt immer ob es da nicht noch was anderes/besseres gibt das ich noch nicht kenne. DAs durchgeschleife kann doch schnell nerven und auf singletons will ich verzichten da es wohl bei dem debuggen Problemen geben kann.

    Das Entity/Component System finde ich auch ganz interessant. Gerade da die Anwendung auch eine 3D Editor haben wird. Diesen Part will ich versuchen mal damit umzusetzen.

    Sonst jeder Hinweis/Link auf Infos zu solchen Themen sind begehrt 🙂



  • Unsere Software hat 14 000 Klassen und 6 Millionen Zeilen Code. Wurde vor 20 Jahren angefangen. Mittlerweile haben wir natürlich kaum noch so alten Code, aber die Software wurde nie komplett neugeschrieben. Sind immer wieder einzelne Module umgebaut worden, die aber zu jeder Zeit in das jeweils gültige Gesamtsystem passen mussten. Gibt also insgesamt keine so tolle einheitliche Architektur.
    Wie würde man sowas from scratch planen? Wahrscheinlich gar nicht. Ich bin sehr skeptisch, ob das möglich ist.



  • Kennt ihr den Spruch/Ausrede "Das ist nun mal so historisch gewachsen!"? 😃

    Ich denke, jeder der an einem älteren Software-Produkt arbeitet, wird diesen Spruch kennen.

    Es gibt das Lehrbuch, und es gibt die Praxis. Und die stimmen nie 100% überein. Denn der Code wird von Menschen geschrieben und nicht von Maschinen.



  • Klar aber mal abgesehen davon. Wie macht ihr es denn in Größeren Programmen. Mir geht es hauptsächlich um das bekannt machen der Objekte.

    Wie ihr schreibt werden es ja schnell hunderte wenn nicht gar tausende Klassen.
    Nun muss ja jeder seine Abhängigkeiten und partner kennen.

    Man startet bei einem Start Objekt. Wie und wo legt ihr nun Klassen für die Daten, die Logik Schicht und die UI an. Wie verknüpft ihr diese.

    Stickworte Dependency injection. Object pool. Abstract factory.

    Idee1: Eine globale app klasse die die Daten, Logik und UI Haupt Objekte enthält und dann als Konstruktor Parameter allen Klassen mit gegeben wird. So hat man an allen Stellen über app Zugriff auf data etc.

    Idee2: Oder ein Objekt Pool Objekt das auf Anfrage die entsprechenden Abhängigkeiten übergibt und durch alle Klassen geschleift wird.

    Idee3: Oder Aufruf wo man sie halt braucht über singletons... ja macht man nicht 😉 Wäre aber eine Möglichkeit.

    Mir geht es wirklich um das Gerüst der Anwendung das alles zusammen hält und bereit stellt. Nicht um die Problemlösungen im kleinen. Und das für Projekte die auch mal größer werden können.



  • Modularer aufbau und Abstraktionsschichten.

    Von den von dir genannten Begriffen wuerde ich solange wie moeglich abstand nehmen, weil sie Fehler in andere Modulteile verschleppen und so schwer zu finden sind.

    Erstmal stellt man die Grundstruktur auf und hat dann voneinander unabhengige Komponenten. Fuer jede dieser Komponenten geht man genauso vor und stellt Unterkomponenten auf.
    Manche sind voellig unabhaengig und werden nur von aussen aufgerufen. Diese sind besonders einfach zu behandeln.

    Schwierig wird es erst, wenn man einen grossen Umfang von verschiedenen Funktionalitaeten in einem objekt haben will, also z.B. in einem Spiel 3d-Objekte verschiedene Bewegungsarten (lineare bewegung, rotierend, ai-gesteuert, spielergesteuert, durch schwerkraft beeinflusst, Ragdoll, jeweils mit oder ohne Kollision). Dann kommt man wohl um inversion of control nur schwer herum. Auf jeden Fall sollte man diese Teile aber soweit wie moeglich einschraenken.

    Von abstract Factories halte ich gar nichts. Die einzige sinnvolle Anwendungsweise habe ich bisher in Plugins gesehen, denen auf diese weise erlaubt wird, selbst entwickelte Objekttypen in ein fertiges Programm einzubinden.



  • Erstmal stellt man die Grundstruktur auf und hat dann voneinander unabhengige Komponenten. Für jede dieser Komponenten geht man genauso vor und stellt Unterkomponenten auf. Manche sind voellig unabhaengig und werden nur von aussen aufgerufen.

    Mir geht es genau um diese Grundstruktur. Die verschiedenen Schichten haben ja Abhängigkeiten und müssen kommunizieren. Sprich ich brauche nach der Zeit der Erzeugung die entsprechenden Objekte an der Stelle und muss sie dem Objekt mitgeben.

    Ich hab ein main UI Fenster das einen devider manager erzeugt das rechts ein pan enthält das ein Suchfeld, eine Liste und einige Elemente zum hinzufügen neuer Elemente hat. Nun muss das das UI Elemente im UI Element im UI Element auf meine Logik zugreifen können. Diese hab ich ja gaanz oben in der Applikation Hauptklasse erzeugt. Wie schleife ich das alles durch und gruppiere die verschiedenen zusammengehörigen Objekte.

    Mein problem ist das es massen an tutorials über OOP gibt. Auch über Design Patterns aber im MAIN wird immer nur zum Beispiel direkt die entworfene Klasse direkt erzeugt und aufgerufen. Nirgends finde ich best practice zur Grundsätzlichen Programm Struktur.

    Dabei ist das doch denke ich meistens dasselbe. Verschiedene Daten (Files, DB access xmL), Logik und UI.

    Dann kommt man wohl um inversion of control nur schwer herum. Auf jeden Fall sollte man diese Teile aber soweit wie moeglich einschraenken.

    Inversion of control meint ja nur das ich Abhängigkeiten nicht IM Objekt erzeuge sondern per dependency injection von außen rein gebe um eine größere Entkopplung zu erreichen und somit meine Klassen wiederverwendbarer mache.
    Das würde ich immer machen 🙂



  • Ich kenne bis jetzt nur meine kleinen Projekte, in denen ich zwar Klassen einsetzen, aber so gut wie nie eines der berühmten Designpattern und ich mache mir auch da gar keinen Kopf darum. Ich denke, wenn ich so ein Pattern einmal brauchen sollte, dann werde ich das schon merken, weil ich dann an einer Stelle nicht weiter komme.

    Alles schon auf den Reißbrett, für alle möglichen Änderungen, vorzubereiten mündet bestimmt in verschachtelten und unübersichtlichen Code, kann ich jedenfalls so vorstellen. Ich kann mir auch gut vorstellen, dass man viele Designentscheidungen auch erst in der Entwicklung trifft und nicht schon vorher, weil man gar nicht an alles denken kann. Oder man versucht an alles zu denken und kommt nicht zu Potte, oder verhaspelt sich dann.

    Mich würde auch hier mal die Meinung der Profis interessieren.



  • tntnet schrieb:

    Um Gottes willen. Warum sollte man die GUI mit einer anderen Sprache erstellen? Das erschwert die Wartung ganz erheblich.

    Kommt auf's Projekt drauf an. GUI in C++ macht z.B. oft keinen Sinn. Backend in C++ macht dagegen oft Sinn.
    Wenn das Interface dazwischen schmal genug ist, kann das super funktionieren.

    tntnet schrieb:

    Und ein Commandlinetool als Interface ist fehleranfällig, langsam und schwer wartbar 😮 .

    Kommt wieder drauf an was man macht. Und Dinge in externe Prozesse auszulagern kann schon viel Sinn machen. Dadurch hat man automatisch eine sehr harte und klar sichtbare Trennlinie. Man kann schlicht und ergreifend kaum unerwünschte Zugriffe über Modulgrenzen hinweg übersehen.
    Und es zwingt einem diverse Marshaling-Schichten auf, die z.B. Thread-Safety garantieren und eben auch die Kapselung erhöhen. Und wenn man nicht muss, dann verzichtet man halt gerne darauf. Was dann zu Fehlern führen kann.

    Wobei es natürlich nicht unbedingt ein Commandline-Utility sein muss. Kann auch gerne ein Web-Service sein, ein COM- oder CORBA-Service, ...

    Was Sinn macht und was nicht, kommt natürlich immer auf die Art der Anwendung drauf an.



  • Steff_mc schrieb:

    Ich hab ein main UI Fenster das einen devider manager erzeugt das rechts ein pan enthält das ein Suchfeld, eine Liste und einige Elemente zum hinzufügen neuer Elemente hat. Nun muss das das UI Elemente im UI Element im UI Element auf meine Logik zugreifen können. Diese hab ich ja gaanz oben in der Applikation Hauptklasse erzeugt. Wie schleife ich das alles durch und gruppiere die verschiedenen zusammengehörigen Objekte.

    Lies dir mal was du im Netz so zum Thema MVVP findest durch.
    Bzw. auch MVC, wobei mir persönlich MVC zu schwammig definiert ist als dass es besonders hilfreich wäre.



  • Naja hierbei geht es ja um die Verbindung einer UI mit eine Datenobjekt und einem Kontroller. Ober einem dazwischengeschalteten ViewModel um die Logik die Anzeige und die Daten sauber zu trennen. Das Hilft mir aber immer noch nicht in einer komplexen Umgebung immer an der richtigen Stelle sauber Zugriff auf meine Datenschicht zu haben.

    Im Moment denke ich darüber nach einen Objektpool zum Verwalten der benötigten Objekte zu nutzen und diesen dann überall durch zu schleifen wo ich Zugriff auf die Datenschicht oder Anforderungen auf Kontroller brauche.

    Früher hab ich ja immer ein APP objekt über durch geschleift was ja aber eher eine globalen variable entspricht und nicht wirklich zu einer sauberen Entkopplung führt.

    @Citizen42: Ich beschäftige mich jetzt schon länger mit Patterns und man merkt dabei das man sie oft bereits unbewusst eingesetzt hat.

    Ich finde es wichtig das man sich damit beschäftigt, da es einem erstens hilft in Entscheidungssituationen schneller gute Entscheidungen, basierend auf existierenden und erprobten Lösungen, zu fällen. Andererseitr hilft es ungemein wenn man mit anderen Codern Schreibt/Redet ein gemeinsames Vokabular zu haben um über mögliche Lösungen zu diskutieren.



  • Steff_mc schrieb:

    Das Hilft mir aber immer noch nicht in einer komplexen Umgebung immer an der richtigen Stelle sauber Zugriff auf meine Datenschicht zu haben.

    Du schreibst von einer "komplexen" Umgebung, aber mir kommt es eher so vor, als ob du dir das Gegenteil eher zu einfach vorstellen würdest. Das "nehme ich A oder B" passt irgendwie nicht, in jeder komplexen Umgebung wirst du alle möglichen Varianten haben.
    Besser ist im Endeffekt immer, die benötigten Objekte als Parameter durchzureichen. Vielleicht zusammengefasst in Form eines Kontextobjekts. Mit Singletons und wahrscheinlich auch Objectpools wirst du dir evtl. später was verbauen, wenn dein System tatsächlich noch komplexer wird und irgendwelche Features bekommen soll, an die du noch nicht gedacht hast. Wir haben auch genug Singletons in unserem System und es gibt immer wieder Fälle, wo man bei einer neuen Anforderung denkt, ich will aber nicht DAS Objekt, ich will jetzt zwei davon haben, oder halt ein anderes. Weil so wie Singletons meist benutzt werden, gehts ja nicht darum, dass es nur eine Instanz geben darf, sondern an eine globale Instanz ranzukommen. Und sobald du viele Komponenten hast, die dieses Objekt nicht als Parameter bekommen, sondern sich einfach vom Singleton holen, hast du ein Problem, wenn du plötzlich mit einem anderen Objekt arbeiten willst. Genauso mit Objectpools, wenn die irgendwie global sind.



  • Citizen42 schrieb:

    Ich kenne bis jetzt nur meine kleinen Projekte, in denen ich zwar Klassen einsetzen, aber so gut wie nie eines der berühmten Designpattern und ich mache mir auch da gar keinen Kopf darum. Ich denke, wenn ich so ein Pattern einmal brauchen sollte, dann werde ich das schon merken, weil ich dann an einer Stelle nicht weiter komme.

    Gute Einstellung. Hau Dir trotzdem ein Buch über Designpatterns oder sowas in den Kopf, es kann viel Zeit sparen. Und dann meide sie weiter.

    Citizen42 schrieb:

    Alles schon auf den Reißbrett, für alle möglichen Änderungen, vorzubereiten mündet bestimmt in verschachtelten und unübersichtlichen Code, kann ich jedenfalls so vorstellen.

    Jo, das läßt regelmäßig Projekte sterben. Drei bis fünf verspielte Abstraktionsebenen, nur um irgendwo was umschalten zu können, was man viel einfachder durch Austausch von drei Zeilen Code bekommen würde.

    Citizen42 schrieb:

    Ich kann mir auch gut vorstellen, dass man viele Designentscheidungen auch erst in der Entwicklung trifft und nicht schon vorher, weil man gar nicht an alles denken kann. Oder man versucht an alles zu denken und kommt nicht zu Potte, oder verhaspelt sich dann.

    Außerdem kann man vorher gar nicht alle entscheidenden Details wissen. Es reicht, den groben Plan zu planen. Ich finde auch wichtig, daß der Entwurf auf die Sprache eingehen muss, um sehr gut zu sein.



  • Bei volkard muss man etwas aufpassen 😉 Ich habe meine Zweifel, ob er jemals an wirklich größeren Projekten mitgearbeitet hat. Grundsätzlich geb ich ihm Recht. Aber die Einstellung "da kann man auch 3 Zeilen Code ändern" führt oft zu viel übleren Problemen, mit denen man viel länger kämpft als paar Abstraktionsebenen zu viel. Jedenfalls habe ich persönlich da schon viel mehr Projekte gesehen, denen DAS das Genick gebrochen hat.



  • Mechanics schrieb:

    mit denen man viel länger kämpft als paar Abstraktionsebenen zu viel



  • @Mechanics: Im Moment benutze ich wie geschrieben ein Sammel objekt fürs durchschleifen. Singletons nutze ich eigentlich nur wenn es um System unkritsche Teile wie logs oder sowas geht. Daher ja auch die idee des Objektpools. Je nach angefordertem Objekt typ könnte man dann entwerder ein festes Objekt ala singleton zurück geben oder halt ein gepooltes. Diese werden dann im Erzeigungsfall genutzt um die Nötigen Abhängigkeiten zum injecten zu erhalten

    this.dingens = new soEinEditor(app.getObject("neededDataClass"));

    @volkard: Hab mir die letzten monate ca 10 rein gezogen 🙂
    Zu: Alles schon auf den Reißbrett- Mir geht es um die Struktur der UI/Datenschicht/Logik. Es Handelt sich um einen IDE die verschiedene Editoren managen wird die auf einiges an verschiedenen Datenquellen zugreifen muss. Geht also nicht um die Details in den Datenklassen.

    Zu: 3 Zeilen Code ändern - Meine Methoden habenmiest nciht mher wie 3 bis 5 Zeilen code 🙂 Da ändert man nicht viel 😉

    Danke schonmal an alle. Falls noch jemanden was Einfällt immer her damit.



  • genau das ist die Kunst - so viel Abstraktion im Entwurf einzuplanen, daß man zukünftige Projekt-Anforderungen wird erfüllen können, aber trotzdem jede Abstraktionsebene eine klare Bedeutung hat und nicht aus Jux und Tollerei gekapselt wird, wo niemals Generizität gebraucht werden wird.

    Deshalb ist Abstraktionsvermögen auch eine der wichtigsten Eigenschaften guter Programmierer. Und dies wiederum vielleicht der Grund, warum so manche Spitzenklasse-Programmierer von Hause aus Mathematiker oder Physiker sind.

    Entwicklung und Problemverständnis gehen oft Hand in Hand - je mehr Funktionalität bereits implementiert sind, umso besser versteht man das Problem, und mit der Zeit wächst eine Intuition für das richtige Maß an Generizität.

    Vielleicht ein Grund, warum es manchmal besser ist, eine Software evolutionär zu entwickeln, mit einem kleinen Kern zu einer Minimal-Spezifikation zu beginnen, schichtweise drumherumzubauen und ständig in der Praxis zu überprüfen, ob das dies ist, was der Kunde braucht - statt erst komplett durchzuplanen, und dann (so ziemlich der worst-case) nach drei Vierteln der Implementation feststellen zu müssen, daß eine entscheidende Abstraktion fehlt, die Spezifikation inkonsistent ist oder der Kunde seine Anforderungen ändert, weil er selbst erst am Prototypen merkt, daß er eigentlich etwas Anderes braucht, als er anfangs dachte.



  • großbuchstaben schrieb:

    genau das ist die Kunst - so viel Abstraktion im Entwurf einzuplanen, daß man zukünftige Projekt-Anforderungen wird erfüllen können, aber trotzdem jede Abstraktionsebene eine klare Bedeutung hat und nicht aus Jux und Tollerei gekapselt wird, wo niemals Generizität gebraucht werden wird.

    Seh ich genauso.

    Steff_mc schrieb:

    Singletons nutze ich eigentlich nur wenn es um System unkritsche Teile wie logs oder sowas geht. Daher ja auch die idee des Objektpools. Je nach angefordertem Objekt typ könnte man dann entwerder ein festes Objekt ala singleton zurück geben oder halt ein gepooltes.

    Das hört sich für mich zu technisch an. Kann nicht immer passen, man muss wissen, was man braucht. Wir haben z.B. ein Singleton für die "Datenbankverbindung" bei uns (nicht nur technisch eine Datenbankverbindung, sondern was alles was bei uns dazugehört). Es ist ein Singleton, weil es eh nur eine Datenbank gibt und die an 20 000 Stellen benutzt wird, um Daten anzureichern, und natürlich niemand Lust hatte, die überall als Parameter durchzureichen. Hier würde eine Pool wenig Sinn machen, weil man will nicht irgendeine Datenbank, sondern die richtige 😉
    Dass es ein Singleton ist, stört aber trotzdem ab und zu. Weil einige Entwickler haben bei einigen Projekten doch die Anforderung, mal auf eine andere Datenbank zugreifen zu müssen, oder auf zwei Datenbanken. Überhaupt nicht der typische Usecase, war so nie wirklich vorgesehen, ist aber nun mal die Anforderung und macht dann auch Sinn, wenn man sich das im Detail anschaut. Und es geht natürlich nicht nur um die Datenbankverbindung, die wollen natürlich alle schon vorhandenen Komponenten benutzen, nur ist es eben schwierig, weil die ganzen Komponenten halt nur DIE Datenbank kennen.
    Da würde auch ein Pool nicht wirklich helfen, weil jetzt müssten die Komponenten immer noch die richtige Datenbank bekommen. Und wenn sie keine willkürliche Datenbank bekommen sollen, müssten die doch irgendwelche Informationen mitschleifen, z.B. eine ID.


Anmelden zum Antworten