7 Punkte von GN⁺ 2023-06-28 | 1 Kommentare | Auf WhatsApp teilen
  • ORM wird zwar als „Spielzeug für Startups“ kritisiert, doch der eigentliche Streitpunkt liegt weniger bei ORM selbst als bei falscher Nutzung
  • Objektgraphen und relationale Tabellen sind unterschiedliche Modelle, wodurch eine Paradigmen-Impedanz entsteht; das allein macht ORM aber noch nicht zum Anti-Pattern
  • Die Debatte um Verstöße gegen SRP und SOC ist berechtigt, doch ORM ist von vornherein eine Abstraktion, die zwei Datenmodelle verbindet, sodass eine Bewertung allein anhand von Prinzipienverstößen schwierig ist
  • Performance-Probleme entstehen häufiger durch Muster, bei denen Daten in der Logik der Host-Sprache zusammengesetzt werden, als durch ORM selbst; sie lassen sich mit den SQL-ähnlichen Funktionen von ORM reduzieren
  • Der Hauptgrund, warum Lago Active-Record-Abfragen durch Raw SQL ersetzt hat, war weniger Geschwindigkeit als Transparenz und Debugging; bei großen Abfragen kann der Wechsel zu Raw SQL in der Praxis vorteilhaft sein

Grundhaltung zur ORM-Kritik

  • ORM wird häufig als „Anti-Pattern“ angegriffen, doch die Schlussfolgerung, ORM selbst sei schlecht, ist eher überzogen
  • Wie andere Abstraktionen ist auch ORM nicht perfekt und kann gewisse Transparenzverluste sowie Performance-Kosten verursachen
  • Lago stieß auf Probleme, während es auf Active Record, das ORM von Ruby on Rails, setzte, und nahm dies zum Anlass, den Umgang mit ORM-Abhängigkeiten neu zu prüfen
  • Die Schlussfolgerung geht weniger dahin, ORM aufzugeben, sondern ORM als Abstraktion mit klaren Vor- und Nachteilen zu behandeln

Unterschiede zwischen Objektmodell und relationaler Datenbank

  • Die Objekte, mit denen ORM arbeitet, ähneln eher einem gerichteten Graphen, der auf andere Knoten verweist
  • Tabellen in relationalen Datenbanken ähneln eher einem ungerichteten Graphen, in dem Daten über gemeinsame Schlüssel bidirektional verbunden sind
  • ORM kann einen ungerichteten Graphen zwar nachbilden, doch Konfiguration und Verhalten sind nicht immer einfach
    • Einem User-Objekt kann das Posts-Array fehlen
    • Die Entitäten im Posts-Array haben möglicherweise keinen Rückverweis auf dasselbe User-Objekt
    • Selbst wenn ein Rückverweis vorhanden ist, kann es sich statt um dasselbe Objekt um ein kopiertes Objekt handeln
  • So kann ein ORM beispielsweise die Beiträge eines Nutzers als Array zurückgeben, ohne in jedem Beitrag einen Rückverweis auf den Nutzer in der Rolle des Autors einzuschließen
  • Diese Diskrepanz ist eine gute akademische Kritik an ORM, doch im realen Betrieb zeigen sich größere Probleme eher in der konkreten Nutzung

SRP- und SOC-Debatte

  • Single-Responsibility-Prinzip (SRP)

    • ORM wird dafür kritisiert, gegen das Single-Responsibility-Prinzip (SRP) zu verstoßen
    • Denn es kann dazu führen, dass eine Klasse oder Schicht mehrere Rollen gleichzeitig übernimmt
      • Ausführung von Datenbankoperationen und Transaktionen
      • Darstellung von Datensätzen
      • Definition von Beziehungen
      • Erzeugen und Ausführen von Migrationen
    • Da der Zweck von ORM jedoch gerade darin besteht, zwei unterschiedliche Datenparadigmen zu verbinden, lässt sich ORM nicht allein wegen einzelner Prinzipienverstöße verwerfen
  • Separation of Concerns (SOC)

    • ORM kann auch das Prinzip der Separation of Concerns (SOC) verwischen
    • SOC besagt, dass eine Infrastrukturkomponente nur ein einziges Anliegen haben sollte
    • Weil ORM das Datenbankmanagement in Richtung Backend verlagert, kann man darin einen SOC-Verstoß sehen
    • Allerdings kombinieren heutige Infrastrukturkomponenten und Coding-Patterns mitunter mehrere Rollen, um Performance, Latenz und Code-Struktur zu verbessern
      • CPU-Aggregatoren in OLAP-Datenbanken
      • Edge-Backend-Frontend
      • Monorepo

