Skip to content
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

Closed
lukaseder opened this issue Mar 20, 2017 · 23 comments
Closed

Deprecate DAO #5984

lukaseder opened this issue Mar 20, 2017 · 23 comments

Comments

@lukaseder
Copy link
Member

@lukaseder 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 improbable if deprecating DAOs will also lead to deprecating POJO and interface generation (another heavily debated topic). The last word has not been spoken, 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
Copy link

@guss77 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
Copy link

@deinspanjer 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
Copy link
Member Author

@lukaseder 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
Copy link
Member Author

@lukaseder 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
Copy link

@ecnaidar 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
Copy link
Member Author

@lukaseder 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
Copy link
Contributor

@ooxi 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
Copy link
Member Author

@lukaseder lukaseder commented Oct 15, 2017

@ooxi: That's correct

@billoneil
Copy link

@billoneil 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));
@lukaseder lukaseder added this to the Version 3.13.0 milestone Feb 18, 2019
@masc3d
Copy link

@masc3d masc3d commented Jul 2, 2019

At this stage, it is unclear if deprecating DAOs will also lead to deprecating POJO and interface generation (another heavily debated topic).

DAOs can go but please don't deprecate POJOs. debated where @lukaseder )

@lukaseder
Copy link
Member Author

@lukaseder lukaseder commented Jul 2, 2019

DAOs can go but please don't deprecate POJOs

They're not going anywhere any time soon, although once we do deprecate DAOs, it will be a good moment to critically review related features.

debated where @lukaseder

On various github issues and on the mailing list. But that's irrelevant. A new debate will be held (if at all).

@shorn
Copy link

@shorn shorn commented Jul 18, 2019

One benefit that I might mention here, is that I was initially confused by the existence of the DAO/records functionality. It didn't seem to me at the time that it was very useful - I had to spend some time reviewing the situation to figure out that they were a "me too" feature that I didn't need or want.

In this way, deprecation of those features will actually improve the user-experience for folks like me. If these features aren't removed - I think the manual could be improved by highlighting the features as very much an "alternative" implementation style that is likely not suitable for folks that weren't already looking for some kind of DAO / POJO solution.

Some of the key questions I had when trying to figure out what DAO's / POJOs were for and why they existed:

  • Do they enable some other, more advanced JOOQ features?
  • Do they represent an intended "future direction" of the framework?

I think the addition of a few statements to the current manual, clarifying that those aren't the case, would assist people who are learning / evaluating JOOQ.

@lukaseder
Copy link
Member Author

@lukaseder lukaseder commented Jul 22, 2019

I had to spend some time reviewing the situation to figure out that they were a "me too" feature that I didn't need or want.

Absolutely! They're nothing more than a "me too" feature.

I think the manual could be improved by highlighting the features as very much an "alternative" implementation style that is likely not suitable for folks that weren't already looking for some kind of DAO / POJO solution.

We could improve the manual in many ways, but this would just lead to us spending even more time thinking about a rather non-essential feature, time which could be better spent otherwise.

I mean, currently, there's a single chapter about DAOs in an otherwise vast manual. To think that this could be an essential feature is a bit of a stretch :)

The same can be said about POJOs:
https://www.jooq.org/doc/latest/manual/sql-execution/fetching/pojos

Fetching data in records is fine as long as your application is not really layered, or as long as you're still writing code in the DAO layer. But if you have a more advanced application architecture, you may not want to allow for jOOQ artefacts to leak into other layers. You may choose to write POJOs (Plain Old Java Objects) as your primary DTOs (Data Transfer Objects), without any dependencies on jOOQ's org.jooq.Record types, which may even potentially hold a reference to a Configuration, and thus a JDBC java.sql.Connection. [...]

If you're using jOOQ's code generator, you can configure it to generate POJOs for you, but you're not required to use those generated POJOs

That's it. They're really ... just POJOs (as in DTOs). People use DTOs for many different reasons. A DTO is just a tuple/record/struct/whatever you want to call it.

I do appreciate that these features seem to lure people into the confusion you were experiencing, @shorn. This isn't the first time and it will not be the last. But instead of "improving" the manual using explicitly suggested wording, (which might confuse other people), I would much rather like to understand why you had these expectations towards DAOs and POJOs. What made you wonder about:

  • Do they enable some other, more advanced JOOQ features?
  • Do they represent an intended "future direction" of the framework?
@shorn
Copy link

@shorn shorn commented Jul 22, 2019

I do appreciate that these features seem to lure people into the confusion you were experiencing, @shorn. This isn't the first time and it will not be the last. But instead of "improving" the manual using explicitly suggested wording, (which might confuse other people), I would much rather like to understand why you had these expectations towards DAOs and POJOs. What made you wonder about:

  • Do they enable some other, more advanced JOOQ features?
  • Do they represent an intended "future direction" of the framework?

