Previously in this series:
WhoDaBest - Post 1
WhoDaBest - Post 2
So I've made a couple of decisions. The first is that I'm going with tools from CastleProject.org for my object-relational mapping (ORM) and for my inversion of control (IOC). I'll talk about IOC later, but first I want to focus on ORM. Castle's ActiveRecord is open source and sits on top of NHibernate. I've used NHib by itself, and it's a great tool, but there are a number of nice little features that Castle ActiveRecord gives you that I like a lot, such as transaction management, mapping attributes (so no hibernate mapping xml files), property validators, and easy configuration just to name a few.
There are also some features of ActiveRecord that I don't like, so I'll discuss these to explain my approach:
- Inheriting from ActiveRecordBase - I simply don't want to do this for several reasons.
- The first reason is that I'll probably want to inherit from my own base domain class, maybe a base "Entity" class or some other class for specific domain objects. I hate being tied into an inheritance heirarchy.
- While I like the ActiveRecord utilities, I don't really want to follow the ActiveRecord Pattern. I don't want my domain objects to be responsible for their own persistence. I'd rather use a separate repository to make my domain model as loosely coupled and clean as possible.
- If I don't inherit from ActiveRecordBase, the other option is to use the ActiveRecordMediator. The guys at Castle were thoughtful enough to realize that everybody might not want to inherit from ActiveRecordBase and separated out the mediator that actually conducts the save operations. The only thing I don't like about this is that it is static! This makes unit testing difficult because I can't use dependency injection to drop in my reference.
Because of the preceding issues, I created my own abstract Repository<T, IdType> that wraps the ActiveRecordMediator calls. Because ActiveRecordMediator is static, I don't have a good way to unit test this class, but I'll punt on that for right now since they are basically all passthrough calls in order to convert the mediator's static methods to instance methods of a repository. The Repository is abstract because I really do want specific repositories for each aggregate that the site will use. In addition, I've made all methods that accept anything other than the IdType protected. This is because I don't want these find and count methods to be called externally using made up criteria. I want specific methods to be made available for finds and counts in the concrete repositories that will inherit from Repository.
You may have noticed that I'm not making an effort to loosely couple my ORM technology. I don't expect on this project to use another data access technology so I'm tightly coupling to ActiveRecord/Nhibernate. For the scope of this project and most projects I've worked on, I will realistically only be working with data sources that can be utilized by NHibernate, so the added complexity of using an ORM "provider" approach is just not worth the effort. If I need to ditch NHibernate and ActiveRecord I will have some work to do, but I'm willing to accept that risk. But at the very least the separation of my Domain layer and the creation of my own base repository gives me some marginal protection here.
I've made a few other project changes as well. The first is that I went ahead and renamed my WhoDaBest.Domain class to WhoDaBest.Core. The reason is that I decided this library would contain non-domain items, so that Core was a better term. I then added a Domain folder to the core project and added the first two domain classes that I will be working on. These are User and Role. I'll elaborate more on these classes in the next post. Now that I have some very base infrastructure in place, I'll have to begin writting tests first and filling in the class functionality.