Ruby on Rails wird zehn Jahre alt
Seite 2: Von Rails 1.0 bis heute
Ein RĂĽckblick auf die Meilensteine
15 Monate nach der ersten öffentlichen Vorstellung durch Heinemeier Hansson erschien am 13. Dezember 2005 die Version 1.0 des Frameworks. Das erste Major-Release des Frameworks hatte bereits einen beachtlichen Funktionsumfang und bestand aus folgenden Modulen:
- ActiveRecord zur Datenbankabstraktion,
- ActionPack zur Kapselung des Controller- und View-Layers,
- ActionMailer fĂĽr den Versand von E-Mails,
- ActionWebService zum Bereitstellen und Konsumieren von Webservices sowie
- ActiveSupport mit Spracherweiterungen von Ruby und unterstĂĽtzenden Funktionen fĂĽr das Framework.
Zu den Kern-Features zählten das HTTP-Routing, der noch heute enthaltene HTTP-Server WEBrick, Caching, Validatoren, Assoziationen, Datenbankmigrationen und diverse Hilfsmethoden zur Implementierung von AJAX-Funktionen über Prototype beziehungsweise Scriptaculous. ActiveRecord lieferte Adapter für die Datenbanken MySQL, PostgreSQL, SQL Server, SQLite, DB2 und Oracle.
In weiteren Minor-Releases wurden bis Januar 2007 die Performance optimiert und neue Features hinzugefügt, unter anderem Eager Loading, Einbindung von Integrationstests sowie verbesserte Unterstützung von HTTP inklusive Status-Codes, MIME-Types und verschiedener Ressourcenrepräsentationen.
Die Liebe zu HTTP
Der vom Core-Team eingeschlagene Weg setzte sich in weiteren Versionen fort: Rails 2.0 erschien im Dezember 2007 und stellte REST in den Mittelpunkt – das Team nahm damit eine klare Position in der Debatte SOAP versus REST ein und hat damit nicht unerheblich zur Popularität von REST beigetragen. Unter anderem musste das Modul ActionWebService zugunsten von ActiveResource weichen und Entwicklern wurden weitere Werkzeuge und Konventionen mit an die Hand gegeben, welche die Entwicklung von RESTful-Applikationen erleichterten.
ActiveResource bildet Modellklassen auf REST-konforme Ressourcen ab und war ĂĽber Jahre Kernbestandteil des Frameworks. ActionWebService stand weiterhin als Ruby-Gem, also als externe Bibliothek, zur VerfĂĽgung.
Der Lebenszyklus der 2.x-Version brachte weitere Features hervor: das Internationalisierungsmodul (i18n), Engines, Thread-Sicherheit und Kompatibilität zur alternativen, in Java geschriebenen Ruby-Implementierung JRuby. Die Entwicklung des Frameworks findet seither über die Kollaborationsplattform GitHub statt.
Rails und Merb werden eins
Bei der Entwicklung von Rails 3.0 lag das Augenmerk auf Modularisierung. Rails wurde in diesem Zuge mit dem ebenfalls in Ruby implementierten Webframework Merb zusammengeführt. Die Merb-Entwickler, allen voran Yehuda Katz, verwirklichten dessen modularen Ansatz auch in Rails. Beispielsweise wurden Validatoren und Callbacks von ActiveRecord in das neue Modul ActiveModel extrahiert.
Heinemeier Hansson verglich 2012 auf seinem Blog Rails mit dem japanischen Begriff "Omakase": ein Menü, bei dem man dem Koch das Vertrauen ausspricht und ihm die Zusammenstellung der Speisen überlässt. Der Leitsatz "Rails is Omakase" gilt zwar bis heute, die Modularisierung ermöglichte jedoch von nun an den Austausch von Standardkomponenten des Frameworks. So stand der Nutzung alternativer Test-Frameworks wie RSpec oder Persistenzmappern wie Sequel nichts mehr im Wege. Eine weitere große Neuerung war die Einführung von Bundler als Antwort auf die bis dato ungenügende Abhängigkeitsverwaltung in Rails.
In den auf Rails 3.0 folgenden Releases ging man wieder zur iterativen Einführung neuer Features über. So wurde die Asset-Pipeline eingeführt, jQuery löste das JavaScript-Framework Prototype ab, und SASS und CoffeeScript wurden standardmäßig als CSS- und JavaScript-Abstraktionen integriert.
Die kleine Vier
Rails 4.0 wurde am 25. Juni 2013 veröffentlicht. Im Gegensatz zur kompletten Kernsanierung in Version 3.0 erfuhr Rails nun mehrheitlich iterative Verbesserungen. Die großen Umbauarbeiten durch Yehuda Katz und das Team tragen bis heute ihre Früchte: Ein Rütteln an der grundlegenden Framework-Architektur war seither nicht mehr nötig.
Zu den Neuerungen in Version 4 zählten Turbolinks zum Optimieren der clientseitigen Performance, Russian-Doll-Caching und Live-Streaming. Die Version 4.1 brachte dann den Preloader Spring, Enums für ActiveRecord sowie ein generisches Interface zur Verwendung von Umgebungsvariablen.
Neuheiten in Rails 4.2
An vorderster Front des neuen Releases steht sicherlich ActiveJob, eine einheitliche API fĂĽr Queue-Systeme wie Resque und Delayed Job. In der Webentwicklung gibt es seit jeher den Bedarf, bestimmte Aufgaben auĂźerhalb des Request/Response-Zyklus ausfĂĽhren zu lassen. Ein prominentes Beispiel ist das Versenden von E-Mails: Blockiert der Prozess, beispielsweise durch einen langsam reagierenden Mail-Server, leidet darunter auch direkt die Antwortzeit der eigentlichen Anwendung.
Dieser häufig begangene Fauxpas ist dem Core-Team bekannt, und genau dort setzt es an: Neben der eigentlichen Framework-Komponente ActiveJob stellt es eine native Integration in ActionMailer bereit. Ab sofort sollten E-Mails, die mit ActionMailer versendet werden, explizit mit deliver_now oder deliver_later übermittelt werden. Wichtig zu beachten ist dabei, dass Rails ohne weiteres Zutun der Entwickler standardmäßig eine synchrone Ausführung über ActiveJob durchführt. Man muss sich also weiterhin eigenständig um eine Lösung zur asynchronen Ausführung von Aufgaben kümmern, ActiveJob agiert dabei "nur" standardisierend als einheitliche API für Bibliotheken wie Resque und Delayed Job.
Verbesserungen bei der Performance
Aaron Patterson, Mitglied des Core-Teams, verpasste seinen Performance-Optimierungen von ActiveRecord den nicht ganz erst gemeinten Titel "Adequate Record". Wie sich herausstellte, hatten einige Finder-Methoden in ActiveRecord deutliches Verbesserungspotenzial in Sachen Performance. Laut Patterson werden einige Aufrufe nun bis zu zweimal schneller ausgeführt – etwa einfache Anfragen wie
User.find(1)
User.find_by_name('Arnulf Beckenbauer')
oder auch das Laden von Relationen durch Assoziations-Helper wie user.orders. Erreicht wird das durch das Caching von generierten Query-Fragmenten. Bisher ließ sich das für einfache Primärschlüsselselektionen und Finder-Methoden (s. o.) bewerkstelligen, da in diesen Fällen keine Query-Generierung durch Methodenverkettung ermöglicht wird – Rails muss keine Relationsobjekte (ActiveRelation) erstellen.
Hilfreiche Web Console
Mit der Web Console wurde ein hilfreiches Tool eingeführt, mit dem das lokale Debugging deutlich einfacher von der Hand geht. Die bisherigen Fehlerseiten, die den Stacktrace einer Exception im Browser darstellen, bieten nun auch im unteren Bereich eine Terminal-artige Konsole an, wo sich beliebiger Ruby-Code eingeben und ausführen lässt. Die Ausführung erfolgt dabei im Kontext der aktuellen Exception. Das heißt, der Code wird an der Stelle ausgeführt, an welcher der Fehler aufgetreten ist.
Darüber hinaus kann man die Web Console auch in einem selbst definierten Kontext des aktuellen Requests ausführen: Ruft man den Helper console im aktuellen Controller oder View auf, legt sich die Konsole im Browser über die aktuelle Seite. Das ermöglicht schnelles interaktives Debugging im Geiste von Drittbibliotheken wie pry.
Wer die Web Console in bestehenden Rails-Anwendungen nach dem Update auf 4.2 nutzen will, muss noch einen entsprechenden Eintrag im Gemfile vornehmen:
group :development do
gem 'web-console', '~> 2.0'
end
FremdschlĂĽssel in der Datenbank
Viele langjährige Rails-Entwickler werden die Einführung von echten Foreign-Key-Constraints sicherlich mit offenen Armen begrüßen. Lange Jahre wurde die Datenbank durch Rails nur stiefmütterlich als relativ "dumme" Persistenzschicht behandelt. Nun scheint man auch im Core-Team erkannt zu haben, dass es nicht unbedingt zweckdienlich ist, viele Errungenschaften der relationalen Datenbanken einfach zu ignorieren. Echte Foreign-Key Constraints auf Datenbank-Ebene bieten zahlreiche Vorteile: Modifizieren Entwickler Tabelleninhalte händisch mit SQL und nicht über die Rails-Anwendung, kann es schnell passieren, dass sie Inkonsistenzen erzeugen. Löschen sie etwa händisch eine Zeile aus der primären Tabelle (1) einer 1:n Beziehung, so fehlt den Zeilen in der sekundären Tabelle (n) nun die Beziehung, wodurch sie gegebenenfalls inkonsistent werden. Ein Foreign-Key Constraint hätte das Löschen beispielsweise unterbunden oder die betroffenen Relationen gleich mitgelöscht (Cascading Delete). Der Ansatz von Rails war seit jeher, solcherlei Logik in den Modellklassen zu definieren:
has_many :comments, dependent: :destroy
Vergisst man die dependent-Option, entstehen schnell Inkonsistenzen. Auch bei korrekter Definition beschränkt sich das Verhalten lediglich auf CRUD-Aktionen, die die Rails-Anwendung auslöst. Zugriffe, die beispielsweise direkt über SQL-Werkzeuge erfolgen, sind damit außen vor. Foreign-Key Constraints lassen sich über Datenbankmigrationen, das heißt über den Ruby-Code, der für das Erzeugen der Datenbank-DDL-Statements zuständig ist, hinzufügen beziehungsweise entfernen, sodass das DRY-Prinzip erhalten und Duplikation vermieden wird. Zum Release-Zeitpunkt von Rails 4.2 wird das von den Datenbankadaptern für MySQL und PostgreSQL unterstützt.
Kleinvieh macht auch Mist
Neben den großen neuen Features gibt es wie in jedem größeren Release noch unzählige kleine Erweiterungen und Verbesserungen. Eine davon ist ein komplett neuer HTML-Sanitizer, der auf Nokogiri basiert. Man verspricht sich davon eine robustere Implementierung: Nokogiri ist der am meisten genutzte HTML- und XML-Parser im Ruby-Ökosystem.
Ebenfalls neu ist ein fĂĽr alle Konfigurationen angeglichener Standardwert fĂĽr den Log-Level. Rails verwendet nun in der "production"-Umgebung ebenfalls den Level :debug zum Loggen.
Außerdem gibt es nun einen extra Namespace (x) in der Rails-Konfiguration, worin Entwickler anwendungsspezifische Konfiguration ablegen können, die nicht direkt etwas mit dem Framework zu tun hat:
# config/environments/production.rb
config.x.meine_app.newsletter_sender = 'newsletter@meine-app.com'
DarĂĽber hinaus wurde wieder EntrĂĽmpelung betrieben: respond_with[ und respond_to auf Klassenebene wurden in ein separates Gem "responders" verschoben.