Hallo Alle,
Ich habe eine Frage was den grundsätzlichen Aufbau meines Programmes angeht und hoffe, ihr könnt mir dabei helfen.
Vielleicht zuerst kurz als Background. Für mich ist Python programmieren ein Hobby, das mir auch im Job hilft, um gewisse Dinge schneller und effizienter zu machen. Ich habe mir mein aktuelles Wissen selber beigebracht, also nie etwas in die Richtung gelernt (Schule, Uni,...). Trotzdem möchte ich das Ganze so "professionell" machen, wie möglich. Alleine schon um mir mein eigenes Leben leichter zu machen, wenn ich einen Code mal überarbeiten möchte. Die Details meiner Frage (z.B. dass ich tkinter verwende), sind eine Vorgabe von der ich nicht abrücken kann. Ebenso, dass ich das Model-View-Controller-Pattern verwende.
Nun zu meinem Problem:
Ich möchte ein Programm schreiben, dass folgende Aufgabe hat (sehr vereinfacht):
Ich habe eine Excel-Datei, die Informationen zu Flügen enthält (unter anderem die Höhe und Flugroute in Koordinatenform). Jeweils eine Zeile steht für einen Flug und pro Datei gibt es zig Zeilen (immer unterschiedlich).
Ich möchte nun die Flüge auf einem Canvas darstellen, über dieses Canvas die Flüge verändern können (z.B. indem man die Flugroute als Text ändert) und dann alles wieder speichern können.
Das Ganze mache ich mit tkinter.
Meine Frage bezieht sich jetzt nicht auf Einzelheiten (die Darstellung und Anpassung der Details über Textboxen ist kein Problem), sondern wie ich das Programm grundsätzlich aufbaue.
Folgenden Plan habe ich bis jetzt (Dateinamen sind nur Platzhalter und heißen in Wirklichkeit anders):
main.py --> Mein "Controller"
view.py --> Erstellt die Oberfläche inklusive aller Elemente die dazu gehören
data.py --> Lädt, verwaltet und speichert die Details der Flüge
Frage 1: Beim MVC-Pattern müssen View und Model getrennt sein, oder? Das bedeutet, dass die Klasse(n), die die Daten verwalten (z.B. das eigentliche Laden aus der Excel-Datei), niemals direkt auf die View zugreifen. Wenn ein Flug dargestellt (=am Canvas gezeichnet) werden soll, ruft das Model eine Methode im Controller auf, welcher wiederum der View "sagt", was angezeigt werden soll. Umgekehrt genauso. Angenommen, ich stelle einen Flug auf dem Canvas dar, dann klickt der User darauf und ändert etwas am Flug (z.B. indem er die Flugroute verändert - wie auch immer das dann tatsächlich gemacht wird), so muss das ja wieder in der Model-Klasse gespeichert werden (damit das dann auch bei Bedarf wieder in der Excel Datei gespeichert werden kann). Das würde bedeuten, dass die View dem Controller "sagt", was geändert werden soll (in diesem Beispiel die Flugroute) und der Controller wiederum ruft eine Methode im Model auf, die genau dieses macht. Verstehe ich das so richtig? Grundsätzlich würde das meiner Meinung nach Sinn machen, denn, wenn ich irgendwann z.B. von tkinter auf pyQt wechseln möchte, muss ich nur die View anpassen, Controller und Model bleiben aber gleich. Umgekehrt, wenn irgendwann Daten nicht mehr aus einer Excel-Datei laden möchte, sondern z.B. aus einer Datenbank, muss ich nur das Model anpassen und der Rest bleibt gleich. Was ich nur verwirrend finde, ist, dass ich immer den "Umweg" über den Controller gehen muss, der riesige Ausmaße annehmen wird (= viele Methoden).
Frage 2: Vorausgesetzt meine Annahme in Frage 1 ist korrekt, würdet ihr dann abstrakte Klassen als Trennung zwischen View und Controller, bzw. Model und Controller anlegen?
Frage 3: Zusätzlich zu den veränderlichen Daten im Model, also den Flügen, die sich je nach Ursprungsdatei unterscheiden, muss ich auch statische Daten laden und anzeigen, die sich nie verändern und in Form einer json-Datei gespeichert sind. Genauer gesagt geht es dabei um Informationen, wie zum Beispiel Ländergrenzen, die ich zeichne. Kann ich das im View machen, oder sollten auch diese Daten wieder im Model gespeichert werden?
Das wars mal fürs Erste;). Ich hoffe, ich habe mich verständlich ausgedrückt.
LG Flo
Programm-Architektur
Hallo Flo!
Ganz schön viel Text...
zu 1: "Model-View-Controller-Pattern". wenn Du die Vorgabe einhalten willst, dann sind V und M zu trennen. Python ist ja zunächst mal objektorientiert, aber sehr flexibel; die MVC-Trennung wird sich daher sicher auch umsetzen lassen. Eine Klasse hält die Daten, eine (oder mehrere) andere die - Methoden oder Funktionen oder so ähnlich.
zu 2: Ich bin eigentlich immer eher für pragmatische Lösungen...
zu 3: Die Daten liegen in 2 Dateien (und Strukturen) vor, Excel und json. Ich würde die jeweiligen Daten im Hinblick auf eventuell spätere Rückspeicherung getrennt halten und erstmal versuchen, einen einfachen Viewer zu bauen.
LG juwido
Ganz schön viel Text...
zu 1: "Model-View-Controller-Pattern". wenn Du die Vorgabe einhalten willst, dann sind V und M zu trennen. Python ist ja zunächst mal objektorientiert, aber sehr flexibel; die MVC-Trennung wird sich daher sicher auch umsetzen lassen. Eine Klasse hält die Daten, eine (oder mehrere) andere die - Methoden oder Funktionen oder so ähnlich.
zu 2: Ich bin eigentlich immer eher für pragmatische Lösungen...
zu 3: Die Daten liegen in 2 Dateien (und Strukturen) vor, Excel und json. Ich würde die jeweiligen Daten im Hinblick auf eventuell spätere Rückspeicherung getrennt halten und erstmal versuchen, einen einfachen Viewer zu bauen.
LG juwido
- __blackjack__
- User
- Beiträge: 14032
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@Flo: Das Du von MVC nicht abrücken kannst würde ich als ernstes Problem sehen. So funktioniert das nämlich nicht das man mit einem Entwurfsmuster anfängt und dann auch noch sagt das man davon nicht abrücken kann. Zu Entwurfsmustern gehört immer eine Problembeschreibung die durch das Muster gelöst wird. Und nur wenn man dieses Problem tatsächlich *hat*, macht es überhaupt Sinn das Muster anzuwenden. Was bei GUIs in aller Regel sinnvoll ist, ist eine Trennung von UI und Programmlogik. Das Problem was damit gelöst wird ist die Testbarkeit der Programmlogik ohne das man da was mit dem UI machen muss, was damit ja nichts zu tun hat.
Aufteilung in Module würde ich wahrscheinlich noch nicht von Anfang an festlegen, sondern erst wenn es tatsächlich zu viel wird für ein Modul. Wenn mehrere Module dann auf jeden Fall in einem Package zusammenfassen, damit auf ”oberster” Ebene nur ein einzelner Name mit allen anderen Packages konkurriert und kollidieren kann.
Ad Frage 1: Problem bei MVC ist vor allem auch das jeder davon andere Vorstellungen hat und insbesondere auch GUI-Rahmenwerke. Wenn Du jetzt also ”Dein” MVC machst und dann auf Qt umsteigen willst, wirst Du vielleicht Probleme bekommen das mit der Qt-Vorstellung in Einklang zu bringen und hast dann Deine Klassen die irgendwas mit Model heissen, und dann die Qt-Model-Klassen, und musst einen Adapter dazwischen basteln. Das wird schnell alles etwas „overengineered“. Insbesondere wenn Dein MVC am Ende gar kein Problem löst, sondern einfach nur als Selbstzweck existiert. Da hast Du dann Entkopplung von Sachen die tatsächlich aber immer gleich verbunden sind, also die Entkopplung, und die damit einhergehende zusätzliche Komplexität gar nicht gebraucht hätten.
Wenn der Controller riesige Ausmasse annimmt, läuft was falsch. Das riecht nach dem Gott-Klasse-„anti pattern“.
Ad Frage 2: Jetzt wird es langsam „javaesque“. Das ist Python verdammt noch mal.
Ad Frage 3: Mich stört hier ja wieder die Model- und View-Bezeichnung. Die Antwort ist „kommt drauf an“.
Ich würde das gar nicht so im Voraus im Detail planen. Sondern einfach erst einmal das einfachste implementieren was geht, wo Programmlogik und Benutzerinteraktion sauber getrennt sind. Die Programmlogik sollte nichts über die GUI wissen müssen. Entkoppeln und verallgemeinern erst wenn es *gebraucht* wird, und nicht auf Vorrat. Abstrakte Klassen erst dann wenn man auch tatsächlich mindestens zwei konkrete Klassen hat, die diese abstrakte Klasse brauchen, also echte gemeinsame Eigenschaften/Verhalten dorthin auslagern, was man sonst zweimal schreiben würde. KISS und YAGNI in einer Suchmaschine Deines Misstrauens eingeben.
Und ich würde bei der Implementierung mit der Programmlogik anfangen und da dann die GUI drauf setzen. Man muss nicht erst die komplette Programmlogik fertig haben bevor man die GUI anfängt, aber immer den Teil der Programmlogik vor der GUI ausprogrammieren. So fällt es schwerer von der Programmlogik auf die GUI zugreifen zu wollen, die ja noch nicht existiert. Und man verwendet in der GUI dann nur schon getestete Programmlogik.
Aufteilung in Module würde ich wahrscheinlich noch nicht von Anfang an festlegen, sondern erst wenn es tatsächlich zu viel wird für ein Modul. Wenn mehrere Module dann auf jeden Fall in einem Package zusammenfassen, damit auf ”oberster” Ebene nur ein einzelner Name mit allen anderen Packages konkurriert und kollidieren kann.
Ad Frage 1: Problem bei MVC ist vor allem auch das jeder davon andere Vorstellungen hat und insbesondere auch GUI-Rahmenwerke. Wenn Du jetzt also ”Dein” MVC machst und dann auf Qt umsteigen willst, wirst Du vielleicht Probleme bekommen das mit der Qt-Vorstellung in Einklang zu bringen und hast dann Deine Klassen die irgendwas mit Model heissen, und dann die Qt-Model-Klassen, und musst einen Adapter dazwischen basteln. Das wird schnell alles etwas „overengineered“. Insbesondere wenn Dein MVC am Ende gar kein Problem löst, sondern einfach nur als Selbstzweck existiert. Da hast Du dann Entkopplung von Sachen die tatsächlich aber immer gleich verbunden sind, also die Entkopplung, und die damit einhergehende zusätzliche Komplexität gar nicht gebraucht hätten.
Wenn der Controller riesige Ausmasse annimmt, läuft was falsch. Das riecht nach dem Gott-Klasse-„anti pattern“.
Ad Frage 2: Jetzt wird es langsam „javaesque“. Das ist Python verdammt noch mal.
Ad Frage 3: Mich stört hier ja wieder die Model- und View-Bezeichnung. Die Antwort ist „kommt drauf an“.
Ich würde das gar nicht so im Voraus im Detail planen. Sondern einfach erst einmal das einfachste implementieren was geht, wo Programmlogik und Benutzerinteraktion sauber getrennt sind. Die Programmlogik sollte nichts über die GUI wissen müssen. Entkoppeln und verallgemeinern erst wenn es *gebraucht* wird, und nicht auf Vorrat. Abstrakte Klassen erst dann wenn man auch tatsächlich mindestens zwei konkrete Klassen hat, die diese abstrakte Klasse brauchen, also echte gemeinsame Eigenschaften/Verhalten dorthin auslagern, was man sonst zweimal schreiben würde. KISS und YAGNI in einer Suchmaschine Deines Misstrauens eingeben.
Und ich würde bei der Implementierung mit der Programmlogik anfangen und da dann die GUI drauf setzen. Man muss nicht erst die komplette Programmlogik fertig haben bevor man die GUI anfängt, aber immer den Teil der Programmlogik vor der GUI ausprogrammieren. So fällt es schwerer von der Programmlogik auf die GUI zugreifen zu wollen, die ja noch nicht existiert. Und man verwendet in der GUI dann nur schon getestete Programmlogik.
„A life is like a garden. Perfect moments can be had, but not preserved, except in memory. LLAP” — Leonard Nimoy's last tweet.
Moin,
zu 1.: ich kenne es eher so das alles übers Model läuft:
- beim Model sind durch die Initialisierung interessierte Beobachter angemeldet (u.a. die View)
- wenn der Controller dem Model sagt "ändere mal deine Daten auf 'xyz' " dann ändert das Model eben seine Daten und benachrichtigt dann alle angemeldeten Beobachter mit der Info "bei mir hat sich was verändert, aktualisiert euch mal"
minimal gibt das dann an Methoden:
- bei den Beobachtern (Views und eventuell auch Controller) eine Methode "update", in der dann die jeweilige Aktualisierung passiert
- beim Model: eine Methode zum Daten ändern, vielleicht eine zum abrufen der Modell-Daten (kann vermutlich entfallen) und dann noch zwei Methoden mit denen sich interessierte Beobachter-Objekte beim Modell an bzw. abmelden können
Methoden für Initialisierung und Interaktion mit GUI-Elementen kommen dann noch hin zu.
zu 1.: ich kenne es eher so das alles übers Model läuft:
- beim Model sind durch die Initialisierung interessierte Beobachter angemeldet (u.a. die View)
- wenn der Controller dem Model sagt "ändere mal deine Daten auf 'xyz' " dann ändert das Model eben seine Daten und benachrichtigt dann alle angemeldeten Beobachter mit der Info "bei mir hat sich was verändert, aktualisiert euch mal"
minimal gibt das dann an Methoden:
- bei den Beobachtern (Views und eventuell auch Controller) eine Methode "update", in der dann die jeweilige Aktualisierung passiert
- beim Model: eine Methode zum Daten ändern, vielleicht eine zum abrufen der Modell-Daten (kann vermutlich entfallen) und dann noch zwei Methoden mit denen sich interessierte Beobachter-Objekte beim Modell an bzw. abmelden können
Methoden für Initialisierung und Interaktion mit GUI-Elementen kommen dann noch hin zu.
_______________________________________________________________________________
https://www.python-kurs.eu/index.php
https://learnxinyminutes.com/docs/python/ https://learnxinyminutes.com/docs/de-de/python-de/
https://quickref.me/python https://docs.python-guide.org/
Hallo Flo,
ich würde dir bei Struktur Problemen raten das mal als UML Klassendiagramm und oder als Sequenz Diagramm dar zu stellen (UMLet ist ein Graphisches Tool dafür). Das müsste helfen die Denkarbeit getrennt vom Programmieren zu halten, und beim Programmieren kannst du dich aufs Debuggen fokussieren weil du ja schon weist was rauskommen muss und wie das ganze am besten laufen soll. Ebenso möchte ich dir empfehlen die Programmier-Paradigmen des objektorientierten und funktionellen Programmierens umzusetzen. Wie oben schon genannt Pragmatische Lösungen: Schau das der Code sich selbst dokumentiert, bedeutet das du nicht mit Kommentaren erklären musst was da jetzt passiert. Bitte aber bloß keinen Code schreiben ohne Kommentare, wäre ein Wunder wenn man versteht was da eigentlich passiert bei einer Zeitspanne von längerer Zeit.
Ich hoffe mal das der Rest deiner Fragen oben schon beantwortet wurde, da ich mich mit sowas noch nicht wirklich befasst habe.
Viel Spaß noch!
ich würde dir bei Struktur Problemen raten das mal als UML Klassendiagramm und oder als Sequenz Diagramm dar zu stellen (UMLet ist ein Graphisches Tool dafür). Das müsste helfen die Denkarbeit getrennt vom Programmieren zu halten, und beim Programmieren kannst du dich aufs Debuggen fokussieren weil du ja schon weist was rauskommen muss und wie das ganze am besten laufen soll. Ebenso möchte ich dir empfehlen die Programmier-Paradigmen des objektorientierten und funktionellen Programmierens umzusetzen. Wie oben schon genannt Pragmatische Lösungen: Schau das der Code sich selbst dokumentiert, bedeutet das du nicht mit Kommentaren erklären musst was da jetzt passiert. Bitte aber bloß keinen Code schreiben ohne Kommentare, wäre ein Wunder wenn man versteht was da eigentlich passiert bei einer Zeitspanne von längerer Zeit.
Ich hoffe mal das der Rest deiner Fragen oben schon beantwortet wurde, da ich mich mit sowas noch nicht wirklich befasst habe.
Viel Spaß noch!