Hallo Lukas
I could surely write all the stuff in english to fit to the google group (hi
there), but honestly I'm currently too lazy for it :(.
So I go on writing in German.
------------
Vielen Dank, das waren alles sehr interessante Absätze und Links.
Es ist natürlich sehr legitim, pragmatisch und auch benötigt, einen Ansatz von
"Your database comes first" zu bieten.
Sicher gibt es mehr bestehende Systeme als "grüne Wiese" Situationen. Darum
werden in der SqlEngine auch beide Generierungsrichtungen "DB -> Java" und
"Java -> DB" verfolgt.
Meine Erfahrung ist jedoch (leider, muss ich sagen), dass vor lauter
Altsystemargumentation die Grüne Wiese, bei der echte Innovationen
vorangetrieben werden könnten, vernachlässigt wird. Wenn man dann mal eine
Grüne Wiese vor sich hat verfolgt man doch wieder die alten Ansätze, von denen
man eigentlich weiß, dass sie suboptimal sind weil a) man es so schon immer
gemacht hat und b) die Technologien die innovativen Ansätze ausgeklammert
haben, fast wie eine Art self-fulfilling Prophecy. Und dadurch ändert sich
"nie" oder nur sehr langsam etwas.
Darum sehe ich den Grüne-Wiese-Ansatz entgegem allem Pragmatismus als den
wichtigeren an und die Altsystemkompatibilität eher als das Stiefkind.
Unter dieser Philosophie steht auch das ORM Konzept:
Man kann natürlich versuchen, wie JPA das macht, zwei im Detail unvereinbare
Welten - ER und OOP - doch irgendwie so halb und halb zusammenzumixen. Das
Ergebnis davon ist natürlich unweigerlich auf beiden Seiten unbefriedigend:
OOP-seitig macht man alles "unnötig" kompliziert, eingeschränkt, unsauber und
auf der ER Seite ist trotzdem nicht das alles möglich, was ein ER-Design
eigentlich machen würde.
Für mich ist soetwas bestenfalls eine pragmatische Workaround Lösung, aber
keine saubere Technologie.
Wenn man ORM machen will, dann liegt der Designschwerpunkt sowieso auf der OOP
Seite. Und die wird kompromissmlos in den "Persistenztopf" projiziert. Das ist
erstaunlich einfach, wenn man 2-3 neue Konzepte verwendet - und auf einmal
verschwindet eine unendliche Menge an Problemen, die man sich mit dem "aber wir
müssen Altsystem-kompatibel bleiben"-Ansatz einhandelt (und deren erhöhter
Behandlungsaufwand wahrscheinlich einer sauberen Portierung auf ein neues
System gleich kommt).
Man kann darauf immer noch mit SQL zugreifen und auch gut strukturiert
Änderungen vornehmen. Aber die komplexen Änderungen finden ja doch auf Seite
der Businesslogik, also im Anwendungscode statt.
Der Artikel "Historical Perspective of ORM and Alternatives" ist schon
interessant und enthält natürlich viel richtiges, aber mir ist es etwas zu
einfach. Da werden die guten alten Zeiten von "früher ging es doch auch"
beschworen, als alles noch "ganz einfach" war.
Mir kommt es vor als würden da Komplexität-10 Äpfel von früher mit
Komplexität-1000000 Birnen von heute verglichen.
Es geht bei OOP ja nicht darum, "schönen" Code um seiner selbst Willen zu
haben, sondern um Komplexität besser zu handeln.
Bei "The tables [...] have a place for everything and everything in its place,
and after that the application code mostly writes itself." hab ich dann
aufgehört zu lesen. Zu realitätsfremd. Und das sage ich wohlgemerkt als jemand,
dessen aktuelles Projekt zu 90% aus Datenmengenoperationen in der Datenbank
besteht. Die Tabellen dafür zu definieren ist der leichteste Teil. Der
interessante Teil ist, effizient strukturierten Code zu schreiben der die ganze
Komplexität abbildet und trotzdem übersichtlich, flexibel, leicht wartbar, etc.
ist.
Und dafür muss alles "aus einem Guss" sein (und es klappt tatsächlich).
Die rhetorische Frage "Anders lässt sich die Aussage "mit minimalem Aufwand
austauschen" kaum erhärten...?" hab ich nicht verstanden in dem Zusammenhang
:-/. Mir ist aber aufgefallen, dass ich "Substituieren" komplett falsch
geschrieben hatte :DD.
Mit LINQ habe ich noch nicht gearbeitet. Zugegeben. In den Zusammenhängen, wo
ich darauf gestoßen bin ging es auch eher um Arbeiten auf Collections.
Wie auch immer, mein Punkt war nur: Ich finde Lösungen über APIs (jOOQ, usw.)
besser als fremde Sprachen als Artefakte in der Hauptsprache einzubetten,
einfach weil sie sich besser in die Programmlogik integrieren lassen.
Oh ich wollte noch was konkret zu dem Tutego Gastbeitrag schreiben:
An folgendem Beispiel werden die vielen nötigen Klammern selbstkritisch
angezeigt:
create.select()
.from(BOOK)
.where(Book.AUTHOR_ID.in(create.select(Author.ID)
.from(AUTHOR)
.where(Author.BORN.equal(1920))));
Nun wäre die Zahl der Klammern bei der SqlEngine natürlich genauso ;) (die
Syntax ist in diesem Beispiel fast identisch, außer dass ich SQL-Syntax
entsprechende Methoden in capslock schreibe, also SELECT usw. Man darf das
nicht als "Bruch" mit der Java Naming Convention sehen, sondern als Erweiterung
zur deutlichen Anzeige der SQL Konstrukte).
Worauf ich stattdessen hinaus will ist:
Dieses Einrückungsschema ist ein Graus. Wenn man das verbessert lindert sich
das Problem mit den Klammern schon deutlich.
Zum einen das "create.", das schon gleich mal eine Einrückung nach sich zieht.
Was ist "create" eigentlich? Eine klein benannte static util class? Eine
Factory Instanz?
Im ersten Fall kann man ja immerhin von static imports gebrauch machen.
Z.B. in meiner SqlEngine: SQL.SELECT()
Mit static import der factory Methode SQL.SELECT() steht dann nur noch da:
SELECT()
.FROM(BOOK)
.WHERE(...) //usw...
Ähnlich mit den Sub-SELECTs. Wieso nicht einfach so:
select()
.from(BOOK)
.where(Book.AUTHOR_ID.in(
select(Author.ID)
.from(AUTHOR)
.where(Author.BORN.equal(1920))
));
So sieht man klar die beiden SELECT-Ebenen entsprechend der Einrückung des Java
codes und die "));" schließen optisch ganz natürlich das ".where(" ab. Außerdem
kann man zwei Klammern optisch noch leicht zuordnen. Und auf einmal wird alles
sehr viel kompakter und trotzdem gleichzeitig übersichtlicher.
Der Einrückungsstil macht das Framework natürlich nicht besser oder schlechter.
Ich wollte nur sagen dass man es sich auch unnötig schwer machen kann - aber
nicht unbedingt sollte ;).
Ich weiß nicht, wie interessant es an dieser Stelle ist, aber hier ein Link zu
dem Java RAD-IDE Produkt unserer Firma, in der meine SqlEngine - abgesehen von
unseren Kundenprojekten, die natürlich nicht öffentlich sind - als Kern der
Datenbankabfragen verwendet wird:
http://www.xdev-software.de/
Allerdings wird durch die RAD Konzepte nach außen hin nochmal ein anderer
Ansatz verfolgt (Vereinfachung, Assistenten), so dass die SqlEngine nur ein
internes Modul, aber keine Schnittstelle für den (RAD-)Entwickler mehr ist.
So jetzt hab ich den Großteil des Abends damit geschlachtet, aber war trotzdem
interessant :-)
Gruß,
Thomas
-------- Original-Nachricht --------
> Datum: Fri, 15 Jul 2011 19:51:37 +0200
> Von: Lukas Eder <[email protected]>
> An: "Thomas Münz" <[email protected]>
> CC: [email protected]
> Betreff: Re: SqlEngine vs jOOQ
> Hallo Thomas.
>
> I allow myself to move this discussion to the jOOQ user group since I
> deem the general topic and ideas behind our two frameworks to be of
> interest to a broader public. Also, maybe this will capture Timo
> Westkämper's attention (also a German-speaker), who is behind another
> very nice framework with similar goals: QueryDSL. In general, the user
> group is in English, but since we started in German on Christian
> Ullenboom's blog, I guess non-German-speakers can follow this
> particular thread using Google Translate. Here's the original blog
> entry:
>
> http://www.tutego.de/blog/javainsel/2011/07/gastbeitrag-sql-als-interne-dsl-in-java-mit-jooq/
>
> Start of the German thread:
>
> ----
>
> > Viel wichtiger ist eh die Richtung:
> > Java Klassen -> DB Tabellen.
>
> Das ist durchaus ein gangbarer Ansatz, ähnlich wie Hibernate/JPA.
> Wichtig ist, dass ein framework eine klare Vision verfolgt. Diejenige
> von SqlEngine ist offensichtlich die Idee, dass das Schema in Java
> geschrieben wird. Davon distanziert sich jOOQ allerdings klar durch
> die Aussage:
>
> How does jOOQ help you?
> > Your database always comes FIRST! That's where
> > the real schema is, not in your Java code or some
> > XML mapping file.
>
> Somit richtet sich jOOQ historisch primär an Entwickler, welche auf
> Teile von komplexen, verteilten Systemen in mittelgrossen bis grossen
> Datenbanken zugreifen. Damit meine ich zwischen 1000 und 10000
> Tabellen und anderen Schema-Objekten. Solche Systeme sind sehr
> langlebig und überdauern in der Regel Java/C++/C# und viele andere
> Clients, welche darum herum geschrieben werden. Ein interessanter
> Artikel dazu (auch auf der jOOQ-Seite):
>
> http://database-programmer.blogspot.com/2010/12/historical-perspective-of-orm-and.html
>
> Insbesondere der Absatz über "Persistence" gefällt mir. Dies ist
> natürlich eine Sicht der Dinge, welche nicht "besser" oder
> "schlechter" als eine andere ist. Aber sie ist angepasst an den
> Bedürfnissen von Entwicklern und Architekten, die an einem System
> arbeiten, in dem es höchst relevant ist, ob der Oracle-spezifische
> functional-based Bitmap-Index auf Spalte X im selben Tablespace liegt
> wie die Tabelle selbst. Diese Art von Kontrolle über ein Datenschema
> ist mit dem Ansatz von SqlEngine kaum erreichbar oder wünschenswert,
> aber für die Benutzer von SqlEngine wahrscheinlich auch nicht von
> Bedeutung.
>
> > Also ich meine keine ORM Projektion, sondern aus klassenmäßigen SQL
> Framework Representationen dann in der DB Tabellen erzeugen. Damit hat man
> alles aus einem Guss, kann von der Logikseite aus Dinge wie Initialdaten usw
> reinbringen. Sogar OOP Vererbung für die Definition der Tabellen verwenden
> (wenn auch nicht für die Tabellen selbst in der DB).
>
> Interessant wäre ein Mapping von Vererbung direkt auf die
> darunterliegende Datenbank, dort wo das unterstützt wird. Zum Beispiel
> in Postgres:
> http://www.postgresql.org/docs/9.0/static/ddl-inherit.html
>
> Ich werde in nächster Zeit (logischerweise) den umgekehrten Weg
> überprüfen. Das generieren von Java-Klassenhierarchien aus
> Postgres-Tabellenvererbung. Dies ist allerdings keine Priorität.
>
> > Beispielsweise besteht das Deployment meines Projekts in der Arbeit
> einfach nur aus dem Starten der Anwendung. Der Rest (Tabellen, Indizes, etc.
> anlegen, Initialdaten holen, usw.) geschieht automatisch auf generischem Weg.
>
> Das kann für einen Java-Entwickler in der Tat sehr praktisch sein,
> auch für Projekte, welche auf der "grünen Wiese" beginnen. Ideal ist
> so etwas z.B. für ein Forum, Blog, etc. Einfach .war-File deployen,
> JDBC-Datenquelle konfigurieren und los geht's! Es würde mich
> insbesondere interessieren, inwiefern QueryDSL diesen Ansatz
> unterstützt. QueryDSL bietet ebenfalls DDL Befehle an. Siehe ganz
> unten auf dieser Seite:
>
> http://blog.mysema.com/2011/01/querying-in-sql-with-querydsl.html
>
> > Dialekt Abstraktion war das was ich knapp mit "Wegabstrahieren"
> bezeichnet hatte. Geht bei DDL dann natürlich auch um Datentypen, etc.
> > Das war eine der Hauptmotivationen: komplette DB-unabhängigkeit (die
> JDBC allein ja längst nicht liefert).
> > Einfach alle SQLs abstrahiert entwickeln und wenns sein muss (hatten wir
> tatsächlich mal im Projekt) kann der Datenbankhersteller mit minimalem
> Aufwand einfach ausgetauscht werden.
>
> Aus Java-Sicht ist das natürlich lobenswert. Mit Hibernate/JPA oder
> jOOQ-Konkurrenzprodukten wie QueryDSL, welches sich sehr schön in JPA
> integriert und Criteria Query ersetzt, kann dieselbe Strategie
> gefahren werden. Mit jOOQ stelle ich mich auf den Standpunkt, dass bei
> grossen Systemen die Datenbank ein sehr essentieller Bestandteil
> darstellt, und nicht einfach als "Persistenz-Topf" verwendet wird.
> Unter Umständen sind auch mehrere Datenbanken von verschiedenen
> Herstellern am System beteiligt. Es werden hunderte von Stored
> Procedures geschrieben, welche die Vorzüge der Datenbank des einen
> Herstellers ausnutzen. Dies gilt im Besonderen für DB2, Oracle oder
> SQL Server. Siehe dazu auch mein Artikel über Stored Procedures:
>
> http://java.dzone.com/articles/2011-great-year-stored
>
> > Das Substutieren von Funktionalität ist interessant. Das mach ich
> bisher noch nicht. Teils absichtlich, teil weil ich es in den projekten nicht
> brauche.
>
> Anders lässt sich die Aussage "mit minimalem Aufwand austauschen" kaum
> erhärten...?
>
> > Egal ob SqlEngine oder jOOQ, ich finde solche eine API Lösungen noch
> eleganter als so "built-in" Artefakte wie C#'s LINQ, weil besser in den
> Programmablauf integrierbarer usw. Insofern freu ich mich fast, dass Java kein
> LINQ Pendant hat *gg*.
>
> Hast du denn schon mit LINQ gearbeitet? Bei LINQ geht es ja nicht nur
> um LINQ to SQL, sondern ganz generell darum, dass die Sprache und die
> Syntax von C# mit formell auf Compiler-Stufe um neue Elemente
> erweitert werden kann, in diesem Fall für generelle Abfrage-DSL's.
> Somit kann also formell überprüft werden, ob der Tabellenalias, von
> dem man ein Feld dereferenziert, auch korrekt deklariert wurde. So
> etwas ist weder mit jOOQ noch mit SqlEngine möglich...
>
> Freu mich auf weiteres Feedback
>
> Gruss,
> Lukas
>
> Am 15. Juli 2011 18:06 schrieb "Thomas Münz" <[email protected]>:
> > Hallo Lukas
> >
> > (ich ergreif einfach mal das Du, Internet- und
> Informatiker-mentalitätsmäßig)
> >
> >
> > Ich weiß nicht, wann der Ullenboom den Kommentar freischaltet (wieso
> muss auf einmal freigeschalten werden? Evtl zu lang, hehe), darum schick ich
> ihn gleich nochmal per Mail.
> >
> > Ich kann ja zu ORM und bei Bedarf zu Collections auch noch was schreiben
> =)
> > ---------------------
> >
> > Hi
> >
> > Danke für die Antwort. Denke aber ab einem bestimmten Punkt muss das
> wohl eher in Mails verlagert werden :).
> >
> > FETCH FIRST n ROW[S] ONLY ist tatsächlich inzwischen schon im SQL
> Standard, oder einem Randteil davon, aber sei's drum. Das ist natürlich nur
> ein
> Detail.
> >
> > Code Generator:
> > Klar. Von DB Tabellen nach Java Klassen, hab ich gelesen.
> > Ich will jetzt nicht das leidige "hab ich auch alles" Spielchen
> anfangen. Viel wichtiger ist eh die Richtung:
> > Java Klassen -> DB Tabellen.
> > Also ich meine keine ORM Projektion, sondern aus klassenmäßigen SQL
> Framework Representationen dann in der DB Tabellen erzeugen.
> > Der große Unterschied ist nämlich:
> > Damit hat man alles aus einem Guss, kann von der Logikseite aus Dinge
> wie Initialdaten usw reinbringen. Sogar OOP Vererbung für die Definition der
> Tabellen verwenden (wenn auch nicht für die Tabellen selbst in der DB).
> > Beispielsweise besteht das Deployment meines Projekts in der Arbeit
> einfach nur aus dem Starten der Anwendung. Der Rest (Tabellen, Indizes, etc.
> anlegen, Initialdaten holen, usw.) geschieht automatisch auf generischem Weg.
> > Auch wichtig um wie gesagt nicht ständig an zwei Seiten rumwarten zu
> müssen (Javaklassen aus Tabellen neu generieren lassen erzeugt halt massig
> Compiler Fehler und damit Nacharbeitungsaufwand. Tabellenklassen live
> refatoren und dann automatisiert die DB Struktur anpassen lassen hat dieses
> problem nicht).
> > Das entzerrt dann natürlich wieder ganz enorm Programmarchitekturen,
> weil die DB "nur" noch ein "dummer" von Java aus gesteuerter Container ist
> und mit der Business Logik nichts mehr zu tun hat.
> >
> > Dialekt Abstraktion war das was ich knapp mit "Wegabstrahieren"
> bezeichnet hatte. Geht bei DDL dann natürlich auch um Datentypen, etc.
> > Das war eine der Hauptmotivationen: komplette DB-unabhängigkeit (die
> JDBC allein ja längst nicht liefert).
> > Einfach alle SQLs abstrahiert entwickeln und wenns sein muss (hatten wir
> tatsächlich mal im Projekt) kann der Datenbankhersteller mit minimalem
> Aufwand einfach ausgetauscht werden.
> >
> > Das Substutieren von Funktionalität ist interessant. Das mach ich
> bisher noch nicht. Teils absichtlich, teil weil ich es in den projekten nicht
> brauche.
> >
> > ORM: Okay dann hab ich das missverstanden. Gut dass mal einer saubere
> Grenzen zwischen SQL Abfragedefinition und ORM zieht :-)
> >
> >
> > Jedenfalls muss ich sagen, dass es natürlich eine zweifelhafte
> Legitimität von mir hat, ohne Webseite, Doku, etc. trotzdem rumzukritisieren.
> Bzw
> wenn ich das schon hätte würde ich schon längst mit dem Framework
> hausieren gehen :D.
> > Von diesem Punkt her ist jOOQ natürlich klar "überlegen". Einfach weil
> es dokumentiert verwendbar ist und mein Code eigentlich nur ein Open
> Source firmeninternes Werkzeug ist.
> >
> > Darum ja der Ärger über mich selbst :D.
> >
> > Quellcode gibt's hier: http://jadoth.sourceforge.net/
> > Allerdings hab ich 2010 ein verbessertes Collections framework
> "dazwischengeschoben", an dem ich immer noch hänge (siehe blog
> http://www.jadoth.net), darum längere Zwangspause.
> > War wohl auch die Pause, die es ermöglicht hat, dass vergleichbare
> Frameworks aufkommen bevor ich meins soweit releasereif habe. Denn seit Beginn
> meiner Arbeiten hab ich immer wieder nach vergleichbaren Frameworks
> gesucht, aber nie was ernstnehmbares gefunden (bis heute ^^).
> >
> > Naja Rest per Mail, denk ich.
> >
> >
> > Ach doch, noch was:
> > Egal ob SqlEngine oder jOOQ, ich finde solche eine API Lösungen noch
> eleganter als so "built-in" Artefakte wie C#'s LINQ, weil besser in den
> Programmablauf integrierbarer usw. Insofern freu ich mich fast, dass Java kein
> LINQ Pendant hat *gg*.
> >