The context at the time was that I was just starting to learn JOOQ, I was working my way through the manual while writing some exploratory code to figure out what JOOQ was, how it worked and whether or not I liked it.

At the time, I couldn't see the point of those two features, because I was researching JOOQ for use in a production system and I have a strong personal bias toward the long-term maintenance view of software development.

So I was asking those questions to try and reverse-engineer why those features were part of JOOQ at all and when/if I would use them. Because the documentation wasn't telling me.

But, thinking about other peoples use-cases for JOOQ, I can see situations where these features would be appropriate: prototyping JOOQ itself, prototyping a UI on an existing schema that cannot change, etc. In those scenarios, having generated DAOs and POJOs might well be useful and not the obvious foot-gun they seem. They might even be good tools to help drive JOOQ adoption.

@lukaseder
Copy link
Member Author

@lukaseder lukaseder commented Jul 23, 2019

Thanks a lot for your insight, I really appreciate it!

So I was asking those questions to try and reverse-engineer why those features were part of JOOQ at all and when/if I would use them. Because the documentation wasn't telling me.

I agree about the documentation not telling why to use DAOs, and I'm personally still not convinced that they're a good idea, although they are adoption drivers. Spring Data repositories work in a similar way. It is too easy to get a repository up and running for trivial cases even if they always fall short eventually, as queries become more complex.

So, this issue is really about thinking about deprecating DAOs while replacing them with something more jOOQ idiomatic that does not have the shortcomings of DAOs. One example is API like DSLContext.fetch(Table, Condition).

Regarding POJOs, do you think we should improve that manual section? It does explain the motivation of using DTOs as being the reason for POJOs. Their applicability is more straight forward than that of DAOs.

We'll definitely discuss these issues internally and see where we should be heading here.

@guss77
Copy link

@guss77 guss77 commented Jul 23, 2019

I wanted to chime in as a long time user of DAOs and POJOs.

But, thinking about other peoples use-cases for JOOQ, I can see situations where these features would be appropriate: prototyping JOOQ itself, prototyping a UI on an existing schema that cannot change, etc.

I'm using generated DAOs and POJOs on a production system for a couple of years now, during that time the database schema has changed quite a lot (mostly in a backwards compatible way, but not always), A lot of the code uses pretty straightforward fetches, but in the last year we added a lot of JOIN queries, some of them pretty complex, and the DAO/POJO paradigm has carried us well so far. We've built up some support code around it (automatic schema updates, abstractions for automatic joins between DAOs, generators that support extending POJO classes, and a few more things) and the result is a code base that is easy to understand and extend and lends itself well for both new developers and experienced ones (we have a high intern churn, quite on purpose, so having such high level abstractions is good for us).

I understand that there are some behaviors of POJOs and DAOs that are unwanted (such as updating a record requires sending the entire POJO to the database) and where that kind of attention is needed - we can go down to records and custom queries and do that - but for 99% of use of database access, the higher abstraction levels really help with long-term maintenance.

