The best client I've ever had...

by Ben Hyrman Friday, June 12, 2009

Was actually the State of Minnesota. Specifically, one of the departments there. Yep, goverment. They were fast-paced, progressive, and managed to tight deadlines and stuck to scope. This is why I generally don't like stereotypes. I've seen too many counter-examples. I fall for them sometimes, but I try to avoid them. Anyway, I digress.

So, we did some cool stuff. C# Winforms app with NHibernate 1.0-something hitting a very well-designed (but not necessarily NH-friendly) database (and, boy did we hit the limits of NHibernate).

Now, working with the state, you need a detailed proposal up-front along with a fixed bid. The question is, how do you manage to a fixed bid without losing your shirt, pissing off your client, or generally falling down. I'm no expert, but here are my observations.

0. Spend enough time up-front to lock down scope. If you can get the client to pay for a "discovery phase" then even better. That is, fixed bid locking down scope. At the end, they get scope that they can have you bid on (but can also have others bid). If you can't get the client to pay, then still consider that hours spent here will greatly pay off if you get the contract. You'll waste time and effort if you don't get the work, sure, but, in my opinion it's never a wasted effort.

1. You will never have an exact estimate. But, if you've developed before, then you should have a rough idea of how long something will take. Avoid the pitfall of "I've done it before so it'll take me less time" or "I'm using this new time-saving framework so I can do it faster." No, false. If it took you 8 hours to crease some sort of data edit screen last time, don't assume it'll take 4 this time. You'll either lose time clarifying requirements, learning the new framework, or realizing you didn't like a few things from the last time you did it that you want to correct now. 

This doesn't mean you should pad your estimates. Just don't be overly optimistic. Nor should you assume you're a goldfish and you're approaching this like you've never seen a project before and don't know how to code. Just be realistic. A good baseline as doing it the second time will take (nearly) as much time as doing it the first time.

2. Agree and adhere to scope, especially early-on. You need to make sure the client shares project delivery risk with you. This is more important with new clients and with some clients than others. Don't be the push-over guy. Don't eat those hours. Agree up-front to scope management (I re-estimate and tell you how much the change will cost. Or, we agree to cut scope in some other area). This doesn't need to be some ritualized process.

My state client was actually better at this than I was. He was very up front "we've agreed to this scope, you hold me to that agreement". Now, I still did some work that was outside of the scope but that I felt reflected on my professionalism and craftsmanship. I would never want a fixed-bid client to expect that the scheduling function they want added last-minute is suddenly in scope. But, by the same token, if I realize that spending two more hours to radically improve some part of the app (outside of scope) would make the customer happy, then I tended to do that.  

3. If there's a scope gap, and it's your fault, own up to it and deal with it. Your profit margin will erode, but it's the cost of learning. More experience in a given domain leads to more up-front questions and clarifications leads to better estimates.

4. Be prepared to not win the next phase of the project. Sadly, and this depends on the client, you shouldn't count on automatically getting the next phase of the implementation just because you delivered on time and had a happy client at the end. If they want another fixed bid, then you are now in the best position to deliver a fixed bid. That means, though, that you might end up having one of the most expensive bids on the table.

Bottom line, going in you and your client should have a clear understanding of what is being delivered (not necessarily down to a screen-by-screen level but at least conceptually of what problem is being solved and how). Additionally, you and your client should understand that increasing / changing scope isn't free. You either get more money or cut scope somewhere else. The road has to go both ways though, too. If they want to cut scope then you should be able to indicate how much that would save them (and cover why it won't save a lot if you've already done the wiring and hardcore stuff). Honest and up-front dialog is required. Overly complex and largely ceremonial agreements aren't (although, you need to be smart and cover the scope, agreement, change control, and recourse... err in favor of readability and conciseness)

KennelFinder.com Rewrite - Day 4+ - Revisiting the Repository

by Ben Hyrman Wednesday, June 03, 2009

We should probably talk about patterns for a bit. I like patterns, not because I think they're a design easy button, but because they're, essentially, just markers for how we implement things. Essentially a pattern is the meta-implementation that grabs the essense of what countless people have been implementing before that pattern emerged and boxed and labeled that body of knowledge.

Still, when I'm working on my own projects, I try to push myself to look at things differently, try new approaches to problems, or just play around to see what tastes right. My last post wasa good example of that. After trying things out, going back to Patterns of Enterprise Application Architecture, and thinking more about the feedback I received from Karl Seguin and Tuna Toksoz, I realized I was several miles down the wrong road.

With that, I'm going to step back a bit and introduce where I'm at now. Keep in mind, I'm not espousing these as best practices. Rather, this is an implementation that I'm trying out because I haven't (exactly) done it before but it feels right for my domain. My domain is a small one. When you're representing kennel listings, the services and features they offer, and reviews about those kennels, well let's just say the domain model fits nicely on an 8x11 sketch.

I also realized how truly wrong the vernacular is on a lot of blog posts. Like I said, I don't always go hunting for patterns, but when I use one, I want to make sure I'm calling it the right thing. The great thing about patterns is they (should) give us a universal language.

Enough rambling....

For my application, I assume that I'm going to keep my domain model loosely coupled from the services and persistence. Further, the persistence layer is going to be tightly coupled to a database (SQL Server in this instance). That is, I really don't need to support the ability to save to either xml or a database or flat file. But, if I do change in the future, I would just swap out the implementation behind the persistence concern. Next, I want a clean separation between each layer. I was going down a path where the front-end could just pass linq all the way back but, frankly, I don't need it.

Where my implementation might differ from a large app is that, on the large app, I might look at how I could easily encapsulate my domain queries as specifications or query objects (aside, I think 50% of the Specifiation implementations I've run across on-line should be called Query objects... again, if you're going to use a pattern then call it the right thing). 

What I thought I wanted in a Repository was actually a DataMapper (see, I screwed it up myself... most of the Repository patterns I've seen, my own included, look a lot more like a DataMapper than a Repository).

Oh, yeah, looks like I started tying a bit too much again. Let's get to some code!

I'm going to cover one cross-section of the app, the User.

public interface IRepository<T> where T: IEntity
{
    T Get(int id);
    PagedList<T> List(Pager pager);
}

public interface IUserRepository : IRepository<User>, ISave<User>, IDelete<User> {     User GetByLogin(string email, string password);     User GetByEmail(string email);     bool Exists(string email); }

public interface ISave<T> where T : IEntity {     void Save(T entity); }

Two things to point out here. First, you can see where I'm specifying my queries inline in the user repository. I could have gone another way and just had a Find(Query q) and passed in a new FindUserByLogin query. But, again, that would be utter overkill for this. Second, rather than having an IPersistableRepository that implements IRepository (inheritance chaining), I have other interfaces (ISave and IDelete) to indicate allowed actions on that repository.

Now, on to the NHibernate-based implementation of the UserRepository. As an aside, when I'm going to consider something the core implementation, I prefer to just name it without a technology qualifying name (ie, it's UserRepository not NHibernateUserRepository)

public class UserRepository : PersistableRepository<User>, IUserRepository
{
    public UserRepository(IDataMapper<User> mapper)
        : base(mapper)
    {
    }

    public virtual User GetByLogin(string email, string password)
    {
        return Mapper.FindOne(new ICriterion[] { Expression.Eq("Credentials.Email", email), Expression.Eq("Credentials.Password", password) });
    }

    public virtual User GetByEmail(string email)
    {
        return Mapper.FindOne(new ICriterion[] { Expression.Eq("Credentials.Email", email) });
    }

    public virtual bool Exists(string email)
    {
        return Mapper.Exists(new ICriterion[] { Expression.Eq("Credentials.Email", email) });
    }
}

On the implementation side, I like to implement the specific case first and then move common functionality up to a shared base class as it emerges. So, in this case, I found that every entity I wanted to save I also wanted to be able to delete (contrast this with a domain where one might want to be able to save lots of different entities but some entities can never be deleted or delete means something different.

Anyway, for my entities, some commonality popped out (remember, these repositories are the implementation of interfaces and are very tied to NHibernate! The rest of the app, though, will talk to the interfaces so we can change as we want):

public abstract class Repository<T> : IRepository<T> where T : IEntity
{
    private IDataMapper<T> _mapper;

    protected IDataMapper<T> Mapper
    {
        get { return _mapper; }
    }

    public virtual T Get(int id)
    {
        return Mapper.Get(id);
    }

    public Repository(IDataMapper<T> mapper)
    {
        _mapper = mapper;
    }

    public virtual PagedList<T> List(Pager pager)
    {
        ISession session = Mapper.Session;
        var criteria = session.CreateMultiCriteria()
                            .Add(session.CreateCriteria(typeof(T))
                                .SetFirstResult(pager.FirstRecord)
                                .SetMaxResults(pager.RecordsPerPage))
                            .Add(session.CreateCriteria(typeof(T))
                                    .SetProjection(Projections.RowCount()));

        var queryResults = criteria.List();

        IList<T> data = new List<T>();

        foreach (var o in (IList)queryResults[0])
            data.Add((T)o);

        var count = (int)((IList)queryResults[1])[0];

        return new PagedList<T>(pager, data, count);
    }
}

public abstract class PersistableRepository<T> : Repository<T>, IDelete<T>, ISave<T> where T : IEntity {     public PersistableRepository(IDataMapper<T> mapper): base(mapper)     {     }     public virtual void Save(T entity)     {         Mapper.Save(entity);     }     public virtual void Delete(T entity)     {         Mapper.Delete(entity);     } }

We haven't covered the DataMapper yet. We'll get there in a bit. Also, this is still early code. Once I get into things more, I'll probably refactor the paging so that I can pass in criteria and have it page the results of that. For now, I just want to be able to automatically page through the aggregate of any of my entities.

The DataMapper:

public interface IDataMapper<T> where T : IEntity
{
    ISession Session { get; }

    T Get(int id);

    long Count(ICriterion[] criteria);
    long Count();
    bool Exists(ICriterion[] criteria);

    void Save(T entity);
    void Delete(T entity);

    T FindOne(ICriterion[] criteria);
    IList<T> FindAll(ICriterion[] criteria, params Order[] orders);
}

public class DataMapper<T> : IDataMapper<T> where T: IEntity {     private readonly ISession _session;     public ISession Session     {         get { return _session; }     }         public DataMapper(ISession session)     {         _session = session;     }     public T Get(int id)     {         return _session.Get<T>(id, LockMode.None);     }     private void WithinTransaction(Action action)     {         ITransaction transaction = Session.BeginTransaction();         try         {             action();             transaction.Commit();         }         catch (Exception)         {             transaction.Rollback();             throw;         }         finally         {             transaction.Dispose();         }     }         public void Save(T entity)     {         WithinTransaction(() => Session.SaveOrUpdate(entity));     }     public void Delete(T entity)     {         WithinTransaction(() => Session.Delete(entity));     }     public long Count(ICriterion[] criteria)     {         ICriteria crit = DataMapperHelper<T>.CreateCriteriaFromArray(Session, criteria, null);         crit.SetProjection(Projections.RowCountInt64());         object count = crit.UniqueResult();         return Convert.ToInt64(count);     }     public long Count()     {         return Count(null);     }     public bool Exists(ICriterion[] criteria)     {         return Count(criteria) > 0;     }     public IList<T> FindAll(ICriterion[] criteria, params Order[] orders)     {         ICriteria crit = DataMapperHelper<T>.CreateCriteriaFromArray(Session, criteria, orders);         return crit.List<T>();     }     public T FindOne(ICriterion[] criteria)     {         ICriteria crit = DataMapperHelper<T>.CreateCriteriaFromArray(Session, criteria, null);         return crit.UniqueResult<T>();     } }

Note, the DataMapper is explicitly tied to the NHibernate Session. Also note, I've given up on the NHibernate.Linq implementation I had going on earlier. The library is probably actually there, especially for my needs, but it just felt that, for such a small problem space, I didn't need it.

Testing all of this is really painless (note, we'll get into the StructureMap configuration in another post):

public class UserRepositoryTest : BaseTest
{
    [Fact]
    public void Can_we_get_User()
    {
        ISession session = ObjectFactory.GetInstance<ISession>();
        IDataMapper<User> mapper = new DataMapper<User>(session);
        UserRepository repository = new UserRepository(mapper);

        var user = repository.Get(1);

        Assert.NotNull(user);
        Assert.Equal(user.Id, 1);
    }

    [Fact]
    [AutoRollback]
    public void Can_we_save_User()
    {
        ISession session = ObjectFactory.GetInstance<ISession>();
        IDataMapper<User> mapper = new DataMapper<User>(session);
        UserRepository repository = new UserRepository(mapper);

        User user = new User();

        user.Name = "TestUser";
        user.Credentials.Email = "test@user.com";
        user.Credentials.Password = "password";

        repository.Save(user);

        Assert.True(user.Id > 0);
    }

}

Anyway, there you have it, a cross-section view of where I landed for my persistence layer. I don't think there is a perfect answer to this problem, you have to take it with each new problem space. But, there will be several acceptable solutions that you can live with (forever or at least long enough to figure out where the design needs to go and refactor then). To that end, in my case, choosing to abandon the idea of passing Specification or Query objects around simplified things greatly. I don't have so many data needs that I'm in danger of bloating my repositories. Further, the code, at least in my infant understanding of the principles, seems to implement the SOLID principle fairly well. The Open/Close part of that is a bit questionable since it'd be much more composable if I were passing in query objects.

Later on I'll cover how I use StructureMap and Fluent NHibernate to breath some life into this model.

Oh, one last note, the DataMapperHelper code is a direct copy from one of NHibernate's Repository/UnitOfWork implementations.

NHibernate and natural keys - discussion points

by Ben Hyrman Thursday, May 21, 2009

Sorry, no code with this one yet. I promised @kkozmic that I'd get some thoughts down on a blog post rather than repeatedly spamming his Twitter feed with 140 character bursts.

The question, basically, is around what he called domain-relevant IDs or, in other words, natural keys. A lot of times you'll just see it recommended that you use surrogate keys (example: auto-incrementing id, hilo assigned id, guid) on your entities and the question is, why. I'm by no means an expert on this, but I wanted to throw my two cents out, having done quite a bit in NHibernate with both approaches.

First, let's cover a natural key. Basically, a natural key is the set of attributes that uniquely identify a tuple. Or, in english, the values of your entity that make it unique. In database speak, it's the column values that uniquely identify a row in a table. 

Suppose we have an online event registration system. I have an Event table, a Person table, and a many-many join table between the two called Registrant. Because of the business requirements, we're comfortable choosing email address as the natural key in Person. For our purpose, multiple people can't share an address. Event is a little more complicated, but only a little. Our requirements tell us that an event's name, date and location (city, state) make it unique. 

Ok, I'm going to derail things a little bit here.... some people will state that a natural key needs to be "durable". Essentially, they're saying that the key should be immutable for the lifetime of that record. In theory, this isn't necessary. In practice, it's a function of the database. If your database can't do cascade updates(or if you have cascade updates turned off) then, well, you really do want an immutable key.

Sorry, back on track.

NHibernate can easily (with a bunch of caveats that we'll get into) handle the mapping. You'd set the <id for Person to the email column and set the generator to assigned:

<id name="Id" type="String">
  <column name="EmailAddress" not-null="true" unique="true"/>
  <generator class="assigned" />
</id>

Then set the id for Event to a composite id:

<composite-id>
  <key-property name="Name" column="EventName"/>
  <key-property name="City" column="City"/>
</composite-id>

Easy, all done. 

Wait, not really.....

Let's talk about some of the issues.

First, we've now lost one of the cool features of NHibernate. It no longer knows if we're inserting or updating our entity. We'll need to know that and call ISession.Save or ISession.Update ourselves. That, in of itself isn't a huge deal. In fact, we can get around it if we add a version mapping to NHibernate. This, really though, is just shifting our surrogate key, in a manner, to another column. Still, it's doable.

Next, on the composite id, we must must must override Equals and GetHashode. Otherwise NHibernate will slap you, yell at the dog, drink all your chocolate and storm off. Again, not a huge deal per se. In fact, even if you're using surrogate keys, it may be a good idea to override these methods to give your objects an equality based on domain data (ie, if I have two objects and both have the same email then I should treat them as instances of the same entity)

Last, and again this is somewhat generalized, your pain could potentially increase as your application matures. Your client loves the registration system and wants to expand it to take over for their postal registration system. Email isn't even captured in that system. Bring the new data in and suddenly you've lost your natural key on person. To be sure, this is a bit contrived, but illustrative. 

Random things I want to test out and get code up for:

You typically want to work with aggregate roots in NHibernate. For instance, you'd add registrations to an event and then save the event, letting registrations cascade down - Should triple-check how that works instead of relying on memory.

You'd probably want to model that child relationship as a Set.

Random thoughts:

In my experience, sticking with surrogate keys is easier to implement because then NHibernate can key on that to know when to save versus update (can also accomplish this with a version column which could map to a last updated timestamp which many DB designs seem to sport around anyway [insert date, lastupdate date, updated by, inserted by]).

Choosing a good natural key can be hard. Choosing a surrogate key is easy. That doesn't make it right.

You can still enforce equality based on domain knowledge within the object model and not the database.

Anyway, sorry for the rambling post. I'll get some code up in a new post and formalize some of my thoughts when I'm back from vacation.

KennelFinder.com rewrite, day 4 - The repository, design ideas

by Ben Hyrman Wednesday, May 13, 2009

I can't settle on this....

First, every implementation should be tied to its ecosystem and needs. In this case, it's a small app and I'm the sole developer. So, if I can't trust myself, who can I trust. Still, this app is a chance for me to play around with various ideas and see how they hold up in a quasi-real world app (let's face it, I'm not supporting BestBuy.com-size load with my app).

So, with that, given a repository:

 
public interface IRepository<T> where T: IEntity
{
    TResult FindOne<TResult>(ISpecification<T, TResult> specification);
    IQueryable<TResult> Find<TResult>(ISpecification<T, TResult> specification);
    IQueryable<T> Find();
}

For the purpose of this discussion, that specification up there could easily be replaced with Expression<Func<T, bool>> (I'm playing around with some code by Steven Burman).

I have several benefits:

  • I can easily support further filtering downstream
  • I can easily support paging
  • I can pull data back in any order
  • I can delay execution as long as I want

And, well, that benefit comes with plenty of problems too

  • I have no control over execution
  • I'm essentially telling the client "give me a specification for what you want, I'll give you back matching data, and then you do whatever the heck you want with it"
  • I'm highly reliant on the LINQ provider (haven't had an issue _yet_ with NH.Linq or in-memory list, not even touching anything else)
So, with all of that, I'm not quite sure where to go with this... Let it stand for now, rewrite it to return something more closed (IList) or what.

KennelFinder.com rewrite, day 3 - Fluent NHibernate Config

by Ben Hyrman Monday, May 11, 2009

I'm not sure how far I'll code tonight, but I wanted to show the most basic wiring of Fluent NHibernate:

[TestFixture]
public class NHibernateConfigurationTest
{
    [Test]
    public void Can_we_configure_NHibernate_SessionFactory()
    {
        var sessionFactory = Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2005
            .ConnectionString(c => c
                .Is("Data Source=localhost;Initial Catalog=KennelFinder;Persist Security Info=True"))
            .ProxyFactoryFactory("NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu")
            .UseReflectionOptimizer()
            .DoNot.ShowSql()
            ).BuildSessionFactory();

        sessionFactory.Should().Not.Be.Null();
    }
}

That gives us a valid session factory and, from here, we're off to the races.

If you're reading this, you're probably at least passingly familiar with NHibernate. But, just to recap, you generally want one session factory per database. Session factories are expensive to create. Session factories are, in case you didn't guess, the source for Sessions. We'll use a Session to interact with the database. Sessions are very cheap to create plus they won't actually connect until they need to. So, in my scenario, we'll be creating and abandoning sessions left and right using the idea of a session-per-request. I'll actually use a dependency injection container to manage the lifecycle of these objects, but the idea would be the same if we were doing this ourselves... one session factory for the entire app (since I only have one DB) and one session per user request.

KennelFinder.com rewrite, day 2 - Thoughts on Fluent NHibernate

by Ben Hyrman Sunday, May 10, 2009

I briefly mentioned Fluent NHibernate in day 0. At a high level, Fluent NHibernate provides a fluent interface to configure NHibernate and map your classes. Fluent NHibernate really thrives when you can specify conventions for your maps. That works well in my case as tables are named the same as classes, all of my identity columns are named <tablename>Id, etc. (and you have full control over how the conventions resolve, giving you a lot of power on how things wire up).

Where Fluent NHibernate really shines, though, is in mapping your classes. Again, Fluent NHibernate (or FNH as it's commonly called) is just a wrapper on NHibernate. Behind the scenes it emits .hbm.xml files for NHibernate to consume. But, it provides, in essence, static type checking for you. One of the downsides of using an XML file to map in NHibernate is that it can't pick up when you change the name of a property (or, like I often do, misspell a property in the mapping file). FNH uses your class so it uses the properties on your class. That's pretty darn cool!

Possibly more impressive is that FNH also has an auto-mapper. Again, FNH is really strong on convention. If your domain and database follow a consistant convention, then you can auto-map all of your entities without touching a single class map or XML map.

Last, FNH allows you to combine all three mapping concepts. You can automap, override some automaps with class maps, and substutite in NHibernate mapping files for others.

With all of that, there are some places that I know I'm going to face some challenges and one place where I think I might. FNH is built against NHibernate 2.0 GA. Nothing wrong with that; it's what's publicly available from NHibernate and it's the most stable. However, I'm going against 2.1 on the trunk. I'll need to recompile FNH. No big issue there either since FNH is open source. However, there are some breaking config changes between 2.0 and 2.1. I'm either going to need to patch FNH (making updating source a bit tough) or work around it (potentially making upgrades a bit tough).

The other issue that I think I might face, and that's partially due to how I've chosen to map some data access, is that I have a sql query mapped for the radius distance search for kennels. I'm fairly certain that FNH doesn't support that at this time. Of course, I can get around that by providing an NHiberate mapping for Kennel... but it's my biggest entity in the domain so the value of FNH goes down greatly without it.

Considering everything, I think I'm going to forge ahead with FNH and see where the rough patches are. It's a great, solid library and I'd hate to miss out on it.

KennelFinder.com rewrite, day 1.5 - The repository, first refactoring

by Ben Hyrman Saturday, May 09, 2009

First, let's tidy up that last test and introduce some of Fabio's NUnitEx awesomeness:

        [Test]
        public void Can_we_find_Service_by_Id()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            var services = repository.Find(s => s.Id == 1);

            services.Should().Not.Be.Null();
            services.Should().Not.Be.ToString();
            services.Count().Should().Be.EqualTo(1);
        }

I like the additions from Fabio. Rather than the syntax of Assert(fact) we have a more natural assertion language. This object should (or should not) have these properties.

Next, in my case, I know now that it's going to be very common that I'm only going to want a single instance of something. Most typically, this is going to be loading my persisted entity objects by their id. I have a few options for that. I could keep it off of the Find using a chained LINQ function. Or, I could move it into the repository as a first-class repository operation. We'll revisit this later, but for now, I'm going to promote it to a first class operation. Further, I want to treat finding multiple, or finding none, as an error. Luckily, LINQ has a great built-in function called Single that will behave exactly like I want.

Let's add that to our repository interface first:

     public interface IServiceRepository
    {
        Service Single(Expression<Func<Service, bool>> where);
        IQueryable<Service> Find(Expression<Func<Service, bool>> where);
    }

And then let's implement it in our in-memory repository:

         public Service Single(Expression<Func<Service, bool>> where)
        {
            return data.Single(where);
        }

And, last, let's test it (well, first actually since I wrote that before starting the rest):

        [Test]
        public void Can_we_find_Service_by_Id_using_Single()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            Service service = repository.Single(s => s.Id == 1);

            service.Should().Not.Be.Null();
        }

Everything is green!

But, now, remember, I want to blow up if I don't find the service I'm looking for. Let's write a test to prove the negative:

        [Test]
        public void Verify_that_selecting_bad_id_fails()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            Service service = repository.Single(s => s.Id == 99);

            service.Should().Not.Be.Null();
        }