Performance-Probleme entstehen häufiger durch die Nutzungsweise als durch ORM

  • Die Kritik, ORM sei immer ineffizient, ist größtenteils falsch
  • Viele ORMs können deutlich effizienter arbeiten, als Entwickler vermuten
  • Das Problem ist, dass ORM es leicht macht, Daten mit Logik in der Host-Sprache wie JavaScript oder Ruby zusammenzusetzen
  • Im TypeORM-Beispiel gilt es als schlechtes Muster, zunächst die Autoren eines bestimmten Unternehmens abzufragen, anschließend für jeden Autor erneut dessen Beiträge zu laden und jeden Beitrag separat zu speichern
  • Besser ist es, mit createQueryBuilder() von TypeORM eine einzelne Update-Abfrage zu konstruieren
  • Auch beim Refactoring der Billing-SQLs von Lago gab es zwischen der Active-Record- und der Raw-SQL-Version keinen Performance-Unterschied
    • Da die Daten-Join-Funktionen von Active Record stark genutzt wurden, waren die bestehenden Abfragen bereits optimiert
    • Die Neufassung in Raw SQL diente eher der Transparenz als der Performance-Verbesserung

Fälle, in denen ORM tatsächlich langsam werden kann

  • ORM ist nicht immer so effizient wie Raw SQL und kann in manchen Situationen erheblich ineffizient sein
  • Das erste Problem ist, dass ORM beim Umwandeln von Abfrageergebnissen in Objekte einen großen Rechen-Overhead erzeugen kann
    • TypeORM wird als Beispiel für dieses Problem genannt
  • Das zweite Problem tritt auf, wenn beim Traversieren von One-to-many- oder Many-to-many-Beziehungen mehrere Roundtrips zur Datenbank entstehen
  • Dieses Muster wird als N+1-Problem bezeichnet
    • Zu einer ursprünglichen Abfrage kommen N Unterabfragen hinzu
    • Im Prisma-Beispiel können beim verschachtelten Laden von Nutzern, Beiträgen und Kommentaren für jeden Kommentar neue Datenbankanfragen entstehen
  • N+1 tritt bei ORMs häufig auf, doch mit einem Data Loader lassen sich N+1 Abfragen auf 2 Abfragen zusammenfassen
  • Viele der typischen ORM-Probleme lassen sich vermeiden, wenn man die ORM-Funktionen ausreichend nutzt

Das größere Problem sind Transparenz und Debugging

  • Die größte Schwäche von ORM ist Transparenz
  • Da ORM faktisch ein Query Builder ist, ist es – abgesehen von offensichtlichen Fehlern bei primitiven Typen – nicht der letztliche Überbringer von Fehlern
  • Wenn ein SQL-Fehler zurückgegeben wird, muss das ORM ihn interpretieren und an den Nutzer weiterreichen
  • Active Record hatte an dieser Stelle Schwierigkeiten, und genau das war auch der Grund, warum Lago seine Abfragen für Billing-Abonnements refaktoriert hat
  • Bei unerwarteten Ergebnissen musste der folgende Ablauf wiederholt werden
    • Die gerenderte SQL-Abfrage prüfen
    • Diese SQL-Abfrage erneut ausführen
    • Den SQL-Fehler wieder in Änderungen an Active Record übertragen
  • Dieser Hin-und-her-Prozess schwächt den ursprünglichen Zweck, Active Record zu verwenden, nämlich nicht direkt mit der SQL-Datenbank interagieren zu müssen

Praktische Einschätzung

  • Richtig eingesetzt kann ORM eine Effizienz nahe an Raw SQL erreichen
  • Viele Probleme entstehen, wenn man die SQL-ähnlichen Funktionen von ORM nicht nutzt und sich zu stark auf die Logikstrukturen der Host-Sprache verlässt
  • Wenn große Abfragen Entwicklern Schwierigkeiten bereiten und das Debugging behindern, kann der Wechsel zu Raw-SQL-Abfragen eine gute Investition sein
  • Die meisten ORMs bieten die Möglichkeit, SQL-Abfragen innerhalb des ORM auszuführen

