New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate DAO #5984

Open
lukaseder opened this Issue Mar 20, 2017 · 9 comments

Comments

Projects
None yet
6 participants
@lukaseder
Member

lukaseder commented Mar 20, 2017

jOOQ is a SQL language abstraction library with basic unopinionated mapping functionality.

Having added DAO types in version 2.4 (2012) was one of the most controversial decisions in the jOOQ library thus far. It was a quick win over a competing framework and it kinda made sense for very simple use-cases, but the number of opinionated requests to extend DAO functionality on the mailing list shows that there simply isn't "a right solution" that fits everyone, but a whole set of "opinionated solutions" that fit few people only. We shall therefore plan to deprecate the DAO type and unsupport it in jOOQ 4.0.

DAOs are similar to Spring Data's repositories to some extent, the latter being extremely opinionated (and thus rigid). Using Spring Data is a commitment to a certain kind of software design (heavily DDD inspired). jOOQ should not be as opinionated but focus on one thing (SQL) and do that one thing very well. What jOOQ users do on top of jOOQ on the service layer should not be of jOOQ's concern.

At this stage, it is unclear if deprecating DAOs will also lead to deprecating POJO and interface generation (another heavily debated topic). The last word has not been spoken (although there is a strong probability of this deprecation to be implemented), this issue shall enable a constructive discussion on the matter.

Clarifications from feedback:

  • It should be made clear that there will be no feature removal. The quick-and-dirty fetching of simple objects will remain available, but through more idiomatic API (mostly through DSLContext.fetch() methods et al.) This stuff already exists but probably is not powerful enough / few people know about it.
  • One nice feature that has been reported on the mailing list is the transparent SQL batching that is implemented in DAO. Certainly worth looking into how such transparency can be taken over to DSLContext
  • The POJOs are quite useful occasionally. Sure, people understand that the 1:1 mapping is not necessarily sufficient for complex domains, but in situations where people want to use Jackson or Swagger to export jOOQ Records as JSON, the jOOQ Record won't do it (because those tool use reflection agressively for serialisation), which is when the POJOs are helpful. Just one example.
  • Clearly, this deprecation should be strongly tied to the promise (or even prototype) of a new code generator that allows for quickly generating such DAOs manually

See also discussion here: https://groups.google.com/forum/#!topic/jooq-user/-LnkZtUTb3c

@guss77

This comment has been minimized.

guss77 commented Mar 20, 2017

I like DAOs, and I want them to be stronger faster and made out of gold (possibly not in that order).

If I understand the problem of DAOs - on the one hand they appear on first glance to do everything a user initially needs from their database access, and thus encourage laziness and reliance on them, on the other hand they are hard (impossible?) to extend correctly, instantiate your types for you so locking you into their rigid behaviors, from which it is easy to fall into the trap of "lets extend this and build a rich object hierarchy with generics and stuff" - which is not the jOOQ way (and also creates lots of rabbit holes to trap the unwary traveler).

I think I've learned my lesson - and will go on my way to build the ORM that I want using my own classes on top of jOOQ DSL. For the benefit of others, maybe it is the right choice to remove DAOs.

@deinspanjer

This comment has been minimized.

deinspanjer commented Mar 20, 2017

I'm interested in what deprecating POJO and interface generation would lead to. If you want to write SQL code using jOOQ to query a DB and then transform the resulting rows to objects that can be used in the application, would a POJO-less jOOQ provide any mechanism to facilitate that conversion or would it be up to the developer to transform the map or array into their own object they created?

@lukaseder

This comment has been minimized.

Member

lukaseder commented Mar 20, 2017

@guss77: Your description is exactly what this is about. And your ORM on top of jOOQ is a very interesting thing to learn more about! :) (which perfectly fits the jOOQ design - jOOQ being a SQL API, not a "true" ORM, i.e. jOOQ doesn't solve object graph persistence).

@deinspanjer: The reason I mentioned POJO and interface generation is because it is conceptually closely linked to the DAO idea of having a 1:1 representation of the relational model in the domain model. This works for very small applications, but eventually, a domain model is inevitably different from the relational one, as it models entirely different entities, which might not even be persisted in the same database (or using SQL). jOOQ's generated POJOs are just as opinionated as the DAO type, which might be a quick win for some, but a cognitive hurdle for many others - just as anything that is opinionated.

Note that the DefaultRecordMapper will not be deprecated. In fact, there are plans of adding more features to that aspect, and to improve the RecordMapper (and soon RecordUnmapper SPI) which allows for mapping between the jOOQ record and the domain model / POJO world. This discussion is just about the current opinionated code generator that generates objects that are only of limited use.

@lukaseder

This comment has been minimized.

Member

lukaseder commented May 16, 2017

While the general idea is clear, we'll postpone this change for now to be sure it will be implemented well.

@ecnaidar

This comment has been minimized.

ecnaidar commented Oct 12, 2017

Found myself doing exactly what @guss77 was describing.
While my use-case was use the generated DAO as a base for the Spring Repository and extend it with necessary additional functionality, after reading discussion here and in Google Groups page the reasoning behind dropping DAOs makes sense. Though, dropping both POJOs and DAOs will make JOOQ to lose it's appeal as an out of the box solution (which I understand is not the intention but I am very much sure that many users perceive it this way) it might give a good kick for a community to work out different solutions and use the JOOQ as it intended to be.
I am looking forward to see how this works out, in the meantime I will just drop the generated DAOs usage and extend DAOImpl. Seems like a good ground to me since there won't be tight coupling (in case you decide to murder DAOs) and no need reimplementing the available utility functions like fetching by primary key or getting records from POJO manually.

P.S. @lukaseder Thank you for your great work and incredible perseverance with JOOQ!

@lukaseder

This comment has been minimized.

Member

lukaseder commented Oct 12, 2017

Thanks for your nice words, @ecnaidar

I am looking forward to see how this works out, in the meantime I will just drop the generated DAOs usage and extend DAOImpl. Seems like a good ground to me since there won't be tight coupling (in case you decide to murder DAOs) and no need reimplementing the available utility functions like fetching by primary key or getting records from POJO manually.

I think this paragraph sums it up. It's so easy to do something super generic really simply, e.g. by extending DAOImpl, or by rolling your own base class. But then again, once the simplest use-cases are implemented, the abstraction starts breaking and we move on to more thorough architectures and designs.

Of course, I'm repeating myself :)

@ooxi

This comment has been minimized.

Contributor

ooxi commented Oct 15, 2017

Just to clarify: generated record classes for tables are different from DAO and Pojos as described in this issue and will not be deprecated, correct?

@lukaseder

This comment has been minimized.

Member

lukaseder commented Oct 15, 2017

@ooxi: That's correct

@billoneil

This comment has been minimized.

billoneil commented Nov 22, 2017

but through more idiomatic API (mostly through DSLContext.fetch() methods et al.) This stuff already exists but probably is not powerful enough / few people know about it.

On some new projects I have been excluding DAO generation / POJO generation because it's likely to be deprecated. I decided how hard would it be to just make something like the following.

Crud.fetchOne(Tables.Users, Tables.Users.ID.eq(1L));

Then I saw DSL.fetchOne 😂 which can then easily be chained with into() , map() to convert the Record to a POJO. Slightly more verbose than one might want but really not a big deal. You can easily make your own abstraction around it or maybe let 3rd parties create more opinionated helpers.

I was considering something like this. Might depend on the thread local configurations though. It's also probably not worth cutting out one method call to pollute the Table objects. Just a thought.

Tables.Users.fetchOne(u -> u.ID.eq(1L));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment