views:

322

answers:

2

I've been reading Chapter 11 (Testable Design Patterns) in the Professional ASP.NET MVC 1.0 book. In the examples in this chapter, data access is split into a number of repositories: IOrderRepository, IProductRepository, etc. That all makes sense: a single repository for a single class of data.

However, this breaks down somewhat for me when you consider the links between the tables: an Order contains a number of Products. When the Order class is created by LINQ-to-SQL, the order class will have a Products collection that enumerates all of the products related to that order. So by using this collection we're bypassing the ProductsRepository.

Therefore when mocking, I'm going to not only have to mock the OrderRepository and the ProductRepository, I'm also going to have to populate the Products collection in the returned Order objects. Which means that the mocked OrderRepository has to know about the mocked ProductsRepository and so on.

It seems a waste to ignore these collections that LINQ so kindly created for me, so my question is, in this case wouldn't a single repository make more sense?

+6  A: 

Your problem description is a typical textbook example of when too much blabla about 'this is good, that's bad' becomes the reason why a developer creates the software the way it's created instead of looking at the problem at hand and create software to fix that problem.

Case in point: your problem description isn't your problem to solve: you have an application to create for your client, that's the problem you should solve. If your choice of tools make your life hard, kick them out and use what works: if mocking doesn't work, why bother? Oh, because someone said your software will suck if you don't mock? Why?

You picked up some DDD things here and there, but you've missed some important parts: Product is an aggregate root. This means that you should obtain products from its own repository. Yes, that mitigates the navigation feature in the model, but that's DDD for you, IF you create the repositories strictly how the second part of Evans' book is dictating. But... should you?

If you can't answer why Product has its own repository, yet you can navigate to products from Order, you shouldn't create repositories for aggregate roots. WHY is that repository there? If it's there, shouldn't it be the ONLY point where Products are obtainable? (so also not through lazy loading!).

This indeed will create a lot of overhead and code you likely won't need (so ironically, YAGNI in full effect).

Ok, enough ranting. DDD is all about thinking. So the domain should drive the design, and by practicing that, you'll get a domain model which is representing reality. That's not to say you should implement a lot of code just because you read somewhere you should. Instead, if you have recognized the domain elements, the aggregate roots etc., you then have to place behavior for these types somewhere, e.g. inside the domain classes. You can place fetch logic in separate classes like order oriented fetch logic in an Order repository, but it won't be a repository in the strict sense (e.g. it doesn't have its own local cache etc. ). That's not that bad, it's all about what you should create for your client.

So, first: think, second: think, and third: think... again. What seems logical for you. Make a list of pros/cons of the options you have and choose the one which seems the most right for you. Document that choice and why you picked that one and not the alternatives. This gives way more value to maintainers than any other source: you document the alternatives and why you didn't pick them, you do research what will work for you, and you chose one.

Software engineering isn't hard, it's just that nowadays it seems fashion to simply do first and think later, without proper reasoning why one would do it that way and not the other way.

Good luck :)

Frans Bouma
Thank you. As for "think" - that's what I've been doing, and that's why I asked for opinions here before going ahead! I'm new to this pattern and hoping for some insight from those with more experience. Cheers again.
Groky
Yes, I should have given you more credit, sorry. Your last paragraph of the question suggests indeed that you realized what you were doing wasn't really that helpful. Next time, try to apply that process before writing any code ;) (which is perhaps a step away from how you want to work though) so you don't have to throw code away already written.
Frans Bouma
The rant part of this answer was the best thing I have ever read on SO! There is way too much of "you should do this/that" around and its a breath of fresh mountain air to read someone saying "do what works for your solution".
RemotecUk
+1  A: 

Other factors to consider include the likely lifespan of the product and the likelihood of having to change from LINQ-to-SQL to some other O/R mapper at any point in the lifetime. The smaller the project, the less critical the product, the less you need to worry about abstracting minutae to the nth degree.

Jay