Softwarearchitektur verstehen und entscheiden

Aaron KreisÜber mich
Anwendungsarchitektur

Model View Controller

Trennung von Daten, Anzeige und Steuerung

Die Idee und ihr Nutzen

Die Sachbearbeiterin Frau Meier öffnet in der Schadenanwendung ihrer Versicherung den Schaden 4711 und klickt auf „Freigeben“. Drei getrennte Programmteile erledigen das. Der erste nimmt den Klick entgegen, ruft den zweiten auf und wählt danach die Anzeige. Der zweite prüft Betrag und Berechtigung und ändert die Daten des Schadens. Der dritte zeigt Frau Meier das Ergebnis an. Weil die Freigaberegel nicht im Programmteil für die Anzeige steht, können eine Webseite und eine mobile Fassung der Schadenanwendung dieselbe Regel nutzen, ohne sie doppelt zu programmieren. Diese Aufteilung heißt Model View Controller, kurz MVC. Die drei Rollen heißen Controller (Steuerung), Model (Daten und Regeln) und View (Anzeige).

Bausteine: Frau Meier: klickt „Freigeben“; Controller: nimmt den Klick an, steuert den Vorgang; View: zeigt das Ergebnis, enthält keine Regeln; Model: Daten und Regeln: Betrag und Berechtigung. Verbindungen: Frau Meier — Controller; View — Frau Meier; Controller — Model; Controller — View (wählt die Anzeige). Der Controller steuert, das Model enthält Daten und Regeln, die View zeigt an; die Freigaberegel steht nur im Model.

Wie funktioniert es?

Frau Meier öffnet den Schaden 4711. Der Controller lässt das Model die Daten laden, und das Model liefert den Betrag von 12.000 Euro und den Status „offen“. Der Controller übergibt die Daten des Schadens an die View, die Betrag, Status und den Knopf „Freigeben“ anzeigt. Frau Meier klickt auf „Freigeben“. Der Controller startet im Model den Vorgang „Schaden freigeben“ für Schaden 4711 und Frau Meier. Das Model prüft, ob Frau Meier für diesen Schaden zuständig ist, und vergleicht den Betrag mit ihrer Freigabegrenze. Die Freigabegrenze ist der Betrag, bis zu dem Frau Meier einen Schaden allein freigeben darf. Ihre Freigabegrenze liegt bei 10.000 Euro, der Schaden beträgt 12.000 Euro. Das Model gibt den Schaden deshalb nicht frei, sondern setzt den Status auf „zweite Freigabe ausstehend“. Der Controller erhält dieses Ergebnis und lässt die View den neuen Status zeigen.

Das Model enthält die Daten und die fachlichen Regeln dazu. Zu den Daten gehört der Schaden mit Betrag und Status, zu den Regeln der Vorgang „Schaden freigeben“ mit der Prüfung der Freigabegrenze. Die View zeigt nur an, was sie vom Controller bekommt, und enthält keine fachlichen Regeln. Der Controller nimmt Eingaben entgegen, ruft den passenden Vorgang im Model auf und wählt anschließend die View aus, die das Ergebnis zeigt. Bekommt die Schadenanwendung später eine mobile Fassung, braucht die mobile Fassung nur eine eigene View und einen eigenen Controller. Der Controller der mobilen Fassung ruft denselben Vorgang im Model auf.

Die Schadenanwendung läuft heute als Webanwendung im Browser. Klickt Frau Meier auf „Freigeben“, schickt der Browser eine Anfrage an den Server. Auf dem Server nimmt der Controller die Anfrage entgegen, und am Ende erzeugt die View aus dem Ergebnis eine Webseite, die der Browser anzeigt. Webanwendungen werden meist mit einem Programmrahmen gebaut, einer fertigen Programmbibliothek, die jede Anfrage aus dem Browser an den passenden Controller weiterleitet. Je nach Programmrahmen stehen die fachlichen Regeln im selben Programmteil wie die Daten des Schadens oder in einem eigenen Programmteil.

In Programmen auf dem Arbeitsplatzrechner meldet das Model Änderungen dagegen häufig direkt an die View, damit sich die Anzeige sofort aktualisiert. Ändert sich der Status von Schaden 4711, zeigt die View dann den neuen Status, ohne dass der Controller sie dazu auffordert.

Model View Controller: Freigabe über 10.000 Euro bleibt offen

