Common infrastructure? Don't make me laugh
I am currently in the process of retiring the IRepository<T> from Rhino.Commons. I am moving it to its own set of projects, and I am not going to give it much attention in the future.
Note: Backward comparability is maintained, as long as you reference the new DLLs.
But why am I doing that? If there is anything that I have been thought in the last couple of years is that there is a sharp and clear distinction between technological infrastructure (web frameworks, IoC containers, OR/M) and application infrastructure (layer super type, base services, conventions). The first can and should be made common, but trying to make the application infrastructure shared between multiple projects that aren't closely matched is likely to cause a lot of issues.
To take the IRepository<T> example, it currently have over 50 methods. If that isn't a violation of SRP, I don't know what is. Hell, you can even execute a stored procedure using the IRepository<T> infrastructure. That is too much.
What will I use instead? A project focused infrastructure. A repository interface reflect the application that is using it, and it changes from project to project and even in the same project as our understanding of how the project is built improve.
I am still considering what to do with the other tidbits that I have there, such as the EntitiesToRepositories implementation. Ideally, I want to keep Rhino Commons focused on only session management, and nothing else beside.
Comments
I agree somewhat with your assertion around technological vs. application infrastructure, but that whole discussion quickly starts turning around the semantics of "application" and what 'services/functionality' such an infrastructure might expose / provide. When you say: "multiple projects that aren't closely matched" - I think you are getting closer to the mark relative to such "common infrastructures" overreaching. In some sense I feel you do simply run up against a sweeping 'lowest common denominator' factor that casts a clear light on the risks of overreaching beyond a certain point.
Azure and all the other PaaS offerings are probably a pretty good indicator of that "lowest common denominator" factor at work relative to where the 'natural' boundaries lie between "technological" and "application" infrastructures. But even there I suspect any significant apps you might build atop Azure, Gears, or EC2 would in fact exhibit enough common [admin] code to constitute something one might call a "common application infrastructure". You can argue how thick or thin that stack might be, but I suspect, once recognized, most pragmatists would resue that body of code, however derisible or unclean the exercise might feel due to other sensibilities.
Couldn't agree more with this point and I like the technology infrastructure and application infrastructure split.
Maybe the DDD style Repository is worth another look?
If you base your repository around IQueryable then it becomes much simpler and easier to reuse. That will be more of a possibility for you I guess when LINQ to nHibernate is a little further along.
Something like:
public interface IRepository <t : IQueryable <t where T : class
{
void InsertOnSubmit(T entity);
void DeleteOnSubmit(T entity);
}
My generic parameters got eaten in the comment above if that wasn't obvious.
IRepository of T : IQueryable of T
Rob,
The problem with that is that assume that you have a single query per repository.
I'm not sure I see what you mean. Since repository is queryable you can build any number of queries against it.
var r = from c in CustomerRepository where c.Balance > 0 select c;
or better yet, build specifications that are extension methods on queryable and in your service layer do stuff like:
return customers.ThatAreActive().WithOutstandingBalance()
Hm,
I usually think about IQueryable as mutable.
I guess it doesn't have to be.
@Rob
I guess that example just emphasizes what Ayende is saying because I don't consider that a good repository interface, emphasizing that you need to evolve your own designs in these sorts of cases.
What do you consider a good repository interface?
Linq is a functional approach to querying. Immutability is a core concept - queries are deferred and can be defined and composed without side effects.
IQueryable defines the potential to be queried - the queryee (?) determines what a query actually means.
Here is my take on IRepository (in use in personal libraries):
=== Interfaces ===
public interface IRepository <t : IEnumerable <t
{
}
public interface IQueryableRepository <t : IQueryable <t, IRepository <t
{
}
=== Default implementations ===
public abstract class Repository <t : IRepository <t
{
<t GetEnumerator();
}
public abstract class QueryableRepository <t,> :
<t,
<t
where TSource : IQueryable <t
{
<t GetEnumerator()
}
=== Linq to Sql implementation ===
public class TableRepository <tentity : QueryableRepository <tentity,>
{
<tentity GetTable(DataContext context)
<tentity();
}
And of course those should all be generic types, especially
QueryableRepository{T, TSource} :
Repository{T},
IQueryableRepository{T}
where TSource : IQueryable{T}
Hi Oren,
I had posted some blog posts on my thoughts on implementing a Repository pattern based on the IQueryable. The beauty of using IQuerable as the uderlying base for the repository is that it further decouples the repository from infrastructure concerns, that is assuming that the underlying infrastructure provides an IQueryable implementation (something that NHibernate needs badly). Couple that with composable specifications that uses lambda expressions, that provides a lot of power.
www.codeinsanity.com/.../...ng-repository-and.html
www.codeinsanity.com/.../...ance-and-ddd-with.html
BTW, love your blog. Thanks!
I think the comments might be going off course, IRepository <t was just an example. The question is whether you evolve a solution for your project or try to reuse a generic solution.
I have to agree with Oren and Colin.
Repositories need to be molded against the application their being used for. What if I don't want my repositories responsible for persisting information and want to use a separate unit of work implementation (which i do) and I instead want my repositories to be query-able. In fact that's all I really want them to do; provide the ability to find things in my domain.
Comment preview