Monday, December 15, 2008

Gojko Adzic and Skills Matter are organising an open source .NET exchange 'mini-conference' for January 22nd. The format is an evening of short talks covering some cool stuff currently emerging in the .NET community, but not yet mainstream.

I'm lucky enough to have been asked to contribute. I'll be talking about the rise of the repository pattern. My plan is to scour the open source world and hunt down some prime examples wild repository to serve up to the attendees.

9 comments:

That's great Mike. I hope I can attend the event.Aspects I would like to be talked about are:

- Differences between Repository pattern and DAO. As I see it, a Repository should be composed of a DAO to provide the illusion of an in-memory database to the Domain, and the most common interface for Repositories is very much more DAO-like than Domain specific in the DDD sense.

- Should the Domain Model be able to reference and use Repositories (ref: http://tech.groups.yahoo.com/group/domaindrivendesign/message/7586) ?

- Should there be no common Repository interface to avoid disallowed operations on some entities and instead opt for one Repository per entity (DDD in mind again). For instance : IFooRepository`T : IRepository`T {} will carry all of the IRepository`T members, some of them making no sense (for instance read/only data).

- Should Repositories provide direct transactional control ? As most Repositories out there are (imho) more like DAOs and thin wrappers around NHibernate ISession the ISession.BeginTransaction() is often exposed too. Should this functionality be best delegated to another class (Unit Of Work pattern).

- Using Specification pattern to provide query customization not tied up to specific technology such as ICriteria or IQuery of Nhibernate.

- When using Linq2Sql to create Repositories, is it ok to return IQueryable queries ?

Wow that's an excellent list. I think all your points are valid and I'll do my best to cover them. It's a very interesting and contested field at the moment so I'm planning to show some typical approaches and point out the areas of debate. I'm goinng to try not to be prescriptive, simply because there is so much debate out there about the best implementation.

I remember discussing IRepository`1[[T]] with you at altdotnet. It’s a fascinating topic. I’ve been implementing the Repository pattern for a couple of years now – though not in .net 3.5 ;( - primarily because our company actively changes data source vendors and as such infrastructure concerns (local / remote, XML, YAML, SQL, WS-*, various inconsistent attempts at REST so XML-RPC, FTP & CSV, email…) Essentially Persistence Ignorance is mandatory for us and I learnt the hard way the Repository pattern is the best way to implement PI.

One area where I went through lots of iterations is common (infrastructure) code. Other than NH Unit of Work, NH Session Factory, CSV, etc. classes, my common (repository) code is an ensemble of abstractions including:

The only common class really is an ABC (EqualityAndHashCodeProviderBase`1[[T]], `1[[TKey]]) courtesy of Ayende.

In summary, I have no common concrete classes only interface / abstract types. All my concrete classes are specialisations specific to the current domain. I recommend this approach otherwise I find myself trying to “optimise” prematurely by coercing my code to use a concrete Repository implementation, which is best suited to my previous project but not necessarily the current (essentially violating OCP.)

I’m looking to move to C#3 and Linq in the New Year. Areas, which I’m interested in, which I assume you’ve already tackled are:

- Should your repository implement IQueryable? Or;

- Should IQueryable be a type for members within your repository?

(Basically how best to make use of Linq providers.)

- Are there any good examples of implementing PI specifications?

- Are there any unit tests or code analysis rules that ensure best practices? I.e. prevent entities referencing repositories etc (without the need to build by solution with an assembly for every concern - yuck.)

Good luck Mike, one could easily talk for much longer than fifteen minutes on the subject so I’m sure your talk will be concise and more a primer / fuse lighter for a very sensible pattern. Am very much looking forward to it.

Ed, thanks for a very considered comment. I would be very interested in having a look at your repository code if that's possible. I'm trying to collect as many 'wild' examples as possible.

Our implementations are quite similar. I'm also using an IRepository'1 and an IEntity. So far I've been able to successfully write LINQ-to-SQL and NHibernate versions.

My view of the 'should IQueryable be exposed by the repository' is that it should. LINQ is not a data access API per-se, but a core part of the .NET framework. There are so many cool things you can do with your repository once you have an IQueryable, that you'd be shooting yourself in the foot by not providing it. Of course the current situation in ORM land is far from ideal *cough* NHibernate *cough* but hopefully that will change in the near future.

Re Repository: I think it's best to not allow IQueryable to be carried accross all the layers. The problem I've got with IQueryable is that having a deferred execution and being part of the .Net framework it can easily be overused in situations where it seems to compile and then you get runtime errors because an expression cannot be converted into a SQL statement.

I would agree with Ed and we should use those what we call Repositories as generic DAO implementations and make use of them via composition and not inheritance.At work there is a Repository but I think it's gone a bit wild.

Yes, obviously whether to expose IQueryable is one of key repository fault lines at the moment. You are in very good company, several people I really respect also think that IQueryable should not be exposed. Other common arguments against it are that it's hard to unit test the extension method query specifications that are bolted onto the IQueryable method, and that data access concerns are leaking into the rest of the application.

Thanks for showing us your repository implementation. Do you mind if I use it as an example in my talk?

I tend to fall in the "Repositories not returning IQueryable camp" for a number of the reasons discussed in this post. I also posted my take on it on my blog quite recently - it'd be great to get your input on it.

That's a great post. You very nicely sum up most of the arguments about repository. Your point, "even still using the repository pattern at all?" is key I think, especially when talking about the Evan's repository. If we go down the finely grained interface route with IDelete and IInsert and use those in our client then clearly we've moved some way away from Evan's description. If we also start talking about Udi's lazy loading approach with interfaces representing different behaviours of domain entities then that's a step further still.

But I must admit that I find semantic arguments fustrating: "Is this, or is this not, a repository?" Sure it's good to have commonly understood terms, but 'generic repository' is most definately out there now. No it doesn't conform to repository as described in the blue book, but it's a useful concept none the less.

I think the discussion now is around the more practical aspects. The "should I return IQueryable" debate will run on a while I think, although anyone watching would probably come to the conclusion that you shouldn't. Although I'm going to stick with my contrarian view for the time being.

I'm afraid that the talk is going to be somewhat of a dissapointment after the excellent debate that's been going on in the blogosphere. When I first suggested the subject, I thought it would be just right for a 15 mintute min-talk. Now I realise that all I'll be able to manage is a quick overview of the debate. There won't be any time to get stuck into the details.

Code Rant

Notepad, thoughts out loud, learning in public, misunderstandings, mistakes. undiluted opinions. I'm Mike Hadlow, an itinerant developer. I live (and try to work in) Brighton on the south coast of England. Please don't mistake me for an expert in anything. I love technology and programming, but make no claims to be any good at it. Much of what you read here may be poorly thought out, wrong, or just plain dangerous.