Hanalei, Hawaii 9/2/2010
438 Posts and Counting

MVC Storefront Part 25: Getting Started With Domain-Driven Design

Friday, December 05, 2008 -

I don't like the complexity that's crept into my application. Not sure how else to put it - but the architecture needs to be shaken a bit so in this episode I tackle this complexity head on using DDD.

The Zen of Smell
You can't really define it when your app starts to smell - and I really hate that term! But it really applies to what I'm encountering right now as I begin to not only wrap up what I'm doing, but also demo it. People have questions, things aren't apparent. Zen circleI have answers to many of the architectural decisions but when I explain how they are carried out, I realize that I've just run over some potholes.

In short: I could have done better.

Continuous Learning
That's what this is really all about: we never stop learning and there's always some refinement to be made. Yes I realize this can be a vicious cycle of never-delivery, but I'm also confident that the pursuit is always worth it. In this case, I'm relying on my 20 years of coding and development to elbow me in the ribs and suggest to me that "I can do better". 

I can make this application better, faster, stronger than before.

I don't want to give in just yet and thankfully my new boss is a rockin super star and is letting me further explore this (seriously - send this man some love for letting me experiment).

There is gold in these hills. The journey I've set out on has already transformed the way I do things forever and all I hope and pray is that I am able to inject this goodness into the Storefront.

Your Patience, As Always, Is Appreciated
To me, the payoff of this entire effort has been the journey itself. .NET has matured to major rev 3 and with it we have a great toolset (Linq, Anonymous types, MVC, etc). It's sort of like wandering around [Killer Video Game], realizing you've leveled up and have unlocked The Next Great Zone.

Exploration is in order, the testing of new powers, the downing of bigger bosses, etc.

I can see the finish line - feature-wise there is no more to do. Right now it's all about honing and refactoring so sit back and watch Part 1 of a 3-part process, as I take on the "drift" in the Storefront and try to apply some Zen to the madness.

The Source
I'm working very hard to synch up everything I'm working on now, and it changes (literally) hourly. I just ask your patience as I get things put together and structured properly. This is not a quick affair, but something that takes time and discipline and I don't want to short-change it. I really think it will be worth it.

Download Episode 25 It Here (42 Minutes, 62Mb)

Double-click for full screen

Related


Gravatar
Rob - Monday, January 26, 2009 - Fantasic work Rob. Keep it up as your work is much appreciated!
Gravatar
Chad Moran - Thursday, January 22, 2009 - Rob has adopted the Blizzard model of "It'll be ready, when it's ready."



It is hard to wait when you have no estimated time, though.
Gravatar
nabbed - Monday, January 19, 2009 - What kind of doco would you put together for a maintenance when your all packed up and gone
Gravatar
robconery - Thursday, January 22, 2009 - Little more complicated then that - but it's coming, I promise :)
Gravatar
Chad Moran - Thursday, January 22, 2009 - So what you're saying is you've based it on ASP.NET MVC RC but we can't see it yet? Eh, eh... :P
Gravatar
robconery - Monday, January 19, 2009 - ? what ?
Gravatar
anton - Thursday, January 22, 2009 - cheers mate, really appreciate it! Hopefully we can get some more DDD goodies :-)
Gravatar
robconery - Wednesday, January 21, 2009 - No worries - wasn't too sure what you were asking for :). I don't doc

anything until I'm finished :). Too many spent cycles writing docs that get

outdated the next day.

I have a whole episode I want to do RE "Being a good Dev - Let's Analyze and

Document" etc.
Gravatar
robconery - Wednesday, January 21, 2009 - It's in progress right now - I know it's taking a while but it's on its way.

I'm hard at work on this stuff and am working on something pretty dang cool

at the moment :)
Gravatar
nabbed - Tuesday, January 20, 2009 - Sometimes I find myself in a short term roll which requires hand over documentation or sometimes I need to put a functional specification together before I start work, regardless of the fact we might be Agile or not.

Im just after a practical approach to the documentation that gives a written document not a video. As useful as your are in explaining and bringing together a sensible approach to the technology at our finger tips, I would like to see you apply that same practical common sense to a documentation effort.
Gravatar
robconery - Tuesday, January 20, 2009 - Not sure why you're assuming I won't document this - of course I will (I

have to). Generally people aren't very interested in watching me write docs

- they want to see the code and learn how to do things; thus the videos.
Gravatar
robconery - Thursday, January 22, 2009 - Ding ding ding!
Gravatar
Chad Moran - Thursday, January 22, 2009 - That sucks, oh well I guess at least we get twofer when RC goes live.



WTB ASP.NET MVC RC! (that's a lot of acronyms)
Gravatar
PK - Thursday, January 22, 2009 - Yeah .. i was silently wondering if all this ninja-MVC work is to coincide with the RC that should be coming up soon. I was guessing MIX09 ... but i hope it's not that far away.



/me drools at how close we are learning from this project once more!
Gravatar
Lamin Barrow - Friday, December 05, 2008 - Yeayye.. Finally Part 25. Thanx Rob.. I really appreciate all your efforts. How can we ever repay you?
Gravatar
robconery - Friday, December 05, 2008 - Volunteer your time this holiday doing something good :). If you don't have

a holiday where you live, make one, then do something good for it! Festivus!
Gravatar
MotoWilliams - Friday, December 05, 2008 - When is the source code going back up on Codeplex ( http://is.gd/J3I )? It was nice to have our SVN clients grabbing the bits as we followed along.
Gravatar
citezein - Friday, December 05, 2008 - Damn Rob, now I have to go redesign my entire application! No, not really, but I am very interested in the direction you're going to take this. The state idea looks quite interesting, as does the separation of your code. I can't wait to see how this turns out for you. Thanks for the time you've spent on this, it's been very helpful.
Gravatar
pnocera - Friday, December 05, 2008 - I have just finished developing an application which is running, and does what it 's supposed to do. I'm really not proud of it, so yesterday I went back to Visio to draw the big picture, and I stated that I should just rewrite it from scratch. I am not a very good programmer, but I've been programming for 20 years and its always been the same story for me : when I look back any application, if I had to do it again, I would never do it the same way...
Gravatar
eKnacks - Saturday, December 06, 2008 - You've been knacked. Keep up the good work.
Gravatar
Damian Hickey - Saturday, December 06, 2008 - Timing of this is perfect for me :) Half way through Evans's book, and trying to map it down to something more concrete from an implementation perspective. While domain stuff is very specific to business requirements, it'll be very interesting in how you tackle the infrastructural items.



In other example I've seen, all entities inherit from an EntityBase which implements IEntity, and all aggregate roots specifically implement an IAggregateRoot to specifically differentiate themselves from other entities. Do you see any value in doing that?



Very well delivered, looking forward to the next part!





Gravatar
robconery - Saturday, December 06, 2008 - To be honest I don't see the value in this. Ideally your objects should be

completely free of this kind of thing (according to the books) - they call

it "POCO as a lifestyle" :).

I think I know the example you're referring to and the only thing IEntity

does is make you declare a key (TKey). The only thing that does (in that

example) is allow the developer to build out a SQL string.



Inheritance on your objects is coupling - even if it's helping you out (my

opinion). But again - I'm no expert here :).
Gravatar
robconery - Saturday, December 06, 2008 - There has been a few times where I've been pretty happy with an app - but

you're right. Generally not. It doesn't mean that we shouldn't always try

for something better :)
Gravatar
Daniel - Saturday, December 06, 2008 - Looks interesting. I'm in a similar boat- I've been following these patterns and trying to read up on DDD (and all the other DDs =), and having trouble translating them into code. Even when I do, I have that nagging question - is this _really_ DDD? So it'll be interesting to watch this next phase.
Gravatar
Chris Kolenko - Saturday, December 06, 2008 - I looked at your example.. and i was trying to think of something that wasn't right..



so this is what i came up with..



Unit Of Work.. Currently you're implementing the ISession.. this only works for SQL based items..

At the end of the pipeline i'm assuming there will be some sort of email being generated..



Should this email be using Unit Of Work ?? how are you going to handle non sql work items??

Are these simply ignored because there might be only one email generated?
Gravatar
robconery - Saturday, December 06, 2008 - I think you're talking about a transaction in general? Good question though

- not sure. I'll ask a wonk...
Gravatar
Yitzchok - Saturday, December 06, 2008 - This is great stuff Rob :) and I like the direction to where this is heading.
Gravatar
Randy Ridge - Saturday, December 06, 2008 - It seems to me to be completely valid to have a a super class implementation, this could still be POCO in that you're not doing it to support an external dependency, you're doing it to clarify your domain model. The key point of an entity is that it has an identity, to that point equality should be based on that identity and not it's attributes. If I have a User in a security context and a User in a ordering context, they could both be the same logical entity expressed with completely different attributes. To that end I should think that to avoid duplication I would end up with something like:



// User with attributes related to security context

class Security.User : UserBase {

RoleCollection Roles { get; set; }

EmailAddress Email { get; set; }

}



// User with attributes related to the ordering context

class Orders.User : UserBase {

OrderCollection PastOrders { get; set; }

}



// Base of users across contexts, a Security User and a Orders User could be the same, how? By identity.

abstract class UserBase : EntityBase {

}



// Provides what it means to be an entity, it must have an Identity

// Equals, equality operators, and HashCode have to be based on type, super type, and Identity, not other attributes and pointers

abstract class EntityBase : IEntity {

TIdentity Identity { get; }

Equals(object obj) { ... }

operator ==(left, right)

operator !=(left, right)

GetHashCode() { ... }

}



// generic interface

interface IEntity : IEntity {

TIdentity Identity { get; }

}



// marker interface, can be useful for constraints elsewhere...

interface IEntity {

}



I personally don't see how this is not POCO. I'm avoiding duplication and I haven't implemented anything outside of my control for the sake of satisfying my persistence layer. What I'm satisfying is the definition of what it means to be an entity, it has an identity and that equality should be based on identity... You could still provide complex TIdentity types if you wanted something more than primitive ints, Guids, etc.



Of course, you could implement equality and identity on each and every one of your domain entities if you choose, but why not bubble it up to a super type?

Gravatar
robconery - Saturday, December 06, 2008 - I spose I'm not clear on why I'd need it - how does "EntityBase" clarify the

domain model, and to whom? I'm not disagreeing with you necessarily - I

think it's just not clear to my WHY I need to do what you're suggesting. To

be upfront - it comes off as "Hyper coding". Please don't take offense :) I

really appreciate your thoughts but supporting your points with DDD

terminology isn't making sense to me (sounds jargon-y). In other words:
Gravatar
Chris Kolenko - Saturday, December 06, 2008 - Maybe that example isn't the best tho..

After having a bit of a think about it.. the email seems like a side effect.



But you get the jist.
Gravatar
Damian Hickey - Sunday, December 07, 2008 - The value I see is enforcing a constraint on your repository interfaces, especially if they are generic (oh-oh, IRepository war!). Personally, I can see that it may help readability, particular if there are are a team of people working on the code and not all are fully aware of the domain, or perhaps when new people are introduced. Also, in R#, right click IAggregateRoot -> Find Usages... get list of aggregate roots.. sweet.
Gravatar
Damian Hickey - Sunday, December 07, 2008 - Looks like plain old simple refactoring of common code that you'll probably have in every single entity class, to a base class. I like it... *shrugs*. Actually I can possibly see IUnitOfWork working with IEntity or EntityBase. Hey, I'm learning too...
Gravatar
robconery - Sunday, December 07, 2008 - I understand the idea here, but when you plant a base class onto an Entity, you couple it. In this case we're talking about binding it to my development needs - which isn't serving my client, it's serving me. It may sound odd, but the approach doesn't need to be built in, does it?



One of the samples I've seen uses this technique, but then they also embed SQL calls and use the Key. Knowledge of the key is something I give the domain - it doesn't give it to me (that's the way I see it at least). It seems backwards to me, but I do know that a lot of people do this.



In terms of learning - me too :). But I'm trying to be pragmatic as well and this feels like silliness :)
Gravatar
mike - Sunday, December 07, 2008 - To be honest, you kind of lost me in this episode.



The part about services just calling the repositories. That seems necessary to me, the GUI layer should not directly call the data access layer, right? This was only mentioned, but there was no solution in this screencast.



Another thing I don't get: does bounded context mean that we are going to have multiple Product classes because in a different context it needs to have different properties? It seems to me that at this point you also are talking about two completely separate applications?



Also, this is a huge step for a refactoring. I understood the previous version of the solution pretty well, and it feels like _everything_ was moved around. It kind of puts the previous 24 episodes in a whole new light. It's like you are saying: you know the past weeks all the stuff I showed you, don't do it that way, do it this way. That's fine, IF you are still watching at this point. I don't want to sound to negative, because I still really appreciate this series, but I hope you are not going to tell us in episode 52 that actually, it would be better if... you know what I mean?



Thanks! Looking forward to the next episode.
Gravatar
Randy Ridge - Sunday, December 07, 2008 - I'm baffled by the coupling talk about super classes, but I think I can help on the entity/identity/equality thing, it's somewhat contrived pseudo code but I think it'll show the issue:



var user = Repository.Get(42);

foreach(var order in user.Orders) {

// user has an OrderCollection called Orders

}



// contrived, elsewhere you do this for some reason

var order = Repository.Get(42);



if(user.Orders.Contains(order)) {

// do whatever

}



Assuming that the User's OrderCollection does in fact contain Order #42, the only way this works is via an appropriate definition of equality, otherwise we're relying on object reference equality.



The question then is what is appropriate equality, this should come from the domain, perhaps it's a unique set of attributes on the object, but it often tends to be a surrogate. I think Evans somewhere talks about a person, what identifies a person that's the same for their entire life (and even after they're dead), his answer is nothing, but there's still something that uniquely identifies a person. To me that's something meta, so to me, identities/keys tend to be surrogates.



So is five year old Rob Conery the same as (insert Rob's age now) Rob Conery? Sure. So if I do that in code, youngRob.Equals(currentRob) I should get true, so equality must be implemented around this identity.



Given that we want identity equality, the reasonable thing would seem to be to define entities as having an identity and have a base class implement the equals, gethashcode, and equality operators to avoid duplication. Now if you want a non-surrogate identity, you could implement your own identity type and have it to equality however you want, still the base class delegates to the TIdentity for equality after the normal checks for null and reference and type equality.



This seems completely reasonable to me, hopefully this helps clarify it?
Gravatar
robconery - Sunday, December 07, 2008 - LOL did you call me a 5yr old! :) that made me giggle...



Thanks Randy - appreciate the response. It got me thinking about Aggregate Roots and if I understand correctly, User (in your example) is an Agg root for order. Therefore your second call to the Repository is sort of violating something, no?



As part of my domain, currently, I recognize SKU as the identity of Product (which is what my client does), and OrderNumber is the Identity of the Order (which my client does). I then override Equals as appropriate for each. I don't need to tag SKU as the identity - I know it since that's the design.



I think you're point might be "what about other devs" and that's valid. The question then becomes do I need to implement an interface so other devs know what my Entity key is? I think that's too much (personally) - I'd rather use a comment.



But... I'm still listening...



Gravatar
robconery - Sunday, December 07, 2008 - I don't recall mentioning the GUI calling the Repositories - hopefully that will be cleared up later.



RE Bounded Context - hopefully not - that would be confusing :). I'll do my best to make it clear.



>>> It kind of puts the previous 24 episodes in a whole new light. It's like you are saying: you know the past weeks all the stuff I showed you, don't do it that way, do it this way



The previous episodes worked fine for the shape of the app then - it followed some pretty standard way s of doing things. However as I've been "buttoning up", I've realized I could do better.



I never said it was "wrong" - I said I could "do better". Smells don't mean wrong - they're indicators that refactoring is needed. In this case, I decided to try to work with something that was in the back of my mind, DDD.



I understand it seems like an abrupt course change - it's not really. I'm simply moving a few things around and adding some clarity. When I'm done, hopefully you'll see that. File ops don't necessarily equal Dynamite - all of the main code bits are still the same, and the web site is untouched at this point.
Gravatar
PK - Sunday, December 07, 2008 - Hi Rob (and fellow listeners),



interesting video. It does make me see this all in a new light. I need to go over this a few times to really get my head around it .. but i love the angle of attack you're using. If it works .. great! if not .. we still learn from this. It's a positive direction .. good work!



I LOVE the IQueriable magic - that has solved so many probs for me. Great to see you're a fan of that (still). Adding the ISession is also something that i'm sooo gonna do now - great stuff! I used to have two methods in my Service project (Create and Update), which ended up calling a single Save method on the repository. I can now clean this up even further with the UnitOfWork pattern.



A few questions: (which i'm guessing will be answered in #26 and #27)

*) What happened to 'pipelines' ? I'm now using WF because of what i learnt from your vids. Does this still have a place? I'm guessing there will be seperate workflows per project, as these workflows will be encapsulated within the domain that they are relevant for (eg. order pipelines found inside the OrderProcessing project; sales pipelines found inside the Sales project.. etc).

b) why did u call it ISession and not IUnitOfWork ? (i'm not techincally familiar with the UoW pattern, even though i understand how i've been using it in Linq2Sql).



Hopefully we don't need to wait as long for #26 and #27 (with all due respect). I'm also curious to see how some POCO items will be handled across a number of projects to minimize duplication but to avoid polluting the Infrastructure project.



Lastly, is it worth adding an extra line on the first slide -> Storefront discussion forums: http://forums.asp.net/1165.aspx ?? :)
Gravatar
mikev - Sunday, December 07, 2008 - I just watched the lastest episode and listened to hanselminutes too. I really like your re-packaging. Before it felt odd to see domain services like shipping next to infrastructure services like logging. Also, your application of the state pattern was super cool.



I don't mean to beat a dead horse, but I totally disagree with Dave Laribee defending that DDD is a set of patterns. Sure, there are lots of patterns like repository, unitofwork, factory, specification, etc... but they are just a means to an end which is to write code that captures the essence of the business. DDD is a perspective or philosophy even, not a set of techniques.



I liked Scott Gu's use of the term "impedance mismatch" applied to the rift that exists between the business concepts and the software concepts. Business people think in their language and when they come up with a business idea, it is an extension of their language. So, if your code reads like their business language, the new features are a snap because they extend naturally from your design.



I'm looking forward to the next two episodes! FYI listen to yourself on hanselminutes, you sound just as vague and heady as the rest of us describing DDD! Ha!!!
Gravatar
Randy Ridge - Sunday, December 07, 2008 - Ok, I think that're we're actually in agreement on entities, equality, and identity... It's sounds like you're willing to trade off duplication of identity equality for clear identity naming (SKU vs a generic Identity), while I'm willing to trade off the clearer naming for a super class equality implementation for junior developers... I'll buy that. I think we're on the same page?
Gravatar
robconery - Sunday, December 07, 2008 - Sure - I hope you don't take my thoughts here as disagreement. I've been

thinking about it all day (honestly) and what I think it comes down to is

I'd rather rely on overriding Equals (since it ripples into Contains() and

other collection stuff) than an explicit key definition.

I do think it's worth thinking this part through - I do agree that

programmatically knowing when something is an Agg Root (vs. Entity vs. Value

Object) may be worthwhile. I'm also wondering how that would play out. It

would seem that if you need to ask your model "hey what is this thing" than

maybe you're doing something wrong?



This is good stuff here - and yes I think we're close on this. I'm trying to

figure it out :)
Gravatar
Chris - Sunday, December 07, 2008 - trying to download video... having issues as it always seems to stop midway, currently (4th time) at 69%... maybe put on website instead of live silverlight issues??? like the others.



ps- i'm on cable modem broadband and never had an issue downloading anything before.
Gravatar
PK - Sunday, December 07, 2008 - Good point about the logging (and email) stuff. Looking forward to seeing this implemented in the new project layout.
Gravatar
PK - Sunday, December 07, 2008 - video downloaded fine for me. i watched the full 100%.
Gravatar
Ryan Roberts - Monday, December 08, 2008 - I do this for a domain living on top of db4o where I have a very narrow repository interface, the methods on the generic repository



ByIdentity(string identity) / ByIdentities(string[] identities)



Are both made possible by a contraint to IAggregateRoot on the repository.





I'm very much learning too, but this design seems pretty natural to me. But so did datasets in 2002 ;)
Gravatar
Dave Laribee - Monday, December 08, 2008 - @mikeev



Define "set of patterns" how you will. At a certain point we get into a semantic argument unless we agree to call a pattern anything that's repeatable that we've noticed is good. DDD, the book/approach/philosophy/whatever, is a set of patterns in this light.



All that said, it doesn't really matter how we cut it. The main point is that we can take a number of things and apply them to this project or that. In doing so we should be sensible and not necessarily dogmatic or doctrinaire about our approach. What works for this won't work for that, etc.
Gravatar
Colin Jack - Monday, December 08, 2008 - IAggregateRoot can have value, you can then use a generic constraint on repositories to ensure only aggegates have repositories. EntityBase can also have value, for example identity related rules. Whether you do this or not is not DDD specific though, DDD does not try to enforce implementation level concerns like this.
Gravatar
Colin Jack - Monday, December 08, 2008 - There is nothing un-POCO about creating your own layer supertype and using it in the domain, not at all. Coupling your domain classes to your own lightweight EntityBase class is, in my view, not a major issue at all.
Gravatar
Colin Jack - Monday, December 08, 2008 - "The part about services just calling the repositories. That seems necessary to me, the GUI layer should not directly call the data access layer, right? This was only mentioned, but there was no solution in this screencast."



The key thing is you protect your domain but you can do DDD and have your GUI directly talking to repositories and domain objects. This came up in a recent discussion on the DDD forum:



http://tech.groups.yahoo.com/group/domaindrivendesign/message/9028



Perhaps not the usual case but it can work as long as you make sure your GUI doesn't unduly influence your domain model.





"Another thing I don't get: does bounded context mean that we are going to have multiple Product classes because in a different context it needs to have different properties? It seems to me that at this point you also are talking about two completely separate applications?"



See the book but yes potentially it does. Models make sense in a particular context so to give you a simple example a Customer in a Finance context might be different to a Customer in a CRM context so having seperate representations is valid.
Gravatar
Colin Jack - Monday, December 08, 2008 - Stick to the book, to me almost all the answers are in there.
Gravatar
Colin Jack - Monday, December 08, 2008 - "It would seem that if you need to ask your model "hey what is this thing" than maybe you're doing something wrong?"



If it's a value object it behaves like a value object and if its an aggregate root then likewise. However enforcing constraints, such as that only aggregate roots have repositories, can be useful which is why the interfaces/base classes might help. Having an IDomainEntity interface and (optional) base class is, to me, not a major issue at all.



I'd suggest you mine the DDD newsgroup, its full of discussion on all these sorts of topics.
Gravatar
Colin Jack - Monday, December 08, 2008 - One general comment, Eric Evans himself has gone as far as to say that he's seen DDD becoming gradually overused (http://www.infoq.com/interviews/domain-driven-design-eric-evans) and that it's not DDD without a domain expert (http://tech.groups.yahoo.com/group/domaindrivendesign/message/9008).



I'd thus recommend that before trying DDD you really think about how far they want to go with it. If the problem is simple and not suited to DDD then being too rigorous with it can be silly, having said that I still think some of the patterns like aggregate/repository/service/entity/value object can apply even if the overall project does not suit DDD.
Gravatar
robconery - Monday, December 08, 2008 - I'm scared of that news group :). These are good points - and thank you guys

for your patience. I'll implement!
Gravatar
Colin Jack - Monday, December 08, 2008 - Its honestly not as bad as it might seem, it does repeat itself a lot and get mired in discussions on little details but the real heavyweights (Eric Evans, Randy Stafford etc) really get involved and they've provided some great insights over the years. It really needs an FAQ wiht links to good threads/posts though.
Gravatar
Randy Ridge - Monday, December 08, 2008 - The point I was trying to get across was why you might use those marker interfaces and base classes as an example of what the guy on the first comment asking about... I think Colin got the point I was trying to make across more clearly and concise than I did. Good discussion.
Gravatar
robconery - Monday, December 08, 2008 - Either that or I'm just thick-headed :). Or both!
Gravatar
Chris - Tuesday, December 09, 2008 - tried it just now and it is working fine now... not sure what was the deal...
Gravatar
Chris - Tuesday, December 09, 2008 - The following has nothing to do with DDD, however it does with ASP.NET MVC. I haven't taken a look at it but it sounds interesting and provides another look at ASP.NET MVC and is in production. It is called Oxite and it runs visitmix.com.



About Oxite

http://visitmix.com/Lab/Oxite

Source

http://www.codeplex.com/oxite



also of note is

oomph - a microformat toolkit (hCard, hCalendar)

http://visitmix.com/Lab/oomph
Gravatar
Chris Kolenko - Tuesday, December 09, 2008 - Any successful project will get larger.



Wouldn't it be better for Rob to use DDD and fail to teach the community something anyway?



This project is about learning and sharing. If you have a project that is similar in size then it's your choice to use it or not.



I'm sick of hearing this project isn't big enough non sense, Rob has gone to too much effort to learn this stuff..

Why don't we all go back to the dark ages and argue about which Text Editor is the best?!?!?!?!



I'm not having a go at you Colin just everyone in general shooting down the idea.. what's the worst that could happen really?



Gravatar
huey - Tuesday, December 09, 2008 - Great episode. I finally pulled the trigger on the book, can't wait to read.



These are all great ideas and I can't wait to look over the code. I'm still hazy on exactly the separation of where a repository stops or starts. In my current project I am dealing with shipments. On the database side there are 5-6 different tables each with their own class / mapping in NHibernate. On the other hand, I don't want the shipment to care. I want to create it, ask the user for some information, and then process it.



So this leaves me with two questions I need to examine (in either your code or future screencasts -- this was actually my first one although I've read your blog awhile!):



1) Is the repository responsible for concatenating these 5-6 tables and spitting out a 'shipment' object, or does the repository spit out the 5-6 tables and then a different layer groups them and spits out a 'shipment' object.



2) The 'shipment' class is going to have some values to show the user, some empty values to ask the user, and some values that simply get translated / worked on behind the scenes. Figuring out how to deal with the UI layer is troubling. Do I have another object that the 'shipment' class gets translated to just for the UI? That would mean a shipment exists in 3 sort of contexts -- what a user sees, what the application sees, and what the database sees. Maybe this is right, or maybe the application and user should be the same?
Gravatar
Mohamed Meligy - Wednesday, December 10, 2008 - Hey Rob.

I like your stuff very much. It's been an inspiration for me during my learning process of ASP.NET MVC and DDD.



hmm ... well, J thought you might be interested in this post when I read it via a link in the ALT.NEt Yahoo mail group:

http://the-software-simpleton.blogspot.com/2008/12/twat-of-ddd-increasing-complexity-in.html
Gravatar
Colin Jack - Wednesday, December 10, 2008 - > I'm sick of hearing this project isn't big enough non sense, Rob has gone to too much effort to learn this stuff..



The amount of effort Rob has put in has nothing to do with whether it's a project that DDD is suited to. I'm also not sure that the fact that you are "sick of" hearing something is necessarily a compelling argument. Also note I didn't say it wasn't "big enough", I've worked on a big but relatively simple project and although we did use some DDD patterns it certainly didn't just the full DDD approach.



Back to the original point, my main point was that Eric Evans has indicated that DDD is not for every project. If you think he is incorrect then that's perfectly valid of course.



> Why don't we all go back to the dark ages and argue about which Text Editor is the best?!?!?!?!



Not even sure what this means, I dunno when these dark ages were and why people were arguing about text editors but it doesn't seem related to my point. Also all the "?!?!?!?!" is totally un-necessary and a little childish.



> I'm not having a go at you Colin



I sense this is not true?!?!?!?!?! :)
Gravatar
robconery - Wednesday, December 10, 2008 - Colin I'd like to raise the level of this discussion please...
Gravatar
Todd Smith - Wednesday, December 10, 2008 - Quick question. Is there a difference between these two statements?



dataContext.GetTable().InsertOnSubmit((oxite_MessageToAnonymous)messageTo.MessageToAnonymous);



dataContext.oxite_MessageToAnonymous.InsertOnSubmit (messageTo.MessageToAnonymous);



Gravatar
robconery - Wednesday, December 10, 2008 - You may want to ask the Oxite guys :) not sure
Gravatar
Santos Ray Victorero, II - Wednesday, December 10, 2008 - Rob,



Keep on going on, you are on the right track! I have been using OO development for a while and DDD helps a lot bringing the concepts to reality and managing complexity.



I have to agree with Colin, Damien and others on the use of an EntityBase super class and also an IAgregateRoot interface You will get its benefits when you implement your repository.



Its like meditation; don't listen to the noisy ones. :-)



I really admire your dedication and enthusiasm.



Santos
Gravatar
Colin Jack - Thursday, December 11, 2008 - Thats fine but given the tone of Chris' content I think my reply was in keeping.
Gravatar
adweigert - Thursday, December 11, 2008 - Disclaim: DDD n00b, take with grain of salt and call the professionals if I get out of hand. I have just a few notes I took that maybe will help you with some of the design.



So, are TDD and DDD competing methodologies? Maybe (I don't want to start a religious war - this is based on my experience using both), but I have found that they can both be leveraged to create a form of agility that will help you in reaching for a 'supple' design. Start by designing the domain model first using DDD, then use TDD to validate the design. Before writing a single line of 'implementation' code, make sure the tests feel smooth. Why does this help, it helps to see the big picture by using DDD and having that conversation with your customer. By utilizing TDD, you validate your model will work without too many difficulties. TDD will expose areas that don't feel 'clean' when implementing your scenarios, which is an indicator to go back to the design and clean it up. You may want to iterate over each bounded context, build the Sales model first, validate it, then move on to OrderProcessing. (BTW, TDD for code coverage is a flawed methodology, but that's another religious war I don't want to get involved with)



Next, regarding your OrderState implementation. Is it reasonable to say that an order state is responsible for refunding an order? I get the "smell" feeling you mentioned, which probably means no. The process of refunding an order is not the responsibility of the order state in this context.



To contrast, think of a workflow and it's state. The WorkflowState can keep track of things like: can the workflow start, is it started, is it completed, etc... But should that state be responsible for starting the workflow? Let's take a swag at the code to start a workflow: workflow.State.Start() vs. workflow.Start(). So, just to illustrate this a little more on how the state pattern does helps the workflow object, lets take a look at the framing of a potention workflow.Start() method.



void Start() {

if (!this.State.IsStartable)

throw new InvalidOperationException();

this.State = new StartedWorkflowState(this);

try {

// ... execute the workflow

this.State = new CompletedWorkflowState(this);

} catch (Exception ex) {

this.State = new TerminatedWorkflowState(this, ex);

}

}



I sincerely hope this helps you and keep up the fabulous work, it is quite inspiring.
Gravatar
Todd Smith - Saturday, December 13, 2008 - Would mixing PagedList and LazyList make sense or would that be the equivalent of caffinated beer?
Gravatar
robconery - Saturday, December 13, 2008 - LOL - sure why not!
Gravatar
John Z - Wednesday, December 17, 2008 - HI. Just saw your video and it was great stuff, but I do have a question that other people have asked too. In the video you where talking about the method "GetProductById" which is quite useless. How do you solve that one in a nice way if you wan't to get rid of it. Did you remove it from the servicelayer or do you still have it??



/J
Gravatar
Alex G - Tuesday, December 23, 2008 - Actually... Beer and Red Bull mixed together 50/50 is pretty decent.. I call that cocktail the "busted deadline" :)



Rob, nice article! I wish for these concepts to become broadly adopted. I've been having a hard time promoting DDD amongst my peers... For example, it was just announced that our "business dll" would be named "UBECL" for Unified Back End Common Library...



Personally I was rooting to call it "SAURON" .. one DLL to support 10 applications, one DLL to bring them all, and in the darkness bind them ;)
Gravatar
Todd Smith - Tuesday, December 23, 2008 - In light of your recent efforts, can I ask you now? lol



BTW they're the same because oxite_MessageToAnonymous is a property that just calls GetTable(). I just wasn't sure why they chose to use the more verbose form.
Gravatar
Todd Smith - Tuesday, December 23, 2008 - Wouldn't that make you the servant that ended up killing Sauron?
Gravatar
Girish - Thursday, December 25, 2008 - What's your suggestions about adding Size and Color to the items?
Gravatar
robconery - Thursday, December 25, 2008 - ROFL you just made my week :)



Sent from my phone. Please excuse brief replies.
Gravatar
Todd Smith - Tuesday, January 20, 2009 - I think he was asking for a video describing how to go about creating an initial design document / specification.
Gravatar
weeniearms - Monday, December 29, 2008 - This part seems a little strange to me. At one point you discuss the Law of Demeter and at another one you break it by trying to remove a code smell. The point I'm talking about is the OrderState concept. It's really good to incorporate the state pattern into something like order processing (which is a pretty obvious decision to make) but letting the state object handle the business logic might be a bad choice.

The problem you are dealing with just screams for the strategy pattern and actually, it would be quite easy to refactor the code that you already have. You could keep an abstract class (it might as well be an enum) to determine the state of the order but move all the logic to separate objects implementing an interface like IProcessingStrategy or inheriting from an abstract class ProcessingStrategy, which would have all the methods that your current OrderState class holds. You would also have to add public methods like Refund, Return, etc. to the Order class. All you have to do now is create a factory that will provide the necessary strategies when needed and avoid the necessity to make any changes to your Order class in the future. Here's a bunch of code that will probably better illustrate the pattern than the above text:



public enum OrderState {

State1,

State2

}



public class Order

{

public OrderState CurrentState { get; set; }



public void Charge() {

ProcessingStrategyFactory.GetProcessingStrategy(this).Charge();

}



public void Close() {

ProcessingStrategyFactory.GetProcessingStrategy(this).Close();

}

}



public static class ProcessingStrategyFactory {

// probably the only thing you need to modify if you decide to add new strategies

public static ProcessingStrategy GetProcessingStrategy(Order order) {

switch(order.CurrentState) {

case OrderState.State1:

return new FirstProcessingStrategy(order);

case OrderState.State2:

return new SecondProcessingStrategy(order);

default:

return null;

}

}

}



public abstract class ProcessingStrategy {

protected Order _order;



public ProcessingStragegy(Order order) {

_order = order;

}



public abstract void Charge();

public abstract void Close();

}



public class FirstProcessingStrategy : ProcessingStrategy {

public FirstProcessingStrategy(Order order) : base(order) {}



public override void Charge() {

// some logic here

}



public override void Close() {

// some logic here

}

}



public class SecondProcessingStrategy : ProcessingStrategy {

public SecondProcessingStrategy (Order order) : base(order) {}



public override void Charge() {

// some logic here

}



public override void Close() {

// some logic here

}

}
Gravatar
Nick - Thursday, January 22, 2009 - I don't know Cory. From what I can gather some people like to use the "Endless Loop" design pattern still too! Jokes aside, I like the (from what I can tell) new architecture much better.



Good job with this series. I have learned allot from your masochistic self review. It provides something I have never seen in any dot net blog before : perceptive. Something that is worth allot more than any "Coders Morality Of The Day". Let's face it, the nay Sayers just don't have the balls for it.

Gravatar
Gino - Friday, January 02, 2009 - I didn't have the time to go through all the comments, so please tell me if I'm repeating something here.

First, I really like the way you're heading with your DDD approach now and since you've asked for it: here's a set of Q's/R's:

- Why are you calling SubmitChanges in the repository? Unless you're using something like a TransactionScope, you're breaking your UoW, or not? You'll probably call SubmitChanges in the end anyway (I supppose).

- Why do you expose the OrderState property on Order? Wouldn't it make more sense to call methods like Submit and Close on an order itself (which than delegates it to it's order state)? (You could also implement the state pattern on the Order itself -> NewOrder, SubmittedOrder, ... with the same virtuals on Order of course)

What do you think?
Gravatar
Trevor - Friday, January 02, 2009 - I was going to ask about the SubmitChanges in the repository as well.



Can someone explain the difference between unit of work and a transaction? I assume that in most cases the behavior would be the same and it is very easy to rap everything in a TransactionScope.
Gravatar
nabbed - Tuesday, January 20, 2009 - I hope you don't think i think your not thinking about Documentation ;)

I already see evidence of well thought out architecture and well am impressed frankly.

I like your approach and your results. I am not assuming you won't do any doco.

I am raising it as something I would like to see.

I would like to see both your approach and your results to the doco side of things.

Keep up the good work.
Gravatar
anton - Wednesday, January 21, 2009 - Hey Rob, Loving the work you are doing with storefront app. When can we expect the next episode?
Gravatar
Chad Moran - Thursday, January 22, 2009 - That's actually rather disappointing knowing that any future code is being held back by the RC date considering it's already been pushed back. :(
Gravatar
robconery - Thursday, January 22, 2009 - That's not the only reason :). There is A LOT going on here. Please, I'm

asking you, be patient.
Gravatar
Gino - Monday, January 05, 2009 - IMHO there's no real difference between a UoW and a transaction. The only difference I see is that with UoW you make things more formal/explicit.



I think the term UoW is used far too much anyway, especially in today's world where you have things like TransactionScope and everybody trying to achieve persistence-ignorance (which is basically the opposite of what you would do with a real UoW - you don't want to call methods on your UoW to register dirty objects, for example).

Gravatar
Brandt - Thursday, January 08, 2009 - First, I want to show my appreciation and gratitude for your MVC Storefront series. There is a lot of good code on the net but few actually spend the time to show the thought process. I definitely have learned a lot. I have two questions.



1) I used StructureMap 2.5 with the exact pattern you used to create the DB context. When I used InstanceScope.Hybrid a new instance of the DB object was created on the creation of every new repository object. When I switched it to InstanceScope.HttpContext only one is being created per request. Are you seeing the same occurrence? Have you checked to make sure the context is the same for each http request or just assumed it was?



2) I really like your LazyList. So much to the point I used it in my project. I don't know if you have addressed this, but an object graph containing a LazyList shouldn't be cached as the internal IQueryable holds a reference to the context (DB) object. As long as the object is cached the context object will hang around even if ToList() has been called on IQueryable reference. From what I understand this might not be a problem with LINQ to sql and EF(sql). However, if you decided to use another ORM with a LINQ implementation the connection objects might not be disposed of properly. Since the connection has already been created and not destroyed or returned to the connection pool, I believe you will run into a problem. If I am wrong please let me know. I know you want to keep web apps as stateless as possible however if it can be done it will be done; and runtime exceptions are the hardest type to debug.

Gravatar
Paul Linton - Thursday, January 08, 2009 - I am getting Storefront withdrawal symptoms (the main one is going over eps25 in fine detail). Thanks for all your work but the other day I kicked the dog and I think it was because I didn't have access to the Storefront source code. Please, can we have another episode of this most excellent series?



I noticed that TranslateOrder has a comment that an Order should always be in the database. There is then code to handle it not being present. Would it be better to log and throw an exception if it shouldn't happen?

In TranslateCustomer there is similar code to check if the Customer exists in the database. If they do not then a Customer is newed up. The Customer is never added to the _session however (that I can see) and so is lost. Obviously, this could be fixed with an appropriate call to _session.Insert but I still think it may be better that if you check for something that cannot happen that you flag it as an error.



In OrderProcessing.Order.cs you have declared Items as being of type LazyList. Would that be better if it was IList ?



Keep up the good work, Paul
Gravatar
Goran - Friday, January 09, 2009 - Hi Rob,



Thanks for the great series. I've just seen episode 13, but i'm posting here anyway.

You are actually helping me stay in shape, because I streaming your episodes to the big screen in the living room(xbox 360) where I watch you while working on my hometrainer (hope that didn't sound creepy :-) )



Tell your boss that this is what we want. If he stops listening tell his boss.



I'm toying around with MVC and there is a lot of <%= Html.Encode(Model.Message) %> going around. Which was not the case in asp.net (you could but you should not)

<%= actually means Response.write() so why not change it to <%= is Html.Encode(response.write())

Which you have to do about 95% of the time.

The other 5% can do <% Response.Write("not encoded stuff") %> or <% Reponse.KillerGenericExtensionMethod() %> for the diehards.



That should put a lot XSS baddies out of business.

Gravatar
PK - Saturday, January 10, 2009 - Here Here!!! i'm pulling my hair out that i've not had any MVC Storefront goodness for a while. There's a number of gaps in my app which i'm so not sure about and i'm hoping the storefront fixup Rob is talking about will fix these issues.



They are mainly about code smell, which Rob has identified strongly.



I wish Rob's boss can read all this and ask him to go 100% on MVC SF for a month so he can knock that baby out of the park and we can all celebrate and make awesomesauce websites.
Gravatar
robconery - Sunday, January 11, 2009 - I have the next one queued up for next week! Promise! I just took a rather

long vacation :) so that's the main reason for the slow down. Well, that and

Oxite :).

My boss is Bertrand Le Roy (bleroy) if you want to petition him for my time

:):):)
Gravatar
PK - Sunday, January 11, 2009 - Sent!



I hope others email Bertrand so he (or the powers that be) can see how important this series is and will become. It's our cheat sheet to the taking over the net, one MVC proj at a time.
Gravatar
Chad Moran - Thursday, January 15, 2009 - Hey Rob, loving the series. Can't wait for your next version or at least some release of your latest code.



One thing I'd suggest is using an interface for your domain models/objects instead of creating a whole other concrete class, it just seems... meh. A good example of doing it this way is to take a look at the latest Kigg at http://www.codeplex.com/Kigg. The way they have developed their DAL is fantastic and even contains a UnitOfWork object.



Hope this helps, keep up the good work!
Gravatar
robconery - Thursday, January 15, 2009 - Thanks Chad :). Not sure what an interface gets me versus an object - some

details? Also, with the latest bits I have here, I have Unitofwork built in.
Gravatar
Chad Moran - Thursday, January 15, 2009 - Sorry I wasn't clear.



I meant instead of having 2 sets of concrete objects (POCO and LINQ to SQL generated) you could have an interface. Then extend your LINQ to SQL generated objects by using their partial class-ness and than adding the I interface to the partial. This way you can get the functionality you desire without having to do translation for queries. As far as UnitOfWork I was just saying your new DDD version of the Storefront project and the new Kigg have a lot of similarities you could maybe get some ideas from.



When will we get a chance to get your latest code base? I'm really interested to see the code for your state pattern implementation.
Gravatar
robconery - Friday, January 16, 2009 - Thanks Chad! Interesting approach - I hadn't thought of this. I'll be honest

though and say that it ties me a little too closely to Linq to Sql. In other

words my domain bits will rely on ORM-generated code. I also can't work with

"value objects" really (like Address) which exist in the DB and would have

gets/sets (even though I'm not fully embracing that now :).

Either way - good stuff. If you have a blog I'd love to see more on the idea

since overall it's a nice pattern. RE Kigg/DDD I haven't seen their code but

I did manage to work up a nice UoW thinger for what I'm doing.



I hope to have the new source up in the next few days.
Gravatar
Chad Moran - Friday, January 16, 2009 - Sure do have a blog. Even made a post describing how this can be achieved without having to dig though a huge project.



http://weblogs.asp.net/chadmoran/archive/2009/01/16/using-interfaces-for-domain-entities-part-1.aspx



I know you don't want to be tired to ORM-generated code and you don't have to be if you setup some IoC and spread out your assemblies properly. I agree that you should stay loosely coupled to your DAL so that you code can be very agile. However, I think the interface contracts for domain objects has it's benefits. I'm not against using POCO objects I just think having to translate your queries between the objects can get really messy. I tried following your series step by step to better help me understand the code and I just couldn't stand it when I had multiple one-to-many and many-to-many relationships, I felt like I was writing SQL for something that already was.



Maybe it's just me but unless you have security issues I think you can still stay loosely coupled and still achieve your goal of not dependong on ORM generated code... you have to somewhere.



Hope this helps and can't wait to see your code, nice house by the way.
Gravatar
Todd Smith - Friday, January 23, 2009 - Does it looks like the next release will coincide with a single video or are are you breaking up the transition to DDD into multiple videos?
Gravatar
pnocera - Saturday, December 06, 2008 - I have just finished developing an application which is running, and does what it 's supposed to do. I'm really not proud of it, so yesterday I went back to Visio to draw the big picture, and I stated that I should just rewrite it from scratch. I am not a very good programmer, but I've been programming for 20 years and its always been the same story for me : when I look back any application, if I had to do it again, I would never do it the same way...
Gravatar
robconery - Saturday, December 06, 2008 - There has been a few times where I've been pretty happy with an app - but
you're right. Generally not. It doesn't mean that we shouldn't always try
for something better :)
Gravatar
Lamin Barrow - Friday, December 05, 2008 - Yeayye.. Finally Part 25. Thanx Rob.. I really appreciate all your efforts. How can we ever repay you?
Gravatar
robconery - Friday, December 05, 2008 - Volunteer your time this holiday doing something good :). If you don't have
a holiday where you live, make one, then do something good for it! Festivus!
Gravatar
MotoWilliams - Friday, December 05, 2008 - When is the source code going back up on Codeplex ( http://is.gd/J3I )? It was nice to have our SVN clients grabbing the bits as we followed along.
Gravatar
Brian Vallelunga - Saturday, December 06, 2008 - Damn Rob, now I have to go redesign my entire application! No, not really, but I am very interested in the direction you're going to take this. The state idea looks quite interesting, as does the separation of your code. I can't wait to see how this turns out for you. Thanks for the time you've spent on this, it's been very helpful.
Gravatar
eKnacks - Saturday, December 06, 2008 - You've been knacked. Keep up the good work.
Gravatar
Damian Hickey - Saturday, December 06, 2008 - Timing of this is perfect for me :) Half way through Evans's book, and trying to map it down to something more concrete from an implementation perspective. While domain stuff is very specific to business requirements, it'll be very interesting in how you tackle the infrastructural items.

In other example I've seen, all entities inherit from an EntityBase which implements IEntity, and all aggregate roots specifically implement an IAggregateRoot to specifically differentiate themselves from other entities. Do you see any value in doing that?

Very well delivered, looking forward to the next part!
Gravatar
robconery - Saturday, December 06, 2008 - To be honest I don't see the value in this. Ideally your objects should be
completely free of this kind of thing (according to the books) - they call
it "POCO as a lifestyle" :).
I think I know the example you're referring to and the only thing IEntity
does is make you declare a key (TKey). The only thing that does (in that
example) is allow the developer to build out a SQL string.

Inheritance on your objects is coupling - even if it's helping you out (my
opinion). But again - I'm no expert here :).
Gravatar
Randy Ridge - Sunday, December 07, 2008 - It seems to me to be completely valid to have a a super class implementation, this could still be POCO in that you're not doing it to support an external dependency, you're doing it to clarify your domain model. The key point of an entity is that it has an identity, to that point equality should be based on that identity and not it's attributes. If I have a User in a security context and a User in a ordering context, they could both be the same logical entity expressed with completely different attributes. To that end I should think that to avoid duplication I would end up with something like:

// User with attributes related to security context
class Security.User : UserBase {
RoleCollection Roles { get; set; }
EmailAddress Email { get; set; }
}

// User with attributes related to the ordering context
class Orders.User : UserBase {
OrderCollection PastOrders { get; set; }
}

// Base of users across contexts, a Security User and a Orders User could be the same, how? By identity.
abstract class UserBase : EntityBase<Guid> {
}

// Provides what it means to be an entity, it must have an Identity
// Equals, equality operators, and HashCode have to be based on type, super type, and Identity, not other attributes and pointers
abstract class EntityBase<TIdentity> : IEntity<Tidentity> {
TIdentity Identity { get; }
Equals(object obj) { ... }
operator ==(left, right)
operator !=(left, right)
GetHashCode() { ... }
}

// generic interface
interface IEntity<TIdentity> : IEntity {
TIdentity Identity { get; }
}

// marker interface, can be useful for constraints elsewhere...
interface IEntity {
}

I personally don't see how this is not POCO. I'm avoiding duplication and I haven't implemented anything outside of my control for the sake of satisfying my persistence layer. What I'm satisfying is the definition of what it means to be an entity, it has an identity and that equality should be based on identity... You could still provide complex TIdentity types if you wanted something more than primitive ints, Guids, etc.

Of course, you could implement equality and identity on each and every one of your domain entities if you choose, but why not bubble it up to a super type?
Gravatar
robconery - Sunday, December 07, 2008 - I spose I'm not clear on why I'd need it - how does "EntityBase" clarify the
domain model, and to whom? I'm not disagreeing with you necessarily - I
think it's just not clear to my WHY I need to do what you're suggesting. To
be upfront - it comes off as "Hyper coding". Please don't take offense :) I
really appreciate your thoughts but supporting your points with DDD
terminology isn't making sense to me (sounds jargon-y). In other words:
Gravatar
Damian Hickey - Sunday, December 07, 2008 - Looks like plain old simple refactoring of common code that you'll probably have in every single entity class, to a base class. I like it... *shrugs*. Actually I can possibly see IUnitOfWork working with IEntity or EntityBase. Hey, I'm learning too...
Gravatar
robconery - Sunday, December 07, 2008 - I understand the idea here, but when you plant a base class onto an Entity, you couple it. In this case we're talking about binding it to my development needs - which isn't serving my client, it's serving me. It may sound odd, but the approach doesn't need to be built in, does it?

One of the samples I've seen uses this technique, but then they also embed SQL calls and use the Key. Knowledge of the key is something I give the domain - it doesn't give it to me (that's the way I see it at least). It seems backwards to me, but I do know that a lot of people do this.

In terms of learning - me too :). But I'm trying to be pragmatic as well and this feels like silliness :)
Gravatar
Randy Ridge - Sunday, December 07, 2008 - I'm baffled by the coupling talk about super classes, but I think I can help on the entity/identity/equality thing, it's somewhat contrived pseudo code but I think it'll show the issue:

var user = Repository.Get<User>(42);
foreach(var order in user.Orders) {
// user has an OrderCollection called Orders
}

// contrived, elsewhere you do this for some reason
var order = Repository.Get<Order>(42);

if(user.Orders.Contains(order)) {
// do whatever
}

Assuming that the User's OrderCollection does in fact contain Order #42, the only way this works is via an appropriate definition of equality, otherwise we're relying on object reference equality.

The question then is what is appropriate equality, this should come from the domain, perhaps it's a unique set of attributes on the object, but it often tends to be a surrogate. I think Evans somewhere talks about a person, what identifies a person that's the same for their entire life (and even after they're dead), his answer is nothing, but there's still something that uniquely identifies a person. To me that's something meta, so to me, identities/keys tend to be surrogates.

So is five year old Rob Conery the same as (insert Rob's age now) Rob Conery? Sure. So if I do that in code, youngRob.Equals(currentRob) I should get true, so equality must be implemented around this identity.

Given that we want identity equality, the reasonable thing would seem to be to define entities as having an identity and have a base class implement the equals, gethashcode, and equality operators to avoid duplication. Now if you want a non-surrogate identity, you could implement your own identity type and have it to equality however you want, still the base class delegates to the TIdentity for equality after the normal checks for null and reference and type equality.

This seems completely reasonable to me, hopefully this helps clarify it?
Gravatar
robconery - Sunday, December 07, 2008 - LOL did you call me a 5yr old! :) that made me giggle...

Thanks Randy - appreciate the response. It got me thinking about Aggregate Roots and if I understand correctly, User (in your example) is an Agg root for order. Therefore your second call to the Repository is sort of violating something, no?

As part of my domain, currently, I recognize SKU as the identity of Product (which is what my client does), and OrderNumber is the Identity of the Order (which my client does). I then override Equals as appropriate for each. I don't need to tag SKU as the identity - I know it since that's the design.

I think you're point might be "what about other devs" and that's valid. The question then becomes do I need to implement an interface so other devs know what my Entity key is? I think that's too much (personally) - I'd rather use a comment.

But... I'm still listening...
Gravatar
Randy Ridge - Monday, December 08, 2008 - Ok, I think that're we're actually in agreement on entities, equality, and identity... It's sounds like you're willing to trade off duplication of identity equality for clear identity naming (SKU vs a generic Identity), while I'm willing to trade off the clearer naming for a super class equality implementation for junior developers... I'll buy that. I think we're on the same page?
Gravatar
robconery - Monday, December 08, 2008 - Sure - I hope you don't take my thoughts here as disagreement. I've been
thinking about it all day (honestly) and what I think it comes down to is
I'd rather rely on overriding Equals (since it ripples into Contains() and
other collection stuff) than an explicit key definition.
I do think it's worth thinking this part through - I do agree that
programmatically knowing when something is an Agg Root (vs. Entity vs. Value
Object) may be worthwhile. I'm also wondering how that would play out. It
would seem that if you need to ask your model "hey what is this thing" than
maybe you're doing something wrong?

This is good stuff here - and yes I think we're close on this. I'm trying to
figure it out :)
Gravatar
Colin Jack - Monday, December 08, 2008 - "It would seem that if you need to ask your model "hey what is this thing" than maybe you're doing something wrong?"

If it's a value object it behaves like a value object and if its an aggregate root then likewise. However enforcing constraints, such as that only aggregate roots have repositories, can be useful which is why the interfaces/base classes might help. Having an IDomainEntity interface and (optional) base class is, to me, not a major issue at all.

I'd suggest you mine the DDD newsgroup, its full of discussion on all these sorts of topics.
Gravatar
robconery - Monday, December 08, 2008 - I'm scared of that news group :). These are good points - and thank you guys
for your patience. I'll implement!
Gravatar
Colin Jack - Monday, December 08, 2008 - Its honestly not as bad as it might seem, it does repeat itself a lot and get mired in discussions on little details but the real heavyweights (Eric Evans, Randy Stafford etc) really get involved and they've provided some great insights over the years. It really needs an FAQ wiht links to good threads/posts though.
Gravatar
Randy Ridge - Monday, December 08, 2008 - The point I was trying to get across was why you might use those marker interfaces and base classes as an example of what the guy on the first comment asking about... I think Colin got the point I was trying to make across more clearly and concise than I did. Good discussion.
Gravatar
robconery - Monday, December 08, 2008 - Either that or I'm just thick-headed :). Or both!
Gravatar
Damian Hickey - Sunday, December 07, 2008 - The value I see is enforcing a constraint on your repository interfaces, especially if they are generic (oh-oh, IRepository<T> war!). Personally, I can see that it may help readability, particular if there are are a team of people working on the code and not all are fully aware of the domain, or perhaps when new people are introduced. Also, in R#, right click IAggregateRoot -> Find Usages... get list of aggregate roots.. sweet.
Gravatar
Ryan Roberts - Monday, December 08, 2008 - I do this for a domain living on top of db4o where I have a very narrow repository interface, the methods on the generic repository

ByIdentity(string identity) / ByIdentities(string[] identities)

Are both made possible by a contraint to IAggregateRoot on the repository.


I'm very much learning too, but this design seems pretty natural to me. But so did datasets in 2002 ;)
Gravatar
Colin Jack - Monday, December 08, 2008 - There is nothing un-POCO about creating your own layer supertype and using it in the domain, not at all. Coupling your domain classes to your own lightweight EntityBase class is, in my view, not a major issue at all.
Gravatar
Colin Jack - Monday, December 08, 2008 - IAggregateRoot can have value, you can then use a generic constraint on repositories to ensure only aggegates have repositories. EntityBase can also have value, for example identity related rules. Whether you do this or not is not DDD specific though, DDD does not try to enforce implementation level concerns like this.
Gravatar
Daniel - Saturday, December 06, 2008 - Looks interesting. I'm in a similar boat- I've been following these patterns and trying to read up on DDD (and all the other DDs =), and having trouble translating them into code. Even when I do, I have that nagging question - is this _really_ DDD? So it'll be interesting to watch this next phase.
Gravatar
Colin Jack - Monday, December 08, 2008 - Stick to the book, to me almost all the answers are in there.
Gravatar
Chris Kolenko - Saturday, December 06, 2008 - I looked at your example.. and i was trying to think of something that wasn't right..

so this is what i came up with..

Unit Of Work.. Currently you're implementing the ISession.. this only works for SQL based items..
At the end of the pipeline i'm assuming there will be some sort of email being generated..

Should this email be using Unit Of Work ?? how are you going to handle non sql work items??
Are these simply ignored because there might be only one email generated?
Gravatar
robconery - Saturday, December 06, 2008 - I think you're talking about a transaction in general? Good question though
- not sure. I'll ask a wonk...
Gravatar
Chris Kolenko - Sunday, December 07, 2008 - Maybe that example isn't the best tho..
After having a bit of a think about it.. the email seems like a side effect.

But you get the jist.
Gravatar
Yitzchok - Sunday, December 07, 2008 - This is great stuff Rob :) and I like the direction to where this is heading.
Gravatar
mike - Sunday, December 07, 2008 - To be honest, you kind of lost me in this episode.

The part about services just calling the repositories. That seems necessary to me, the GUI layer should not directly call the data access layer, right? This was only mentioned, but there was no solution in this screencast.

Another thing I don't get: does bounded context mean that we are going to have multiple Product classes because in a different context it needs to have different properties? It seems to me that at this point you also are talking about two completely separate applications?

Also, this is a huge step for a refactoring. I understood the previous version of the solution pretty well, and it feels like _everything_ was moved around. It kind of puts the previous 24 episodes in a whole new light. It's like you are saying: you know the past weeks all the stuff I showed you, don't do it that way, do it this way. That's fine, IF you are still watching at this point. I don't want to sound to negative, because I still really appreciate this series, but I hope you are not going to tell us in episode 52 that actually, it would be better if... you know what I mean?

Thanks! Looking forward to the next episode.
Gravatar
robconery - Sunday, December 07, 2008 - I don't recall mentioning the GUI calling the Repositories - hopefully that will be cleared up later.

RE Bounded Context - hopefully not - that would be confusing :). I'll do my best to make it clear.

>>> It kind of puts the previous 24 episodes in a whole new light. It's like you are saying: you know the past weeks all the stuff I showed you, don't do it that way, do it this way

The previous episodes worked fine for the shape of the app then - it followed some pretty standard way s of doing things. However as I've been "buttoning up", I've realized I could do better.

I never said it was "wrong" - I said I could "do better". Smells don't mean wrong - they're indicators that refactoring is needed. In this case, I decided to try to work with something that was in the back of my mind, DDD.

I understand it seems like an abrupt course change - it's not really. I'm simply moving a few things around and adding some clarity. When I'm done, hopefully you'll see that. File ops don't necessarily equal Dynamite - all of the main code bits are still the same, and the web site is untouched at this point.
Gravatar
Colin Jack - Monday, December 08, 2008 - "The part about services just calling the repositories. That seems necessary to me, the GUI layer should not directly call the data access layer, right? This was only mentioned, but there was no solution in this screencast."

The key thing is you protect your domain but you can do DDD and have your GUI directly talking to repositories and domain objects. This came up in a recent discussion on the DDD forum:

http://tech.groups.yahoo.com/group/domaindriven...

Perhaps not the usual case but it can work as long as you make sure your GUI doesn't unduly influence your domain model.


"Another thing I don't get: does bounded context mean that we are going to have multiple Product classes because in a different context it needs to have different properties? It seems to me that at this point you also are talking about two completely separate applications?"

See the book but yes potentially it does. Models make sense in a particular context so to give you a simple example a Customer in a Finance context might be different to a Customer in a CRM context so having seperate representations is valid.
Gravatar
PK - Sunday, December 07, 2008 - Hi Rob (and fellow listeners),

interesting video. It does make me see this all in a new light. I need to go over this a few times to really get my head around it .. but i love the angle of attack you're using. If it works .. great! if not .. we still learn from this. It's a positive direction .. good work!

I LOVE the IQueriable magic - that has solved so many probs for me. Great to see you're a fan of that (still). Adding the ISession is also something that i'm sooo gonna do now - great stuff! I used to have two methods in my Service project (Create and Update), which ended up calling a single Save method on the repository. I can now clean this up even further with the UnitOfWork pattern.

A few questions: (which i'm guessing will be answered in #26 and #27)
*) What happened to 'pipelines' ? I'm now using WF because of what i learnt from your vids. Does this still have a place? I'm guessing there will be seperate workflows per project, as these workflows will be encapsulated within the domain that they are relevant for (eg. order pipelines found inside the OrderProcessing project; sales pipelines found inside the Sales project.. etc).
b) why did u call it ISession and not IUnitOfWork ? (i'm not techincally familiar with the UoW pattern, even though i understand how i've been using it in Linq2Sql).

Hopefully we don't need to wait as long for #26 and #27 (with all due respect). I'm also curious to see how some POCO items will be handled across a number of projects to minimize duplication but to avoid polluting the Infrastructure project.

Lastly, is it worth adding an extra line on the first slide -> Storefront discussion forums: http://forums.asp.net/1165.aspx ?? :)
Gravatar
mikev - Monday, December 08, 2008 - I just watched the lastest episode and listened to hanselminutes too. I really like your re-packaging. Before it felt odd to see domain services like shipping next to infrastructure services like logging. Also, your application of the state pattern was super cool.

I don't mean to beat a dead horse, but I totally disagree with Dave Laribee defending that DDD is a set of patterns. Sure, there are lots of patterns like repository, unitofwork, factory, specification, etc... but they are just a means to an end which is to write code that captures the essence of the business. DDD is a perspective or philosophy even, not a set of techniques.

I liked Scott Gu's use of the term "impedance mismatch" applied to the rift that exists between the business concepts and the software concepts. Business people think in their language and when they come up with a business idea, it is an extension of their language. So, if your code reads like their business language, the new features are a snap because they extend naturally from your design.

I'm looking forward to the next two episodes! FYI listen to yourself on hanselminutes, you sound just as vague and heady as the rest of us describing DDD! Ha!!!
Gravatar
PK - Monday, December 08, 2008 - Good point about the logging (and email) stuff. Looking forward to seeing this implemented in the new project layout.
Gravatar
Dave Laribee - Monday, December 08, 2008 - @mikeev

Define "set of patterns" how you will. At a certain point we get into a semantic argument unless we agree to call a pattern anything that's repeatable that we've noticed is good. DDD, the book/approach/philosophy/whatever, is a set of patterns in this light.

All that said, it doesn't really matter how we cut it. The main point is that we can take a number of things and apply them to this project or that. In doing so we should be sensible and not necessarily dogmatic or doctrinaire about our approach. What works for this won't work for that, etc.
Gravatar
Chris - Monday, December 08, 2008 - trying to download video... having issues as it always seems to stop midway, currently (4th time) at 69%... maybe put on website instead of live silverlight issues??? like the others.

ps- i'm on cable modem broadband and never had an issue downloading anything before.
Gravatar
PK - Monday, December 08, 2008 - video downloaded fine for me. i watched the full 100%.
Gravatar
Chris - Tuesday, December 09, 2008 - tried it just now and it is working fine now... not sure what was the deal...
Gravatar
Colin Jack - Monday, December 08, 2008 - One general comment, Eric Evans himself has gone as far as to say that he's seen DDD becoming gradually overused (http://www.infoq.com/interviews/domain-driven-d...) and that it's not DDD without a domain expert (http://tech.groups.yahoo.com/group/domaindriven...).

I'd thus recommend that before trying DDD you really think about how far they want to go with it. If the problem is simple and not suited to DDD then being too rigorous with it can be silly, having said that I still think some of the patterns like aggregate/repository/service/entity/value object can apply even if the overall project does not suit DDD.
Gravatar
Chris Kolenko - Tuesday, December 09, 2008 - Any successful project will get larger.

Wouldn't it be better for Rob to use DDD and fail to teach the community something anyway?

This project is about learning and sharing. If you have a project that is similar in size then it's your choice to use it or not.

I'm sick of hearing this project isn't big enough non sense, Rob has gone to too much effort to learn this stuff..
Why don't we all go back to the dark ages and argue about which Text Editor is the best?!?!?!?!

I'm not having a go at you Colin just everyone in general shooting down the idea.. what's the worst that could happen really?
Gravatar
Colin Jack - Wednesday, December 10, 2008 - > I'm sick of hearing this project isn't big enough non sense, Rob has gone to too much effort to learn this stuff..

The amount of effort Rob has put in has nothing to do with whether it's a project that DDD is suited to. I'm also not sure that the fact that you are "sick of" hearing something is necessarily a compelling argument. Also note I didn't say it wasn't "big enough", I've worked on a big but relatively simple project and although we did use some DDD patterns it certainly didn't just the full DDD approach.

Back to the original point, my main point was that Eric Evans has indicated that DDD is not for every project. If you think he is incorrect then that's perfectly valid of course.

> Why don't we all go back to the dark ages and argue about which Text Editor is the best?!?!?!?!

Not even sure what this means, I dunno when these dark ages were and why people were arguing about text editors but it doesn't seem related to my point. Also all the "?!?!?!?!" is totally un-necessary and a little childish.

> I'm not having a go at you Colin

I sense this is not true?!?!?!?!?! :)
Gravatar
robconery - Wednesday, December 10, 2008 - Colin I'd like to raise the level of this discussion please...
Gravatar
Colin Jack - Thursday, December 11, 2008 - Thats fine but given the tone of Chris' content I think my reply was in keeping.
Gravatar
Chris - Tuesday, December 09, 2008 - The following has nothing to do with DDD, however it does with ASP.NET MVC. I haven't taken a look at it but it sounds interesting and provides another look at ASP.NET MVC and is in production. It is called Oxite and it runs visitmix.com.

About Oxite
http://visitmix.com/Lab/Oxite
Source
http://www.codeplex.com/oxite

also of note is
oomph - a microformat toolkit (hCard, hCalendar)
http://visitmix.com/Lab/oomph
Gravatar
Todd Smith - Wednesday, December 10, 2008 - Quick question. Is there a difference between these two statements?

dataContext.GetTable<oxite_MessageToAnonymous>().InsertOnSubmit((oxite_MessageToAnonymous)messageTo.MessageToAnonymous);

dataContext.oxite_MessageToAnonymous.InsertOnSubmit (messageTo.MessageToAnonymous);
Gravatar
robconery - Wednesday, December 10, 2008 - You may want to ask the Oxite guys :) not sure
Gravatar
Todd Smith - Tuesday, December 23, 2008 - In light of your recent efforts, can I ask you now? lol

BTW they're the same because oxite_MessageToAnonymous is a property that just calls GetTable<oxite_MessageToAnonymous>(). I just wasn't sure why they chose to use the more verbose form.
Gravatar
huey - Tuesday, December 09, 2008 - Great episode. I finally pulled the trigger on the book, can't wait to read.

These are all great ideas and I can't wait to look over the code. I'm still hazy on exactly the separation of where a repository stops or starts. In my current project I am dealing with shipments. On the database side there are 5-6 different tables each with their own class / mapping in NHibernate. On the other hand, I don't want the shipment to care. I want to create it, ask the user for some information, and then process it.

So this leaves me with two questions I need to examine (in either your code or future screencasts -- this was actually my first one although I've read your blog awhile!):

1) Is the repository responsible for concatenating these 5-6 tables and spitting out a 'shipment' object, or does the repository spit out the 5-6 tables and then a different layer groups them and spits out a 'shipment' object.

2) The 'shipment' class is going to have some values to show the user, some empty values to ask the user, and some values that simply get translated / worked on behind the scenes. Figuring out how to deal with the UI layer is troubling. Do I have another object that the 'shipment' class gets translated to just for the UI? That would mean a shipment exists in 3 sort of contexts -- what a user sees, what the application sees, and what the database sees. Maybe this is right, or maybe the application and user should be the same?
Gravatar
Mohamed Meligy - Wednesday, December 10, 2008 - Hey Rob.
I like your stuff very much. It's been an inspiration for me during my learning process of ASP.NET MVC and DDD.

hmm ... well, J thought you might be interested in this post when I read it via a link in the ALT.NEt Yahoo mail group:
http://the-software-simpleton.blogspot.com/2008...
Gravatar
Santos Ray Victorero, II - Thursday, December 11, 2008 - Rob,

Keep on going on, you are on the right track! I have been using OO development for a while and DDD helps a lot bringing the concepts to reality and managing complexity.

I have to agree with Colin, Damien and others on the use of an EntityBase super class and also an IAgregateRoot interface You will get its benefits when you implement your repository.

Its like meditation; don't listen to the noisy ones. :-)

I really admire your dedication and enthusiasm.

Santos
Gravatar
Adam Weigert - Thursday, December 11, 2008 - Disclaim: DDD n00b, take with grain of salt and call the professionals if I get out of hand. I have just a few notes I took that maybe will help you with some of the design.

So, are TDD and DDD competing methodologies? Maybe (I don't want to start a religious war - this is based on my experience using both), but I have found that they can both be leveraged to create a form of agility that will help you in reaching for a 'supple' design. Start by designing the domain model first using DDD, then use TDD to validate the design. Before writing a single line of 'implementation' code, make sure the tests feel smooth. Why does this help, it helps to see the big picture by using DDD and having that conversation with your customer. By utilizing TDD, you validate your model will work without too many difficulties. TDD will expose areas that don't feel 'clean' when implementing your scenarios, which is an indicator to go back to the design and clean it up. You may want to iterate over each bounded context, build the Sales model first, validate it, then move on to OrderProcessing. (BTW, TDD for code coverage is a flawed methodology, but that's another religious war I don't want to get involved with)

Next, regarding your OrderState implementation. Is it reasonable to say that an order state is responsible for refunding an order? I get the "smell" feeling you mentioned, which probably means no. The process of refunding an order is not the responsibility of the order state in this context.

To contrast, think of a workflow and it's state. The WorkflowState can keep track of things like: can the workflow start, is it started, is it completed, etc... But should that state be responsible for starting the workflow? Let's take a swag at the code to start a workflow: workflow.State.Start() vs. workflow.Start(). So, just to illustrate this a little more on how the state pattern does helps the workflow object, lets take a look at the framing of a potention workflow.Start() method.

void Start() {
if (!this.State.IsStartable)
throw new InvalidOperationException();
this.State = new StartedWorkflowState(this);
try {
// ... execute the workflow
this.State = new CompletedWorkflowState(this);
} catch (Exception ex) {
this.State = new TerminatedWorkflowState(this, ex);
}
}

I sincerely hope this helps you and keep up the fabulous work, it is quite inspiring.
Gravatar
Todd Smith - Saturday, December 13, 2008 - Would mixing PagedList and LazyList make sense or would that be the equivalent of caffinated beer?
Gravatar
robconery - Saturday, December 13, 2008 - LOL - sure why not!
Gravatar
Alex G - Tuesday, December 23, 2008 - Actually... Beer and Red Bull mixed together 50/50 is pretty decent.. I call that cocktail the "busted deadline" :)

Rob, nice article! I wish for these concepts to become broadly adopted. I've been having a hard time promoting DDD amongst my peers... For example, it was just announced that our "business dll" would be named "UBECL" for Unified Back End Common Library...

Personally I was rooting to call it "SAURON" .. one DLL to support 10 applications, one DLL to bring them all, and in the darkness bind them ;)
Gravatar
Todd Smith - Tuesday, December 23, 2008 - Wouldn't that make you the servant that ended up killing Sauron?
Gravatar
robconery - Thursday, December 25, 2008 - ROFL you just made my week :)

Sent from my phone. Please excuse brief replies.
Gravatar
John Z - Wednesday, December 17, 2008 - HI. Just saw your video and it was great stuff, but I do have a question that other people have asked too. In the video you where talking about the method "GetProductById" which is quite useless. How do you solve that one in a nice way if you wan't to get rid of it. Did you remove it from the servicelayer or do you still have it??

/J
Gravatar
Girish - Thursday, December 25, 2008 - What's your suggestions about adding Size and Color to the items?
Gravatar
weeniearms - Monday, December 29, 2008 - This part seems a little strange to me. At one point you discuss the Law of Demeter and at another one you break it by trying to remove a code smell. The point I'm talking about is the OrderState concept. It's really good to incorporate the state pattern into something like order processing (which is a pretty obvious decision to make) but letting the state object handle the business logic might be a bad choice.
The problem you are dealing with just screams for the strategy pattern and actually, it would be quite easy to refactor the code that you already have. You could keep an abstract class (it might as well be an enum) to determine the state of the order but move all the logic to separate objects implementing an interface like IProcessingStrategy or inheriting from an abstract class ProcessingStrategy, which would have all the methods that your current OrderState class holds. You would also have to add public methods like Refund, Return, etc. to the Order class. All you have to do now is create a factory that will provide the necessary strategies when needed and avoid the necessity to make any changes to your Order class in the future. Here's a bunch of code that will probably better illustrate the pattern than the above text:

public enum OrderState {
State1,
State2
}

public class Order
{
public OrderState CurrentState { get; set; }

public void Charge() {
ProcessingStrategyFactory.GetProcessingStrategy(this).Charge();
}

public void Close() {
ProcessingStrategyFactory.GetProcessingStrategy(this).Close();
}
}

public static class ProcessingStrategyFactory {
// probably the only thing you need to modify if you decide to add new strategies
public static ProcessingStrategy GetProcessingStrategy(Order order) {
switch(order.CurrentState) {
case OrderState.State1:
return new FirstProcessingStrategy(order);
case OrderState.State2:
return new SecondProcessingStrategy(order);
default:
return null;
}
}
}

public abstract class ProcessingStrategy {
protected Order _order;

public ProcessingStragegy(Order order) {
_order = order;
}

public abstract void Charge();
public abstract void Close();
}

public class FirstProcessingStrategy : ProcessingStrategy {
public FirstProcessingStrategy(Order order) : base(order) {}

public override void Charge() {
// some logic here
}

public override void Close() {
// some logic here
}
}

public class SecondProcessingStrategy : ProcessingStrategy {
public SecondProcessingStrategy (Order order) : base(order) {}

public override void Charge() {
// some logic here
}

public override void Close() {
// some logic here
}
}
Gravatar
Gino - Friday, January 02, 2009 - I didn't have the time to go through all the comments, so please tell me if I'm repeating something here.
First, I really like the way you're heading with your DDD approach now and since you've asked for it: here's a set of Q's/R's:
- Why are you calling SubmitChanges in the repository? Unless you're using something like a TransactionScope, you're breaking your UoW, or not? You'll probably call SubmitChanges in the end anyway (I supppose).
- Why do you expose the OrderState property on Order? Wouldn't it make more sense to call methods like Submit and Close on an order itself (which than delegates it to it's order state)? (You could also implement the state pattern on the Order itself -> NewOrder, SubmittedOrder, ... with the same virtuals on Order of course)
What do you think?
Gravatar
Trevor - Friday, January 02, 2009 - I was going to ask about the SubmitChanges in the repository as well.

Can someone explain the difference between unit of work and a transaction? I assume that in most cases the behavior would be the same and it is very easy to rap everything in a TransactionScope.
Gravatar
Gino - Tuesday, January 06, 2009 - IMHO there's no real difference between a UoW and a transaction. The only difference I see is that with UoW you make things more formal/explicit.

I think the term UoW is used far too much anyway, especially in today's world where you have things like TransactionScope and everybody trying to achieve persistence-ignorance (which is basically the opposite of what you would do with a real UoW - you don't want to call methods on your UoW to register dirty objects, for example).
Gravatar
Brandt - Thursday, January 08, 2009 - First, I want to show my appreciation and gratitude for your MVC Storefront series. There is a lot of good code on the net but few actually spend the time to show the thought process. I definitely have learned a lot. I have two questions.

1) I used StructureMap 2.5 with the exact pattern you used to create the DB context. When I used InstanceScope.Hybrid a new instance of the DB object was created on the creation of every new repository object. When I switched it to InstanceScope.HttpContext only one is being created per request. Are you seeing the same occurrence? Have you checked to make sure the context is the same for each http request or just assumed it was?

2) I really like your LazyList. So much to the point I used it in my project. I don’t know if you have addressed this, but an object graph containing a LazyList shouldn’t be cached as the internal IQueryable holds a reference to the context (DB) object. As long as the object is cached the context object will hang around even if ToList() has been called on IQueryable reference. From what I understand this might not be a problem with LINQ to sql and EF(sql). However, if you decided to use another ORM with a LINQ implementation the connection objects might not be disposed of properly. Since the connection has already been created and not destroyed or returned to the connection pool, I believe you will run into a problem. If I am wrong please let me know. I know you want to keep web apps as stateless as possible however if it can be done it will be done; and runtime exceptions are the hardest type to debug.
Gravatar
Paul Linton - Friday, January 09, 2009 - I am getting Storefront withdrawal symptoms (the main one is going over eps25 in fine detail). Thanks for all your work but the other day I kicked the dog and I think it was because I didn't have access to the Storefront source code. Please, can we have another episode of this most excellent series?

I noticed that TranslateOrder has a comment that an Order should always be in the database. There is then code to handle it not being present. Would it be better to log and throw an exception if it shouldn't happen?
In TranslateCustomer there is similar code to check if the Customer exists in the database. If they do not then a Customer is newed up. The Customer is never added to the _session however (that I can see) and so is lost. Obviously, this could be fixed with an appropriate call to _session.Insert but I still think it may be better that if you check for something that cannot happen that you flag it as an error.

In OrderProcessing.Order.cs you have declared Items as being of type LazyList<OrderLine>. Would that be better if it was IList<OrderLine> ?

Keep up the good work, Paul
Gravatar
PK - Saturday, January 10, 2009 - Here Here!!! i'm pulling my hair out that i've not had any MVC Storefront goodness for a while. There's a number of gaps in my app which i'm so not sure about and i'm hoping the storefront fixup Rob is talking about will fix these issues.

They are mainly about code smell, which Rob has identified strongly.

I wish Rob's boss can read all this and ask him to go 100% on MVC SF for a month so he can knock that baby out of the park and we can all celebrate and make awesomesauce websites.
Gravatar
robconery - Sunday, January 11, 2009 - I have the next one queued up for next week! Promise! I just took a rather
long vacation :) so that's the main reason for the slow down. Well, that and
Oxite :).
My boss is Bertrand Le Roy (bleroy) if you want to petition him for my time
:):):)
Gravatar
PK - Monday, January 12, 2009 - Sent!

I hope others email Bertrand so he (or the powers that be) can see how important this series is and will become. It's our cheat sheet to the taking over the net, one MVC proj at a time.
Gravatar
Goran - Friday, January 09, 2009 - Hi Rob,

Thanks for the great series. I've just seen episode 13, but i'm posting here anyway.
You are actually helping me stay in shape, because I streaming your episodes to the big screen in the living room(xbox 360) where I watch you while working on my hometrainer (hope that didn't sound creepy :-) )

Tell your boss that this is what we want. If he stops listening tell his boss.

I'm toying around with MVC and there is a lot of <%= Html.Encode(Model.Message) %> going around. Which was not the case in asp.net (you could but you should not)
<%= actually means Response.write() so why not change it to <%= is Html.Encode(response.write())
Which you have to do about 95% of the time.
The other 5% can do <% Response.Write("not encoded stuff") %> or <% Reponse.KillerGenericExtensionMethod<T>() %> for the diehards.

That should put a lot XSS baddies out of business.
Gravatar
Chad Moran - Friday, January 16, 2009 - Hey Rob, loving the series. Can't wait for your next version or at least some release of your latest code.

One thing I'd suggest is using an interface for your domain models/objects instead of creating a whole other concrete class, it just seems... meh. A good example of doing it this way is to take a look at the latest Kigg at http://www.codeplex.com/Kigg. The way they have developed their DAL is fantastic and even contains a UnitOfWork object.

Hope this helps, keep up the good work!
Gravatar
robconery - Friday, January 16, 2009 - Thanks Chad :). Not sure what an interface gets me versus an object - some
details? Also, with the latest bits I have here, I have Unitofwork built in.
Gravatar
Chad Moran - Friday, January 16, 2009 - Sorry I wasn't clear.

I meant instead of having 2 sets of concrete objects (POCO and LINQ to SQL generated) you could have an interface. Then extend your LINQ to SQL generated objects by using their partial class-ness and than adding the I<EntityName> interface to the partial. This way you can get the functionality you desire without having to do translation for queries. As far as UnitOfWork I was just saying your new DDD version of the Storefront project and the new Kigg have a lot of similarities you could maybe get some ideas from.

When will we get a chance to get your latest code base? I'm really interested to see the code for your state pattern implementation.
Gravatar
robconery - Friday, January 16, 2009 - Thanks Chad! Interesting approach - I hadn't thought of this. I'll be honest
though and say that it ties me a little too closely to Linq to Sql. In other
words my domain bits will rely on ORM-generated code. I also can't work with
"value objects" really (like Address) which exist in the DB and would have
gets/sets (even though I'm not fully embracing that now :).
Either way - good stuff. If you have a blog I'd love to see more on the idea
since overall it's a nice pattern. RE Kigg/DDD I haven't seen their code but
I did manage to work up a nice UoW thinger for what I'm doing.

I hope to have the new source up in the next few days.
Gravatar
Chad Moran - Friday, January 16, 2009 - Sure do have a blog. Even made a post describing how this can be achieved without having to dig though a huge project.

http://weblogs.asp.net/chadmoran/archive/2009/0...

I know you don't want to be tired to ORM-generated code and you don't have to be if you setup some IoC and spread out your assemblies properly. I agree that you should stay loosely coupled to your DAL so that you code can be very agile. However, I think the interface contracts for domain objects has it's benefits. I'm not against using POCO objects I just think having to translate your queries between the objects can get really messy. I tried following your series step by step to better help me understand the code and I just couldn't stand it when I had multiple one-to-many and many-to-many relationships, I felt like I was writing SQL for something that already was.

Maybe it's just me but unless you have security issues I think you can still stay loosely coupled and still achieve your goal of not dependong on ORM generated code... you have to somewhere.

Hope this helps and can't wait to see your code, nice house by the way.
Gravatar
nabbed - Monday, January 19, 2009 - What kind of doco would you put together for a maintenance when your all packed up and gone
Gravatar
robconery - Monday, January 19, 2009 - ? what ?
Gravatar
nabbed - Tuesday, January 20, 2009 - Sometimes I find myself in a short term roll which requires hand over documentation or sometimes I need to put a functional specification together before I start work, regardless of the fact we might be Agile or not.
Im just after a practical approach to the documentation that gives a written document not a video. As useful as your are in explaining and bringing together a sensible approach to the technology at our finger tips, I would like to see you apply that same practical common sense to a documentation effort.
Gravatar
robconery - Tuesday, January 20, 2009 - Not sure why you're assuming I won't document this - of course I will (I
have to). Generally people aren't very interested in watching me write docs
- they want to see the code and learn how to do things; thus the videos.
Gravatar
Todd Smith - Wednesday, January 21, 2009 - I think he was asking for a video describing how to go about creating an initial design document / specification.
Gravatar
nabbed - Wednesday, January 21, 2009 - I hope you don't think i think your not thinking about Documentation ;)
I already see evidence of well thought out architecture and well am impressed frankly.
I like your approach and your results. I am not assuming you won't do any doco.
I am raising it as something I would like to see.
I would like to see both your approach and your results to the doco side of things.
Keep up the good work.
Gravatar
robconery - Wednesday, January 21, 2009 - No worries - wasn't too sure what you were asking for :). I don't doc
anything until I'm finished :). Too many spent cycles writing docs that get
outdated the next day.
I have a whole episode I want to do RE "Being a good Dev - Let's Analyze and
Document" etc.
Gravatar
anton - Wednesday, January 21, 2009 - Hey Rob, Loving the work you are doing with storefront app. When can we expect the next episode?
Gravatar
robconery - Wednesday, January 21, 2009 - It's in progress right now - I know it's taking a while but it's on its way.
I'm hard at work on this stuff and am working on something pretty dang cool
at the moment :)
Gravatar
anton - Thursday, January 22, 2009 - cheers mate, really appreciate it! Hopefully we can get some more DDD goodies :-)
Gravatar
Chad Moran - Thursday, January 22, 2009 - Rob has adopted the Blizzard model of "It'll be ready, when it's ready."

It is hard to wait when you have no estimated time, though.
Gravatar
robconery - Thursday, January 22, 2009 - Little more complicated then that - but it's coming, I promise :)
Gravatar
Chad Moran - Thursday, January 22, 2009 - So what you're saying is you've based it on ASP.NET MVC RC but we can't see it yet? Eh, eh... :P
Gravatar
robconery - Thursday, January 22, 2009 - Ding ding ding!
Gravatar
Chad Moran - Thursday, January 22, 2009 - That sucks, oh well I guess at least we get twofer when RC goes live.

WTB ASP.NET MVC RC! (that's a lot of acronyms)
Gravatar
PK - Thursday, January 22, 2009 - Yeah .. i was silently wondering if all this ninja-MVC work is to coincide with the RC that should be coming up soon. I was guessing MIX09 ... but i hope it's not that far away.

/me drools at how close we are learning from this project once more!
Gravatar
Chad Moran - Thursday, January 22, 2009 - That's actually rather disappointing knowing that any future code is being held back by the RC date considering it's already been pushed back. :(
Gravatar
robconery - Thursday, January 22, 2009 - That's not the only reason :). There is A LOT going on here. Please, I'm
asking you, be patient.
Gravatar
Todd Smith - Friday, January 23, 2009 - Does it looks like the next release will coincide with a single video or are are you breaking up the transition to DDD into multiple videos?
Gravatar
Nick - Thursday, January 22, 2009 - I don’t know Cory. From what I can gather some people like to use the "Endless Loop" design pattern still too! Jokes aside, I like the (from what I can tell) new architecture much better.

Good job with this series. I have learned allot from your masochistic self review. It provides something I have never seen in any dot net blog before : perceptive. Something that is worth allot more than any "Coders Morality Of The Day". Let’s face it, the nay Sayers just don’t have the balls for it.
Gravatar
Rob - Monday, January 26, 2009 - Fantasic work Rob. Keep it up as your work is much appreciated!