Hanalei, Hawaii Tuesday, February 09, 2010

Oxite Refactor, Take 1

I mentioned yesterday on Twitter that I'm helping out the Oxite team with some refactoring and tweaking of their codebase. I got started last night and people have been asking about it a LOT, so I thought that today I'd show you initially what I'm up to.

I mentioned yesterday on Twitter that I'm helping out the Oxite team with some refactoring and tweaking of their codebase. I got started last night and people have been asking about it a LOT, so I thought that today I'd show you initially what I'm up to.

First - the obvious: Oxite as it stands is not acceptable as a starting point for ASP.NET MVC, and they've pointed that out on there project site today. I'd like the pendulum to swing in the positive direction now, If I may.

Please know - this is an initial pass and some basic thoughts. It's very early and if you look at the source you'll see there are precisely ZERO tests. I'm going to change that in 34 minutes from now - I needed to get my head around the model quickly, and it involved diving head first into the existing code and extracting information - that's how I got to the point below.

Step 1: Understanding What The Client Wants
I've been talking to Duncan and Erik a bit of late (and others on their team) and have a good gauge of what they want (in terms of an overall guiding statement):

a highly-functional, scaleable CMS application that renders high quality and well-formatted semantic markup.

They're initially building this for the VisitMix site - so I'll use that as my "client" so I can try to gear what I make and have it be relevant.

Step 2: The Branch
After looking through the codebase and talking to Duncan and Erik, we thought it would be best to do a branch rather than implementing these changes directly in the trunk. So I'm putting this on my SVN server and If you want to view the source as I go, it's here:

http://www.wekeroad.com:8080/svn/Oxite/trunk

UPDATE: you need to login with "pub" as the user and "pub" as the password.

That's my own Subversion repo - when it comes time to move stuff over I'll work with the team to get in place.

Step 3: The Database
In looking over the database and running the application, it seems pretty clear what's needed here (but I'm sure I'll have to expand on this). For now my target is the existing functionality, as opposed to what's planned:

  • A CMS engine for posts which allow comments
  • A Tagging system
  • A "Bucketing" system which does a many/many with posts and associates the posts to an "area"
  • A versioning system that tracks Post changes

In essence (from a DB perspective), this is the everyman blog sample:

WindowClipping (5)

Again I know it's basic - and no I'm not necessarily "starting from the database" - this is a weird situation where I have stuff right here in front of me, and I'm refactoring the existing system down - so in that sense I'm not really doing TDD here. But I promise - I will get to testing. Working on the DB first is helping me to understand the requirements and what the intent is. Please don't flame me :).

I've removed a good many things here. If you're familiar with the Oxite DB (as it was before I started this), it had some extra tables in it that I think we can let the framework handle. In summary, here are the main ones I've removed:

User, Role, and Role Relationships Tables- I'm going to lean on an IAuthentication/IAuthorization service for this, and initially use ASP.NET Auth - this will help existing blog apps (on the .NET platform) merge a bit more happily. Eventually I'll plug in Open ID.

Language, UserLanguage, StringResource Tables- these tables are basically for localization, but this is handled very nicely by the platform. I've removed them in favor of using Resources and System.Globalization.CultureInfo.

Subscriptions (and related tables) - Subscriptions are normally handled (these days) by RSS. I've removed for now simply to get the app on its feet (it wasn't enabled in the original rev). If we need an emailer, we can add later.

Messages (and related tables) - again this is removed until the scope is figured a bit. More of a forums angle - CMS apps don't usually provide this but again I'll add later.

Step 4: Project Structure
I know I'll get some sniggers on this :), but I've restructured the project to lean on a bit more of a DDD approach. I'm not going full-tilt DDD here on this first pass, but hopefully I can set some goodness up that we can extend later, should the need arise (and I'm sure it will).

The solution has five main project:

  • Oxite.CMS - the domain model
  • Oxite.Infrastructure - base classes and other things that span the app
  • Oxite.Web - the MVC web app
  • Oxite.Tests - Unit Testing bits
  • Oxite.SqlRepository - the Repository implementation for SqlServer. Currently I'm using SubSonic because I want to see if I can get this thing to run on MySQL. Also I happen to like SubSonic a lot. If I do this right, it won't matter what I use :).

Here's how things look currently, I'll explain more in a second (the little dots next to the files are VisualSVN):

WindowClipping (7)  

Step 4: The initial Domain Model
I'm laying these out in a hurry, and I'm running with scissors with respect to TDD. Let's just get this out of the way. I won't write a stitch of logic without a test behind it (well, I'll do my best) but right now I need to get this domain down, at least in terms of what's a service and what's an object. I know I'm violating things, but this is triage friends :).

You can see from the diagram above that I've got (basically) two Aggregate Roots: Post and User. Well in truth User isn't much of an Aggregate root right now - but I think it will get there soon enough :).

Post is the main object, and it's also abstract. The idea with the site is that a Post is a a bit of text a user can add to the site:

 

namespace Oxite.CMS {

    public abstract class Post:EntityBase {

        public Post() : base() { }

        public Post(Guid id) : base(id) { }

        public string LanguageCode { get; set; }

        public string Title { get; set; }

        public string Body { get; set; }

        public User Author { get; set; }

        public DateTime DateCreated { get; set; }

    }

}

 

Next up is Article, which inherits from Post:

 

namespace Oxite.CMS {

    public class Article : Post, IAggregateRoot,IEntity {

        public IList<Area> Areas { get; set; }

        public LazyList<Comment> Comments { get; set; }

        public DateTime DatePublished { get; set; }

        public object IEntity.Key {

            get { return this.Key; }

        }

    }

}

 

(Yes Colin, I've taken your advice on the IEntity stuff :)

I've also typed out Comment and Trackback in sort of the same way - they're not all that interesting so I'll save room here and keep moving.

Domain Services
Right now I have five separate domain services defined - but I think they'll get trimmed and tweaked. This is just the start:

  • BlogService - This grabs posts from the repository, sorts comments, etc (whatever logic will be required for pulling posts and displaying). I need to dive a bit more into the Oxite bits to know what's needed here.
  • MessagingService - Pings services like Ping-O-Matic and Google, etc. May handle spam using Akismet - not sure yet.
  • SearchService - Oxite has the notion of a pluggable search service. Good stuff - rather than make it a repository I've made it a service since ... well that's what it is. Not sure of the provider yet.
  • TextService - Handles scrubbing/sanitizing/formatting of post text. This will also handle XSS stuff.
  • UserService - Membership bits

Step 5: Feeds, etc
I'm going to lean on the ASP.NET MVC bits to handle this. I'm not totally sure how that will work, but I know Phil has some ideas :). There's some blog expertise in our group.

Love to hear your comments. Yes I know there are no tests - getting to that. This is triage.


togakangaroo - January 18, 2009 - Rob, the check out is missing the CookComputing.XmlRpc namespace. Can you add that in when you get the chance?
Paul Cowan - December 17, 2008 - You really should be applauded for this.



Positive and affirmative action.



chrisntr - December 17, 2008 - Can't seem to access the svn repository. Is there a username/password we're meant to use to access it?
robconery - December 17, 2008 - Bleh - yah my server has locked it up - can't seem to get it to open the

webapp. Can you use Tortoise out of curiosoty?
chrisntr - December 17, 2008 - Sadly I'm on OS X at the moment so was trying to use Versions or just view it in the web browser.
Javier Lozano - December 17, 2008 - Awesome work here! I also tried hitting the repo with TSVN and no luck, it kept asking for credentials.
hammett - December 17, 2008 - Any chance of using MEF?
robconery - December 17, 2008 - Sure! I don't know anything about it - but ... if you want commit lemme know

:)
MotoWilliams - December 17, 2008 - I'm a little confused. How does a CMS (Content Management System) relate to a blog engine? They are way different in my mind.
Noffie - December 17, 2008 - To me, it seems that a Blog is a sort of specialized CMS. So, if you have the right CMS, it might be able to handle Blog posts and all the stuff that goes along with a Blog. So I guess a CMS could be or include a blogging engine, but a blogging engine can't really replace a decent CMS.



Steve Smith - December 17, 2008 - Looks like a good start, Rob. I hope you get some constructive criticism along the way. I'd love to see some before/after refactorings and ideally some kinds of lessons learned from whomever the original authors were. I know I've got plenty of legacy code that I'm not too proud of and have only in the last couple of years learned better ways to approach things. I try and blog about the things I used to do and why I think the TDD/DDD way is often better - I think if you're able to convince the original devs that your changes are improvements, it would be useful to others to follow along with that learning experience.



ricky - December 17, 2008 - What's the difference between tag and areaa? If I were doing this, I would use tags to do the areas. It would be like the meta-tags in flickr. Your domain model can still have them separate (since it feels cleaner) but they could be using the same data tables. And this would be a great example of having your domain model != data model.



Thoughts?
robconery - December 17, 2008 - Tags are contextual - so on my blog here I have tags that i can use like "SubSonic" and "ASP.NET MVC". I can use both of those and they make sense. But it's not how i want my blog to read, perhaps. In that way I have "Blog" (which is silly - it's just a bucket) but i could also have "Personal" too. I also have "MVC Storefront" above.



You're right - they are sort of the same, but a sense of structure is implied. Also I think tagging is meant to be a public functionality
Jeff Handley - December 17, 2008 - +1

Way to go Rob and good luck with the process!
smhinsey - December 17, 2008 - I would advise against associating comment threads with your content directly in the object model in that way. If scalability is a concern, you will run into issues with this primarily around caching. Does a new comment invalidate the whole object from the cache? Does publishing a minor revision to the document drop all of the comments from the cache? If so, this is problematic. We have experienced problems with this on our site (a big national newsmagazine that can cause a lot of controversy) and it can get out of hand really quickly.



I admit that I haven't looked into what LazyList actually does, so maybe it addresses these issues.



I have a pretty long history of working with CMS's and I would love to help out if you think there is an opportunity.

robconery - December 17, 2008 - OK fixed the issue - it's open now



robconery - December 17, 2008 - Great! Thanks - LazyList is simply an IQueryable defined list that doesn't load until you iterate it, so it would make a call only when you list out the comments.



Good point RE caching.
NotMyself - December 17, 2008 - wow, this isnt so much a branch as a complete rewrite...
smhinsey - December 17, 2008 - Makes sense. I think the ideally scalable commenting system works a lot like

disqus. If I were doing this from scratch id like to see comments

implemented as a separate resource with at least json, atom, and rss

representations. this way you can ajax them into the page or point an xsl

transformer at the atom version to render them inline if you must.



I guess the real thrust of my point is to be careful about the degree to

which related but separate resources are combined during rendering because

this can have disproportionally adverse effects on the rest of the site.



Also, for the content bucketing - I would think about introducing an

IContentMetadata service that can plug into whatever semantic/contextual

system you need and provide a way to drive content aggregation by using that

data. I haven't seen this approach taken yet but I think its closer to what

most people really want. By default you could simply ask for the metadata

but things get super interesting when you hook it into something like

daylife, opencalais or fast esp.
smhinsey - December 17, 2008 - btw, you used to be based out of SF, right? i think we have a mutual friend.
Trevor - December 17, 2008 - Glad to see you are tackling this. I am still evaluating diving into using Oxite and shelving my own effort (codeplex/blogmvc), since I haven't had the time to make it happen. One question: Since you use Disqus on your own blog, is that something that can be plugged into a blog that has it's own comment system? In other words can Oxite use either?
robconery - December 17, 2008 - Yes it sure can :)
robconery - December 17, 2008 - Who's that?
smhinsey - December 17, 2008 - Jason t? Vague but I hate to drop full names in public.
Roger Pence - December 17, 2008 - This is a superlative effort by all concerned. I'm following you all closely. Great stuff (Duncan and Erik--it takes a lot of balls to try to do something at this level and I appreciate your initial efforts greatly).
Todd Smith - December 17, 2008 - I believe CMS can mean different things to different users. It can mean Contact Management System or Content Management System. The later can refer to any kind of content be it assets for a game, web pages and graphics for a website or posts for a blog or forum.





Todd Smith - December 17, 2008 - Areas should be unique maybe and tags are related to multiple areas.



Area-a, Area-b and Area-51 might all be related and each tagged as .NET but Area-a is about C# bleeding edge, Area-b is about asp.net webforms and Area-51 is the cool area devoted to asp.net mvc! Checkout http://stackoverflow.com/tags for a good implementation of tags.





Todd Smith - December 17, 2008 - So you now have Oxite, Subsonic and MVC Storefront all going on at the same time? My OCD is envious.
Falkayn - December 17, 2008 - Rob, I'm sorry to be a pain but your SVN still seems to require username/password to access.
Sham Singh - December 17, 2008 - I assume at some point I'd see the expected MVC directory structure (Controllers Views Models) in your project? I know your just getting the DDD stuff out of the way at first; I just want to make sure I'm on the same page as I'm going to watch and learn as you progress.
digitaldonkey - December 17, 2008 - And he's writing a book too! :S
DTDimi - December 17, 2008 - Would love to get access to your repository, but it requires authentication...

Can you manage to fix this?



Maybe setting up the repository access level to "read only" for anonymous users, and based on individual request you can assign higher permission set to users who requested directly to be

a part of the development.
robconery - December 17, 2008 - I had to turn it back on to make commits
MotoWilliams - December 17, 2008 - Sure I agree. I just think that the blog space is a little played out. With the rock star OSS Content Management Systems out there for PHP etc, I would think that the #aspnetmvc space is due for some more in addition to N2 and MVCMS. Thus my comment on CMS and it's role in Oxite part deux. It looks like they already started some it it, with the create page functionality.
Casey - December 17, 2008 - All credit for your efforts Rob, just bear in mind ... you aren't refactoing, you are rewriting ... there is a large difference ... and as DDD is about the process not the patterns, you aren't doing DDD either, you are using some patterns that are associated with DDD.



Rant over - good luck!

Falkayn - December 17, 2008 - Oh, I see :(



I hate it when you try to make things easy for people and you find you need to do stuff like that to make it work.



It's not that important, but I'd love to see a drop of the code sometime soon anyway.
Colin Jack - December 18, 2008 - +1 from me too, great stuff.
bart plasmeijer - December 18, 2008 - Hi Rob,



Your SVN server requested a username and a password. Can you help?



Bart



Todd - December 18, 2008 - Rob, I have geek envy.



You talk about all of these projects you "work" on but it hardly sounds like work (ASP.NET MVC, Storefront, Subsonic, Oxite, etc.). I'm assuming, of course, that these projects are part of your duties at MSFT. Must be nice to work on really cool apps that the community eats up.



I need to finally start one of my OS ideas and see how it goes...
Henri - December 18, 2008 - Why not leverage the WCF Syndication stuff to handle the feeds?
applecran - December 18, 2008 - Hi Rob,



I'm looking forward to seeing how this develops. I'm trying to connect to the svn repo but I'm getting prompted for a username/password. Any suggestions?



Thanks
abombss - December 18, 2008 - I would love to see MEF. I have just started playing with MEF for my own MVC App for plugins and would love to see some sample work from guys on the team.
robconery - December 18, 2008 - Your point is?
robconery - December 18, 2008 - I'm using VisualSVN and it won't let me check in unless I have a user/pass

setup on Apache. I'll drop it now - but I need to turn it back on when

comitting and Hammett was on it last night.
Subnus - December 18, 2008 - it still does not work
David Nelson - December 18, 2008 - Someone on the Oxite Codeplex pointed to BlogService (http://www.codeplex.com/blogsvc.), which appears to have a very similar roadmap to Oxite and also uses MVC. I am curious whether anyone else has seen it and how they think it compares to Oxite.
robconery - December 18, 2008 - The SVN stuff is fixed - user is "pub", password is "pub" - sorry for the problems
Duncan Mackenzie - December 18, 2008 - That is the path we went on the Channel9.msdn.com codebase, tags == blogs == forums (and areas are just another name for a blog or forum or whatever you want to call your container object).... and while it had some benefits (nearly all queries were some form of 'get me the ids of all entries tagged with x' it also meant that the most common queries (get all the posts for a blog or a forum or the homepage) required a join, compared to the idea of putting area right on the post as an attribute. Oxite actually has the same problem, with the AreaPost relationship table... which I personally think is overkill. As far as I know, we don't have a user scenario in mind where one post would be in multiple areas, so I'd probably go for simplicity over flexibility in this case. This is a topic that our team isn't really in agreement on though, as you can see from the Oxite data structures :)

Josh - December 19, 2008 - What about Silverlight/WPF RIA support? That would be really awesome together with the MEF. Maybe even add support for Mesh and Azure.
mike - December 19, 2008 - In a 'real' CMS you'd have nested categories. That way you can create any hierarchy you want. In Graffiti you can only create categories and subcategories, which can be limiting.



What's your take on this for Oxite?
Bil Simser - December 19, 2008 - @Rob: Kudos to you for doing this. I was apprehensive when I looked at the codebase and found it to be a bit of a dogs breakfast with some of the things you outlined in your posts. I think the steps here are great and needed. In fact, I see some of this as a "best practice" for building ASP MVC apps which is something someone like your or Phil should put together for the P&P guys. It would be great to have a P&P on MVC rather than choppy samples put together by internal teams.
Daniel - December 19, 2008 - I'm trying to get my head around DDD and keep running into an issue I see about to happen here. Namely, where to filter/sort _child lists_ of Aggregate Root objects. In this code, it could happen with Article.Comments. At some point, you'll want to support your popular 10,000 comment post by paging over comments. Where does that logic belong? I keep trying to add it to the service: service.GetArticle(slug, commentPage, commentPageSize), but for classes with multiple children and multiple ways of filtering/sorting them, it gets complex to the point I think I must be doing something wrong: service.GetArticle(slug, commentPage, commentPageSize, commentFilter, commentSort, trackBackPage, trackBackPageSize, trackBackFilter, trackBackSort).
Todd Smith - December 19, 2008 - I ran into this and ended refactoring a bit. Instead of say GetOrder which returns the order and all of its children. I now have 3 separate methods GetOrder, GetOrderItems, GetOrderAttachments. Then you can apply different filtering to each one:



order = GetOrder(orderID)

order.Items = GetOrderItems(orderID, iitemSortName, itemSortOrder, itemFilterBy, itemFilter, itemStartPage, itemPageSize)

order.Attachments = GetOrderAttachments(orderID, attachSortName, attachSortOrder, attachFilterBy, attachFilter, attachStartPage, attachPageSize)



then refactor your service layer accordingly
ashmind - December 19, 2008 - Is having a 'Key' a part of the domain logic? I have always seen keys or ids as a purely infrastructural concepts.

They can be useful for equality, but identity map solves this by making object with same keys reference equal to each other. You obviously need key in some parts of UI, but this seems like something a KeyService or Repository can provide. Same goes for NewKey(). This basically removes the need for EntityBase and IEntity (or turns IEntity into a marker interface).



Also you are explicitly declaring a property as LazyList -- would not it be better to have an IList which is a LazyList when required?
tehlike - December 20, 2008 - Rob,

I believe Akismet implementation shouldn't be in Create action in CommentController. I would decouple it to have more flexible code.

Here is my thoughts:

http://tunatoksoz.com/post/Decoupled-design-with-events.aspx



Thanks for your attention
robconery - December 20, 2008 - I moved to the BlogService. Thanks for the feedback :). Your eventing idea

is interesting but to me it's adding ceremony to what amounts to a boolean

rule check... but I'm listening :).
tehlike - December 20, 2008 - Hi Rob, Thanks for the attention. I said Decoupling but it was my fault, now I say SRP.

My reasoning is that spam service is one of the many possibilities that can be done with the comment. Other possibilities, for example, are sending a notification to the author of the post that there is a new comment etc. Thinking on those, I see that adding those new actions to the controller would be ugly and an indicator of SRP, too. If you use event handlers, new handlers can easily be attached, and you'll have cleaner code.
robconery - December 20, 2008 - I completely agree on the "plugging" idea - and yes I see that events can be

preferable to direct method invocation. That said - the BlogService is my

business logic and it seems fairly straightforward with what's in front of

me. So walk me through this - where do I wire the event? And how is the

process clearer than putting the spam check / email author calls into the

business method? I'm very interested...
tehlike - December 20, 2008 - This is what business layer is for, correct but you can divide business into several points too. Isn't having a hook makes the design more clear? And you remove one concern from your business to another point, with a bonus of extensibility.

You can wire up the events using containers, this is a piece of cake.
robconery - December 20, 2008 - Not really disagreeing with you :). Maybe you can put up a post showing more

of what you mean. I'm trying to work from simple --> complex and right now I

don't see the need to craft an event then put in the wiring logic - all to

replace a single call. I do believe you have a point, I'm just having a hard

time getting there so I need your help :)
tehlike - December 20, 2008 - Actually I think we both understand each other, and I really get what you mean, but i am probably failing at some points that i want to tell. If I can tidy up my mind and can find time, I am glad to write on my point, maybe I will have to agree with you if I think densely on that, who knows? :)



Thanks for you attention, Rob. I really appreciate it.
robconery - December 20, 2008 - I hope you don't take this as push-back :). Well not full push-back at

least. I do get how events will loosen things up - I just want to see more

of what you're talking about. I trust your judgement here :) I'm just way

too visual.

Please...?
tehlike - December 20, 2008 - No, definitely not a push back! I like to discuss about software as it is a great way to learn.

The thing that me and you differentiate at is (probably) that I am thinking a little further, and trying to provide extension mechanism at the beginning, while you are doing things as you come across, ie iteratively. Maybe you would do this my way when needs require this.



On the other hand, I still think that Spam Check is better to be a seperate concern and this seperation brings more flexibility.



Anyway, I started to repeat myself, I probably cannot find the right technical term for this issue.



I liked this discussion as it made me think again and again. Thanks, Rob!

Daniel Auger - December 20, 2008 - Rob,



I really appreciate your appropriate and level-headed reaction to this entire scenario. It would be interesting if you could turn this whole thing into a transparent learning experience as you are doing with the MVC Storefront. I can already see that you are going to be transparent in your analysis and redesign, but I think In this case I'm also interested in the learning experience the original Oxite team will be going through. It could be very educational for everyone if handled in the right way.
alberto - December 21, 2008 - I agree with Casey about calling this refactoring. What you are doing goes beyond refactoring, you are rearchitecting the app (and kudos to you for that). It just about calling things by their name.
oxite-newbie - December 22, 2008 - I have a very stupid question.

since oxite is a database related application, and why can't I figure out any transaction comtrol code in entire code?

Is for some reason or I missed something?
Anthony - December 23, 2008 - So what would you recommend for someone else who has started to hack the Oxite code (http://blogs.conchango.com/anthonysteele/archive/2008/12/22/adding-openid-to-oxite-part-1.aspx)



1) Give up, work on a different project. Oxite's not going to fly

2) wait until Rob's fork is merged and see if he did it first

3) Go ahead.



?
Anthony - December 23, 2008 - There probably aren't any transactions used. Where do you think they need to be used?
tehlike - December 23, 2008 - Rob, some little things I have noticed:



1. Instead of using System.Configuration.ConfigurationManager.AppSettings as the store for wordpress api key, wouldn't it be better to have it injected, to increase easier testability? (The same thing goes with AccountController:OpenId)

I _believe_ it is better to have something like IAuthenticationProvider to hide OpenId details, it's place, imho, is not the controller.

And also passing "localhost" may not be a good thing, but it doesn't matter much.



2.I am not sure if this returns null ever (in LocalizationService)

List result= (from p in _phraseRepo.GetPhrases()

where p.LanguageCode == languageCode

select p).ToList();

By convention, it should return a list with no element.



3. I believe(no strong thoughts on that)



public LazyList Tags { get; set; }



I would personally return IList for the sake of abstraction.(even though it hides some detail)
tehlike - December 23, 2008 - Join me, maybe ? :)
29decibel - December 25, 2008 - You really did a good job!!

i am learning those code,but sometimes it confuse me,

i bid your blog can help me a lot

great thanks
Anthony - December 26, 2008 - Now I'm looking for code that does OpenId Provider. There are a lot less examples of this :(
robconery - December 26, 2008 - Check out the AccountController:

http://www.wekeroad.com:8080/svn/Oxite/trunk/Oxite.Web/Controllers/AccountController.cs



This uses RPXNow and is a really nice way of doing Open ID.
robconery - December 26, 2008 - Hey Tuna - totally agree RE the key. I need to fix the way it and Akismet

are worked here :). do you think setting these things in Bootstrapper would

be the way to go?
tehlike - December 26, 2008 - Does structure map support xml config? I assumed it does, configuring it there may not be good, because it should be set during compiletime, which means this should be recompiled. If it supports xml, it is better to mix this(or better have your own configuration scheme, but this may not be as beneficial) otherwise AppSettings seems to be the way to go.
tehlike - December 26, 2008 - Well, now I understand what you mean. Yes, I would also go with Bootstrapper, register AppSettings["apikey"] thing as a dependency for AkismetSevice.

Jarrett - December 28, 2008 - I'm the creator of BlogSvc http://blogsvc.net and I think BlogService is ahead in some areas that oxite is lacking (such as ease of setup, architecture design, and refactoring). However, Oxite is ahead in terms of having some Admin pages functionality and also publicity. On the other hand, BlogSvc can be greatly customized (in terms of backend and frontend) and already comes with three themes. BlogSvc already supports, trackbacks, pingbacks, rss and atom feeds, comment feeds, atompub, windows live writer, full theming on MVC with Strict XHTML support through the use of HTML cleansing (even comments are XHTML). We also have XSS protection through the use of whitelisted html tags. Also, BlogSvc heavily utilizes jQuery.
Anthony - January 1, 2009 - I haven't looked into RPX much. I guess I need persuading why it's necessary. I thought that the point of OpenId was that there weren't any middlemen, and RPX looked at first glance like one. I hope I'm wrong on that.
Anthony - January 3, 2009 - I have looked at RPX a bit more, and it looks very much like a middleman. Why does OpenId need to have a single point of failure under proprietary control again?
john - January 5, 2009 - I know that you have the hole paged list collection. and it makes sense how you use it on articles. I also get the fact that articles is the aggregate root. so comments are accessible through article. However what i would like to understand is what would you do if say you wanted a paged list for the comments. My personal though might be to just handle this in client javascript.



just wondering what you all might consider doing.
robconery - January 5, 2009 - I've never seen paged comments - even on Atwood's blog. In terms of what I

would do - I'd probably fight the requirement :)
john - January 5, 2009 - lol, I can understand that. I forget where it was that I saw it but I thought that it was cool.
David Nelson - January 6, 2009 - SourceForge has paged comments, and I often wish that ScottGu's blog had paged comments.
David Nelson - January 6, 2009 - Sorry, I said SourceForge, I meant CodeProject.
Anthony - January 6, 2009 - Slashdot, Digg and Livejournal use paged comments when there are enough of them. Make of that what you will.
Jeff - January 9, 2009 - i have been taking a look at your code, I am not very familiar with DDD, but i am looking at the entity base class. I see you default GUID. Is this really a good idea. I know that you could override this to no be the case, but why even have it in the first place. Why not just make the entity implementing EntityBase tell EntityBase what the key will be.



To me there are going to be other business rules in place that would suggest the identity of an entity instead of some randomly created GUID.



I mean employees/users for example. They can have the same name, they can have the same address, heck with identity theft they can have the same everything. That is why companies created EmployeeID or why you have Usernames. A user/employee will never have the same username or employeeID in your system (or else they couldn't log in) and i would guess that a GUID would never be your choice to represent that. So why even have it.



Again not a huge deal cause you can overwrite that functionality. But why have it there. I mainly ask because I simply could be missing something.
jeff - January 10, 2009 - Ok, so I must be really stupid here. Like I said above I am reading through your code. There aren't many tests so I started writing some. Based on what I learned from your mvc storefront series about TDD.



I wrote a test entities_can_test_for_equality().



I tried testing with both a Guid and int. I created to TestEntity objects with the same Guid and/or int.



the I tried an Assert.AreEqual(testEntityA, testEntityB); it failed. Id I test the two keys directly it works. I tried debugging.



"if (base1.Key != base2.Key)" from the EntityBase is true even though the keys are the same, shouldn't it be false.



Can't figure it out. So I thought I would ask the people who are here, as you are all probably smarter than I.
jeff - January 10, 2009 - OK, I got the test to pass. I had to change the line of code in EntityBase



from

"if (base1.Key != base2.Key)"



to

if (base1.Key.GetHashCode() != base2.Key.GetHashCode())



not sure why but this works.
oxite-newbie - January 11, 2009 - I thought any enterprise application or operation will cross 2 tables should use transaction.

Am I right?

I just want to learn and know how to use and define transaction boundary in this refator architecture design.
Todd Smith - January 12, 2009 - Anemic Domain Model



From looking at the current snapshot it seems that you've ended up with an Anemic Domain Model (not criticizing, just curious as I learn DDD concepts). Is that by choice or is Oxite simply devoid of "validation, calculations and business logic" that you might find in a "business application"? In Nilsson's book his DDD experiences have resulted in him putting most of this business logic in his service layers so that he can provide different implementations of business logic using the same domain models. But the majority of articles I've read say to start with your logic in your domain models and move it to services only when it no longer fits.



What say you?
robconery - January 12, 2009 - You might be right - but this is a weird situation in that I'm not building

this from the ground up, per se. There's not much logic present since the

app is quite simple now - but as it grows I'm sure you'll see the services

grow too.
Condominium Calgary - April 17, 2009 - The fact of the matter is that people need somewhere to live, it's not like buying luxury items that can be avoided in a recession...
Condos Calgary - April 17, 2009 - Some interesting thoughts in your articles that will come in handy with my next client - Thanks for taking the time to share!
Paul Cowan - December 17, 2008 - You really should be applauded for this.

Positive and affirmative action.
Jeff Handley - December 17, 2008 - +1
Way to go Rob and good luck with the process!
Colin Jack - December 18, 2008 - +1 from me too, great stuff.
chrisntr - December 17, 2008 - Can't seem to access the svn repository. Is there a username/password we're meant to use to access it?
robconery - December 17, 2008 - Bleh - yah my server has locked it up - can't seem to get it to open the
webapp. Can you use Tortoise out of curiosoty?
chrisntr - December 17, 2008 - Sadly I'm on OS X at the moment so was trying to use Versions or just view it in the web browser.
Javier Lozano - December 17, 2008 - Awesome work here! I also tried hitting the repo with TSVN and no luck, it kept asking for credentials.
hammett - December 17, 2008 - Any chance of using MEF?
robconery - December 17, 2008 - Sure! I don't know anything about it - but ... if you want commit lemme know
:)
Adam Tybor - December 18, 2008 - I would love to see MEF. I have just started playing with MEF for my own MVC App for plugins and would love to see some sample work from guys on the team.
MotoWilliams - December 17, 2008 - I'm a little confused. How does a CMS (Content Management System) relate to a blog engine? They are way different in my mind.
Adam Nofsinger - December 17, 2008 - To me, it seems that a Blog is a sort of specialized CMS. So, if you have the right CMS, it might be able to handle Blog posts and all the stuff that goes along with a Blog. So I guess a CMS could be or include a blogging engine, but a blogging engine can't really replace a decent CMS.

</rant>
Todd Smith - December 18, 2008 - I believe CMS can mean different things to different users. It can mean Contact Management System or Content Management System. The later can refer to any kind of content be it assets for a game, web pages and graphics for a website or posts for a blog or forum.
MotoWilliams - December 18, 2008 - Sure I agree. I just think that the blog space is a little played out. With the rock star OSS Content Management Systems out there for PHP etc, I would think that the #aspnetmvc space is due for some more in addition to N2 and MVCMS. Thus my comment on CMS and it's role in Oxite part deux. It looks like they already started some it it, with the create page functionality.
Steve Smith - December 17, 2008 - Looks like a good start, Rob. I hope you get some constructive criticism along the way. I'd love to see some before/after refactorings and ideally some kinds of lessons learned from whomever the original authors were. I know I've got plenty of legacy code that I'm not too proud of and have only in the last couple of years learned better ways to approach things. I try and blog about the things I used to do and why I think the TDD/DDD way is often better - I think if you're able to convince the original devs that your changes are improvements, it would be useful to others to follow along with that learning experience.
ricky - December 17, 2008 - What's the difference between tag and areaa? If I were doing this, I would use tags to do the areas. It would be like the meta-tags in flickr. Your domain model can still have them separate (since it feels cleaner) but they could be using the same data tables. And this would be a great example of having your domain model != data model.

Thoughts?
robconery - December 17, 2008 - Tags are contextual - so on my blog here I have tags that i can use like "SubSonic" and "ASP.NET MVC". I can use both of those and they make sense. But it's not how i want my blog to read, perhaps. In that way I have "Blog" (which is silly - it's just a bucket) but i could also have "Personal" too. I also have "MVC Storefront" above.

You're right - they are sort of the same, but a sense of structure is implied. Also I think tagging is meant to be a public functionality
Todd Smith - December 18, 2008 - Areas should be unique maybe and tags are related to multiple areas.

Area-a, Area-b and Area-51 might all be related and each tagged as .NET but Area-a is about C# bleeding edge, Area-b is about asp.net webforms and Area-51 is the cool area devoted to asp.net mvc! Checkout http://stackoverflow.com/tags for a good implementation of tags.
mike - December 19, 2008 - In a 'real' CMS you'd have nested categories. That way you can create any hierarchy you want. In Graffiti you can only create categories and subcategories, which can be limiting.

What's your take on this for Oxite?
Duncan Mackenzie - December 18, 2008 - That is the path we went on the Channel9.msdn.com codebase, tags == blogs == forums (and areas are just another name for a blog or forum or whatever you want to call your container object).... and while it had some benefits (nearly all queries were some form of 'get me the ids of all entries tagged with x' it also meant that the most common queries (get all the posts for a blog or a forum or the homepage) required a join, compared to the idea of putting area right on the post as an attribute. Oxite actually has the same problem, with the AreaPost relationship table... which I personally think is overkill. As far as I know, we don't have a user scenario in mind where one post would be in multiple areas, so I'd probably go for simplicity over flexibility in this case. This is a topic that our team isn't really in agreement on though, as you can see from the Oxite data structures :)
smhinsey - December 17, 2008 - I would advise against associating comment threads with your content directly in the object model in that way. If scalability is a concern, you will run into issues with this primarily around caching. Does a new comment invalidate the whole object from the cache? Does publishing a minor revision to the document drop all of the comments from the cache? If so, this is problematic. We have experienced problems with this on our site (a big national newsmagazine that can cause a lot of controversy) and it can get out of hand really quickly.

I admit that I haven't looked into what LazyList actually does, so maybe it addresses these issues.

I have a pretty long history of working with CMS's and I would love to help out if you think there is an opportunity.
robconery - December 17, 2008 - Great! Thanks - LazyList is simply an IQueryable defined list that doesn't load until you iterate it, so it would make a call only when you list out the comments.

Good point RE caching.
smhinsey - December 17, 2008 - Makes sense. I think the ideally scalable commenting system works a lot like
disqus. If I were doing this from scratch id like to see comments
implemented as a separate resource with at least json, atom, and rss
representations. this way you can ajax them into the page or point an xsl
transformer at the atom version to render them inline if you must.

I guess the real thrust of my point is to be careful about the degree to
which related but separate resources are combined during rendering because
this can have disproportionally adverse effects on the rest of the site.

Also, for the content bucketing - I would think about introducing an
IContentMetadata service that can plug into whatever semantic/contextual
system you need and provide a way to drive content aggregation by using that
data. I haven't seen this approach taken yet but I think its closer to what
most people really want. By default you could simply ask for the metadata
but things get super interesting when you hook it into something like
daylife, opencalais or fast esp.
smhinsey - December 17, 2008 - btw, you used to be based out of SF, right? i think we have a mutual friend.
robconery - December 17, 2008 - Who's that?
smhinsey - December 17, 2008 - Jason t? Vague but I hate to drop full names in public.
robconery - December 17, 2008 - OK fixed the issue - it's open now
Falkayn - December 18, 2008 - Rob, I'm sorry to be a pain but your SVN still seems to require username/password to access.
robconery - December 18, 2008 - I had to turn it back on to make commits
Falkayn - December 18, 2008 - Oh, I see :(

I hate it when you try to make things easy for people and you find you need to do stuff like that to make it work.

It's not that important, but I'd love to see a drop of the code sometime soon anyway.
NotMyself - December 17, 2008 - wow, this isnt so much a branch as a complete rewrite...
Trevor - December 17, 2008 - Glad to see you are tackling this. I am still evaluating diving into using Oxite and shelving my own effort (codeplex/blogmvc), since I haven't had the time to make it happen. One question: Since you use Disqus on your own blog, is that something that can be plugged into a blog that has it's own comment system? In other words can Oxite use either?
robconery - December 17, 2008 - Yes it sure can :)
Roger Pence - December 17, 2008 - This is a superlative effort by all concerned. I'm following you all closely. Great stuff (Duncan and Erik--it takes a lot of balls to try to do something at this level and I appreciate your initial efforts greatly).
Todd Smith - December 18, 2008 - So you now have Oxite, Subsonic and MVC Storefront all going on at the same time? My OCD is envious.
digitaldonkey - December 18, 2008 - And he's writing a book too! :S
Sham Singh - December 18, 2008 - I assume at some point I'd see the expected MVC directory structure (Controllers Views Models) in your project? I know your just getting the DDD stuff out of the way at first; I just want to make sure I'm on the same page as I'm going to watch and learn as you progress.
DTDimi - December 18, 2008 - Would love to get access to your repository, but it requires authentication...
Can you manage to fix this?

Maybe setting up the repository access level to "read only" for anonymous users, and based on individual request you can assign higher permission set to users who requested directly to be
a part of the development.
Casey - December 18, 2008 - All credit for your efforts Rob, just bear in mind ... you aren't refactoing, you are rewriting ... there is a large difference ... and as DDD is about the process not the patterns, you aren't doing DDD either, you are using some patterns that are associated with DDD.

Rant over - good luck!
robconery - December 18, 2008 - Your point is?
alberto - December 21, 2008 - I agree with Casey about calling this refactoring. What you are doing goes beyond refactoring, you are rearchitecting the app (and kudos to you for that). It just about calling things by their name.
bart plasmeijer - December 18, 2008 - Hi Rob,

Your SVN server requested a username and a password. Can you help?

Bart
Todd - December 18, 2008 - Rob, I have geek envy.

You talk about all of these projects you "work" on but it hardly sounds like work (ASP.NET MVC, Storefront, Subsonic, Oxite, etc.). I'm assuming, of course, that these projects are part of your duties at MSFT. Must be nice to work on really cool apps that the community eats up.

I need to finally start one of my OS ideas and see how it goes...
Henri - December 18, 2008 - Why not leverage the WCF Syndication stuff to handle the feeds?
applecran - December 18, 2008 - Hi Rob,

I'm looking forward to seeing how this develops. I'm trying to connect to the svn repo but I'm getting prompted for a username/password. Any suggestions?

Thanks
robconery - December 18, 2008 - I'm using VisualSVN and it won't let me check in unless I have a user/pass
setup on Apache. I'll drop it now - but I need to turn it back on when
comitting and Hammett was on it last night.
Subnus - December 18, 2008 - it still does not work
David Nelson - December 18, 2008 - Someone on the Oxite Codeplex pointed to BlogService (http://www.codeplex.com/blogsvc.), which appears to have a very similar roadmap to Oxite and also uses MVC. I am curious whether anyone else has seen it and how they think it compares to Oxite.
Jarrett - December 28, 2008 - I'm the creator of BlogSvc http://blogsvc.net and I think BlogService is ahead in some areas that oxite is lacking (such as ease of setup, architecture design, and refactoring). However, Oxite is ahead in terms of having some Admin pages functionality and also publicity. On the other hand, BlogSvc can be greatly customized (in terms of backend and frontend) and already comes with three themes. BlogSvc already supports, trackbacks, pingbacks, rss and atom feeds, comment feeds, atompub, windows live writer, full theming on MVC with Strict XHTML support through the use of HTML cleansing (even comments are XHTML). We also have XSS protection through the use of whitelisted html tags. Also, BlogSvc heavily utilizes jQuery.
robconery - December 18, 2008 - The SVN stuff is fixed - user is "pub", password is "pub" - sorry for the problems
Josh - December 19, 2008 - What about Silverlight/WPF RIA support? That would be really awesome together with the MEF. Maybe even add support for Mesh and Azure.
Bil Simser - December 19, 2008 - @Rob: Kudos to you for doing this. I was apprehensive when I looked at the codebase and found it to be a bit of a dogs breakfast with some of the things you outlined in your posts. I think the steps here are great and needed. In fact, I see some of this as a "best practice" for building ASP MVC apps which is something someone like your or Phil should put together for the P&P guys. It would be great to have a P&P on MVC rather than choppy samples put together by internal teams.
Daniel - December 19, 2008 - I'm trying to get my head around DDD and keep running into an issue I see about to happen here. Namely, where to filter/sort _child lists_ of Aggregate Root objects. In this code, it could happen with Article.Comments. At some point, you'll want to support your popular 10,000 comment post by paging over comments. Where does that logic belong? I keep trying to add it to the service: service.GetArticle(slug, commentPage, commentPageSize), but for classes with multiple children and multiple ways of filtering/sorting them, it gets complex to the point I think I must be doing something wrong: service.GetArticle(slug, commentPage, commentPageSize, commentFilter, commentSort, trackBackPage, trackBackPageSize, trackBackFilter, trackBackSort).
Todd Smith - December 19, 2008 - I ran into this and ended refactoring a bit. Instead of say GetOrder which returns the order and all of its children. I now have 3 separate methods GetOrder, GetOrderItems, GetOrderAttachments. Then you can apply different filtering to each one:

order = GetOrder(orderID)
order.Items = GetOrderItems(orderID, iitemSortName, itemSortOrder, itemFilterBy, itemFilter, itemStartPage, itemPageSize)
order.Attachments = GetOrderAttachments(orderID, attachSortName, attachSortOrder, attachFilterBy, attachFilter, attachStartPage, attachPageSize)

then refactor your service layer accordingly
Andrey Shchekin - December 19, 2008 - Is having a 'Key' a part of the domain logic? I have always seen keys or ids as a purely infrastructural concepts.
They can be useful for equality, but identity map solves this by making object with same keys reference equal to each other. You obviously need key in some parts of UI, but this seems like something a KeyService or Repository can provide. Same goes for NewKey(). This basically removes the need for EntityBase and IEntity (or turns IEntity into a marker interface).

Also you are explicitly declaring a property as LazyList -- would not it be better to have an IList which is a LazyList when required?
Tuna Toksoz - December 20, 2008 - Rob,
I believe Akismet implementation shouldn't be in Create action in CommentController. I would decouple it to have more flexible code.
Here is my thoughts:
http://tunatoksoz.com/post/Decoupled-design-wit...

Thanks for your attention
robconery - December 20, 2008 - I moved to the BlogService. Thanks for the feedback :). Your eventing idea
is interesting but to me it's adding ceremony to what amounts to a boolean
rule check... but I'm listening :).
Tuna Toksoz - December 20, 2008 - Hi Rob, Thanks for the attention. I said Decoupling but it was my fault, now I say SRP.
My reasoning is that spam service is one of the many possibilities that can be done with the comment. Other possibilities, for example, are sending a notification to the author of the post that there is a new comment etc. Thinking on those, I see that adding those new actions to the controller would be ugly and an indicator of SRP, too. If you use event handlers, new handlers can easily be attached, and you'll have cleaner code.
robconery - December 20, 2008 - I completely agree on the "plugging" idea - and yes I see that events can be
preferable to direct method invocation. That said - the BlogService is my
business logic and it seems fairly straightforward with what's in front of
me. So walk me through this - where do I wire the event? And how is the
process clearer than putting the spam check / email author calls into the
business method? I'm very interested...
Tuna Toksoz - December 20, 2008 - This is what business layer is for, correct but you can divide business into several points too. Isn't having a hook makes the design more clear? And you remove one concern from your business to another point, with a bonus of extensibility.
You can wire up the events using containers, this is a piece of cake.
robconery - December 20, 2008 - Not really disagreeing with you :). Maybe you can put up a post showing more
of what you mean. I'm trying to work from simple --> complex and right now I
don't see the need to craft an event then put in the wiring logic - all to
replace a single call. I do believe you have a point, I'm just having a hard
time getting there so I need your help :)
Tuna Toksoz - December 20, 2008 - Actually I think we both understand each other, and I really get what you mean, but i am probably failing at some points that i want to tell. If I can tidy up my mind and can find time, I am glad to write on my point, maybe I will have to agree with you if I think densely on that, who knows? :)

Thanks for you attention, Rob. I really appreciate it.
robconery - December 20, 2008 - I hope you don't take this as push-back :). Well not full push-back at
least. I do get how events will loosen things up - I just want to see more
of what you're talking about. I trust your judgement here :) I'm just way
too visual.
Please...?
Tuna Toksoz - December 20, 2008 - No, definitely not a push back! I like to discuss about software as it is a great way to learn.
The thing that me and you differentiate at is (probably) that I am thinking a little further, and trying to provide extension mechanism at the beginning, while you are doing things as you come across, ie iteratively. Maybe you would do this my way when needs require this.

On the other hand, I still think that Spam Check is better to be a seperate concern and this seperation brings more flexibility.

Anyway, I started to repeat myself, I probably cannot find the right technical term for this issue.

I liked this discussion as it made me think again and again. Thanks, Rob!
Tuna Toksoz - December 23, 2008 - Rob, some little things I have noticed:

1. Instead of using System.Configuration.ConfigurationManager.AppSettings as the store for wordpress api key, wouldn't it be better to have it injected, to increase easier testability? (The same thing goes with AccountController:OpenId)
I _believe_ it is better to have something like IAuthenticationProvider to hide OpenId details, it's place, imho, is not the controller.
And also passing "localhost" may not be a good thing, but it doesn't matter much.

2.I am not sure if this returns null ever (in LocalizationService)
List<Phrase> result= (from p in _phraseRepo.GetPhrases()
where p.LanguageCode == languageCode
select p).ToList();
By convention, it should return a list with no element.

3. I believe(no strong thoughts on that)

public LazyList<Tag> Tags { get; set; }

I would personally return IList<Tag> for the sake of abstraction.(even though it hides some detail)
robconery - December 26, 2008 - Hey Tuna - totally agree RE the key. I need to fix the way it and Akismet
are worked here :). do you think setting these things in Bootstrapper would
be the way to go?
Tuna Toksoz - December 26, 2008 - Does structure map support xml config? I assumed it does, configuring it there may not be good, because it should be set during compiletime, which means this should be recompiled. If it supports xml, it is better to mix this(or better have your own configuration scheme, but this may not be as beneficial) otherwise AppSettings seems to be the way to go.
Tuna Toksoz - December 26, 2008 - Well, now I understand what you mean. Yes, I would also go with Bootstrapper, register AppSettings["apikey"] thing as a dependency for AkismetSevice.
Daniel Auger - December 20, 2008 - Rob,

I really appreciate your appropriate and level-headed reaction to this entire scenario. It would be interesting if you could turn this whole thing into a transparent learning experience as you are doing with the MVC Storefront. I can already see that you are going to be transparent in your analysis and redesign, but I think In this case I'm also interested in the learning experience the original Oxite team will be going through. It could be very educational for everyone if handled in the right way.
oxite-newbie - December 22, 2008 - I have a very stupid question.
since oxite is a database related application, and why can't I figure out any transaction comtrol code in entire code?
Is for some reason or I missed something?
Anthony - December 23, 2008 - There probably aren't any transactions used. Where do you think they need to be used?
Anthony - December 23, 2008 - So what would you recommend for someone else who has started to hack the Oxite code (http://blogs.conchango.com/anthonysteele/archiv...)

1) Give up, work on a different project. Oxite's not going to fly
2) wait until Rob's fork is merged and see if he did it first
3) Go ahead.

?
Tuna Toksoz - December 23, 2008 - Join me, maybe ? :)
Anthony - December 26, 2008 - Now I'm looking for code that does OpenId Provider. There are a lot less examples of this :(
robconery - December 26, 2008 - Check out the AccountController:
http://www.wekeroad.com:8080/svn/Oxite/trunk/Ox...

This uses RPXNow and is a really nice way of doing Open ID.
Anthony - January 1, 2009 - I haven't looked into RPX much. I guess I need persuading why it's necessary. I thought that the point of OpenId was that there weren't any middlemen, and RPX looked at first glance like one. I hope I'm wrong on that.
Anthony - January 3, 2009 - I have looked at RPX a bit more, and it looks very much like a middleman. Why does OpenId need to have a single point of failure under proprietary control again?
29decibel - December 25, 2008 - You really did a good job!!
i am learning those code,but sometimes it confuse me,
i bid your blog can help me a lot
great thanks
john - January 5, 2009 - I know that you have the hole paged list collection. and it makes sense how you use it on articles. I also get the fact that articles is the aggregate root. so comments are accessible through article. However what i would like to understand is what would you do if say you wanted a paged list for the comments. My personal though might be to just handle this in client javascript.

just wondering what you all might consider doing.
robconery - January 5, 2009 - I've never seen paged comments - even on Atwood's blog. In terms of what I
would do - I'd probably fight the requirement :)
john - January 5, 2009 - lol, I can understand that. I forget where it was that I saw it but I thought that it was cool.
David Nelson - January 6, 2009 - SourceForge has paged comments, and I often wish that ScottGu's blog had paged comments.
David Nelson - January 6, 2009 - Sorry, I said SourceForge, I meant CodeProject.
Anthony - January 6, 2009 - Slashdot, Digg and Livejournal use paged comments when there are enough of them. Make of that what you will.
Jeff - January 9, 2009 - i have been taking a look at your code, I am not very familiar with DDD, but i am looking at the entity base class. I see you default GUID. Is this really a good idea. I know that you could override this to no be the case, but why even have it in the first place. Why not just make the entity implementing EntityBase tell EntityBase what the key will be.

To me there are going to be other business rules in place that would suggest the identity of an entity instead of some randomly created GUID.

I mean employees/users for example. They can have the same name, they can have the same address, heck with identity theft they can have the same everything. That is why companies created EmployeeID or why you have Usernames. A user/employee will never have the same username or employeeID in your system (or else they couldn't log in) and i would guess that a GUID would never be your choice to represent that. So why even have it.

Again not a huge deal cause you can overwrite that functionality. But why have it there. I mainly ask because I simply could be missing something.
jeff - January 10, 2009 - Ok, so I must be really stupid here. Like I said above I am reading through your code. There aren't many tests so I started writing some. Based on what I learned from your mvc storefront series about TDD.

I wrote a test entities_can_test_for_equality().

I tried testing with both a Guid and int. I created to TestEntity objects with the same Guid and/or int.

the I tried an Assert.AreEqual(testEntityA, testEntityB); it failed. Id I test the two keys directly it works. I tried debugging.

"if (base1.Key != base2.Key)" from the EntityBase is true even though the keys are the same, shouldn't it be false.

Can't figure it out. So I thought I would ask the people who are here, as you are all probably smarter than I.
jeff - January 10, 2009 - OK, I got the test to pass. I had to change the line of code in EntityBase

from
"if (base1.Key != base2.Key)"

to
if (base1.Key.GetHashCode() != base2.Key.GetHashCode())

not sure why but this works.
oxite-newbie - January 12, 2009 - I thought any enterprise application or operation will cross 2 tables should use transaction.
Am I right?
I just want to learn and know how to use and define transaction boundary in this refator architecture design.
Todd Smith - January 12, 2009 - Anemic Domain Model

From looking at the current snapshot it seems that you've ended up with an Anemic Domain Model (not criticizing, just curious as I learn DDD concepts). Is that by choice or is Oxite simply devoid of "validation, calculations and business logic" that you might find in a "business application"? In Nilsson's book his DDD experiences have resulted in him putting most of this business logic in his service layers so that he can provide different implementations of business logic using the same domain models. But the majority of articles I've read say to start with your logic in your domain models and move it to services only when it no longer fits.

What say you?
robconery - January 12, 2009 - You might be right - but this is a weird situation in that I'm not building
this from the ground up, per se. There's not much logic present since the
app is quite simple now - but as it grows I'm sure you'll see the services
grow too.
togakangaroo - January 18, 2009 - Rob, the check out is missing the CookComputing.XmlRpc namespace. Can you add that in when you get the chance?
Gecko