Beteiligte: Frau Meier: Freigabegrenze 10.000 Euro; View: zeigt Schaden und Knopf „Freigeben“, ohne Regeln; Controller: nimmt Eingaben an, ruft das Model, wählt die View; Model: Schaden und Vorgang „Schaden freigeben“ mit Grenzprüfung. Ablauf: 1. Frau Meier öffnet den Schaden 4711. 2. Der Controller lässt das Model die Daten von Schaden 4711 laden. 3. Das Model liefert den Betrag von 12.000 Euro und den Status „offen“. 4. Der Controller übergibt die Daten des Schadens an die View, die Betrag, Status und den Knopf „Freigeben“ anzeigt. 5. Frau Meier klickt auf „Freigeben“. 6. Der Controller startet im Model den Vorgang „Schaden freigeben“ für Schaden 4711 und Frau Meier. 7. Das Model prüft die Zuständigkeit und vergleicht 12.000 Euro mit der Freigabegrenze von 10.000 Euro. Weil der Betrag darüber liegt, setzt das Model „zweite Freigabe ausstehend“. 8. Der Controller erhält vom Model das Ergebnis „zweite Freigabe ausstehend“. 9. Der Controller lässt die View den neuen Status zeigen. Eine mobile Fassung bräuchte nur eine eigene View und einen eigenen Controller; die Freigabegrenze gilt dort ebenso.

Wann ist es sinnvoll und wann nicht?

MVC lohnt sich

  • Eine Webanwendung oder eine andere Oberfläche zeigt Nutzern Daten an und lässt die Nutzer die Daten bearbeiten. Ohne Aufteilung stehen Anzeige, Eingabe und Freigaberegel im selben Programmteil, und jede Änderung an der Seite berührt auch die Freigaberegel.
  • Die fachlichen Regeln sollen für mehrere Oberflächen gelten. Steht die Prüfung der Freigabegrenze im Code der Webseite, direkt beim Knopf „Freigeben“, muss sie für die mobile Fassung ein zweites Mal programmiert werden. Vergisst das jemand, kann über die mobile Fassung ein Schaden ohne Prüfung freigegeben werden.
  • Die fachlichen Regeln sollen sich ohne die Anzeige testen lassen. Ein automatischer Test übergibt dem Model zum Beispiel einen Schaden über 12.000 Euro und eine Freigabegrenze von 10.000 Euro und prüft, ob das Model „zweite Freigabe ausstehend“ setzt. Eine Webseite muss der Test dafür nicht aufrufen.
  • Die Gestaltung der Seiten ändert sich häufiger als die fachlichen Regeln. Ändert sich die Farbe des Knopfs „Freigeben“, ändert das Team für die Webseite nur die View und kann die Freigaberegel dabei nicht versehentlich beschädigen. Stünden Datenbankzugriff, Freigaberegel und Aufbau der Seite in einem einzigen Programmteil, müsste dieser Programmteil auch für eine neue Knopffarbe angepasst werden.
  • Die Teams für Webseite und mobile Fassung sollen getrennt arbeiten. Jedes der beiden Teams arbeitet an eigenen Views und Controllern, ohne sich bei der fachlichen Regel abstimmen zu müssen. Stünde die Freigaberegel in den Controllern beider Fassungen, müssten das Team für die Webseite und das Team für die mobile Fassung jede Änderung der Regel gemeinsam vornehmen.

MVC ist nicht das Richtige

  • Die Oberfläche im Browser merkt sich viele Eingaben und Zwischenwerte und berechnet vieles selbst. Ein Beispiel ist eine Seite, die beim Tippen sofort Beträge neu berechnet. Mit MVC auf dem Server müsste der Browser nach jeder Eingabe eine Anfrage an den Server schicken, und der Controller müsste die View jedes Mal eine neue Webseite erzeugen lassen. Dann baut das Team die Oberfläche nach Model View ViewModel. Ein Zwischenmodell hält dabei die Eingaben und Zwischenwerte, und die Anzeige aktualisiert sich von selbst, sobald sich das Zwischenmodell ändert. Verbindliche Regeln wie die Freigabegrenze prüft weiterhin das Programm auf dem Server.
  • Das Programm hat keine Oberfläche. Ein Beispiel ist ein nächtlicher Rechnungslauf. Dann besteht der Rechnungslauf nur aus seinen fachlichen Regeln und dem Datenzugriff. View und Controller, die nichts anzeigen und keine Eingaben annehmen würden, entfallen.
  • Die Anwendung ist klein, hat eine einzige Seite und kaum fachliche Regeln. Es gibt keine zweite Oberfläche, die dieselben Regeln nutzen müsste, und kaum Regeln, die sich getrennt testen ließen. Dann schreiben die Entwickler Anzeige, Eingabe und die wenigen Regeln in einen Programmteil. Drei getrennte Programmteile und die Übergaben zwischen ihnen entfallen.
  • Nicht nur die Oberfläche, sondern die ganze Anwendung soll aufgeteilt werden, auch der Datenzugriff. MVC ordnet nur die Oberfläche und legt nicht fest, wo der Datenzugriff steht. Dann teilen die Entwickler die ganze Anwendung nach der Layered Architecture in Schichten für Oberfläche, fachliche Regeln und Datenzugriff. Die Oberfläche ruft nur die fachlichen Regeln auf, und nur die fachlichen Regeln rufen den Datenzugriff auf. MVC ordnet dann nur noch die Schicht für die Oberfläche.

Nachteile und typische Fehler

Drei Rollen bedeuten mehr Dateien und mehr Übergaben als ein einziger Programmteil, der alles erledigt. MVC ordnet nur die Oberfläche. Wie das Model selbst aufgebaut ist, etwa wo es auf die Datenbank zugreift, legt MVC nicht fest; große Anwendungen brauchen dafür zusätzlich eine eigene Aufteilung, etwa in Schichten für fachliche Regeln und Datenzugriff. MVC verhindert auch nicht von selbst, dass eine Regel im falschen Programmteil landet. Die Teams müssen deshalb bei der Durchsicht des Codes darauf achten, wo neue Regeln stehen. Wer einen Programmrahmen wie Spring MVC oder Ruby on Rails nutzt, bindet sich zudem an dessen Auslegung der drei Rollen.

Typische Fehler und woran man sie erkennt:

  • Regel im Controller: Die Prüfung der Freigabegrenze steht im Controller der Webseite statt im Model. Die mobile Fassung hat einen eigenen Controller ohne diese Prüfung, und dort lassen sich Schäden über 10.000 Euro freigeben. Erkennbar ist das an Freigaben über der Freigabegrenze, die nur über eine der beiden Oberflächen entstehen.
  • Controller mit fremden Aufgaben: Der Controller nimmt nach und nach Datenbankzugriffe und Regeln auf, die ins Model gehören, und wird zu einem großen Programmteil. Ein Entwickler schreibt zum Beispiel die Abfrage aller offenen Schäden von Frau Meier direkt in den Controller, weil das ohne Änderung am Model geht. Jede Änderung an der Seite berührt dann wieder die Regeln. Erkennbar ist das an Controllern mit Hunderten Zeilen und an Tests, die nur über die Webseite möglich sind.
  • Regel in der View: Die View blendet den Knopf „Freigeben“ bei Beträgen über 10.000 Euro aus, aber das Model prüft die Freigabegrenze nicht. Ein ausgeblendeter Knopf ersetzt diese Prüfung nicht: Eine direkt an den Server geschickte Anfrage gibt den Schaden trotzdem frei. Erkennbar ist das an Freigaben über 10.000 Euro, die ohne Prüfung im Model durchgehen.
  • Missverstandene Rollen: Die drei Begriffe werden in verschiedenen Programmrahmen unterschiedlich ausgelegt. Zwei Teams verstehen deshalb unter „View“ und „Controller“ Verschiedenes, etwa weil in Django die View die Rolle des Controllers übernimmt. Regeln landen dann in unterschiedlichen Programmteilen. Erkennbar ist das an gleichartigen Prüfungen, die in verschiedenen Rollen programmiert sind.

Weiterführend

Verwandte Ansätze

  • Separation of Concerns: der Grundsatz, jede Aufgabe in genau einem Programmteil zu erledigen, der hinter der Aufteilung in Model, View und Controller steht.
  • Inversion of Control: beschreibt, dass ein Programmrahmen den Code der Anwendung aufruft und nicht umgekehrt. Bei MVC ruft der Programmrahmen den passenden Controller auf.

Werkzeuge und Umsetzungen

  • Spring MVC: Programmrahmen für Webanwendungen in Java nach MVC.
  • Ruby on Rails: Programmrahmen für Webanwendungen in der Programmiersprache Ruby, der MVC fest vorgibt.
  • ASP.NET Core MVC: MVC-Programmrahmen der Plattform .NET.
  • Laravel: Programmrahmen für die Programmiersprache PHP mit MVC-Aufbau.
  • Django: Programmrahmen für Python nach demselben Prinzip, dessen Rollen Model, Template und View heißen.

Quellen

  • Martin Fowler: GUI Architectures: ordnet MVC als Trennung von Anzeige und Fachlogik ein, beschreibt die Benachrichtigung der View durch das Model und die unterschiedlichen Auslegungen des Begriffs.
  • Microsoft: Overview of ASP.NET Core MVC: erklärt die Aufgaben von Model, View und Controller in einer Webanwendung und rät, fachliche Regeln aus dem Controller ins Model zu verlagern.