I would be very sad to see DAOs and POJOs go the way of the dodo, and in such a case would likely search for an alternative (or fork - I'm pretty sure there are other people like me that like all of the features of jOOQ - even those pesky abstractions).

@shorn
Copy link

@shorn shorn commented Jul 23, 2019

Regarding POJOs, do you think we should improve that manual section?

I just had a look at https://www.jooq.org/doc/3.11/manual/sql-execution/fetching/pojos/

Look at all those comments on that page asking for composite-this, constructor-that, private-this, immutable-that. I think people stumble across this functionality and try to compare it to the "M" features of their ORM (Hibernate, etc.) and it comes up lacking.

I think it might help to point out that POJO generation is a "convenience" feature that's not intended as the JOOQ analogue of the "object mapping" of an ORM. It's limited and mostly just intended to assist people who want to get started quickly. Most importantly, it's not a work-in-progress - what you see is what you get. There's no roadmap for the POJO generation / DAO mapping stuff to be fleshed out further one day into a fully-fledged ORM alternative.

@sofiageo
Copy link

@sofiageo sofiageo commented Jul 23, 2019

I think it might help to point out that POJO generation is a "convenience" feature that's not intended as the JOOQ analogue of the "object mapping" of an ORM

So what's the alternative? Use an UpdatableRecord and let it leak to other layers (e.g controllers?) It's not very tempting. Plus it gives the impression you get too attached to the framework by doing it.

I would expect a way to map the POJOs (generated or custom) with the UpdatableRecord. This already exists, but it's not very strict in the way it does it.. For example the naming strategy of the mapper will change if you use the JPA entity annotation, and some fields will map as null values.

I've also asked about it on SO, but I'm still trying to convince myself with the answer.. I'm not experienced with JOOQ so I might be thinking it wrong.

@lukaseder
Copy link
Member Author

@lukaseder lukaseder commented Jul 25, 2019

Thanks a lot, everyone, for chiming in.

@guss77 We've built up some support code around it (automatic schema updates, abstractions for automatic joins between DAOs, generators that support extending POJO classes, and a few more things)

I'm very curious about that. Would you be interested in sharing how that works in detail? Perhaps something we could build into jOOQ?

@guss77 I would be very sad to see DAOs and POJOs go the way of the dodo,

POJOs (and the DefaultRecordMapper) won't go away, that option has already been removed from the discussion. DAO deprecation will only be considered, if there is a really viable alternative offered out of the box by jOOQ.

@guss77 and in such a case would likely search for an alternative (or fork - I'm pretty sure there are other people like me that like all of the features of jOOQ - even those pesky abstractions).

In case DAOs are deprecated, it would be relatively simple to fork just DAOs out of jOOQ. If you look at the DAOImpl class, it really does absolutely nothing spectacular. And that's already all there is to DAOs.

But nothing has been decided yet, as this issue is still open and not implemented, and since the creation of this issue, I've seen that despite my own reservations with the feature, there is a very high interest in DAOs (much higher than I would have expected), so their deprecation has grown much more unlikely, whereas the deprecation of POJOs has been definitely rejected.

@shorn Look at all those comments on that page asking for composite-this, constructor-that, private-this, immutable-that. I think people stumble across this functionality and try to compare it to the "M" features of their ORM (Hibernate, etc.) and it comes up lacking.

Yes, and when they do have the "M" features of their ORM, they find it too complicated and difficult to understand :) I think "M" / "Mapping" is really an unsolved problem, still. I haven't seen the solution yet.

@shorn I think it might help to point out that POJO generation is a "convenience" feature that's not intended as the JOOQ analogue of the "object mapping" of an ORM. It's limited and mostly just intended to assist people who want to get started quickly. Most importantly, it's not a work-in-progress - what you see is what you get. There's no roadmap for the POJO generation / DAO mapping stuff to be fleshed out further one day into a fully-fledged ORM alternative.

But that's not true. It's just lower priority, but it is work-in-progress.

One problem in the status quo is that POJOs are generated out of the box, and as such of course, they're not exactly as people would have written them manually. I mean, in 22 years of Java and JavaBeans, there had been myriad of criticism about how those silly JavaBeans should really be. Everyone and their dog criticised them for their lack of ... everything. And now, with project Amber, we might finally get what they should have always been. Data classes (which we'll obviously support, too).

POJO / DTO style is almost as big a bikeshed as nullability in Java, so I would say the number of comments on that page relates to that, much more than to something jOOQ could improve systematically. We could (and will) support more styles, of course. And we should definitely delete old comments on the manual to prevent distraction.

But I think the core concept of a DTO is valuable, regardless of the relatively unimportant discussion about its style.

At a customer site, I've recently worked with protobuf generated code. jOOQ's POJOs are really lean and simple in comparison! :)

I do take your central criticism seriously though, @shorn. The way I understand it is: Currently, DAOs and POJOs do not clearly communicate that they're convenience rather than essential functionality. We can definitely improve that wording. Maybe even create a new section and move all convenience features in there. We'll discuss this internally.

@sofiageo So what's the alternative? Use an UpdatableRecord and let it leak to other layers (e.g controllers?) It's not very tempting. Plus it gives the impression you get too attached to the framework by doing it.

Letting UpdatableRecord "leak" into other "layers" is an option for some, but not for all. I personally find 2 tier architectures very tempting, as I've often seen layering being much overengineered, with people spending more than half of their time writing glue code to map between layers. But that's me. Others don't agree with me, so there must be an alternative, and the DefaultRecordMapper / DefaultRecordUnmapper addresses this, along with generated POJOs as a useful default.

@sofiageo For example the naming strategy of the mapper will change if you use the JPA entity annotation, and some fields will map as null values.

Is that something worth reporting separately as an issue?

@sofiageo I've also asked about it on SO, but I'm still trying to convince myself with the answer.. I'm not experienced with JOOQ so I might be thinking it wrong.

As this discussion has proven, jOOQ simply cannot be too opinionated here. In many years of software engineering, the only thing that is certain is that we as an industry do not agree (at all) on architecture and design. Hence, a library should never be opinionated about these topics either, because it will not make the right choices for a significant number of users.

