ReviewMicrosoft N Layer App Sample, part IX–Not Invented Here is FUN
Continuing my review of http://microsoftnlayerapp.codeplex.com/, an Official Guidance (shows up at: http://msdn.microsoft.com/es-es/architecture/en) which people are expected to read and follow.
Is it not invented here if a Microsoft project chooses to re-invent something that Microsoft already did?
Take a look at how queries are being performed:
That looks strange, let us dig a bit deeper, shall we?
And it is not alone! It has a full family and some friends too:
So you create a specification, and then you call that specification to create an expression tree, and then you use that expression tree for the queries. If only we had builtin specification support in the framework! Oh, wait! It is called Linq! And it is already being used here, so they obviously know about it.
And no, this isn’t the case of needing to serialize specification over the wire, they are used in the same process as the one where the queries execute on.
I mean, seriously! You didn’t consider just dropping all of those abstractions and getting the work done? Oh, I forgot, there isn’t any work to be done, the application isn’t actually doing anything, all the abstractions are the point.
Comments
I'm still wondering what those casts all over the place are for... (I can see R# marked them as irrelevant). And why there are as many region-tags as there are methods...
Well, I don't think that the Query Specification pattern has been invented by that Microsoft team or that it is something weird. I believe that the Query Specification pattern was originally defined by Eric Evans and Martin Fowler, and it is a good way to encapsulate query criteria and do query composition operations. Then, there are quite a few other people who think that Query Specifications plus Linq/Lambda Expressions can be useful: Fabio Maulo: http://fabiomaulo.blogspot.com/2010/07/enhanced-query-object.html
I think Greg Young also wrote something about Query Specifications.
And there is even a Codeplex project doing a comparable approach, Linq+Specifications: http://linqspecs.codeplex.com/ (by jfromaniello)
Does Microsoft ever pay attention to these ....? Remember Oxite!
I've read that Martin Fowler and Eric Evans discussion about specs. The essence is to try to encapsulate query spec patterns in one domain in a manner that it could be applied in another domain, where you might have similar query spec requirements.
However, I think using it in a "demo" does not quite illustrate the need for it. Ayende said it best- "...abstractions are the point..." in this guidance. Using it to do a query by country name is really over kill. You shouldn't apply spec patterns to any and all queries.
That being said, I haven't really found a real scenario where I could re-use spec patterns across domains. But, there are people much more experienced than I, so my mind is not closed to the idea.
I would be interested to see a developer spend their own time and money to design and develop an application like that. It would not be a pleasant experience. This would keep a business owner up at night.
Woah now, don't be too hasty to slam this. I use this in my code in places also as a way to reuse multiple common specifications and build them into a single composite specification that I query with.
The benefits are 1) DRY - no need to repeat same where clause everywhere 2) Composition - I can compose several specifications together
Last thing, and it's important enough to break it out from the list, is that linq is not that easy to compose queries with OR semantics. The only way you can do OR's in linq in any meaningful way is to make one giant expression. You can compose AND's by just applying multiple .Where() calls, but there's no easy way to do that with OR.
I think the intention here is to illustrate the Specification pattern. This post would make a clearer point if it would explain what's wrong with that implementation. It is obvious that this soft is not real software. Now, it is not a bad idea to try to illustrate DDD patterns or concepts in a sample app.
The point of the whole articles was this: You can't create abstractions for the sake of it. They are here to help and not just stay and be pretty. If there is no domain, there hardly is a DDD.
Yes, in simple apps that looks like a overkill but specification pattern in my practice much more useful than LINQ when we have a very complicated domain model.
I'm with msuarz: it uses the specification pattern as suggested by most DDD specialists.
IF the point of this post is to show that the specification pattern is actually bullshit, then it indeed drives the point home. If the point is to show that the specification pattern is implemented using a lot of code, then I think the article misses the point: sure it's a lot of code, but it simply implements the specification pattern: it has to implement a pattern to specify a predicate with ... code which specifies a predicate. Of course that's silly, but the whole point is ... to use the specification pattern.
They could have also used String.Equals(str1, str2, StringComparison.Ordinal) or String.Compare(...) instead of making both strings lowercase.
Even making the strings UPPER case would have been better in terms of performance, according to Fx Cop.
It should have been StringComparison.OrdinalIgnoreCase
Yeah my application uses this pattern extensively.
In our case however, we have X% of our queries going through an ORM, Y% to stored procedures, and Z% generating cross-service calls. And the values of X,Y,Z are still in flux.
@Dmitry
The expression must be translatable into an SQL query. I don't know, maybe EF handles String.Equals(str1, str2, StringComparison.OrdinalIgnoreCase).
I think the actual point ayende is making is that Microsoft already had an implementation of the specification pattern that is pretty well known its called LINQ. Do we really need a whole collection of classes to create an abstraction over an abstraction? This abstraction over an abstraction requires maintenance, and doesn't really buy us much over what LINQ provides. What is does buy is clarity so we can give a decent name to a sufficiently complex query, however we can just as easily create a named predicate that can be shared and achieves the same clarity.
Awesome! Lets use a Pattern because a pattern exists instead of asking ourselves "Do i really NEED to do this?"
@people I just don't buy the idea that this is a guidance project to show HOW to use a pattern. IMO, the idea is to guide people to how to use a pattern in a semi-realistic (i'll use that term lightly) .NET application. Love the idea! don't really dig how it's been implemented.
I'm with LeeW here -> isn't Linq a pretty good implementation of a spec pat? Opinions vary. shrug
Main point -> why why and why?
I just do believe this is a uni lecture explaining what various DDD patterns are. It's trying to be more than that and people are defending it because they don't want to believe the truth.
This is why I see frak loads of crap .NET developers out there .. and why I'm stuck in that bucket, trying to pull myself out of it.
One of the main things I've learnt from people like Ayende and RConrey, etc ... BE PRACTICAL, PRAGMATIC AND KISS. U don't need to over complicate things to get the solution. Always keep your eye on the goal.
Meh - anyways ....
I use specication pattern, and it's a useful DDD pattern to reuse and represent business-related queries or policies, and compose the logic into a (linq) expressions that your data-layer can understand. I don't think it's necessarily wrong or a case of NIH. Having said that, this particular implementation is probably more bloated than it needs to be.
fail-quote myself: "I just do believe this is a uni lecture explaining what various DDD patterns are."
That should read: "I just do NOT believe...."
@Lee Witherington, writing Linq expression that your ORM can interpret correctly is hard. Very hard sometimes. But what if it's a common query? A querying criteria that you will reuse in multiple places, and most likely to be mixed and matched with other criteria. If you're only relying on naked Linq expresisons, you'll have to copy paste all those queries (that you have proven to work) to multiple places (and perhaps modifies accrodingly to be mixed with additional criteria). If you find a bug in your linq expressions, you need to fix it all over your source-code. This is what specification-pattern (or query-object pattern, or even just repository method.. there are various patterns to address this particular problem) are for.
@Hendry Luk
Correct, i could not agree more, there should potentially be a central place to store these commonly used Expressions. Also if the expressions warrant sufficient complexity then these can grow into a specification class, however I would watch out for overly complex expressions they could be a domain smell.
Cheers, Lee
This time I think you're a bit unfair. I agree that the whole sample application is quite a poor example of a DDD system. But, I think it's a good decision to keep your entity queries well-known and defined, so you don't have a million different linq expressions all over the place. I prefer to code "GetOrders(activeOrdersSpec)" than re-write the same expression N times in any place I need to retrieve active orders: DRY.
Specification pattern can be used when constructing a more complicate query, which might be used in different place. It had better have a API to return Expression<Func<T, bool>>, then in DAL, we can call something like: GetOrders(Expression<Func<T, bool>> expression); For the simple case like above, just directly passing" c => c.CountryName == 'Something'". A specification is overkilled.
A few people have pointed out that they use the specification pattern to encapsualte re-usable query logic. Why not just encapsulate re-usable queries in methods? Even return the IQueryable?
public IQueryable<Customer> GetCustomers(string firstName, params ...) { return _customerRepository.Customers.Where( c => c.FirstName == firstName ); }
I don't have to rewrite query logic/copy and paste a query I don't have to implement specs, or learn the intricices of the spec implementation
It can be optimized contextually. If I just want to know the count: I could call it as follows: GetCustomers().Count();
@KierenH
You can do that, but when you do that you can ONLY append AND conditions. You can't compose an OR predicate without combining expression trees.
@Darren,
re Kieren's suggestion: What's wrong in using the method - which returns an IQueryable - like this:
var result = repository.GetCustomers(firstName: "Jack").Union(repository.GetCustomers(firstName: "John")? This is a perfectly simple OR query built up of reusable query methods.
Well to start with, the concat will happen in memory
Comment preview