Well, that works, we get back an InvalidOperationException. However, a red bar in NUnit isn't exactly what I was after. So, lets set up the expecation for that failure:

        [Test]
        public void Verify_that_selecting_bad_id_fails()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            new Action(() =>            
                repository.Single(s => s.Id == 99))
                .Should()
                .Throw<InvalidOperationException>();
        }

Now, I'm a little on the fence on if my repository should just throw InvalidOperationException up the call stack. My first impression is that, no, it shouldn't. InvalidOperationException is a fairly generic framework exception whereas I want to translate it to a very specific business exception. Actually, in thinking about it, I have three paths that I want to clearly communicate. The first is that I found the object... which I'll return as normal. The second is that I couldn't find any entities matching my criteria. For example, suppose I gave the option to a user to search by id and they simply supplied an id that didn't exist. However, the third path is that I might find multiple entities where I expected just one. That can't happen selecting by id but not all of my entities have autoincrementing ids.

Let's address those two paths now:

        [Test]
        public void Verify_that_selecting_bad_id_fails()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            new Action(() =>            
                repository.Single(s => s.Id == 99))
                .Should()
                .Throw<NoResultsFoundException>();
        }

        [Test]
        public void Verify_that_selecting_duplicates_fails()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            new Action(() =>
                repository.Single(s => s.Name.Length > 0))
                .Should()
                .Throw<MultipleResultsFoundException>();
        }

I've added the two exceptions to my repositories assembly.  Now, it's not quite pretty yet, but let's add our checking to our in-memory repository:

        public Service Single(Expression<Func<Service, bool>> where)
        {
            try
            {
                Service service = data.SingleOrDefault(where);

                if(service == default(Service))
                    throw new NoResultsFoundException("Multiple results were found");

                return service;
            }
            catch (InvalidOperationException e)
            {
                throw new MultipleResultsFoundException("No results found", e);
            }
        }

Compile. Run tests. Green bar. Good enough for now!

KennelFinder.com rewrite, day 1.5 - The repository, taste test

by Ben Hyrman Saturday, May 09, 2009

Ok, time to write some simple tests for the repository to see how it feels to code against. The easiest way, in my opinion, to try out a new concept is to start as simple as possible and keep pushing it forward until you're happy. Writing the tests first is a great way to accomplish this. Basically, write a test the way you want the backend to feel, and then write a backend that passes your tests!

I'll be using NUnit (hopefully you've heard of that by now!) along with NUnitEx. NUnitEx is a wonderful collection of extensions and additions written by rockstar developer Fabio Maulo. (He's one of the main committers on NHibernate.

On to the tests!

In it's most basic form, I want to be able to query the repository and find entities that match my criteria. In my domain, I have kennels and kennels have services. So, let's try and find a Service by its Id. Also, I don't want to wire up to the database yet, so let's access an in-memory repository (our design would be pretty bad if it couldn't even support substituting different implementations along well-defined seams):

    [TestFixture]
    public class InMemoryServiceRepositoryTest
    {
        [Test]
        public void Can_we_find_Service_by_Id()
        {
            IServiceRepository repository = new InMemoryServiceRepository();

            Service service = repository.Find(s => s.Id == 1);

            Assert.IsNotNull(service, "Expected to find a service but our super-cool code didn't work");
        }
    }

You know, that feels pretty good. Get a service repository and query it to find a service with a certain id. I think that'll work for now.

Wait, actually, it's not going to work at all because none of those things exist. Oops. Well, let's build enough to make it compile. First, let's define a Service class in the KennelFinder.Domain assembly:

namespace KennelFinder.Domain
{
    public class Service
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

I'll cover this with some tests too as this class evolves, but for now it's sufficient for us to try out the repository.

Now, let's add a repository to KennelFinder.Repositories. First the interface (presumably, we'll want a repository that interacts with our persistence store too, so let's assume it'll provide the same interface as our test class)

    public interface IServiceRepository
    {
        IQueryable<Service> Find(Expression<Func<T, bool>> where);
    }

If you're not familiar with the expression call. I'm returning a LINQ queryable source that's filtered by a LINQ expression. And, the beauty of it all is that we can defer execution as long as possible. So, we can write something cool like .Find(s => s.Id > 0).Skip(0).Take(10) and we have paging built in (more on that later).

The downside of this approach is that my repository is being very open, from a query standpoint, with downstream systems. The plus side of that is that I give consumers a great amount of flexibility in how they interact with my repository. The downside is that, well, I give consumers a great amount of flexibility in how they interact with my repository. Since I'm the end-to-end customer for this and, most days, I trust myself, I'm going to let this stand. Your mileage may vary.

Ok, enough of that, now on to a hard-coded implementation of an in-memory repository for my service class (note, since in-memory repository is going to be used for testing, I'm making it in the test assembly as well):

namespace KennelFinder.Repositories.Tests
{
    public class InMemoryServiceRepository : IServiceRepository
    {
        private IList<Service> services = new List<Service>
            {
                new Service { Id=1, Name="Daycare" },
                new Service { Id=2, Name="Boarding" },
                new Service {Id=3, Name="Grooming"}
            };

        private IQueryable<Service> data;

        public InMemoryServiceRepository()
        {
            data = services.AsQueryable();            
        }

        public IQueryable<Service> Find(Expression<Func<Service, bool>> where)
        {
            return data.Where(where);
        }
    }
}

Alright. That looks like a test and some code to back up the test. Now I'm going to create a new NUnit project, add the repositories.test assembly, and see what happens


  

And it's green! Not bad for a first shot!

Woohoo. Time for a brownie break.

KennelFinder.com rewrite, day 1.5 - The repository, design ideas

by Ben Hyrman Saturday, May 09, 2009

The previous version of KennelFinder followed the repository pattern. However, I wasn't quite happy with the level of nesting that happened. I have a couple read-only entities that don't have unique identifiers so I ended up with a base QueryableRepository that ReadOnlyRepository extended that, in turn, ReadWriteRepository extended. That was mainly to support a Get(int id) function on the ReadOnlyRepository. But, in thinking about it, Get is nothing more than a Find(entity => entityID == id).FirstOrDefault() call.

Additionally, one thing that got a bit combersome was embedding all the find operations in each repository. While it was fine, it felt like it blurred concerns just a bit. The repository was responsible for both data retreival / persistence and query specifications (DoesUserExist, FindUserByEmail, FindUserByLoginCredentials). One concept from several DDD practictioners that I've seen, and liked, is the idea of a formalized specification that gets passed to the repository. 

In keeping with that, I'm going to base my repository on a combination of what I had along with the Fluent NHibernate repository and Steven Burman's specification project. I'll post on my repository, and associated tests, shortly. You know, one of the keys to figuring out if the repository feels right, for me at least, is going to be to create an in-memory repository and just try out various test cases to make sure it tastes and smells delicious.

KennelFinder.com rewrite, day 1.5 - The directory structure

by Ben Hyrman Saturday, May 09, 2009

I have to admit, I'm not very original with my project layout. My structure follows a lot of open source projects I've seen. But, for completeness, I'll show it here. 

 

All of my external assemblies go into lib. Interesting sql scripts (database backup, restore scripts, load scripts, etc) go in sql. Anyway, you get the point. I'm not sure how I feel about segmenting the domain from the repositories. Usually I just segment them by folder/namespace in the same assembly, but I'm going to try it a little different this time. There will probably be another project or two as I progress, but this is more than enough for a first day.

 
Awesome site design by Mike Evans | Some icons copyright FamFamFam | Social bookmark icons copyright FastIcon | Powered by BlogEngine.NET 1.4.5.0