I've recently run into this myself as I discovered Spring Data's opinion about the @Procedure annotation: https://stackoverflow.com/q/48524189/521799 (while consulting with a client who uses Spring Data). An anecdote

Spring Data is all about DDD, according to the authors. Most procedures, however, are not at all about DDD. So, in most cases, attaching a procedure to a root aggregate entity is not what people want. But they have already strategically chosen Spring Data.

Of course they can use JDBC or jOOQ or even JPA to call the procedure explicitly, but introducing a new dependency for just one procedure call seems wrong. So, the solution is to hack something. One possible approach was to create a repository that uses a random dummy entity as its root aggregate, and then the @Procedure annotation happens to work.

The only thing this proves is that the abstraction is too opinionated, much more than it should be. It could be made much more useful if it gave a reasonable option to people who don't care that much about the opinion of embracing DDD. Because repositories (which are "just" more opinionated DAOs) can be convenient in applications that don't care too much about the relational model, but just want to persist some tuples.

So, my take here is that DAOs in jOOQ should either not be opinionated at all (apart from an opinionated default, e.g. currently, POJOs follow JavaBeans conventions, and are thus mutable, for example) or not exist at all.

The price of not being opinionated is that users have to make up their own opinions.

@guss77
Copy link

@guss77 guss77 commented Jul 25, 2019

@guss77 We've built up some support code around it (automatic schema updates, abstractions for automatic joins between DAOs, generators that support extending POJO classes, and a few more things)

I'm very curious about that. Would you be interested in sharing how that works in detail? Perhaps something we could build into jOOQ?

Most of the stuff is in my company's MIT-licensed and very-much-a-work-in-progress vertx-jooq-extensions project. As the name implies, this project is a lot about consuming jOOQ through the vertx-jooq library (which is itself very invested in DAOs and POJOs), but some of the stuff may be interesting to people not using Vert.x:

  1. SchemaManager assumes schema updates are delivered in files named schema/schema-<version>.sql on the classpath (probably should be customized, patches are welcome) and some knowledge of the "current schema version" and will then playback the version updates. We use this to automatically deploy schema updates to production when a new version of the product starts running. In itself, this actually has no dependencies on either jOOQ or Vert.x.

  2. QueryManager is used to automatically detect join fields from foreign keys and create jOOQ join queries. It is heavily dependant on vertx-jooq's AbstractVertxDAO API and specifically its JDBC-CompletableFuture variant, which we use, but the general logic can probably be adapted quite easily to plain jOOQ (and jOOL for the companion ResultsCollector). If this functionality is ever offered in jOOQ I would be happy to gut these two into the very thin adaptation layer they deserve to be ;-).

  3. The closest we got to an ORM is the POJO extending generator that is an awful hack (mostly due to the need to work around inaccessible (☹️) or missing extension points in the jOOQ and vertx-jooq generators and strategies) so I recommend staying away if your sanity (and specifically, respect for my work) is important to you.

@lukaseder
Copy link
Member Author

@lukaseder lukaseder commented Jul 25, 2019

@guss77 Thanks a lot for sharing this insight!

  1. I've been thinking about database migrations a few times in the past. Nothing to share yet, but there are a lot of unsolved problems in this area... and a tighter integration with jOOQ would be great too. Currently, we recommend Flyway: https://blog.jooq.org/2014/06/25/flyway-and-jooq-for-unbeatable-sql-development-productivity. Would be great to build something on top of Flyway/jOOQ, combined.
  2. Note that jOOQ has ResultQuery.collect() since jOOQ 3.11. And we're planning to offer a collector library for common operations in the near future. In fact, a lot of our internal mapping code is very redundant and would be better implemented using a more composeable, collector style approach. But that hasn't been designed yet.
@sofiageo
Copy link

@sofiageo sofiageo commented Aug 19, 2019

@lukaseder Is that something worth reporting separately as an issue?

Sorry for late answer, I didn't have time to experiment with anything and the summer break got in the way as well. I don't think there is an issue, it's the expected behaviour. If a JPA annotation is available, use only those, as explained in the Javadoc. It might have not been clear from the start but it gets better now :) I will post anything not relevant to this issue, to the SO question.

@lukaseder
Copy link
Member Author

@lukaseder lukaseder commented Jun 6, 2020

In 3 years after having created this issue, I cannot think of any sufficiently good replacement for DAO, and simply removing the feature is something a lot of users disagree with for good reasons.

I'm still not convinced that DAO is jOOQ's most brilliant feature. It was mostly added "because we can", and I'm still hoping to eventually find something better, but the priorities of jOOQ development are elsewhere right now.

This means that I will close this issue and reject the deprecation, continuing to maintain DAO in the foreseeable future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
9 participants