Too Cool for Internet Explorer

ORMs sind doof


ORM

Wikipedia sagt dazu:

Objektrelationale Abbildung (englisch object-relational mapping, ORM) ist eine Technik der Softwareentwicklung, mit der ein in einer objektorientierten Programmiersprache geschriebenes Anwendungsprogramm seine Objekte in einer relationalen Datenbank ablegen kann. Dem Programm erscheint die Datenbank dann als objektorientierte Datenbank, was die Programmierung erleichtert. [...]

Inzwischen bringt ja so ziemlich jedes PHP Framework seine eigene ORM Implementierung mit, es gibt aber auch einige Framework-unabhängige ORM Implementierungen. Ich habe mir in den letzten Jahren immer mal wieder verschiedenste ORM Implementierungen angesehen -- immer dann, wenn in mir der Wunsch nach einer objektorientierten Zugriffsweise auf meine Datenbanken aufkam. Leider jedoch konnte mich bisher keine ORM Implementierung überzeugen.

ORMs sind doof

Auch in mir kommt immer mal wieder der Wunsch auf objektorientiert auf meine Datenbanken zuzugreifen, da dies den Zugriff auf einzelne Datensätze -- Objekte -- erheblich vereinfacht. Jedoch -- zu welchem Preis wird diese Vereinfachung erkauft?

Modellierung

Ich modelliere meine Datenbanken schon seit Jahren mit dem ER Modeller dbWrench. Das ist meiner Meinung nach super komfortabel. Ich sehe auf einen Blick all meine Tabellen und die Abhängigkeiten bzw. Verknüpfungen zwischen einzelnen Tabellen. Über die Funktion "Forward Engineering" kann dbWrench mein Datenbankschema in der Datenbank immer aktualisieren. Da ich bei MySQL den Tabellentyp InnoDB verwende, sind auch in der Datenbank sämtliche Verknüpfungen festgehalten und liessen sich z.b. über die INFORMATION_SCHEMA Tabelle leicht auslesen.

Nun ist es leider so, dass offenbar so ziemlich jede ORM Implementierung die Datenbankdefinition auf Ihre Weise bekommen möchte. Da muss man entweder seitenweise XML oder YAML Konfiguration, oder gar ellenlangen PHP Code schreiben -- nur um der Anwendung eine Information bekannt zu geben, die eigentlich exakt so schon in der Datenbank vorhanden ist?

Abstraktion

Wie weit muss man die Datenbankzugriffe abstrahieren? Nun, es gibt da sicherlich die verschiedensten Anforderungen. Ich denke bei der Entwicklung von Unternehmenssoftware kann man die Anforderungen ziemlich genau spezifizieren. Man entscheidet sich zu einem gewissen Zeitpunkt für ein bestimmtes Datenbankprodukt. Normalerweise wird diese Entscheidung nicht nach wenigen Monaten oder Jahren über den Haufen geworfen -- es sei denn es gibt sehr triftige Gründe dafür.

Deshalb bin ich der Meinung, dass die Abstraktion nicht so weit gehen muss, dass sämtliche Datenbankzugriffe abstrahiert werden und für beliebige Datenbanksysteme geeignet sind. Im Gegenteil: ich entscheide mich ja nicht für eine bestimmte Datenbank nur aus Kostengründen, sondern auch, weil diese vielleicht Features mitbringt, die ein anderes Datenbanksystem nicht unterstützt.

So erweitert z.b. MySQL den SQL Standard um eigene spezifische Befehle, die es in anderen Datenbanken nicht gibt, die aber sehr praktisch sind. Das ist kein Alleinstellungsmerkmal von MySQL. Beispiel: Hätte ich mich für Oracle entschieden, wäre ich doch dumm, würde ich zum Abbilden / Abfragen von Hierarchischen Strukturen nicht CONNECT BY verwenden -- nur weil dies nicht Teil des SQL Standards ist und dies so mit keiner anderen Datenbank funktioniert.

Nur: keine ORM Implementierung kann auf diese einzelnen Datenbankfeatures eingehen -- womit ich beim nächsten Punkt angelangt wäre.

Abfrage

Das grösste Manko aller (PHP) ORM Implementierungen ist meiner Meinung nach die Abfrage einer Datenbank. Ich gebe zu: ich mag SQL -- es gibt mir das passende Werkzeug zum Abfragen einer relationalen Datenbank in die Hand -- es wurde zu diesem Zweck entwickelt! Ich schreibe gern SQL, da es strukturiert und übersichtlich ausschaut und mich schnell zum Ziel führt. Ich gebe weiterhin zu: Ich nutze auch gern MySQL spezifische SQL Features -- aus den oben genannten Gründen.

Nun ist es jedoch so, dass die ORM Implementierungen in der Regel den Zugriff soweit abstrahieren, dass -- normalerweise -- kein SQL mehr geschrieben wird. CONNECT BY und ähnliche Dinge wären damit Unmöglich. Heutzutage hat sich folgende Schreibweise zum Erstellen von Datenbankabfragen etabliert:

$dbo
    ->select(array(
        'media.media_id', 'media.media_name', 'member.member_name', ...
    ))
    ->from('media')
    ->join('member', 'member.member_id = media.member_id')
    ->where('media.category_id = ?')
    ->order('media.media_id')
...

Ich bin kein Fan einer solchen Schreibweise:

  1. Es ist kein SQL ;-)
  2. Es ist wesentlich mehr Aufwand als beim Schreiben von SQL erforderlich
  3. Ich kann keine Datenbankspezifischen SQL Erweiterungen verwenden
  4. Ich habe keine Kontrolle darüber, welchen SQL Code die ORM Implementierung daraus generiert
  5. Es liegt in der Natur der Sache, dass ein derartiges Konstrukt niemals auch nur annähernd so performant sein kann wie ein simples SQL Statement übergeben an die Datenbank
  6. Ich kann das Statement nicht per Copy / Paste zwischen meinem Datenbank Client und der Anwendung hin und her kopieren -- praktisch, wenn man das ganze erstmal testen will
  7. Wenn ich den Datenbanktreiber einer nicht-relationalen Datenbank hinterlege, weil ich mich z.b. entscheide statt MySQL MongoDB anzusprechen, wird diese Schreibweise ohnehin ad Absurdum geführt. (Nur als beispiel -- ich weiss nicht, ob irgendeine PHP ORM Implementation überhaupt nicht-relationale Datenbanken unterstützt)

Natürlich bietet so ziemlich jede ORM Implementierung einen Fallback zur Herkömmlichen Absetzung von SQL Anfragen ohne ein Objekt-Mapping. Nur, wenn ich damit an einer Stelle in meiner Anwendung anfange: warum dann überhaupt eine derartige Abstraktion nutzen?

Fazit

Meiner Ansicht nach erkauft man sich den konsequenten Einsatz eines ORM zu einem zu hohen Preis. Deshalb habe ich den Einsatz eines solchen für mich immer wieder verworfen. Mein Wunsch wäre ein SQL -> Objektmapper. D.h.: Ich schreibe SQL, zurück bekomme ich Objekte, mit denen ich weiterarbeiten kann ...



Trackbacks

Keine Trackbacks

Kommentare
Ansicht der Kommentare: (Linear | Verschachtelt)

Ich bin hier immernoch geteilter Meinung. Zum einen halte ich den ORM Weg für sehr komfortabel und auch sehr gut lesbar, zum anderen ist er von der Performance und der Mächtigkeit nicht so umfassend wie ich mir das wünschen würde. Deshalb hängt der Einsatz aus meiner Sicht stark vom Kontext ab. Habe ich z.B. eine Seite die sehr schnell sein muss, wo es viele Millionen Aufrufe am Tag gibt, dann sind ORMs eher ungeeignet. Genauso wenn man auf komplexe Abfragen angewiesen ist (z.B. ein Statistik Tool oder vergleichbares).

Für durchschnittliche Applikationen (wie z.B. mein Blog) sind ORMs ideal. Im Grunde werden Daten ausgelesen, verändert oder gelöscht und meist ist hier auch nur eine Entität betroffen (ober wenige Entitäten, die nur eine einfache Beziehung untereinander haben). Hier führt das zu Code, der sich weitaus besser lesen läßt und kompakter ist.

Für mich gehe ich einen Mittelweg: für Standardoperationen nutze ich lieber Objekte, für komplexe Zugriffe sind direkte SQL Statements gefragt.

Pauschal würde ich keinen Weg ausschließen oder bevorzugen. SQL -> Objekt wär natürlich genial, aber das ist nur sehr schwer möglich, weil man für die Objekte wieder Strukturinformationen benötigt. Schließlich soll ja dann sowas funktionieren:
$photos = $db->query("SELECT name, age FROM user")->findDependend("photos");

Werde mir hier noch verschiedene ORMs ansehen. Da gibt es auch nochmal große Unterschiede, vor allem was dann auch das Thema Performance und Flexibilität angeht.

Viele Grüße
Tobi
#1 Tobi (Link) am 14.03.2009 12:52 (Reply)

Hallo Harald,

in der .NET Welt stellt sich ja auch die Frage was man da macht. Wir haben aber den Vorteil, dass sich .NET nicht in x Unterframeworks aufteilt. "Wir" bekommen von MS einen Weg vorgegeben. Der Weg wird durch aktuelle Entwicklungen und nicht zu letzt durch die Community beeinflusst. Das ist natürlich keine Demokratie und nicht immer ein Garant für Erfolg.

