Semantik im MVC-Pattern

Wednesday, 29 August 2007, 09:53 von Blackflash

Wer schon häufiger und vor allem auch umfangreicher mit dem MVC-Pattern programmiert hat - sei es mit einem Framework wie dem Zend Framework oder einer Eigenproduktion, sowie bei mir MVCLite - wird wissen, dass es gelegentlich gar nicht so einfach ist, seine Controller zu gestalten.
Was macht es schwierig? Die Interdependenzen.
Warum? Eine Komponente gehört logisch zu einer anderen Komponente.
Was heißt das? Als Beispiel führe ich einen Webshop an. Webshop ist die gesamte Komponente. In dieser Komponente gibt es weitere Komponenten wie z.B. die Artikel oder den Warenkorb. Zu diesen Artikeln sollen allerdings auch Rezensionen geschrieben werden können, die dann wiederum bewertet werden können (siehe Amazon).
Wie wird so was ermöglicht? Ich versuche es mal darzustellen.

+--+ Webshop | +--+ Artikel | | | +--+ Rezensionen | | | +--+ Bewertungen | +--+ Warenkorb

Hier sieht man die Struktur der Unterkomponenten. Zu jeder Komponente gehören einige Aktionen, die man ausführen kann:

  • Artikel
    • Erstellen/Ändern
    • Löschen
    • Anzeigen
  • Rezensionen
    • Erstellen/Ändern
    • Löschen
    • Anzeigen
  • Bewertungen
    • Abgeben
  • Warenkob
    • Artikel hinzufügen und entfernen
    • Bestellung aufgeben

Dies ist nur eine kurze Liste und zeigt nur einige der wichtigsten Möglichkeiten an. Wie würde so was im Controller aussehen: Ich stelle es mir mal vor:

public function addArticleAction (); [...] public function addArticleReviewAction (); [...] public function addArticleReviewRatingAction (); [...]

Natürlich kann man einige Methoden auch besser benennen, aber das geht leider nicht immer. Daraus entstehen unelegante URLs:

/webshop/addArticle
[...]
/webshop/addArticleReview
[...]
/webshop/addArticleReviewRating
[...]

Die finde ich nicht nur sehr unleserlich, sondern auch sehr verwirrend. Dennoch müssen die URLs semantisch sein. Aber es geht nicht nur um die Schönheit der URLs und deren Methodennamen. Nein, es hat direkten Einfluss auf den Code. Wenn ich alles in den Webshop-Controller implementiere, dann wird der Controller riesig mit mehreren tausend Zeilen Code - was natürlich immer vom Programmierer und dem tatsächlich Umfang zusammenhängt -, was die unliebsame Tendenz zeigen soll.
Nebenbei möchte ich anmerken, dass man mittels des Zend Frameworks die "Ebenen" mit den Modulen möglich ist. Dadurch würden die URLs folgendermaßen aussehen:

/webshop/article/add
[...]
/webshop/article/addReview
[...]
/webshop/article/addReviewRating
[...]

Besser, aber dennoch nicht perfekt. Die Kapselung ist definitiv besser, aber es löst das Problem einfach noch nicht. Eine weitere Idee, die mir gekommen ist, sieht folgendermaßen aus:
Vor jeden Großbuchstaben in der Action-Methode wird ein Slash gesetzt.

// ohne die Module im ZF public function articleAddAction (); [...] public function articleReviewAddAction (); [...] public function articleReviewRatingAddAction (); [...]

Daraus enstünden folgende URLs:

/webshop/article/add
/webshop/article/review/add
/webshop/article/review/rating/add

Sieht auf jeden Fall sehr semantisch und lesbar aus. Das darunterliegende Prinzip wird außerdem nicht so deutlich sichtbar, wie bei der Verwendung von Methodennamen ohne den Suffix "Action".
Leider löst es das Problem überfüllter Controller nicht.

Mein Ansatz zur Lösung des Problems ist simpel aber dafür sehr effektiv. Nebenbei muss ich sagen, dass keine Module verwendet werden.
Ich erstelle neue Controller:

  • WebshopController
  • ArticleController
  • ReviewController
  • RatingContrller

Der WebshopController ist die Eingangsseite des Webshops und stellt die Seite zusammen, ist für die technische Seite eher nicht von Belang.
Ich erstelle jetzt einfach mal die Signaturen der verschiedenen Controller:

// ArticleController public function addAction (); public function deleteAction (); public function editAction(); public function indexAction (); public function showAction (); // ReviewController public function addAction (); public function deleteAction (); public function editAction(); public function indexAction (); // RatingController public function addAction (); public function deleteAction (); public function indexAction ();

Die URLs nochmal aufzulisten tue ich der Kürze halber nicht.

Nun sind die ganzen Funktionalitäten in eigene Controller ausgelagert worden. Der logische Zusammenhang ist anhand der URL zwar nicht mehr zu erkennen, aber dafür wird der Code wartbarer, was meiner Meinung nach wichtiger sein sollte. Wenn wirklich Bedarf besteht, den logischen Zusammenhang in der URL ersichtlich zu machen, gibt es nette Features wie mod_rewrite, die so was ändern können.
Ein Manko ist jedoch, dass es bei einer großen Applikation zu Problemen kommen kann, wenn man wirklich viele Controller hat, aber so was ist bei wirklich großen Projekten häufig der Fall.
Durch diesen neuen Aufbau ist es übrigens viel leichter möglich, sie auf andere Komponenten anzuwenden: Die Wiederverwendbarkeit wird signifikant gesteigert. Warum keine schriftl. Bewertungen für Verkäufer einführen mithilfe des ReviewControllers? Das ist jetzt ganz einfach:

// ReviewController public function addAction () { // $component ist ein über den URL übergebener Parameter // $data ist der Inhalt der Rezension switch ($component) { default: case 'Article': $this->reviewArticle($data); // korrektes Template setzen break; case 'Seller': $this->reviewSeller($data); // korrektes Template setzen break; } }

Wie der restliche Code aussieht, wird sicherlich leicht zu erahnen sein, weshalb ich darauf nicht näher eingehen werde.
Wer dennoch Vorschläge bzgl. grundlegenden Verfahren hat, der darf sich gerne bei mir melden. ;-)
Es mag vllt. so aussehen, als ob dieses zu einem überfüllten ReviewController mutiert, wenn man den ReviewController exzessiv wiederverwendet, aber die Aussage muss ich relativieren, denn die Rezensionen sind immer sehr ähnlich aufgebaut, sodass ein Großteil des Codes wiederverwendet werden kann. Sicherlich gibt es u.U. bei verschiedenen Komponenten einige spezielle Eigenschaften, aber der Großteil bleibt doch konsistent.

Wie ich hoffentlich zeigen konnte, ist die Semantik ein wichtiger Punkt in MVC-Applikationen. Und ich würde mich freuen, wenn ich euch auch näher bringen konnte, wie man mehr Semantik in den MVC-Pattern einfließen kann.

Im Übrigen werden ich dieses System demnächst auch auf meiner eigenen Webseite integrieren. Es handelt sich dabei um die Kommentare, sodass man endlich meine Blogeinträge kommentieren kann. Natürlich werde ich dann von dem Aufbau profitieren, sodass man später sicherlich auch Inhaltsseiten oder andere Komponenten kommentieren kann.

Kommentare


Kommentiere!

Your Name:


Your Email:


Your URL:


Spam Prevention:
Enter the text above into the box below.
If you are unable to read it, refresh the page.


Your Comment: