Taking a look at S#arp Lite–final thoughts
This is a review of the S#arp Lite project, the version from Nov 4, 2011.
This project is significantly better than the S#arp Arch project that I reviewed a while ago, but that doesn’t mean that it is good. There is a lot to like, but frankly, the insistence to again abstract the data access behind complex base classes and repositories makes things much harder in the longer run.
If you are writing an application and you find yourself writing abstractions on top of CUD operations, stop, you are doing it wrong.
I quite like S#arp approach for querying, though. You expose things directly, and if it is ugly, you just wrap it in a dedicated query object. That is how you should be handling things.
Finally, whenever possible, push things to the infrastructure, it is usually pretty good and that is the right level of handling things like persistence, validation, etc. And no, you don’t have to write that, it is already there.
A lot of the code in the sample project was simply to manage persistence and validation (in fact, there was an entire project for that) that could be safely deleted in favor of:
public class ValidationListener : NHibernate.Event.IPreUpdateEventListener, NHibernate.Event.IPreInsertEventListener { public bool OnPreUpdate(PreUpdateEvent @event) { if (!DataAnnotationsValidator.TryValidate(@event.Entity)) throw new InvalidOperationException("Updated entity is in an invalid state"); return false; } public bool OnPreInsert(PreInsertEvent @event) { if (!DataAnnotationsValidator.TryValidate(@event.Entity)) throw new InvalidOperationException("Updated entity is in an invalid state"); return false; } }
Register that with NHibernate, and it will do that validation work for you, for example. Don’t try too hard, it should be simple, if it ain’t, you are either doing something very strange or you are doing it wrong, and I am willing to bet on the later.
To be clear, the problems that I had with the codebase were mostly with regards to the data access portions. I didn’t have any issues with the rest of the architecture.
Comments
I find it very interesting that so many developers still abstract away the CRUD functionality even when they don't have to.
I would still like to see more examples/discussion about the "query object" pattern, as I can't seem to find much in the way of concrete samples and it seems like a very good idea to start using.
@Wayen M I believe it is called the specification pattern
Maybe it would have been good to elaborate on a few more of the good points then Ayende?
I would love to see a discussion about the "query object" pattern and the pros and cons of using it.
I have read Fabio's take on it here http://fabiomaulo.blogspot.com/2010/07/enhanced-query-object.html
When's Ayende's framework (or best practice example solution) coming? :) Something that brings together all of what you've been critiquing lately into a concrete example of the "right way" to do things. I'm sure a lot of developers would be inspired by it. It would be a great service to the community and serve the same purpose the S#arp authors are providing. Not just critiquing but a concrete example and valid attempt to make the lives of us developers easier.
@ayende,
Did you find any benefits of using this framework? Querying is something that can easily abstracted using straight NHibernate.
@magelings: https://github.com/ayende
I wonder if rather than using a "framework" perhaps having a scaffolding that uses a bunch of libraries would be a better way to go...
magelings, he said specifically raccoonblog was built recently with these principles, so go look for that.
Your ValidationListener works nice in theory but what about integration in Asp.Net MVC validation pipeline? I also don't like some aspects of SharpArch. For example I don't like Tasks and I prefer Fluent Validation instead validation attributes, but I must defend the Repository pattern. NHibernate Session exposes at least 50 public properties and methods. WTF??? Session has stuff like Connection, Dispose(), ActiveEntityMode and so on. Such API should be used in Controller? I think generic Repository exposing IQueriable, Get adn Remove methods is very cheap pattern and it can be easily extended if neccessary.
raccoonblog uses ravendb...a document database. I was leaning more towards a best practice NHibernate example...
I quite like having validation wired into your ORM. Like DB constraints but usable. I'll keep that in mind next time I'm using NHibernate (though I presume Hibernate has something similar).
Granted, you need to have some nicer stuff in place in case of bad input, but that style of validation has the advantage of being all-encompassing.
@magellings
I hate to say it, but you just inadvertently outed yourself as a newbie. Dont worry though, it happens weekly, if not daily.
This guy is never going to do this. Remember MADCO, or MATCO, or whatever ?? Heck it's been so long I bet he even forgot the name. I few rough screen drawings and he lost interest.
It's much easier to dissect and destroy instead of laying your own footprints in the concrete - lest they be dissected by someone else.
Yawn, smack, smack, Ayende, arent you bored by reviewing other peoples work by now?
@magellings,
You could also look at Effectus and Alexandria. These both use NHibernate.
I don't know why people keep inventing these frameworks, did they just create these projects for their work and then made them open source later?
@Ayende: They asked you for a review e.g. this project, Ntier architecture from MS Spain etc., did you get their feedback later since there were many negative points?
P.S: I can't login by Goolge, the error is No OpenID endpoint found.
Ayende, I'm quite interested in using validation that way, as well as in another point from your previous post:
I just opened up RacoonBlog to take a look at an example of those, but there's still
Sorry for ugly code formatting, it seems parser ate my line-breaks.
I think Ayendes post about SharpArch is harmfull. It creates sense that SharpArch is bad framework, but that is far from truth. Maybe it's not perfect, but it's still better than 90% of handroll solutions. And for example RacoonBlog has also code smells. Some controller methods are really fat. Nothing is perfect...
"Finally, whenever possible, push things to the infrastructure, it is usually pretty good and that is the right level of handling things like persistence, validation, etc."
I agree. However, one must be weary of creating needless abstractions in this way, as you caution. In fact I believe the repository abstraction and in particular the overly abstract LINQ specification pattern based repository results from an attempt to push things to infrastructure by detecting patterns in data access. Just like validation injected directly into the ORM is a result of the observation that the ORM persists entities, entities must be validated before persistence, so lets inject validation.
If they want to separate responsibilities like this, YOU HAVE TO use the DetachedCriteria construct. This would allow you to solve that need to include the child items to avoid the N+1 problem.
@dotnetchris, actually, you don't have to use the DetachedCriteria. In fact, you can still use NHibernate directly if you find LINQ to NHibernate to be inadequate for any specific scenarios.
This provides as good as any opportunity to provide a couple of links to specifically address dotnetchris' concern, as well as discussion concerning my response to Ayende's series of posts on S#arp Lite:
Encapsulating NHibernate-specific calls within a custom repository - http://groups.google.com/group/sharp-lite/browse_thread/thread/c653325f5f61e46c
Why have a task layer? - http://groups.google.com/group/sharp-lite/browse_thread/thread/692c4baf1454cc
A direct response to the Ayende's review - http://groups.google.com/group/sharp-lite/browse_thread/thread/77a4ed0b857427b0
When it comes down to it; if S#arp Lite jives with the way you/your-team wants to develop, then consider using it. If it doesn't, then don't. ;)
What is the difference between repositories and queries? As I understand they are both use NHibernate in this sample. So they are both abstraction over abstraction.
Comment preview