Unsere "ORM" Tools heißen: LINQ to SQL und LINQ to Entity. Es gibt auch noch ein Markt an Dritthersteller, aber da stellt sich immer die Frage der Kosten und der Qualität (nHibernate, genom-e, ..). Ich bin selber kein FAN von ORM und der Abstraktion der Datenbank Features, da in meinen Projekten der Wechsel der Datenbanken eh "nie" passiert, ist das alles nicht so ein Thema. Aber... heute wirklich alles selber schreiben ist nun wirklich nicht so dolle... je nach Projekt eben. Für MS heißt die Lösung also Linq... und das ist gut so. Wie immer und du sagst es selber... das Projekt entscheidet es... für mich interessant: MS hat hier vielleicht ein Tick die Nase vor... weil sie den "ORM" Weg vorgeben :-) Mehr ist es auch nicht... technisch bin ich mit LINQ to Entity zufrieden, aber kann es nicht mit anderen Plattformen wie PHP vergleichen.

Ciao Marco
#2 Marco Scheel (Link) am 15.03.2009 22:38 (Reply)

Hallo Herr Lapp,

mir wurde Ihr Artikel von einem Kollegen weitergeleitet und ich möchte kurz darauf eingehen.
Ich denke Sie betrachten nur einen kleinen technischen Teil der Aufgaben eines ORMs (OR-Mapper) bzw. das Thema selbst sehr pragmatisch.
Letzteres finde ich persönlich nicht falsch, aber evtl. nicht weit genug gedacht.
Ein objektorientiertes Design oder in dem Fall das Tool welches dieses umsetzt (OR-Mapper) hat nicht nur was mit "objektorientierten Zugriffsweise auf meine Datenbanken" zu tun.
Vielmehr sollen komplexe Geschäftsprozesse feiner granuliert und in eine allgemeingültige Sprache umgesetzt werden.
Jede Definition eines Models kann dabei beliebig komplexe Prozesse beinhalten, die der Entwickler nicht benötigt oder verstehen muss um seinen Bereich der Anwendung fertig zu stellen.

Folgende Punkte sind mir beim lesen aufgefallen:
1. Alle von Ihnen beschriebenen Probleme bzgl. Performance können durch Hardware erschlagen werden. Hardware ist sehr viel günstiger als Entwickler.
2. Jede API oder Programmiersprache muss man erlernen. SQL selbst auch. Kryptische Tabellen sind evtl. weniger lesbar als an Geschäftsprozesse angelehnte Modelle.

Ich denke bei einer kleinen Anwendung, mit wenig Entwicklern ist ein ORM evtl. overhead.
Jedoch mit steigenden Anforderungen, steigender Komplexität der Prozesse und einer großen Anzahl von Entwicklern sollte man sich den Einsatz überlegen.

Ein plastisches Beispiel [1] aus dem aktuellen Doctrine-ORM (http://www.doctrine-project.org/).
In diesem Beispiel werden Datensätze über ein Attribut lediglich als gelöscht markiert.
Die Tabelle sieht wie folgt aus: tableFoo: id, name, deleted_at

Ihrer Argumentation zufolge muss jeder Entwickler wissen, welche Tabelle ein solches "SoftDelete" enthält und beim löschen eines Datensatzes dann anstatt eines DELETE ein UPDATE auf das entsprechende Attribut mit der aktuellen Zeit machen.
Beim selektieren aller Daten widerum muss dieses Attribut darauf geprüft werden ob es gesetzt wurde oder nicht (NULL, NOT NULL).
Ziemlich viel Aufwand, meinen sie nicht?

In der "ORM-Welt" wird dieses transparent behandelt. Dem Entwickler ist es egal wie sich das Model verhält, er benutzt es einfach.

Insgesamt ein relativ komplexes Thema über das man viel philosophieren kann. Hier eventuell interessanter Lesestoff [2].

[1] http://www.doctrine-project.org/documentation/manual/1_1/en/behaviors#core-behaviors:softdelete
[2] http://www.orm.net/pdf/dppd.pdf

Mit freundlichen Grüßen
Enrico Stahn
#3 Enrico Stahn (Link) am 17.03.2009 12:25 (Reply)

Ich halte ORMs in gewisser Weise für sehr nützlich, wenn man z.B. einen Programmierer hat, der kein SQL kann. Aber wo gibt es das schon?

Ich selbst verwende kein ORM, weil ich mit herkömmlichen SQL-Statements noch die beste Kontrolle habe.

Ebenso nervig finde ich die Konfiguration dieser Frameworks. Das hat mich bisher immer vor deren Benutzung abgeschreckt.

Simon
#4 Simon (Link) am 01.04.2009 21:58 (Reply)


Kommentar schreiben

Umschließende Sterne heben ein Wort hervor (*wort*), per _wort_ kann ein Wort unterstrichen werden.
Standard-Text Smilies wie :-) und ;-) werden zu Bildern konvertiert.

Um maschinelle und automatische Übertragung von Spamkommentaren zu verhindern, bitte die Zeichenfolge im dargestellten Bild in der Eingabemaske eintragen. Nur wenn die Zeichenfolge richtig eingegeben wurde, kann der Kommentar angenommen werden. Bitte beachten Sie, dass Ihr Browser Cookies unterstützen muss, um dieses Verfahren anzuwenden.
CAPTCHA