Am heutigen Tage durfte ich das vielversprechende Rails-Pluging Rails Cells einmal genauer inspizieren. In einem aktuellen Projekt wären alle Voraussetzungen erfüllt, die den Einsatz dieses "Mini-MVC"-Frameworks im MVC-Framework rechtfertigen würden:
- aufwändige Display-Logik mit einer großen Menge an bedingten Ausgaben
- Datenbank-Abfragen in Views (á la
Users.find_by_trallalla.each {...}
) - Helper-Methoden, die nur an einer Stelle aufgerufen werden, um dort die View zu entrümpeln
- Controllermethoden, die assoziierte Resourcen der eigentlich darzustellenden Resource laden, weil "sie" wissen, dass sie irgendwo in der entsprechenden View verwendet werden (was zu Fehlern führen kann, wenn die View in einem anderen Kontext wiederverwendet wird)
- Partials, die nur an einer stelle verwendet werden, um die "Haupt-View" "übersichtlicher" zu halten
Cells verspricht in solchen Fällen Besserung, da es ein ähnlich Komponentenbasiertes Oberflächendesign erlaubt wie es in Desktopanwendungen oder JSF etc. schon lange verwendet wird: einzelne Komponenten (Cells) enthalten sowohl eine Logik- als auch eine Darstellungsschicht und kapseln so Helper und Templates für einen abgegrenzten Oberflächenbereich. Cells agieren wie stark abgespeckte Rails-Controller, ihre Methoden werden States genannt. So kann man sich z.B. eine Login-Box als GUI-Komponente vorstellen, die wie folgt verwendet wird:
in /app/cells/loginboxcell.rb:
class LoginBoxCell < Cell::Base
def logged_out
# lots of display logic
# ...
# If a string is returned, it will be shown as the result.
# However, we want the template logged_out.html.erb to be rendered
# so we return nil here:
nil
end
def logged_in
# lots of display logic
nil
end
def super_special_login_button
"<button #{complex_stuff_here}>Yay!</button>"
end
end
in /app/cells/loginbox/loggedout.html.erb:
<div class="login_box">
<!-- here goes lots of HTML and a login form -->
<!-- cells can include cells -- this makes them SO useful -->
<% render_cell :login_box, :super_special_login_button %>
</div>
in /app/views/layout/application.html.erb:
<!-- lots of HTML -->
<%= render_cell :login_box, (logged_in? ? :logged_out : :logged_in) %>
<!-- more lots of HTML -->
Wie man sieht, ist in der "herkömmlichen" View nicht mehr oder weniger zu sehen als beim Aufruf eines render :partial
-Aufrufes. Jedoch stellt die Cell an dieser Stelle eine in sich abgeschlossene Komponente dar, die ihre eigene Displaylogik kennt und von anderen Bereichen der Applikation abkoppelt. So wird man keine Partials und Helper-Methoden mehr zusammensuchen müssen, wenn man die Loginbox an anderer Stelle (z.B. in einem anderen Projekt?) wiederverwenden möchte.
Ich höre schon leise Schreie aus dem Hintergrund, Wiederverwendung werde maßlos überbewertet. Diese Meinung pflege ich durchaus zu teilen, mehr noch nachdem ich Heute in besagtem Projekt einige Teile der UI nach Cells Refactor'd habe (kennt jemand dafür bitte auch ein deutsches Wort?). Vorläufiges Fazit der Aktion:
- der Code wird insgesamt nicht sauberer oder aufgeräumter
- man wundert sich, wie wenig signifikante Wiederholung in einem Rails-Projekt auftritt, die man nicht schon sehr effektiv durch den geschickten Einsatz von Helpermethoden erschlagen kann.
- im Zusammenspiel mit Rails 2.1 erscheint Cells noch sehr unausgereift. der Aufruf von render_cell aus einem Controller heraus (was im Zusammenspiel mit XmlHttpRequests sehr attraktiv wäre) funktioniert z.B. noch nicht. Auch das Zusammenspiel mit dem Rails-Routing, Gettext-internationalisierung und Helper-Modulen klappt noch nicht reobungslos. Vielleicht sieht das in Rails 2.3 besser aus, was sich in den nächsten Tagen zeigen wird.
- Eine Oberfläche im Nachhinein in Komponenten zu zerlegen macht wenig Sinn, vielmehr sollte man seine Oberfläche aus Komponenten aufbauen.
- ein Totschlagargument für dieses Projekt: Cells verwendet eine eigene, modifizierte Version des Rails-Template-Finder-und-Rendering-Systems, genauso wie das verwendete Dynamime-Plugin. Somit können beide Plugins nicht ohne Monkey-Patching miteinander spielen.
Insgesamt sieht dieses Fazit etwas negativ-lastig aus, was jedoch nicht meinen Gesamteindruck widerspiegelt. In Cells steckt durchaus großes Potential, wenn man sich frühzeitig in seiner Applikation dafür entscheidet und seine Oberflächen entsprechend Aufbaut. Gerade wenn die Reise etwa in Richtung Web2.0-Ajax-Rich-UI-$foo geht, kann ich mir einen enormen Gewinn an Modularität vorstellen.
Ich könnte mir vorstellen, dass Cells in Rails 2.3 im Zusammenspiel mit Metal eine interessante und performante Lösung für Ajax-Anwendungen mit viel Client-Server-Kommunikation darstellen könnte. Die Ecke gilt es in den nächsten Wochen zu erkunden.
Weitere Seiten zu Cells: