Lessons Learned @ NZZ – Teil 4 – Symfony2 Controller

Beruflich arbeite ich momentan intensiv mit Symfony2. Wir hatten in den letzten 1,5 Jahren im Team immer wieder grosse Meinungsunterschiede, welchen Ansatz man für Symfony2 Controller wählen soll.

  • Direkt vom Symfony2 Controller erben?
  • Die Controller als Services aufsetzen und alle benötigten Services per Dependency Injection übergeben?
  • Die Controller als Services instanzieren und nur den Container per Dependency Injection übergeben und die Services aus dem Container laden?

Es gibt für alle 3 Positionen pro’s und kontra’s. Einige von unseren Argumenten, waren aber geprägt von der bereits bestehenden Umgebung/Applikation. Eigentlich sollte man aber von einer idealen Umgebung ausgehen und überlegen, was das beste ist und erst dann auf die bestehende Situation adaptieren.

Was ist die Aufgabe eines Controllers?

Als erstes sollte man verstehen, was die Aufgabe eines Controllers in der Webentwicklung ist.

  1. Request zu einem Modelrequest konvertieren
  2. Anfrage an Model
  3. Fehlerhandling
  4. Korrekte View auswählen
  5. Model an View weiterleiten

Wie man hier schön sehen kann, macht ein Controller nicht sehr viel. Er sollte also möglichst klein sein und nur die ihm zugetragenen Aufgaben erledigen (Idealerweise zwischen 10-20 Zeilen Code).

Unsere Controller und unsere Argumente

Wir hatten fat Controller, was bedeutet, wir haben alles mögliche in die Controller gepackt (ja, ich weiss, das ist nicht gut). Natürlich war die Situation wieder einmal dem Termindruck geschuldet und wie es halt so ist, wenn einmal ein gewisses Design da ist, dann macht man halt das gleiche, wie der Kollege vorher.

Vom Symfony2 Controller vererben, Services aus Container beziehen

  • + Es ist so offiziell in der Doku
  • + Symfony2 Controller bietet bereits viele nützliche Funktionen und Services an
  • – Es kann zu schlechtem Design führen, weil jederzeit irgendwo irgendwelche Services aus dem Container geladen werden könnten

Controller als Service + Services als Dependency Injection

  • + Man weiss schon im Konstruktor, welche Services verwendet werden.
  • + Es besteht nicht die Gefahr, dass irgendwo im Verlaufe des Controllers über den Container nicht existierende oder fehlerhafte Services verwendet werden
  • + Man hat Code Completion in der IDE

Erkenntnisse

Ich hoffe jetzt mal, dass die Argumente im vorherigen Abschnitt Sinn für Euch machen. Es gibt sicher noch mehr. Einige der Argumente entstanden aber nur, weil wir im Controller das Single Responsibility Principle verletzten. Uns war nicht wirklich bewusst (bzw. wir haben nicht lange genug darüber nachgedacht), was ein Controller genau zu tun hat. Dadurch entstanden interessante aber falsche Argumente.

Wir haben uns nun dazu entschieden, von den Symfony2 Controllern zu vererben und die Controller sollten als Faustregel nicht länger als 20 Zeilen beinhalten. Jetzt kann man die Argumente, die für den Controller als Service sprechen leicht entkräften.

Es kann zu schlechtem Design führen, weil jederzeit irgendwo irgendwelche Services aus dem Container geladen werden könnten.
Man weiss schon im Konstruktor, welche Services verwendet werden.

Weil die Methoden jetzt klein sind, müssen generell nur wenige Services geladen werden, der Code ist/bleibt übersichtlich.

Es besteht nicht die Gefahr, dass irgendwo im Verlaufe des Controllers über den Container nicht existierende oder fehlerhafte Services verwendet werden.

Ok, die Gefahr besteht immer noch, aber mit funktionalen Tests und dem wenigen Code ist dies sehr einfach zu verhindern. In der vorherigen Situation mit riesen Controllern, war es echt heavy gute Funktionale Tests zu schreiben.

Man hat Code Completion in der IDE

Durch die kurzen Methoden, ist dies nicht mehr wirklich relevant.

Was nun mit unseren Fat Controllern?

Das klingt ja alles schön und gut, wenn man auf der grünen Wiese beginnt, aber was machen wir nun mit unseren bestehenden Controllern?

Refactoring, refactoring, refactoring. Uns bleibt nichts anderes übrig, als Schritt für Schritt Aufgaben im Controller Code zu identifieren und in Serviceklassen auszulagern.

Entscheidend ist, dass alle die gleiche Vorstellung davon haben, wie der Code bzw. die Controller in Zukunft aussehen sollen und jeder ein kleines Stück dazu beitragen kann.

Quellen

 

3 Responses

  1. Meine Controller erben im Grunde auch vom Symfony2 Controller. So erspart man sich zu einem jeden Controller als Service zu registrieren und zum anderen kann man die “Short-Cuts-Methoden” von Symfony2 verwenden.

    Das Problem mit dem “Code Completion” in der IDE kann man umgehen, in dem man selber eine Abstrakte Controller Klasse erstellt, die vom Symfony2 Controller erbt. Alle anderen Controller erben dann von der eigene Abstrakten Controller Klasse, die unter anderem eigene “Short-Cuts-Methoden” bereitstellt.

  2. This article is very informative but it took me a long
    time to find it in google. I found it on 20 spot, you should focus
    on quality backlinks building, it will help you to rank to google top 10.

    And i know how to help you, just type in google – k2 seo tips and tricks

Leave a Reply

Your email address will not be published. Required fields are marked *