MVVM, VIPER, MVC, ... wie binde ich es richtig in mein Projekt ein?

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • MVVM, VIPER, MVC, ... wie binde ich es richtig in mein Projekt ein?

    Moin Zusammen,

    ich denke einige werden von euch schon vom MVVM Model gehört haben - Model, View, ViewModel. Daneben gibt es natürlich noch viele andere, MVC, Viiper etc.. Über Für und Wider der einzelnen Modelle möchte ich eigentlich garnicht sprechen, sondern eher über die Frage - "Wie binde ich zb. MVVM in mein Projekt ein?".. Ich habe schon das ein oder andere Projekt angefangen, einige beendet, aber nie so wirklich mit einem Entwicklungsstruktur wie MVVM gearbeitet, daher wollte ich das in mein neues Projekt gerne einbinden.

    Ich habe das so verstanden..

    Model - ist die Implementierung von meinem Datenmodellen... Wir haben also zB. eine "User class", die unser Nutzer Objekt modelliert.
    View - ist das wo die "Magie" passiert... Also unsere ContentView und LoginView etc. die der Nutzer sieht und mit der, der Nutzer interagieren kann.
    ViewModel - da kneifts mir im Hinterkopf. Laut einigen Seiten habe ich hier die Logik die zwischen Model und View steckt.. Also Netzwerkzugriffe, Datenverarbeitung und Listener, sobald sich Daten auf der View ändern. Das scheint für mich aber irgendwie unnötig komplex.

    Ein kleines Beispiel.

    Als Model habe ich zb. UserModel.swift, welches mir alle Daten zum Nutzer speichert.
    Die View wäre dann, zum Beispiel, die LoginView.swift, die mir die Eingabe des Nutzers einfängt (und hier würde ich rein logisch auch die Abfrage machen) ...
    Und das ViewModel wäre dann (in diesem Fall) ja, das abgreifen der eingegebenen Userdaten auf der LoginView.swift und das anschließende Vergleichen ob der Nutzer sich anmelden kann - oder?

    Gehen wir jetzt davon aus, ich habe eine App die recht viel mit einer Datenbank kommuniziert. Nach dem Modell würde ich dann ja an jeder Ecke wo ich einen DB Zugriff habe, ein eigenes ViewModel implementieren, dass diesen Datenbankzugriff macht.. Richtig?
    Sagen wir, wir haben später irgend eine Stelle in der App wo wir die Daten abgreifen würden, dann hätte ich neben meinem LoginViewModel noch das.. XyzDatenAbgreifenViewModel, wo wir ebenso einen Datenbankabgriff implementiert haben...?

    Für mich fühlt sich das erst einmal recht unübersichtlich an, denn dann habe ich ja an jeder Ecke und Kante einen Datenbank zugriff, je nachdem in welcher View ich welche Daten benötige. Ich würde das, gefühlsmäßig, irgendwo zentralisieren, dass ich meine Datenbankzugriffe in einer .swift File habe...

    Wenn man MVVM aber leben / implementieren möchte, würde man das doch so machen oder wie seht ihr das? Wie implementiert ihr denn solche Entwurfsmuster, bzw. macht ihr das überhaupt?

    Lg!
  • Hallo,
    also MVVM oder auch andere Patterns bedeutet ja nur, das Du Daten von der View trennst. Bei MVVM regelt das das ViewModel.
    Datenbank Zugriffe hat ja nix mit der View zu tun, also kommt das auch nicht ins ViewModel.
    Ich erstelle für sowas immer einen Service. Im Falle von Login, Register usw. eben einen AuthService der Daten aus der DB holt oder rein schreibt.
    Das LoginViewModel holt sich dann eine Instanz des Service und gibt an diesen einfach nur die Daten weiter, die es aus der View bekommt.
    Der Service arbeitet dann damit.

    Wenn Du jetzt andere Daten aus der DB holst, also zum Beispiel Artikel oder so, dann gibt es dafür einen eigenen Service.

    Für den Datenbank Zugriff oder die Erstellung der Datenbank usw. habe ich meist einen DB Manager der wiederum vom Service genutzt wird.

    Der Sinn dahinter ist eigentlich, das die Datenschicht ausgetauscht werden kann.
    Also wenn Du statt CoreData vielleicht Firebase nutzen willst, dann musst Du nur den DBManager austauschen. (Eventuell noch den Service anpassen) aber View und ViewModel bleiben gleich, ebenso das Model
  • MichaHo schrieb:

    Hallo,
    also MVVM oder auch andere Patterns bedeutet ja nur, das Du Daten von der View trennst. Bei MVVM regelt das das ViewModel.
    Datenbank Zugriffe hat ja nix mit der View zu tun, also kommt das auch nicht ins ViewModel.
    aaaah.. Ich honk hab gedacht du musst nach dem Pattern ALLES irgendwie in eines dieser Pattern(View, ViewModel oder Model) drücken. Und das hat mich dann gerade im Bezug der DB Zugriffe extremst verwirrt.
    Aber das hat mir enorm weiter geholfen, danke dir!
  • ja, das ging mir Anfangs auch so.
    Du kannst aber im ViewModel alles an Logik rein packen was du benötigst, auch DB Zugriff usw. du musst nicht eine Extra Schicht dafür haben.
    Es hilft halt eine extra Schicht dafür zu haben wenn das Projekt wächst, denn sonst hast Du Code Duplizierung überall und das willst du ja verhindern.

    Ich mache es halt immer abhängig vom Projekt. wenn ich nur 1 Model habe dessen daten in eine Tabelle in der DB soll, mach ich das auch schon mal im ViewModel.

    Ich hab mir das immer so hergeleitet:
    Das Model kennt nur seine Daten
    Das ViewModel kennt nur das Model (bei größeren Projekten natürlich noch die Services)
    Und die View kennt nur das ViewModel

    Somit kann 1 Viewmodel auch in mehreren Views verwendet werden.
  • Ich habe bisher nur MVC verwendet. Der (View)Controller verbindet dann das Datenmodell mit dem View.

    MichaHo schrieb:

    Der Sinn dahinter ist eigentlich, das die Datenschicht ausgetauscht werden kann.

    Also wenn Du statt CoreData vielleicht Firebase nutzen willst, dann musst Du nur den DBManager austauschen. (Eventuell noch den Service anpassen) aber View und ViewModel bleiben gleich, ebenso das Model
    Klingt von der Idee natürlich interessant, aber wie kann dies in der Praxis aussehen?

    Wenn ich z.B. CoreData verwende, dann verwende ich im (View)Controller z.B. einen NSFetchedResultsController. Wenn ich jetzt von CoreData z.B. auf Firebase umstelle, dann muss ich nicht nur den "DBManager" ändern/austauschen, sondern auch den (View)Controller anpassen, da ich NSFetchedResultsController dann natürlich nicht mehr verwenden kann.
  • der NSFetchedResultsController ist zB. in einem CoreDataManager implementiert (gekapselt), der wiederum dem Protokoll "ManageDataService" confirmed.

    ManageDataService > hat die Funktionen

    - getAllUsers
    - deleteUserWith(Id: String)
    - add(user: User)

    Den ManageDataService benutzt du als opaque Implementation (im Unterschied zur concrete Implementation, wenn du den CoreDataManager direkt einbinden würdest) zB in deinem DatenRepo, welches dann in dem ViewModel benutzt werden koennte.

    Nun kommt der Umstieg auf Firestore. Der FirestoreManager muss ebenso dem ManageDataService entsprechen und dessen Funktionen implementieren.
    Jetzt sind der CoreDataManager und der FirestoreManager vollkommen agnostisch. Das einzige was für dein DataRepo zählt, ist der ManageDataService.
    CoreDataManager, wie auch FirestoreManager entsprechen diesem Protokoll und können somit, ohne eine Zeile Code im DataRepo oder wo auch immer ManageDataService verwendet wird, ausgetauscht werden.

    PS: eigentlich würde man es nicht als ManageDataService Protokoll implementieren, sondern es als UseCases (Beispiel: GetAllUsersUseCase ) einbinden. Aber das würde jetzt echt zu weit führen.
  • MichaHo schrieb:


    Im Grunde ist das Protokoll das wichtige und alle DatenManager egal wo sie hin speichern implementieren das Protokoll.
    In den Controllern (benutze ich nie weil ich nur SwiftUI mache) oder in den ViewModels wird dann mit dem Protokoll gearbeitet, somit brauchst da nix zu ändern.
    Die Intention hinter der Verwendung eines Protokolls ist mir klar ... und auch der Wunsch einer kompletten Kapselung aller Abhängigkeiten zur Datenhaltungsschicht. Aber mir geht es wie @MCDan: Wenn ich z. B. für TableViews den NSFetchedResultsController verwende, interessieren mich nicht nur seine Methoden zur Datenbereitstellung, sondern auch viele Methoden des NSFetchedResultsControllerDelegate-Protokolls, z. B. um auf Aktualisierungen mit der UI zu reagieren.

    Insofern haben meine ViewController nicht selten Abhängigkeiten zur Datenhaltung. Natürlich könnte man auch dieses Protokoll abstrahieren (quasi doppeln) und bei Änderung der Datenhaltungsschicht zentral anpassen ... aber lohnt sich der Aufwand wirklich? Diese Frage mag sich bei Verwendung von SwiftUI nicht stellen, aber bei der "klassischen" Programmierung schon. Letztlich wohl eine Abwägung, wie viel Aufwand man in eine architektonisch saubere App investieren kann - und wie wahrscheinlich es ist, dass sich dieser Aufwand rentiert.

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Bei diesem Punkt habe ich (privat) mittlerweile auch so meine Zweifel.
    In eigenen Projekten schreibe in so gut wie nie Tests, somit entfällt damit einer der wesentlichsten Grund für die meisten Interfaces.

    Du hättest ohne die Masse an Interfaces mehr Übersicht in deinem Projekt und wärst schlicht schneller.

    Einen Trennung von BusinessLogic, Presentation und sagen wir Services, sollte es auch tun.
    Eine Architektur sollte nicht zum Selbstzweck werden. Diese Gefahr besteht im Besonderen bei Clean Architecture. Denn die hier sehr stark vertretenen UseCases machen Code oftmals in einer recht fragwürdigen Weise komplexer, wo sich dann wirklich die Frage stellt:
    Lohnt sich das denn noch?

    Ich habe für mich diese Frage noch nicht abschließend beantwortet. Aber ich weiss auch, dass ich den wichtigsten Grundsatz des Codes in den letzten Jahren etwas vernachlässigt habe.
    > Komplexität ist der größte Feind des Entwicklers / keep it simple <
  • Ich sehe das ähnlich. Das Ganze "theoretisieren" des Codes bringt eigentlich nur was, wenn du mit mehreren Leuten an einer Software sitzt. Dann kann man nämlich wunderbar einzelne kleine Module bearbeiten und ändern, ohne das es die anderen Team-Mitglieder betrifft oder wenn man ein Team für Model hat und ein Team fürs UI dann kann man sich viel besser absprechen und definieren was wie aussehen soll, wie es dann aber umgesetzt wird bleibt wieder jedem selbst überlassen.
    Im Endeffekt wird der Code dadurch aber aufgeblasen und alles andere als verständlicher.
    2 Stunden Try & Error erspart 10 Minuten Handbuchlesen.

    Pre-Kaffee-Posts sind mit Vorsicht zu geniessen :)
  • Wolf schrieb:

    Aufgeblasen? Ja, aber wenn gut gemacht dann auch wartbarer. und auf das kommt es an, selbstdokumentierender Code, der auch nach 1, 2 Jahren noch verständlich ist. Wie man das macht, kommt drauf an. Hier definiert das Ergebnis den Weg.
    So sehe ich das auch.
    Klar, es gibt als "Solo-Entwickler" sicher auch andere Möglichkeiten bzw. einfachere Möglichkeiten seinen Code in irgend einer Art und Weise zu dokumentieren - aber wenn du nach langer Zeit mal wieder rein guckst und nicht komplett verloren sein willst, dann finde ich so ein Model wie MVVM als Ansatz sehr gut.
    Zumal es dann später, sollte man die Möglichkeit haben in einem professionellen Team zu arbeiten, einfacher ist sich einzufinden.
  • Zitat: "... aber wenn du nach langer Zeit mal wieder rein guckst und nicht komplett verloren sein willst, dann finde ich so ein Model wie MVVM als Ansatz sehr gut"

    MVVM ist das architectural pattern, welche SwiftUI zugrunde liegt. Sollte das nicht so dein Ding sein, dann wird es schnell schwierig :)

    Wenn dir das öfters passieren sollte, wird dich MVVM erstens nicht retten und zweitens wird es dann Zeit, sich mit dem grundlegenden Aufbau von SoftwareProjekten zu befassen.

    Zitat: "Einen Trennung von BusinessLogic, Presentation und sagen wir Services, sollte es auch tun." > kann da helfen.

    Aber MVVM pros und contras waren nicht Thema des Einwurfs vom Mattes, es ging um etwas vollkommen anderes.

    Beispiele:
    - Domian Driven Design
    - Clean Architecture
    - Event-Driven Microservices Architecture
    - Async Composable Architecture
    - TDD / BDD
    - reactive programming / Streams

    All diese Dinge kommen mit einem erheblichen Overhead einher. Und die Frage war, macht dies wirklich Sinn, diesen Ansätzen zu folgen, denn mit jedem ArchitekturElement steigt die Komplexität. Und diese wird häufig zu einem grösseren Problem, denn der versprochene Nutzen der Technik.

    Beispiel: TDD

    Alle sagen, wir machen TDD > die Wahrheit ist, es macht fast niemand in Reinform. TDD ist seit seiner Einführung sehr umstritten und gilt als ein Ding, was sehr schnell zu einem Monster auswachsen kann, welches mehr TestCode, denn ProductionCode erfordert. Um dieses Missverhältnis ging es im Kern.
  • Dieser Tread aus den Apple Developer Foren hat es gerade auf meine Leseliste geschafft: Bei etwas Muße in den nächsten Tagen werde ich mich mal durch die Postings wühlen und versuchen zu verstehen, warum SwiftUI eigentlich ohne MVVM eingesetzt werden sollte … für mich als Newbie in beiden Themen wird das spannend :)

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von MyMattes ()