Rails gegen Grails

Webframeworks für JVM-Sprachen

Möchten mit der Java Virtual Machine vertraute Programmierer bei der Webentwicklung in bekannten Territorien bleiben, landen sie bei der Framework-Suche schnell bei Rails mit [JRuby] (http://jruby.org) und Grails mit [Groovy] (http://groovy-lang.org). Dieser Artikel durchleuchtet hauptsächlich funktionale Aspekte der populären Kandidaten und blickt auf ihre Historie zurück. Außerdem wird betrachtet, was positiv heraussticht oder weniger gut gelungen ist, da nicht Features allein den Ausschlag bei der Wahl geben können. So gesehen, ist eine Gegenüberstellung von Webframeworks gar nicht so weit von den Vergleichstests entfernt, die in Autozeitungen zu finden sind.

Im Autobau teilen sich oft unterschiedliche Modelle und Hersteller gemeinsame Plattformen, um Entwicklungs- und Herstellungskosten zu sparen. In vielen IT-Projekten ist die JVM-Plattform gesetzt, die Auswahl der darauf laufenden Systeme ist wiederum relativ frei, sodass JRuby schon viele Jahre eine ernstzunehmende Option ist. JRuby wurde 2001 veröffentlicht und ist für eigentlich alle populären Ruby-Anwendungen einsetzbar (Rails seit 2006). Im Funktionsumfang ist es der Referenzimplementierung [MRI] (https://www.ruby-lang.org/) (auch als CRuby bekannt) immer einen Schritt hinterher (das kommende [JRuby 9000] (https://github.com/jruby/jruby/wiki/Roadmap#jruby-9000) wird kompatibel zu MRI 2.2 sein). Zudem erfordert es mehr Geduld beim Anwendungsstart, sodass JRuby beim lokalen Entwickeln eher gemieden wird.

Außerdem fügt es sich nicht nahtlos in den Java-Kosmos ein, was beispielsweise die Unterscheidung von Ruby- und Java-Objekten oder das stets einzufügende require 'java' verdeutlichen. Viele Ruby-Plug-ins (Gems) funktionieren oder es gibt spezielle, mitunter veraltete, Wrapper Gems. Concurrency und Parallelisierung sind lange vernachlässigte Stiefkinder des MRI. Obwohl es inzwischen auf native OS-Threads setzt, sorgt der eingebaute Global Interpreter Lock (GIL) dafür, dass jeweils nur ein Thread läuft. Für echte Parallelisierung gibt man daher JRuby oder Alternativen wie Rubinius oder IronRuby den Vorzug.

Groovy wurde 2003 veröffentlicht und ist, nach einer längeren Dämmerphase, seit 2008 stabil. Nicht Grails allein ist das Zugpferd der Sprache, auch [Gradle] (https://gradle.org), Spock und [Geb] (http://www.gebish.org) sind in dem Kontext bekannte Projekte. Groovy gilt zudem als geschliffene Fassung von Java und ist als reine JVM-Sprache nur im zugehörigen Ökosystem überlebensfähig, wo sie allerdings bestens integriert ist.

Java-Code ist, bis auf wenige Ausnahmen, syntaktisch valider Groovy-Code (JDK 7). Daher können Groovy- und Java-Klassen voneinander erben, ohne dass der Entwickler über Typ-Konvertierung oder Class-Loading stolpert. Was das Kompilieren und Typisieren angeht, erlaubt Groovy mit def und @CompileStatic beides – sogar im wilden Mix. Groovy-Neulingen erleichtert die Sprache so den Einstieg – auch in die Welt der dynamischen Sprachen.

Zum Vergleich der Sprachen folgen ein paar einfache Code-Beispiele:

(1..1000).inject(:+) # Summe aus Range
[49, 58, 82,90].partition { |n| n > 60 } # Gruppieren
(z ||= []) << 'test' # 'z' lazy initialisieren
{first_name: 'Max'}[:last_name].downcase rescue "Musertmann"
assert "[%s]" % "Ruby, Ruby, Ruby" == '[Ruby, Ruby, Ruby]' # sprintf
Code-Beispiele in Ruby
(1..1000).sum() // Summe aus Range
[49, 58, 82, 90].split { it > 60 } // Gruppieren
assert ['PHP', 'Java']*.size() == [3, 4] // Spread Operator
assert campaign.name ?: "Default" == campaign.name ? campaign.name : "Default"
println(campaign?.product?.name) // Safe Navigation
Code-Beispiele in Groovy
Wissenswertes zu JRuby und Groovy
JRuby Groovy
Einführung 2001 (MRI Ruby 1995) 2003; stabil seit 2008
JVM–Plattform Portiert für die JVM, extra Layer für Java–Integration Designed für die JVM, nahtlose Java–Integration
Editoren und IDE's Vim, Emacs, TextMate, Sublime, Eclipse, NetBeans, IntelliJ IDEA
Besonderheiten sehr schnelle Ruby–Implementierung, dynamische Typisierung Superset von Java, Typisierung optional, statisch Kompilieren optional
Projekte und Libs Rails, Sinatra, Rspec, Rake, Bundler Grails, Spock, Gradle, Geb, GPars, Griffon

Gefragte Youngtimer

Webframeworks sind seit vielen Jahren De-facto-Standard für die moderne Webentwicklung, vor allem um den Boilerplate-Anteil zu reduzieren. Die herangezogenen Full-Stack-MVC-Webframeworks haben naturgemäß viele konzeptionelle Gemeinsamkeiten wie „Convention over Configuration“ (CoC), „Don’t Repeat Yourself“ (DRY), Support für Rapid Prototyping von CRUD-Anwendungen (Create, Read, Update, Delete), Hot-Reloading sowie Unterstützung für Mehrsprachigkeit, Tests und Deployment. Integrierte Webserver wie Webrick in Rails oder Tomcat für Grails vereinfachen und beschleunigen das lokale Entwickeln.

Der Vorläufer von Ruby on Rails entstand bei der Entwicklung einer Projektmanagement-Anwendung (Basecamp), die im Wesentlichen durch David Heinemeier Hansson getrieben und ab 2005 stabil genug für den Projekteinsatz außerhalb seiner Firma wurde. Ruby verdankt Rails einen Großteil seines Erfolgs und Rails wiederum, abgesehen von seinen pragmatischen Ansätzen (REST statt SOAP etc.), die frühen Einsätze bei Diensten wie GitHub und Twitter. Gerade die Mikroblogging-Anwendung kratzte später allerdings erheblich am Ruf, als häufige Performance-Probleme auf Rails zurückgeführt wurden. Bedeutende architektonische Verbesserungen (unter anderem Modularisierung) folgten 2008, nach der [Framework-Hochzeit mit Merb] (http://yehudakatz.com/2008/12/23/rails-and-merb-merge/).

Groovy on Grails entsprang tatsächlich der Idee, eine mit Groovy arbeitende JVM -Alternative zu Rails zu entwickeln. Um Verwechselungen zu vermeiden und auf Drängen von Hansson wurde der Name später auf Grails reduziert. Die Open-Source -Entwicklung war immer schon kommerziell gesponsert (bis [05/2015 Pivotal] (http://blog.pivotal.io/pivotal/news-2/groovy-2–4-and-grails-3–0-to-be-last-major-releases-under-pivotal-sponsorship)). Das Interessante an Grails ist sicherlich, dass es im Grunde die gleichen modernen Konzepte wie Rails verfolgt, sie aber mit erprobten und umfangreichen Evergreens wie Java EE, Spring, Hibernate, Quartz und Sitemesh zusammenbringt.

Wissenswertes zu Ruby on Rails und Grails
Ruby on Rails Grails
Einführung (v1.0) 2005 2008
Lizenz MIT License Apache License 2.0
Reifegrad und Community Rails ist länger im Umlauf und verfügt über die größere Community Grails ist jünger als Rails und gefühlt weniger imEinsatz (diverse JVM–Konkurrenten)
Sprache und Plattform Ruby, plattformunabhängig (JVM: JRuby) Groovy, plattformunabhängig mit JVM
App–Server (Beispiele) Passenger (mod_rails) + nginx/Apache, Mongrel, Thin, Unicorn oder JRuby + Warbler auf Java Application Server Java Application Server (Tomcat, Glassfish, Jetty …)
„Unter der Haube“ Core–Extensions (Gems) u.a. ActiveRecord, ActiveSupport oder ActionPack u.a. Java EE, Spring, Hibernate, Sitemesh, Spock
Produktivität RAD, COC, DRY, Scaffolding …
Testen Rspec, Cucumber, Minitest JUnit, Spock

Blick in den Motorraum

Architektonisch besteht Rails aus mehreren Ruby-Gems, sogenannten Core-Extensions wie ActiveRecord für objektrelationale Abbildungen (Object Relational Mapping, ORM), ActiveSupport für Ruby-Spracherweiterungen und ActionPack für Routing, Controller und View-Rendering. Grails hingegen vereint zum Großteil bewährte Java-Projekte wie Spring-Komponenten für Request Routing oder Hibernate für ORM und vereinfacht sie in Set-up und Konfiguration.

Plus-Size Models

ORM ist das geheimnisvolle Bindeglied zwischen den Datenbanktabellen und Objekten der Anwendung. Die das Active-Record Pattern (nach Fowler) zugrunde legenden ORMs beider Frameworks bieten ein ähnliches Feature Set, vor allem bei dynamischen Find*-Methoden, Query-APIs, Validierung und Callbacks.

Rails zieht bewusst keine Trennung von Domain-Logik und Persistenz. Vor allem, wenn der Controller einfach bleiben soll, landet alles in den jeweiligen Domain-Klassen (in Rails Models genannt). Derartige Ableitungen von ActiveRecord::Base enthalten die Datenstruktur, die Constraints und eben Fachlogik, die oft mit anderen Models – schlimmstenfalls mit anderen Datenquellen oder Webservices – kommuniziert. Der Ausweg daraus ist steinig (Separierung) und erhält kaum Unterstützung durch das Framework. Positiv dagegen ist, dass in Rails der ORM-Austausch bereits eingeplant ist und DataMapper beziehungsweise sein Nachfolger RubyObjectMapper gerade bei Adaptionen aus der NoSQL-Ecke eine Alternative sein kann.

Grails Object Relational Mapping (GORM) ist ein mächtiges Groovy-Pendant, das konsequent auf Hibernate, ein weiteres, schlachterprobtes Java-ORM, setzt. Dabei sind zunächst auch Mapper-Klassen zu definieren (in Grails Domains genannt), die den Datenzugriff, die Validierung (Constraints) aber auch grundlegende Domain-Logik enthalten. Für nicht relationale Datenbanken gibt es GORM-Adapter für Neo4j, Redis, standardisierte REST-Clients und so weiter.

Wenn man mit Rails' [ActiveRecord] (http://guides.rubyonrails.org/active_record_basics.html) und ähnlichem gearbeitet hat, fühlt sich das Hibernate-Konzept zunächst fremd an, denn ein save() oder delete() hält erst einmal alle Änderungen in seiner Session (Datenbank, nicht HTTP) und gibt sie erst an die Datenbank weiter, wenn der darüber liegende Thread (beispielsweise eine Controller Action) beendet oder ein manuelles Session-Flush ausgerufen wird. Noch heikler ist das automatische Speichern von mit get("SomeId") geladenen Entitäten, ohne explizites save(). Grails bietet zur sauberen Strukturierung der Fachlogik eine Services-Schicht, die sich vergleichsweise einfach einbinden lässt (Namenskonvention, Auto-Injection), standardmäßig transaktional arbeitet und unter dem Gesichtspunkt erste Wahl für Datenbankinteraktionen aus dem Controller heraus ist.

Viele Entwickler ziehen zum Beispiel SQLite in Rails oder [HSQLDB] (http://hsqldb.org) (In-Memory) in Grails Oracle im lokalen Set-up vor. Dafür und wenn die Datenbank-Migrationen unter den Blicken der Administratoren durch die Testumgebungen in Richtung Produktion wandern, braucht es ein unabhängiges, textbasiertes Format. In den meisten Projekten kommt hierfür Liquibase (via Plug-in) zum Einsatz. Rails liefert zudem eine eigene Migrations-DSL, die sich mit Rake-Tasks auf der Ziel-DB ausführen lässt. Grails wiederum kennt unterschiedliche Konfigurations-Modi, die die Domain-Klassen mit der Datenbankstruktur beim App-Start oder Klassen-Reload abgleichen und gegebenenfalls anpassen.

Beispiele für Aufbau und Vererbung von GORM Domain-Klassen sehen wie folgt aus:

class Address {
    String number
    String code
}

class Person {
    Address homeAddress
    Address workAddress
    static embedded = ['homeAddress', 'workAddress']
}
GORM Composition
class Content {
    String author
}

class BlogEntry extends Content {
    URL url
}
GORM Inheritance (Typ-Spalte oder weiteren Tabelle)

Magere Controller

Viel mehr, als Daten aus der Webschicht entgegenzunehmen und nach deren Verarbeitung eine Response (beispielsweise an die View delegiert) zurückzuliefern, muss ein Rails/Grails-Controller gar nicht. Beide Frameworks unterstützen bei der Routing-Konfiguration und bieten Callback-Interceptors. Regelbasierendes, übergreifendes Filtern lässt sich in Rails in der Rack-Middleware beziehungsweise in Grails über Servlet- oder Grails-Filter (mit Hooks zum Beispiel beim View Rendering einer Aktion) implementieren.

Unter anderem hat die Rails-Community „Fat Model, Skinny Controller“ als Pattern manifestiert, das Wiederverwendbarkeit und besseres Testing verspricht. Wenn Projekte ohne strukturelle Vorgaben wachsen, führt das unweigerlich zu aufgeblasenen Model-Klassen mit verwässerter Verantwortlichkeit. Grails gibt daher mit Command- und Service-Objekten Möglichkeiten vor, den Persistenz-Teil abzukoppeln. In Rails hingegen gibt es kaum Standards dazu. Dennoch kann man sich bei Framework-unabhängigen Paradigmen wie Data Context Interaction (DCI) oder [Hexagonal Architecture] (http://victorsavkin.com/post/42542190528/hexagonal-architecture-for-rails-developers) Anregungen holen.

Während Rails auch dem Thema Data Binding kaum Beachtung schenkt, kann Grails beispielsweise Request-Parameter automatisiert auf nahezu beliebige Datenstrukturen mappen, die sich in der Signatur der Action-Methode vorgeben lassen. Ist der Parameter eine Domain-Klasse oder ein Command-Object, kann das Programm ihn sogar vor der eigentlichen Verarbeitung validieren und Assoziationen laden.

def show(String id) {
    respond Campaign.get(id)
}
Parameter-Mapping und ggf. TypeCast von id
def create(CampaignCommand campaignCommand) {
    respond new Campaign(campaignCmd.properties)
}
Binding und Validierung von campaignCommand
def edit(Campaign campaign) {
    respond campaign
}
Laden der GORM Domain vorab (über den Campaign id Parameter)

Layout und Frontend-Assets

ERB (Embedded Ruby), eine Mischung aus beispielsweise HTML mit eingebettetem Ruby, ist Rails' View-Technik und sorgt zusammen mit Template Partials und Helper-Funktionen für wartbare Views. Grails' Gegenstück dazu sind Sitemesh als Layout Engine und Groovy Server Pages (GSP) für Markup und GSP-Tags (ähnlich JSP/ASP). Komplexer Code lässt sich in selbstgeschriebenen GSP-Tags (Taglibs) verstecken.

Die Präprozessor-Verarbeitung von SASS oder CoffeeScript, die Komprimierung von Bildern oder JavaScript in für das Web geeignete Größen sowie Abhängigkeiten zu weiteren Komponenten decken die mitgelieferten Asset-Pipeline Plug-ins ab. Nur wer noch feingranularer testen und optimieren will, muss sich noch selbst mit Bower, Grunt oder Gulp die Hände beschmutzen.

class SimpleTagLib {
    /**
     * @attr bye Begrüßung ('true') oder Verabschiedung ('false')
     */
    def helloOrGoodbye = { attrs, body ->
        out << (attrs.bye == 'true' ? "Tschüss " : "Hallo ") << body()
    }
}

%{--in der GSP Datei, Ausgabe: "Tschüss Jochen"--}%
<g:helloOrGoodbye bye="true">Jochen</g:helloOrGoodbye>
Erstellung und Verwendung eines eigenen GSP-Tags

REST einsetzen

Bereits zu einer Zeit (~2007), als SOAP noch schwer angesagt war, hat Rails konsequent auf REST gesetzt. Heutzutage helfen sowohl Rails als auch Grails auf ihre Art beim Exponieren und Konsumieren von Ressourcen, beispielsweise initial durch Restful CRUD Scaffolding, Routing oder Content-Negotation, aber auch durch Model-Serialisierung. Viel Zeit fließt erfahrungsgemäß in die Integration und Anpassung der Schnittstellen, sodass die bereitgestellten Features mit ihren Annahmen zu Hypermedia, Content-Type, Versionierung oder technischer Dokumentation nur teilweise nützlich sind.

Das neuzeitlich-schlanke Rails liefert viele seiner im REST-Kontext gebrauchten Funktionen nur noch über Gems und überlässt die Auswahl dem Entwickler. Ein Beispiel dafür ist ActiveResource, früher Bestandteil des Rails-Core und probates Mittel, um zwei Rails-Applikationen per RESTful HTTP über eine ActiveRecord ähnliche API kommunizieren zu lassen.

Grails hat im Auslieferungszustand einen mächtigen Funktionsumfang. Zum Beispiel können Entwickler Domain-Klassen einfach per Annotation in eine Ressource verwandeln. Wird es spezifischer, erfolgt die Implementierung im Controller, der wiederum Funktionen des grails.rest.RestfulController und diverser, anpassbarer Converter, Renderer und Binder (zum Beispiel für HAL-JSON), nutzen kann.

So sieht Content Negotiation in Grails etwa wie folgt aus:

    // Neuen Mime-Type und Renderer in Config.groovy
    def campaignMimeType = new MimeType("application/vnd.campaign+json")

    // und spring/resources.groovy definieren
    beans = { campaignRenderer(JsonRenderer, Campaign, campaignMimeType) }

    // Aus dem Controller, via JsonRenderer für den neuen Mime-Type, rendern
    respond Campaign.get(1L)

Asynchrone Verarbeitung

HTTP Requests sind oft der Flaschenhals einer Webanwendung, daher sollte man nur das Nötigste zum schnellen Rendern der Seite tun und lang laufende Aufgaben auf nicht blockende Nebenschauplätze verlegen.

Frühe Versionen von Rails waren nicht thread safe und so wurde der gesamte Request vom Webserver (bspw. Mongrel) mit einer Mutex-Klasse ummantelt. Das ist lange her, aber genau wie das Parallelisierungsproblem in MRI kommt dieser Punkt in Diskussionen immer wieder auf. Blockende HTTP-Zugriffe nach Außen lassen sich so refakturieren, dass sie die Rack-Middleware-Schicht (Webserver API) direkt verarbeitet.

Unter JRuby gibt es keinen Grund, die Java-Concurrency-Bibliotheken nicht zu nutzen. Allerdings gibt auch unabhängige Gems wie Sidekiq (Celluloid, Threads, Redis), um Tasks asynchron abzuarbeiten. Grails erspart die Suche nach entsprechenden Bibliotheken und bietet mit dem integrierten [GPars-Framework] (http://gpars.codehaus.org) eine mächtige Async API (Promise Pattern), die beispielsweise Services durch Verwenden der @DelegateAsync-Annotation einen asynchronen Klon hinzufügt. GORM bietet für viele seiner Funktionen entsprechende Varianten (async Namespace) und die Action Response lässt sich als grails.async.PromiseMap direkt aus dem Controller zurückgeben:

import static grails.async.Promises.*
import Campaign

class CampaignController {
    def index() {
        // return grails.async.PromiseMap
        tasks   campaigns: Campaign.async.list(),
                totalCampaigns: Campaign.async.count(),
                otherValue: task { 2 * 2 }
    }
}

Nicht nur in Enterprise-Projekten ist entkoppelte, skalierbare und komponentenübergreifende Kommunikation über Message Services gewünscht. Im Rails-Umfeld kann man dafür ebenfalls Sidekiq einsetzen, aber eigentlich sind beliebige JMS-Provider (Java Message Service) unter JRuby beziehungsweise Groovy denkbar. Task Scheduler, die Aufgaben zu festgelegten Zeiten starten, sind eine weitere Möglichkeit.

In Rails kann man tatsächlich einem Betriebssystem-Job die Ausführung eines Rake Task überlassen oder man setzt eines der dazu verfügbaren Gems (zum Beispiel Whenever) ein. Noch einfacher geht es mit dem Quartz-Plug-in in Grails.

Automatisiertes Testen

Beide Frameworks ermöglichen Unit- und Integrationstests, erzeugen ein rudimentäres Test-Codegerüst beim Generieren von Klassen und liefern eine gesondert konfigurierbare Testumgebung. Rails stellte Tests von Anfang an in den Vordergrund. Seit Version 4.0 nutzt es MiniTest als Test-Framework, aber auch andere Langzeit-Alternativen wie Rspec sind möglich. Grails hingegen setzt auf den populären Vertreter [Spock] (https://github.com/spockframework/spock).

Ein Beispiel für einen Unit-Test sähe damit etwa wie folgt aus:

    def "Länge der Strings"() {
        expect:
            name.size() == length

        where:
            name     | length
            "PHP"    | 3
            "Java"   | 4
            "Groovy" | 6
    }
Spock Unit-Test

Allerdings lassen sich auch Legacy-Grails-Tests und reine JUnit-Tests durchführen, was in der Praxis zu Durcheinander bei den diversen Annotationen, Code-Mixins, Ableitungen und Mock-Möglichkeiten führen kann.

Modularisierung, Caching und Sicherheit

Während sich vor ein paar Jahren noch jedes halbwegs ernstzunehmende Webframework nur mit aufgeblasenem Feature Sets sehen (und vergleichen) lassen konnte, ist dieser Trend inzwischen gegenläufig: Mit jedem Major Release werden altgediente Kernkomponenten in Frage gestellt und in optionalen Modulen weiterentwickelt. Rails hat sein Modularisierungskonzept noch weiter in Ruby-Gems und Engines unterteilt, wobei man sich letztere wie eine Art Mini-/Standalone-App vorstellen kann, die sich in eine Hauptanwendung einbinden (mounten) lässt. Grails bietet entfernt Vergleichbares nur über seinen Plug-in-Mechanismus oder verlinkte Bibliotheken. In der Praxis unterteilt man monolithische Applikationen jedoch eher in Services auf App-Ebene und lässt sie beispielsweise über REST APIs kommunizieren.

Caching ist einer der komplizierteren Aspekte der Informatik und so bieten Rails und Grails vom SQL Query bis hin zu komplett gerenderten HTML-Seiten diverse Caching-Möglichkeiten innerhalb des Framework-Stacks. Dabei kann In-Memory als Standardoption gelten, allerdings lässt sich auch auf die üblichen Cache Stores wie Ehcache oder Redis zurückgreifen. Grails sorgt mit Annotationen und seiner Spring Bean DSL für mehr Übersichtlichkeit, um Methoden-Rückgaben besser im Cache zu lagern als es der programmatische Ansatz von Rails vorgibt.

Eine Verbesserungen in Rails 4 lässt sich bei verschachtelten Caches finden:

    # :touch updated auch den parent-cache (Campaign model)
    class Campaign < ActiveRecord::Base
        has_many :activities
    end

    class Activity < ActiveRecord::Base
        belongs_to :campaign, touch: true
    end
Russian Doll Caching

Auch wenn in beiden Frameworks Filter zur Authentifizierung und Autorisierung leicht selbst implementiert sind, werden viele Entwickler dieses sensible Thema gern an ein gereiftes Plug-in abgeben wollen. Das Devise Gem ist ein solches und wird über Mixins in die Rails-Modelklasse eingebunden, sodass beispielsweise im Controller ein authenticate_user! ausreicht. Grails hat mit Spring Security nur eine ernstzunehmende, aber sehr umfangreiche Alternative. Das Grails-Plug-in hilft mit vereinfachter Konfiguration sowie einer DSL und bietet zudem etliche Erweiterungen (zum Beispiel für OAuth oder LDAP).

Flügeltüren in der Aufpreisliste - ein Fazit

Während die Java-Community schon immer seriös und unternehmenssorientiert daher kommt, sind Nutzer und Entwickler von Groovy und Ruby mehrheitlich pragmatisch und geben sich nur ungern mit umständlichen Workflows zufrieden. Der Umgang mit beiden Sprachen und Frameworks macht durch ihre zumutbare Lernkurve und ihre pragmatisch-tolerante Art von Anfang an Spaß. Natürlich muss man sich dabei auf das jeweilige Framework einlassen, die Ideen und Entscheidungen dahinter akzeptieren und nicht dagegen arbeiten.

Ruby ist eine ausgereifte Programmiersprache, die zusammen mit den Rails-Spracherweiterung und den JRuby-Möglichkeiten nur noch besser wird. Rails ist über die Jahre gereift und eben kein kurzlebiger Modetrend mit Kinderkrankheiten mehr. Zur richtigen Zeit, nämlich als Webentwicklung noch wirklich schmerzhaft war, konnte es mit prominenten Anwendungen und guter Community-Arbeit einen bis heute andauernden guten Ruf aufbauen. Dem Rails-Entwicklungsteam, vor allem Hansson, sagt man allerdings auch Arroganz und Engstirnigkeit bei Entscheidungen nach. Ähnlich wie in der PHP-Entwicklung unterschätzen viele gelegentlich die Einfachheit von Rails, und ordentliches Design der Komponenten und Schnittstellen wird besonders in großen oder wachsenden Projekten vernachlässigt.

Eines der größten Argumente, das für Grails spricht, ist Groovy. Die Sprache vereinfacht den Einstieg – gleichermaßen für Ruby- und Java-Entwickler – und die sich durch die Java Virtual Machine ergebenden Vorteile sind gewaltig. Sicherlich, die Community ist kleiner und Grails jünger, dafür haben deren Anwender und Entwickler oftmals ein vertieftes Java-Wissen und kennen daher viele der unter der Haube eingesetzten Techniken bereits. Gerade dieser Zweckverband der besten und umfangreichsten Java Tools macht es nicht gerade zu einem schlanken Framework und ein Austausch von Komponenten ist oftmals nicht vorgesehen oder scheitert an echten Alternativen.

Grails hat im direkten Vergleich ein engeres Korsett an Konventionen und zwingt den Entwickler, mehr über die Strukturierung seiner Anwendung nachzudenken. Wie bei Ruby ist die „Magie“, die in allem zu stecken scheint, Segen und Fluch zugleich. Zudem ist die Zukunft nach dem Ausscheiden von Pivotal als Sponsor für Groovy und Grails ungewiss.

Gibt es einen klaren Gewinner? Nein, vielmehr hängt die Entscheidung für oder gegen eines der vorgestellten Frameworks vom Projekt und seinen Rahmenbedingungen ab. Sollen Java-Entwickler mitarbeiten, die möglicherweise unerfahren mit dynamischen Sprachen sind, dafür aber fit mit Spring & Co., oder gibt es bereits eine signifikante Menge JVM-Code, geht die Empfehlung in Richtung Groovy und Grails. Umgekehrt, wenn die JVM kein Muss ist und Ruby-Vorkenntnisse und -Bibliotheken zum Einsatz kommen, spricht das eher für Ruby und Rails.

Und um es ein letztes Mal im Jargon der Autozeitschrift zu sagen: Rails ist das Webframework mit kraftvollem Turbolader und langer Aufpreisliste, während Grails eher ein vollausgestattetes Sondermodell mit großem Hubraum präsentiert. Schnelles Kurvenfahren ist mit beiden möglich.

TAGS

Kommentare

Um die Kommentare zu sehen, bitte unserer Cookie Vereinbarung zustimmen. Mehr lesen

Finden können Sie uns auch auf