Ayende @ Rahien

Refunds available at head office

RavenDB Conf Videos: Abstracting RavenDB: Don't Do It!

Kijana Woodard’s 1st talk ever, and he picked a really good topic, and delivered a masterful performance.

Tags:

Posted By: Ayende Rahien

Published at

Originally posted at

Comments

Chris Marisic
05/05/2014 06:49 PM by
Chris Marisic

Abstracting the database from the data tier is silly as you're strongly coupled to the database.

The app tier should certainly be entirely decoupled from raven, zero knowledge of anything behind the contract the data tier provides to the app. Which from watching the video in 35 seconds it does seem to do this.

Dominic Zukiewicz
05/05/2014 08:52 PM by
Dominic Zukiewicz

@Chris,

IRepository shouldn't be treated as a panacea as it simply does not work for every scenario, which is the impression given from architects and pattern frameworks. Switching from NoSQL to RDBMS and vice versa will not work as expected, as their physical implementations do impact the application design.

Take for example the Attach() in Entity Framework. Records must be committed to the DB before you get an ID. NHibernate doesn't. Whats more, Oracle gets PKs from sequences, SQL Server from IDENTITY fields. So the application must use UoW with EF but not for NHibernate in certain scenarios? Doesn't that seem ... wrong, especially for a what-if scenario? \

(DotNet Austria - Ayende Rahien - Breaking apart conceptions)

If it was me and a lead developer comes to me and says "All that SQL Server stuff - just switch it over to Oracle.. T-SQL, stored procs, full-text search, triggers, DB deployment script, table schemas - easy job..", I'd be mortified!

Its a major risk and should be treated as such, so should there be some at least some rework required anyway? 'What-if' they switch to storing in CSV's? Oh dear, UoW is now 1000 x more complicated .. Having to re-write the entire DAL code is not unreasonable, even if it is centralised. But the point to take away is to change when it is needed, not on the premise that it might.

I have never had a project change DB platform mid-way through - or ever! I can take on board @Kijana's presentation on a personal level, but if this has not been the case for you, then I hope it has given you some direction on abstracting to a mediator level, which is still a good place for the abstraction, as the query is optimised for the platform. Remember .Query<> will be a table-scan. But not for RavenDB.

@Kijana

Fantastic presentation! I did chuckle to myself with the IRepository { out TEntity, in TKey } - I've done that too :-)

As a suggestion for future presentations, please can you repeat the questions for the internet audience, as we aren't able to hear them.

Chris Marisic
05/05/2014 09:09 PM by
Chris Marisic

@Dominic I say the unit of work pattern is basically an anti-pattern to start with. Once you pass that through boundaries, design doesn't exist in a solution when you can make Module C rollback changes that Module A completed. That's just good luck to your sanity there.

I would say IRepository { out TEntity, in TKey } is the definition of boilerplate fluff code (and hence why Kijana had it in his presentation). You can build meaningful generic repositories. http://dotnetchris.wordpress.com/2009/01/28/creating-a-common-generic-and-extensible-nhiberate-repository/ here's an example how to NOT to do it, note the hard coupling and brittle codez. Compare to that my blog that was written 14 months later http://dotnetchris.wordpress.com/2010/03/15/creating-a-common-generic-and-extensible-nhiberate-repository-version-2/ compare the amount of code in DataProvider vs the old blog.

With RavenDB you never need to write what I did in the v2 blog because the IDocumentSession already gives you this baseline generic repository pattern.

Dominic Zukiewicz
05/05/2014 09:40 PM by
Dominic Zukiewicz

Hi @Chris,

Do you have concerns with the Raven specific IDocumentSession specifically being in there? Would you be happier with the ISession instead?

You can still use NHibernate with RavenDB, although you wouldn't have any of the benefit of transformers, specific selection of Map/Reduce ..

I mean worst case (and only provided here as an option), you could check the session is an instance of IDocumentSession and use a custom query in the XXQuery class. Yes, we're getting some coupling, but at least its isolated to the query and not the controller.

Chris Marisic
05/06/2014 04:16 PM by
Chris Marisic

@Dominic As far as I can tell we're in agreement here. A generic repository with RavenDB is an anti-pattern because IDocumentSession/ISession is already a generic repository. It doesn't make sense to add the repository pattern on top of the repository pattern.

This is very different from most ORMs where they do not implement the repository pattern.

Judah Gabriel Himango
05/06/2014 04:17 PM by
Judah Gabriel Himango

This was one of my favorite talks of the conference. +1 Kijana!

João Bragança
05/06/2014 05:27 PM by
João Bragança

It's too bad the repository pattern is so misunderstood. IRepository and IRepository of T only makes your code suck because they are too generic to be useful. If you are going to use it, the repository needs to be expressed in domain terms e.g. [I]CustomerRepository. If you want to implement RavenCustomerRepository or (blech) EntityFrameworkCustomerRepository behind than then go for it.

The real benefit comes from fast testing. I don't need / want to test that the database abstraction is working properly when I call save. I can supply an in memory version for that.

Ayende Rahien
05/07/2014 07:28 AM by
Ayende Rahien

João, With RavenDB, you can have the full database as an in memory instance. Requiring no disk access. That is very fast, and require you to write no special code, or contort your system into a pretzel trying to get it to be "Testable"

Suedeuno
05/09/2014 12:14 AM by
Suedeuno

How do you handle scenarios where you have data in different databases and so as to not duplicate that data in different data stores, pull that data together from those databases and Raven into one object or collections of objects and do it gracefully without abstracting it away?

Kijana Woodard
05/12/2014 05:17 PM by
Kijana Woodard

@Suedeuno - There are many ways this can play out, but lack of abstraction is critical here.

For one case, assume that they are different raven databases on the same server. In this case, we have one document store and use OpenSession("db-name") to get the data from different databases.

If there are different servers, we might be using sharding. We might be using different stores.

If the databases are on different servers, we might be able to query them simultaneously is the user request has sufficient information and the persistence mechanism supports async. If we're using, say, mysql which doesn't really support async, we have to make choices. If we need information from one db to make the request to others, we have other choices.

It's fairly difficult for an abstraction to encompass all of these scenarios. Ultimately, it doesn't seem very useful. We can abstract away that fact that we need a certain data shape, but then implement that directly against the persistence engine.

Suedeuno
05/23/2014 12:46 PM by
Suedeuno

@Kijana

I understand that part, say I have some data in SQL server, some in Raven and both maybe shared between different apps. If we were to use Raven, this would likely be a real scenario.