RavenDB - Image Gallery Project (V) - The Structure

Published on 2010-10-1

The code for this and all other entries can be found here: http://github.com/robashton/RavenGallery/ 

Disclaimer: The structure of this application will be as simple as I can get it whilst still maintaining some semblance of maintainability going forward, any complaints can be directed at the comments field below if you think I’m committing some heinous crimes with the contents of this entry. The beauty of writing code with a high separation of concerns is that any of this can change without too much fuss if the initial code proves unworthy. This is all largely irrelevant anyway, but as the following entries will all utilise code using this structure, I thought it best to write an entry describing the basic principles of how the system works.

Views vs Entities

We have one data storage system, it stores documents and allows us to query those documents. Those documents are generally a lot flatter than those we have been used to in the past, and that allows us to store all the information required for a single entity in a single document (for the most part). A couple of assumptions therefore

It makes sense therefore to separate these two concerns into two different systems

Views

Without getting into the detail of how we get these views out yet, views are something we need. In our application here, a view is a single class containing all the information required to render a page of information. Generally, some information will be required to know what data is required for that view – that might just be an ID, or it might be the type of view and some information about how many items are to be displayed, some search terms to look for and a few other snippets beyond that.

We therefore have two types to be aware of, the input type containing information about the view we want, and the view itself.

I’m going to be brave and define an interface here, I can always change it later on it if proves unworthy of our love

   1:  public interface IViewRepository
   2:  {
   3:          TOutput Load<TInput, TOutput>(TInput input);
   4:  }

 

And with that, an interface for our view factories to implement:
   1:  public interface IViewFactory<TInput, TOutput>
   2:  {
   3:          TOutput Load(TInput input);
   4:  }

If a controller action takes in a TInput as a parameter, then it can go ahead, request the view and return that for delivery. We’ll talk more about how we’ll get hold of these views later, as there are numerous ways to go about it. They could be pre-computed manually, they could be composed by aggregating multiple documents together or they could come from somewhere else entirely; they are read only.

Entities

Here is where I might make a few enemies, I won’t count the documents themselves as my entities, documents are just how I talk to the data store, have getters/setters all over them and don’t contain any behaviour  – I’ll be creating entities that wrap up the documents and provide behaviour around them. This will follow the pattern of

   1:      public class WrappingEntity : IEntity<WrappedDocument>
   2:      {
   3:          private WrappedDocument innerDocument;
   4:   
   5:          public WrappingEntity(string someProperty, string someOtherProperty)
   6:          {
   7:              innerDocument = new WrappedDocument()
   8:              {
   9:                  SomeProperty = someProperty,
  10:                  SomeOtherProperty = someOtherProperty
  11:              };
  12:          }
  13:   
  14:          public WrappingEntity(WrappedDocument innerDocument)
  15:          {
  16:              innerDocument = innerDocument;
  17:          }
  18:   
  19:          private WrappedDocument IEntity<WrappedDocument>.GetInnerDocument()
  20:          {
  21:              return innerDocument;
  22:          }
  23:   
  24:          public virtual void PerformSomeAction()
  25:          {
  26:   
  27:          }
  28:   
  29:          public virtual void PerformSomeOtherAction()
  30:          {
  31:   
  32:          }
  33:      }

 

Because we shouldn’t ever need to query for entities, the interface for getting/saving/deleting entities will be very simple and look something like this:

   1:      public interface IEntityRepository<TEntity, TDocument> where TEntity : IEntity<TDocument>
   2:      {
   3:          TEntity Load(string id);
   4:          void Add(TEntity entity);
   5:          void Remove(TEntity entity);
   6:      }

Note, on a simple project like this, there would probably be no problem with just using the documents directly and enacting change on them via separate “scripts” within a transaction – I choose to do this because I want to show I’d use RavenDB to solve a more complicated problem/project.

Unit of work

I mentioned in the previous entry that I was going to leave committing changes to the application itself, I’m going to assume that in our application we’ll be able to represent all of the changes required by a HTTP post action with a single class structure, and for ease of understanding we’ll call that a Command. For now we’ll go ahead with the understanding that we can fire off a command to a magical interface and that interface will take care of the unit of work.

   1:      public interface ICommandInvoker
   2:      {
   3:          void Execute<T>(T command);
   4:      }

The command invoker will look for an appropriate handler (seen below) and pass the command to that for processing (most likely it will retrieve entities by ID and call methods on them)

   1:      public interface ICommandHandler<T>
   2:      {
   3:          void Handle(T command);
   4:      }

The Command Invoker implementation will be responsible for finding the appropriate command handler to execute and calling SaveChanges at the end of this process, flushing any changes through to the underlying store.

Implementation of the above

The above all uses StructureMap magic to locate the appropriate handlers/view factories in much the same way we’ll be using StructureMap to find validators, model binders and other such niceties.

In the next instalment of this series, we’ll create our user document, our user entity and the necessary infrastructure required to create/retrieve user entities from the repository, as well as demonstrating the functionality of the ICommandInvoker that we’ll be using throughout this series.

Why not hire me?

I am available for emergency consults, workshops, training and short-term development work anywhere in Europe

C#, JavaScript, Clojure, RavenDB, NodeJS, Architecture review.. etc

Get in touch

blog comments powered by Disqus

Doug


Loving where this series is going. Keep 'em coming!

Chris Swain


I'm so glad you're doing this blog series. It's going to be helpful to those of us looking for guidance with RavenDB and ASP.NET MVC. I downloaded the sample project and I'm not sure why you have documents, entities, and viewmodels. Could you explain a little more about the difference between your entities and your viewmodels and why you need both?

Rob Ashton


Ah - well that is definitely a non-contentious question :)I don't *need* those things, and I could just return the documents and use those as my view models, but I'm doing this project as not just a RavenDB primer but as an example of how CQRS can work well with a single data store when that data store is a document database with pre-computed map/reduce indexes.As a purist, this means entities shouldn't really be used for the view layer (querying).The "Should I use my entities on my view model" question has been done to death in the DDD threads/forums/etc - and for simple projects like this you probably wouldn't have any issues with doing so - but architecturally it doesn't scale (and in RDBMS projects you can swiftly end up with Select N+1 problems as you try to traverse through the relationships of the entity). You could still end up with that in this kind of project if you were not careful too.Even if I merged Entities and Documents, I'd still not be using the Entities as View Models - it's just bad karma to do so :)I hope that explains it at least a little bit - it will make more sense as I add more views to the project.

cowgaR


one of the advantage of NoSQL was that POCO was finaly possible in a simple manner and there wasn't any mapping done (impedance mismatch was almost gone), store whatever you want (no joins, no big-deal about optimal data schema thoughts and so on...).thus developing application became simpler with NoSQL, but I see you're missing itso you're trying over-complicate architecture...and present useless mapping withyour entities-document nonsense...premature optimization is the root of all evil

Rob Ashton


I think you're right - there is a certain element of undoing the good done here - but I also know I'm not alone in doing this because leaving code unguarded from troublesome developers makes people uncomfortable.I'm actually considering going back to quitting this because bugrit, mis-using direct access to modify documents can be prevented through code reviews and education and not_being_lazy.

cowgaR


what a swift response, thank you - my (angry) point was, seeing you're doing TDD:"how in the hell" did you come to the point you NEED entities in your projectisn't that once I'm doing TDD/BDD, anything I need can be brought later on + refactor?Once we hit some nasty problem that we can't solve?Seeing CQRS mentioned I thought this will overcomplicate things, although I'm not against the idea of seperating the views/documents as NoSQL fits this nicely...one can't allways assume that there are "bad" developers that screw the code, and we need to "guard" it. That's what tests are for.there are many RubyOnRails application out there which architecture is elegant and simple (even using active record beneath!) and are working fine (twitter front layer is RoR), only we in .NET world aim somewhere to LHC/NASA labs with our code...I like Rob Conery take on this, Web is simple, so should your app be...

Rob Ashton


Ah, you see - I don't need entities in this project, but I already said that :)This is supposed to be a full vertical slice of how you *could* build a proper application (not just a website) on top of RavenDB, but obviously a real application wouldn't be appropriate for a blog series introducing new concepts.I kinda figured that if I did it one way in one set of blog entries, and did it a different way in the upcoming screencasts then people could make their own mind up for their own projects where it makes sense.Clearly this is the wrong choice for a simple little image gallery, but in an enterprise environment (urgh, I hate that phrase) with a complex domain you might wish to do something similar because it keeps the boundaries well defined.I think my personal preference (seeing as the serializer does support it), is to just use read-only properties and have your cake *and* eat it with simplicity AND safety.

Rob Ashton


And you're right, most websites and even simple web applications simply don't need those well defined boundaries because it *adds* complexity instead of taking it away.

Rob Ashton


And sticking to simple CQRS principles won't be complicating things, that's a separate point from the entities/documents discussion.It just means I have one port of call to get views out, and port of call for enacting change on the model - no fancy architecture/patterns/trickery to be seen here.

Rob Ashton


One further thing I forgot to say (Sorry, I think all over the place when I'm writing), unless I had done it this way and started a big discussion in the mailing list and wrote a blog entry summarising that discussion then it wouldn't have taken place and that would be quite sad :)

cowgaR


agreed, I've glanced further articles (and discussion, but I started from part 1, gosh! ;-) so continue to bring flame and quality to NoSQL world ;)good job