Ich habe mich ein bisschen verfahren mit dem Projekt Pressure. Nein, ich habe nicht aufgegeben, aber ich habe mich in einigen Dingen in der Entwicklung etwas ungünstig entschieden.
Das Ende vom Lied ist, dass ich teilweise das CMS neu schreibe. Als Grundlage für die neue Code-Basis dient mir nun ein ziemlich gut vorausgestattetes Rails-Template. Ich habe schon zwar davon gelesen, aber diesmal auch selbst ausprobiert, ein neues Projekt anhand eines Templates zu generieren kann viele Dinge von Anfang an erleichtern, sofern das Template mit den gewünschten Einstellungen daherkommt.
Was ich noch festgestellt habe:
Test Driven Development (TDD) [→] und Behavior Driven Development (BDD) [en:→] sind tolle Sachen, erfordern aber auch Einarbeitung und Gewöhnung. Die Vorteile sind ja unbestritten, man erstellt Code, der zuvor geschriebene Tests durchläuft, da diese ja die Ausgangsbasis für den Code stellen. Auch beim verhaltensbasierten Entwickeln steht die zu erreichende Funktionalität am Anfang inklusive einiger Test-Szenarien, die der Code ebenfalls durchlaufen muss.
In der Rails-Entwicklergemeinde sind wohl die Gems Cucumber (BDD) und Rspec (TDD) für beide Entwicklungsarten die bevorzugte Wahl.
Für mich haben diese beiden Paradigmen aber auch einen kleinen bitteren Nebengeschmack: die ersten Erfolge stellen sich nun wesentlich später ein, da man zuvor mit viel Schreib-Overhead beladen wird. Denn: die Features und Szenarien wie auch die Tests müssen ja erst geschrieben werden. Und dann stellt sich mir die Frage, ob ich eher auf Cucumber oder Rspec setzen soll, denn beides zugleich frisst dann doch zuviel Zeit. Wobei ich ohnehin schon auf eine kleine Fußangel bei Cucumber gestoßen bin: es lässt sich viel eher für den äußeren Test des Codes einsetzen (wie erfährt der Nutzer die Rails-Anwendung), während man mit Rspec viel eher unter der Bühne arbeitet (also systemnah, direkt einzelne Komponenten unabhängig voneinander testen).
Während ich also mit Cucumber als Allererstes beschreibe, was ich mit der Anwendung machen will, überprüfe ich dann mit Rspec die Arbeitsweise der Modelle, Controller und Helper (Views müssten theoretisch ja gar nicht mehr mit Rspec noch einmal durchexerziert werden, da ich dies ja bereits mit Cucumber erledigt habe; Tests sollte man aber vielleicht trotzdem schreiben).
Wie ihr seht, geht also schon viel Zeit am Anfang flöten, die hoffentlich hintendran aber dann wegfällt. Es heisst ja wohl ohnehin, dass bei der Entwicklung einer Software mehr Zeit ins Testen als in die Code-Basis selbst gesteckt wird. Mit den oben genannten Paradigmen verlegt man aber das Testing bereits an den Anfang und spart sich somit Zeit am Ende.
Warum? Wie ebenfalls oben schon erwähnt, werden ja die Tests nicht erst im Nachhinein geschrieben, sondern dienen als Baubeschreibung. Außerdem verleitet das sicherlich auch nicht dazu, die sonst nachgegliederten Tests an die Anwendung anzupassen (man kann sich beim Entwickeln bestimmt so einiges schön reden ;o). Siehe hierzu auch das Grey-Box-Testing [→].
Rails, Routing und Dynamik
Mein größtes Problem an Rails ist das Routingmodel. Es muss zwingend für jeden Controller eine festgeschriebene Route definiert werden.
Routen selbst sind natürlich keinesfalls statisch, immerhin gibt es beim Rails-Routing unzählige Möglichkeiten, die seltsamsten Routen zu definieren.
Seit Rails3 versucht man uns ja nun auch das RESTful Routing mit Resourcen schmackhaft zu machen, aber ich mag keine Anwendungen, die an jeder nur denkbaren Stelle stur dem REST-Prinzip folgen, die URLs sehen damit teilweise unheimlich hässlich aus. Auch wenn heutzutage ohnehin gern mit URL-Shortener gearbeitet wird, mag ich auch in der eigentlichen Webanwendung eine gewisse URL-Ästhetik.
Am Beispiel eines Blogs, gerade mit WordPress, ein sehr einleuchtendes Beispiel: Kaum einer mag die Form /?page=1, die Variante /meine-seite-ueber-muell liest sich dagegen viel angenehmer, auch die Permalinkstruktur für die Blogposts, die man z. B. datumsbasiert untersortieren lässt scheint viel angenehmer als nur /?post=2342.
Jetzt kann WordPress aber was ganz Tolles: die Permalinkstruktur lässt sich nach der Installation des Blogs beliebig anpassen, zur “Laufzeit” will ich hier nicht sagen, da ja auf den meisten Servern wohl kaum die PHP-Anwendung persistent vor sich hindümpelt. Bei Rails dagegen ist dieses Modell des dynamischen Permalinkings gar nicht direkt möglich, da hier die Applikation im Regelfall einmal geladen wird und dann im Speicher auf seine Arbeit wartet, es ist ein eigener, ständig laufender Webdienst, der nur meist mit Apache oder nginx an die Welt extra angebunden wird (kaum einer wird wohl eine Standalone-Lösung nutzen, wenngleich dies durchaus möglich ist).
Zudem hab ich mit Rails das Problem, dass nur Controller dann angesprochen werden können, wenn sie via routes.rb festgehalten worden sind. Ein Ein- und Aushängen zur Laufzeit ist somit nicht möglich. Selbst das Ansprechen durch einen anderen Controller quittiert Rails nur mit der Meldung, dass für jenen Controller mit der betroffenen Action eben keine Route definiert sei.
Und das ist echt blöd so!
Ich wollte ursprünglich nur eine Art Catch-All-Route definieren, die an den ApplicationController gebunden ist, und dieser sollte dann in einer Router-Action dann dynamisch verzweigen. Und woher sollten die Routen kommen? Klar, einige essentielle wären zwar vordefiniert (beispielsweise sowas wie /admin), aber die meisten sollten eben aus der Datenbank kommen.
Der Spaß wäre gewesen, sowohl Controller in einer laufenden Anwendung mit einer Aktivierungsfunktion auszustatten bzw. wäre dadurch ein Plugin-System möglich, was ebenfalls darauf abzielt, nicht im Code rumfuschen zu müssen. Jedoch kann ich diese Idee wohl vorerst komplett verwerfen.
Seitenblicke
Das Padrino-Framework (welches auf dem Microframework Sinatra beruht) habe ich mir am Wochenende ebenfalls kurz angeschaut. Hier ist ein alternativer und sehr interessanter Ansatz drin: man kann in Padrino mehrere Apps kreieren, die dann in verschiedene Basis-Routen eingehangen werden (also /app1, /app2, /app3 …). Die Versuchung war recht groß, zumal viele Dinge in Padrino ähnlich aufgebaut sind wie in Rails.
Aber ich werde nun erst einmal eisern am Rails-Framework lernen und gelegentlich einige Gehversuche mit Padrino erledigen. Padrino hat noch einen entscheidenen Vorteil: wenn man sich schon alle Modelle definiert hat, kann man wunderbar eine /admin-Subapplikation einrichten, mit der man dann schon die Daten verwalten kann (ein Seeding könnte damit entfallen). Sozusagen ein rohes Admin-Interface, welches man sicherlich später durchaus auch für die Endanwendung umgestalten kann, aber vornehmlich auch zum Entwickeln und Testen gut geeignet ist. So etwas fehlt im Rails-Kern noch.
Eventuell werde ich mal testen, ob es funktioniert, die Rails-Modelle in eine Padrino-App zu symlinken und ich dort nur die Admin-App installiere und nutze (eben nur zum Testen, nicht für den Produktiveinsatz).
Da ich bei beiden Frameworks nämlich Mongoid als ORM nutzen kann, sind die Modelle also ohnehin recht weit weg vom Framework abstrahiert. Solange man also keinen Framework-typischen Code einschleust, sind Modelle schön portierbar.
Alle Theorie ist grau, darum werde ich einfach weiter probieren und studieren.
Der alte, noch unfertige Dampfkessel ist zwar etwas beschädigt, aber wird trotzdem als Grundlage für den neuen gelten.
Oder anders ausgedrückt: Ich schmelze Teile davon wieder ein und schmiede mir andere daraus.
Bis bald — dann mit neuen Erfahrungen!