1 Kommentare

 
GN⁺ 2023-06-28
Hacker-News-Kommentare
  • Ich nutze ORMs seit dem Erscheinen von Hibernate in Java, aber ich fand sie immer eher schlecht.
    Der angebliche Vorteil „man kann auf eine andere Datenbank wechseln“ ist rückblickend fast Unsinn, und in der Praxis macht das ohnehin niemand.
    Auch die Aussage „man muss kein SQL kennen“ ist falsch; bei langlebigen, nicht trivialen Apps muss man am Ende individuelle Queries doch auf String-Ebene nachbearbeiten.
    Die Datenschicht sollte meiner Meinung nach Query für Query als String-SQL aufgebaut und interpoliert werden, und je näher man an raw JDBC ist, desto besser.
    Auch die Behauptung, ORM unterstütze ein „Domain Model“, ist ein schlechtes Argument, weil dieses Domain Model am Ende immer ein anämisches Domain Model ohne Logik wird.
    Wenn ich an die vergeudete Zeit für ORM, XML, Annotationen und das Debuggen des generierten SQL denke, möchte ich weinen.

    • Stimme voll zu. Ich würde ORMs so beschreiben: „Die einfachen Teile werden ein bisschen einfacher, aber die schwierigen Teile werden wirklich schwierig.“
      Die einfachen Teile sind ohnehin schon einfach und interessieren mich nicht besonders; stattdessen wurde die Arbeit oft millionenfach schwerer, weil ich genau in den schlimmsten Momenten, wenn Queries unter Last und Größe zusammenbrechen, zusätzlich noch mit dem ORM selbst kämpfen musste.
      Query Builder sind nicht vollständig dasselbe wie ORMs, aber ich mag den Artikel https://gajus.medium.com/stop-using-knex-js-and-earn-30-bf41... und bin ein Fan von Technologien wie Slonik geworden.
      Sie liefern 90 % der Funktionen, die ich haben will, etwa automatisches Binden der Ergebnisse an Objekte und starke Typprüfung, lassen mich aber einfach normales SQL schreiben.
      Ich verstehe auch nicht, warum SQL als mysteriös schwierige Sprache gilt. Sie ist alt und hat Schwächen, aber bevor ich eine eigens von ORM-Tools erfundene Query-Sprache lerne, lerne ich lieber SQL.
    • Ich mochte ORMs seit dem ersten Einsatz vor langer Zeit aus genau diesen Gründen nicht und hielt sie für ein Antipattern.
      Damals blickten andere Entwickler auf einen herab, wenn man solche Kritik äußerte.
      Auch heute gibt es als Entwickler viele Werkzeuge und Techniken, die man widerwillig benutzen muss und die Antipatterns sind; die unglückliche Realität der Branche ist, dass viele weit verbreitete Tools nicht besonders gut sind und Antipatterns sogar fördern.
      In der Tech-Branche gibt es eine kleine Zahl gut vernetzter Entwickler und Ex-Entwickler mit Entscheidungsmacht, und ich habe das Gefühl, dass sie nicht besonders gut sind.
    • Du hast ausgerechnet mit einem der schlimmsten ORMs angefangen, die es gibt.
      Es gibt auch ORMs mit einem vernünftigen Verhältnis von Vor- und Nachteilen, besonders im Python-Umfeld.
      Das Django ORM ist grob und nicht besonders performant, aber gut integriert, praktisch, produktiv und angenehm in der Nutzung.
      Peewee bietet ORM in einem kleinen Paket, sodass man kleine Programme angenehm schreiben kann, wenn man keine großen Funktionen braucht und sich nicht lange damit herumschlagen will.
      SQLAlchemy erfordert mehr Investition, ist aber sehr flexibel, erzeugt sauberes SQL und funktioniert korrekt.
      Es stellt auch einen Low-Level-Query-Builder bereit, für Fälle, in denen man kein objektorientiertes Paradigma will, sondern idiomatisches SQL-Verhalten abstrahiert in Python ausdrücken möchte.
      Am Ende ist es einfach eine normale Engineering-Entscheidung nach Return on Investment.
    • Die Aussage, man müsse „auf String-Ebene nachjustieren“, ist meiner Erfahrung nach Unsinn.
      Ich mache das seit über zehn Jahren, aber es gab keine Query, die sich nicht besser lösen ließ, wenn man fünf Minuten die Hibernate-Dokumentation liest und dann genau das tut, was dort für den Fall empfohlen wird.
      Es wirkt, als wollten SQL-Fanboys, die glauben, jeder Entwickler müsse Dreiwertigkeits-Logiktabellen und COBOL-artige Funktionsnamen auswendig kennen, sich ausgerechnet nicht die Mühe machen, die Hibernate-Dokumentation zu lesen.
    • „Man muss kein SQL kennen“ wurde von niemandem mit auch nur etwas Verstand je als Vorteil von ORM angeführt.
      ORMs sind für OLTP-Workloads gedacht, nicht für OLAP, und das hat auch einer der Hibernate-Gründer so gesagt.
      Der Hauptnutzen besteht nur darin, dass man lange, fehleranfällige INSERT-/UPDATE-Queries nicht von Hand schreiben muss und SQL-Zeilen automatisch auf Objekte gemappt werden.
      Wenn man auf den raw-Ansatz geht, implementiert man vieles davon wieder selbst; auch das ist also kein Nullsummenspiel.
  • In hinreichend komplexen Apps entsteht irgendwann so etwas wie ein Query Builder, bei dem mehrere Teile der App gemeinsam Queries verzögert zusammensetzen können
    Die Struktur läuft darauf hinaus, Daten nicht im Speicher zusammenzuführen, zu filtern und zu sortieren, sondern dies per Query zu kombinieren
    Ein ORM ist ein Werkzeug, mit dem sich so etwas leicht bauen lässt, kann einen aber auch unabsichtlich ins Knie schießen lassen, weil man damit leicht N+1-Queries erzeugt
    Wie bei jedem Werkzeug muss man die Trade-offs zusammen mit dem tatsächlichen Anwendungsfall abwägen, und SQL-Strings direkt zusammenzumanipulieren würde ich in keinem Fall empfehlen

    • Die Erfahrung mit ORMs kann sich je nach verwendeter Sprache, Integrationsgrad und Art der Arbeit extrem unterscheiden
      Trotzdem gibt es immer Leute, die diese Unterschiede ignorieren und absolut behaupten, ORMs seien gut oder schlecht
      Das sollte man besser als provokante Haltung zur Aufmerksamkeitserzeugung abhaken und sich auf Diskussionen konzentrieren, die bei „ORMs haben Vorteile, aber man muss wissen, wo sie gelten, und darauf achten, dass die Nachteile in der Nutzung die Vorteile nicht überwiegen“ anfangen
    • Ich halte es nicht für selbstverständlich, dass man in hinreichend komplexen Apps einen Query Builder braucht, und in meiner App akzeptiere ich das nicht
      Wenn Daten benötigt werden, geht man zur Datenzugriffsschicht, und wenn diese das Benötigte nicht bereitstellt, erstellt man ein neues Repository oder einen Provider oder etwas anderes, das zum gewählten Muster passt
      Ob ORM oder selbstgebauter Query-Kombinierer: Wenn eine App so weit ist, dass man sich einredet, sie sei „hinreichend komplex und brauche das“, ist sie bereits zu komplex, um noch stabil nutzbar zu sein
      Am Ende bewertet man den Builder auf der falschen Schicht oder übersieht beim Iterieren über Ergebnisse, dass man N+1-Queries erzeugt
      Ein ORM ist nicht nötig
    • Ich denke, das kommt dem nahe, was LINQ seit 2007 tut
      LINQ ist nicht exakt ein ORM; wenn man stark typisierte LINQ-Ausdrücke erstellt, werden sie in Ausdrucksbäume umgewandelt, die dann von einem Query-Provider wieder in Queries übersetzt werden
    • Da ich sowohl ORM als auch raw SQL verwende, kann ich beiden Seiten etwas abgewinnen
      Während der Entwicklung bevorzuge ich die Lesbarkeit eines ORMs innerhalb des Modells, beobachte aber bei Bedarf N+1 und andere Ineffizienzen sehr genau und optimiere dann
      Wo genau „bei Bedarf“ beginnt, ist nicht klar, aber ich versuche, nicht zu früh zu optimieren
      Bei neuen Projekten beginne ich eher von der Datenbank aus und verschaffe mir vor dem Coden mit Factorys, Seedern und raw-SQL-Queries ein Gefühl für das Datenmodell
      Ein ORM wie Eloquent von Laravel hat gute Methoden, um N+1 zu lösen und Lazy Loading auszuführen, aber es gibt immer Trade-offs
    • Es gibt auch Bibliotheken, die das ORM-Konzept auf den Kopf stellen
      Statt Bibliotheken, die verzögerte Query-Komposition erlauben, schreibt man die Query direkt, und die Bibliothek generiert zur Compile-Zeit den Code für genau diese Query
      Man schreibt zum Beispiel eine Query wie getUser: SELECT * FROM users WHERE id = ?, und daraus werden eine Klasse GetUserQuery und eine Methode wie getUser(id: String): GetUserQueryResult erzeugt; dieses Modell halte ich für deutlich besser
  • Mein Hauptproblem mit ORMs ist, dass sie moderne SQL-Engines oft wie übertrieben dumme Bit-Speicher behandeln
    CTEs, LATERAL-Joins und RETURNING-Klauseln können die Verarbeitung stark vereinfachen oder die Möglichkeit von Dateninkonsistenzen beseitigen, trotzdem bleiben ORMs meist dabei, Basistabellen und Views nur simpel auf vordefinierte Objekte abzubilden
    Wenn das ORM sogar die Tabellen erstellt, wird es noch schlimmer
    SQL ist im Kern ein Werkzeug zur Datengewinnung und zugleich eine Transformationssprache, aber ORMs ignorieren diese Seite fast vollständig, sodass viele Entwickler gar nicht wissen, dass SQL mehr bietet als INSERT/SELECT/UPDATE/DELETE
    Es gibt Pivot-Tabellen, temporale Abfragen, CUBE/ROLLUP, Window Functions, mengenrückgebende Funktionen, materialisierte Views, externe Tabellen, JSON-Verarbeitung, Datumsverarbeitung, Exclusion Constraints, Typen wie Range/Intervall/Domain, Row-Level Security, MERGE und vieles mehr
    Das ist, als hätte man eine komplette Werkstatt, aber jemand reicht einem nur je einen Hammer, Schraubendreher und eine Metallsäge und redet einem ein, das reiche völlig aus, während man die Karriere verbringt, ohne zu ahnen, dass nur ein paar Meter weiter Tischsäge, Oberfräse, Schleifer und ein Satz Keile stehen

    • Die meisten ORM-Frameworks bieten eine Funktion zum Ausführen von raw SQL, daher kann man solche Features auch mit ORM sehr wohl nutzen
      Ein ORM bringt einen zwar meist dazu, in einfachen CRUD-Statements zu denken, aber vielleicht ist genau das besser und fortgeschrittene Features sollten sparsam eingesetzt werden
    • Ich habe das Glück, meist an Projekten ganz ohne Datenbank zu arbeiten
      Selbst wenn ich eine DB benutze, versuche ich absichtlich, nur einen sehr kleinen Teil der DB-Funktionen zu verwenden
      Denn „Code“ ist ein Bereich, den man kontrollieren kann, während die „Datenbank“ ein gefährlicher, schwer greifbarer Bereich ist, in dem Fehler erst später in langsamen Integrationstests oder ähnlichem sichtbar werden
      Logik, die innerhalb der DB passiert, liegt außerhalb der Reichweite von Low-Level-Tests und ist mir deshalb unheimlich; wahrscheinlich würde ich nicht einmal select-from-select-Queries verwenden
      Auf den Großteil der Werkstatt würde ich gern verzichten
    • Deshalb überrascht es mich auch nicht, dass viele Entwickler den Unterschied zwischen SQL und NoSQL nicht erkennen
    • Mit wachsender Größe ist es aus Performance-Gründen üblich, Datenbanken stark zu denormalisieren und sie wie übertrieben dumme Bit-Speicher zu benutzen
    • Ich habe ein paar Projekte erlebt, in denen es hieß: „Solche schicken Datenbank-Features brauchen wir nicht“, und es war frustrierend, mit dem Ergebnis umzugehen
      Die meiste Zeit ging dafür drauf, ausgefeilte Umgehungslösungen zu bauen, um grundlegende Schutzmechanismen für Datenintegrität neu zu erfinden
      Seine eigene Datenbank zu bauen mag zum Lernen Spaß machen, aber nicht für Produktionsanwendungen
  • ActiveRecord hat sich immer gut angefühlt
    Es gibt einige Ausnahmen, aber es trifft den 80/20-Punkt gut, man kann bei Bedarf zu SQL ausbrechen, und die Lifecycle-Hooks zum Organisieren von Domänenlogik sind großartig und leicht zu verstehen
    Praktische ORMs, die nicht alles hinter „Magie“ verstecken oder eine eigene Query-Sprache einführen, sind gut
    Schwer handhabbar sind die ORMs, die versuchen, das ORM-Problem vollständig zu „lösen“

    • ActiveRecord macht wirklich Spaß in der Nutzung, und wenn man auf einen Edge Case stößt, kann man jederzeit zu raw SQL zurückkehren
      So sollte ein ORM gebaut sein
    • Es ist schwer vorstellbar, eine große CRUD-App noch einmal ohne ActiveRecord zu bauen; Lesbarkeit und Wartbarkeit würden darunter leiden
      Um es aber richtig zu verwenden, braucht man gute SQL-Vorkenntnisse
      Probleme entstehen, wenn Leute SQL nicht lernen und die von AR erzeugten Queries sowie seine Grenzen nicht verstehen
    • Ich verstehe die Beschwerden über ORMs nicht so ganz, aber das könnte daran liegen, dass das einzige ORM, das ich benutzt habe, ActiveRecord ist
  • Die Prämisse ist falsch. Ein ORM war nie eine „schädliche Idee“.
    Es gibt ORMs, mit denen die Zusammenarbeit schrecklich ist, aber das bedeutet nicht, dass das ganze Genre eine schlechte Idee ist.
    SQLAlchemy nutze ich seit Jahren gern, weil es nicht versucht, das Konzept von SQL selbst neu zu erfinden.
    Stattdessen bietet es eine praktische Schicht zum Erstellen und Übergeben von Queries und kümmert sich sauber um die kleinen Details, sodass man nicht selbst daran herumfummeln muss.

    • Meine ORM-Erfahrung beschränkt sich fast nur auf SQLAlchemy und ein wenig Ecto, daher frage ich mich beim Lesen dieses Threads, ob alle anderen ORMs wirklich so schrecklich sind.
      Während ich zuletzt Rust gelernt habe, fühlte es sich schmerzhaft und wie Zeitverschwendung an, Boilerplate für einfaches CRUD selbst zu schreiben.
      Das SQLAlchemy-ORM kann bei komplexeren oder zu optimierenden Queries etwas im Weg sein, aber in solchen Fällen kann man jederzeit direkt auf SQL heruntergehen.
    • Es ist wirklich lange her, dass ich die Formulierung „begging the question“ einmal korrekt verwendet gesehen habe.
    • SQLAlchemy kann ich empfehlen, weil es einem erlaubt, SQL selbstbewusst so zu schreiben, dass der Code zur Query passt.
  • Wie bei allem gibt es Situationen, in denen es gut passt, und solche, in denen es das nicht tut, und Technologie lässt sich leicht überstrapazieren oder falsch einsetzen.
    ORMs wie zum Beispiel Entity Framework in .NET können ein großer Gewinn sein, besonders wenn man mit einem Database-First-Ansatz arbeitet.
    Wenn man eine DB mit Hunderten von Tabellen und korrekt angelegten Fremdschlüsselbeziehungen hat, hilft ein ORM dabei, ein komplexes Schema zu durchdringen und bei Änderungen Prüfungen zur Compile-Zeit zu bekommen.
    Eingebettetes SQL ist ein zweischneidiges Schwert, das wie ein Performance-Vorteil wirken mag, aber besonders bei Joins ist hart kodiertes, ausuferndes SQL sehr schwer wartbar.
    Gemeint sind nicht 5 bis 10 Tabellen, sondern Hunderte davon.
    Ich will niemanden überzeugen, aber man sollte nicht einfach alles glauben, was man im Internet über Best Practices liest.
    Es kann gut sein, dass Leute über völlig unterschiedliche Dinge sprechen, und es gibt schlechte Entwickler, egal welche Technologie man verwendet.

  • Wenn man kein ORM oder anderes DB-Interface verwendet, schreibt und pflegt man am Ende selbst eines für Dinge wie CRUD.
    Und darin landen dann mit hoher Wahrscheinlichkeit seltsame Bugs, Edge Cases und Sicherheitslücken.
    Es ist auch problematisch, wenn Prinzipien wie SOLID in Universitätskursen als Prinzipien des Softwaredesigns gelehrt werden.
    In der Wissenschaft ergibt das Sinn, weil dort Randbedingungen wie Zeit, Wartbarkeit, Geld und Aufwand weniger wichtig sind, aber wenn frische Absolventen in die Praxis kommen, führt das zu einem sehr unangenehmen Aufprall.
    Sie sind daran gewöhnt, den ganzen Tag Yak Shaving zu betreiben und das Rad neu zu erfinden, um eine „perfekte“ Lösung zu finden.
    Wenn es nicht genug fähige Senior-/Lead-Entwickler gibt, die das einfangen, bekommt man sehr interessante Produkte, Budgetüberschreitungen, Großbrände oder eine Kombination daraus.
    Noch schlimmer ist es, wenn etwas, das in der Wissenschaft entwickelt und für die Wissenschaft entworfen wurde, auf die breite Öffentlichkeit losgelassen wird.
    Ein typisches gutes/schlechtes Beispiel ist OpenStack: Es hat so viele Hebel und Stellschrauben und seine Komponenten sind wahnsinnig modularisiert, damit es die Spezialumgebungen von CERN und Hunderten von Universitäten unterstützen kann, aber es ist so byzantinisch, dass der Einstieg nahezu unmöglich ist.

    • In diesem Thread wird viel darüber geklagt, dass ORM nicht zu den Versprechen der Anbieter passt, und das stimmt auch.
      ORM macht den Wechsel der Datenbank nicht mühelos, nimmt einem nicht die Notwendigkeit ab, das erzeugte SQL zu lernen und zu verstehen, und glättet auch das Schema nicht.
      Trotzdem nutzt man es, weil es eine Standardabstraktion ist, die man sonst ohnehin duplizieren müsste.
      Es macht Caching von DB-Zugriffen möglich, was mit manuellem SQL mit wachsender Größenordnung überraschend schwierig wird.
      Dazu kommen standardisierte Werkzeuge und Best Practices, die Probleme wie N+1 irrelevant machen können.
      Das Hauptproblem bei ORM sind falsche Erwartungen und schlechte ORMs.
      Wenn man den Wert von ORM verstehen will, öffnet man einfach ein Projekt, das ohne ORM geschrieben wurde, und versucht, irgendetwas daran zu ändern.
    • „Am Ende baut man selbst eines“ stimmt nur dann, wenn man darauf besteht, die Logik nicht nach Zeilen, sondern nach Objekten zu strukturieren.
      Siehe https://news.ycombinator.com/item?id=36498583.
    • Einige Abteilungen und mehrere Firmen haben gelitten oder sind gescheitert, weil ein oder ein paar Supergenies der Perfektion hinterhergelaufen sind.
      Dadurch kamen nützliche Dinge nicht voran oder dauerten 20- bis 100-mal länger als ein schneller, schmutziger Ansatz.
      Am schlimmsten war ein Fall, in dem ein Team erfahrener HTML-Designer gezwungen wurde, funktionale Programmierung zu lernen.
      Der Backend-Konfigurationszauber war ein Wunderwerk moderner Ingenieurskunst und eleganten Designs, aber 10 Leute haben ein Jahr dafür gebraucht.
      VC-Geld macht Menschen seltsam.
    • Ich habe so viel Negatives über SQLAlchemy gehört, dass ich beschlossen hatte, selbst einen leichten Query Builder zu bauen, aber acht Monate später benutze ich doch SQLAlchemy.
      Die SQL-Sprache ist sehr komplex, und einen ordentlichen, voll funktionsfähigen Query Builder zu bauen, ist wirklich alles andere als trivial.
      Das gilt selbst dann, wenn man den eigentlichen relationalen Mapping-Teil außen vor lässt.
    • Es ist besser, ein gutes ORM zu verwenden, andernfalls lädt man sich am Ende die Hälfte eines schlechten ORM selbst auf.
  • Ich denke, SQL ist ein Fall von „programmiere den verdammten Kram einfach direkt“
    Es hat wenig Sinn, SQL oder ORM-Bibliotheken zu lernen; es ist besser, SQL direkt zu lernen und zu verwenden
    Datenbankzugriff ist wahrscheinlich eine grundlegende Aufgabe, die einen die ganze Karriere begleitet, daher ist es am besten, die eigentliche Technik direkt zu lernen
    Bei CSS ist es ähnlich: Statt CSS-Bibliotheken zu lernen, sollte man CSS selbst lernen und verwenden
    Eigentlich gilt das für fast alle Aspekte der Frontend-Entwicklung, und statt einer „Form-Library“ kann man direkt mit der Form-API des Browsers arbeiten
    Für mich persönlich war SQL viel leichter zu lernen als jedes ORM
    Man sollte keine Kosten darauf verschwenden, etwas Falsches zu lernen

    • Wenn man zuerst SQL lernt, weiß man auch, wann man ein ORM verwenden sollte, und kann ORMs besser beurteilen
      Bei CSS ist es genauso: Wenn man CSS kennt, ist man viel flexibler und versteht besser, wie man Bibliotheken aus Bequemlichkeit auswählt
    • SQL wird schon lange als ewige Sprache bezeichnet
      Über Mainframes, Desktops, Client/Server, das Web und die vielen Sprachen auf diesen Plattformen hinweg war SQL immer der gemeinsame Faden
      Ich stimme völlig zu, dass Entwickler, die die Datenschicht und das, was darunter passiert, gut verstehen, stärkere Entwickler sind
      Wenn man ohnehin Zeit darauf verwenden will, die Eigenheiten eines ORMs zu lernen, warum diese Zeit nicht stattdessen in SQL investieren? Das ist die klassische Frage
      Der Zinseszinseffekt von SQL-Erfahrung dürfte in 10–15 Jahren wertvoller sein als das ORM einer bestimmten Plattform oder Sprache
      Es gibt Gründe, ORMs zu lernen und zu verwenden, aber man sollte sich nicht nur deshalb in Richtung ORM bewegen, weil man SQL nicht lernen will
    • Im Kern geht es eher um „lerne zuerst die Grundlagen, bevor du die Abstraktion lernst“
      Nur dann weiß man, welchen Preis man für diese Abstraktion zahlt. Außer natürlich, es handelt sich um eine „Zero-Cost-Abstraction“
    • Seit 1992 habe ich SQL direkt mit Pro*Pascal und CS130 verwendet
      Heute nutze ich jedoch crud von azer, das wegen des Marshalling/Unmarshalling mit Go-Typen als ORM eingeordnet werden könnte
      Die Go-Standardbibliothek sql ist so elementar, dass man Objekt-Marshalling/Unmarshalling praktisch selbst schreiben muss, und das ist wirklich langweilig
      Wenn ich heute ein ORM verwenden würde, dann wahrscheinlich nur für genau diesen Zweck
  • Ich mag Mikro-ORMs als „Mittelweg“ wie Dapper oder Diesel
    Man schreibt die Queries in SQL, bekommt aber starke Typisierung und automatisches Objekt-Mapping der Result Sets
    Man erhält also Produktivität zusammen mit einer vollwertigen „echten“ Query-Sprache
    Außerdem mag ich inzwischen den Ansatz, Objekt-Mapper nur für Read-only-Queries zu verwenden
    Updates erfolgen per Command-Pattern, also über Stored Procedures, die man so mappen kann, dass sie wie native Methoden aussehen

    • Dapper war die angenehmste Lösung für Datenzugriff, die ich bisher verwendet habe
      Entwickler sollten nicht so tun, als gäbe es SQL nicht, sondern es einfach akzeptieren
    • Mir gefällt, dass ich weder Modellfunktionen direkt selbst schreiben muss, die am Ende doch nur auf SQL abgebildet werden, noch Boilerplate-PHP für korrekt parametrisierte Queries schreiben muss
      Eloquent abstrahiert diese Routinearbeiten ausreichend, sodass ich mich auf die Logik konzentrieren kann
      Ich schreibe gerade eine „alte“ PHP-App, die nur aus Arrays und Queries besteht, auf eine Struktur mit Modellen und Eloquent um, und es fühlt sich nach einem kompletten Gamechanger an
    • Ich mag den Mittelweg. In TypeScript gibt es zum Beispiel Kysely oder mein eigenes Projekt Zapatos
    • Ich halte das für den Sweet Spot
      Früher, als ich SQLite unter .NET verwendet habe, habe ich sogar selbst eine Wrapper-Bibliothek in diese Richtung gebaut: https://github.com/zmj/sqlite-fast
  • Dieser Thread zeigt sehr gut die Mindshare-Dominanz von ORMs
    In fast allen Kommentaren ist die implizite Alternative zum ORM rohes SQL als String-Literal im App-Code
    Schon vor 6 Jahren gab es Tools, die SQL als eigene Sprache verwenden und Wrapper generieren, die Queries der App als Methoden bereitstellen
    Dinge wie queryfirst, pgtyped, pugsql und sqlc
    Das war ein Paradigmenwechsel oder hätte zumindest einer werden können, und es zeigt sich, dass es eine klar überlegene Art zu arbeiten ist; aber ORMs und diese unveränderliche Diskussion saugen den ganzen Sauerstoff auf, sodass das am Rand bleibt

    • Stimmt. In Go gibt es auch sqlc
      SQL ist eine Sprache, und zwar eine Sprache auf sehr hohem Niveau
      SQL in einer noch niedrigeren Sprache zusammenzustückeln ist ein Paradebeispiel für „wenn man einen Hammer hat, sieht jedes Problem wie ein Nagel aus“
      Wenn man zum Beispiel in einer Low-Level-Sprache wie Assembler codiert und mit einem großen System interagiert, dessen Dokumentation sagt, dass Eingaben nur in JavaScript ausgedrückt werden können, dann hat man eine Wahl
      Man kann eine obskure Bibliothek holen, mit der man in reinem Assembler irgendetwas zusammenstückelt und dann keine xxx.js-Datei ins Repository committen muss, oder man drückt es einfach als .js-Datei aus und nutzt die Stärke der High-Level-Sprache
    • Seit ich sqlc in einem Projekt verwendet habe, glaube ich nicht, dass ich jemals zurückgehen könnte
      Man bekommt eine Single Source of Truth für die verwendeten SQL-Queries, und weil das, was man tatsächlich schreibt und pflegt, die Queries selbst sind, werden Optimierungen wie das Anlegen neuer Indizes ebenfalls einfacher
    • ActiveRecord war immer ziemlich schlecht, aber arel, das intern Queries aufbaut, hat mir immer gefallen
      Eine Abstraktion über rohe SQL-Strings zu legen ist sehr nützlich, aber Relationen so zu behandeln, als wären sie Objekte, ist ein unnötig verworrener Ansatz
    • Das Enterprise Objects Framework von NeXT konnte das schon vor über 25 Jahren
      TopLink wahrscheinlich auch
      So wurde damals das Mapping zwischen Stored Procedures und lokalen Entitäten gehandhabt
    • Ich frage mich, welche Tools das sind