Monday, December 15, 2008

Open Source .NET Exchange

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.

The rest of the evening looks even better...

Dylan Beattie talking about jQuery.

David Ross talking about Postsharp.

Sebastien Lambla on Fluent NHibernate.

David de Florinier on Active MQ and NMS.

Russ Miles on Spring.NET

See you there!

9 comments:

Daniel Fernandes said...

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 ?

Looking forward the talk!
Daniel

Mike Hadlow said...

Hi Daniel,

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.

Ed said...

Hi Mike,

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:

IAggregateRoot`1[[T]]
IEntity`1[[T]]
IRepository`1[[T]] where T : IAggregateRoot
IReadOnlyRepostory`1[[T]] where T : IAggregateRoot

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.

Sorry for the long comment, I probably should have emailed you!

Daniel Fernandes said...

Bizarre, I've registered to the event several times now and no email to confirm my attendance. Mmmh..

Mike Hadlow said...

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.

Daniel,

Try contacting Gojko Adzic. He's the organiser of the event.

Daniel Fernandes said...

@Mike : I think I'm sorted, got confirmation from Skill Matters.

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.

I was thinking of something like :

IRepository`1[[TEntity]]`2[[TKey]] {

T First(ISpecification spec);
T First();

T FirstOrDefault(ISpecification spec);
T FirstOrDefault();

T Single(ISpecification spec);
T Single();

T SingleOrDefault(ISpecification spec);
T SingleOrDefault();

int Count(ISpecification spec);
int Count();

bool Exists(ISpecification spec);

T Get(TPK key);

void Save(T item);
void Save(IEnumerable[[T]] items);

void Delete(T item);
void Delete(IEnumerable[[T]] items);
void Delete(ISpecification items);

IEnumerable[[T]] All(ISpecification spec);
IEnumerable[[T]] All();
}

I've just reused some of the Linq words here.
And I would use Extension methods to simulate a Fluent API such as:

var repo = new Repository[[Entity,Int>]]);
var foo = repo.WithPaging(int pageSize,int currentPage).First();

Well hopefully..

Mike Hadlow said...

Hi Daniel,

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?

Craig Cavalier said...

Mike,

Another great post, as per usual!

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.

http://craigcav.wordpress.com/2008/10/22/what-purpose-does-the-repository-pattern-have/

I'm also hoping to attend the skill matters event this week - hopefully I recieve confirmation soon! Some aspects I'd be interested to see discussed are:

- Where do specifications fit in with the Repository Pattern?

- Are generic repositories worthwhile?

- How to manage fetching strategies in Repositories

Mike Hadlow said...

Craig,

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.