bennadel / Streamlined-Object-Modeling

I am currnently working through the book, Streamlined Object Modeling: Patterns, Rules, and Implementation. True object oriented programming (OOP) is a new world for me and it's really hard for me to wrap my head around. I'd like to get a nice set of code samples here that I can use to practice the modeling techniques outlined in the book.
25 stars 8 forks source link

Loading Large Object Trees #2

Closed bennadel closed 10 years ago

bennadel commented 10 years ago

@jonahx As I am working on this, the fear that keeps creeping into the back of my mind is the need to load a large object tree to create and validate collaborations. I know the answer to this is often times to simply, "Use lazy-loading in your ORM." But, let's assume we don't have that.

Take the "SocialCircle" for example. One of the rules is that it can't have >150 members. In my old-school approach, I'd "Script" it like:

var count = socialCircile.getMemberCount( id );
if ( count > 150 ) throw error....
socialCircle.addMember( member )

In this case, the "coordinating" object is the "service layer", not the domain model. But, it means that I don't have to load 150 "people" into memory (and all the other stuff they might need in turn).

How do you deal with something like this?

I thought maybe the "count" could be calculated outside of the domain model, but could be validated inside the domain model. Like, have the count passed-in as part of the action:

var count = socialCircle.getMemberCount( id );
socialCircle.addMember( member, count );

Here, the count is passed-in as part of the add-action.

Anyway, I appreciate all of your help!

jonahx commented 10 years ago

Definitely don't do that thing with count :)

The important insight to have here is that your object model is only about specifying an interface, that is, what behavior is each of these objects responsible for? How you implement that behind the scenes is up to you.

There is the design that's best for your brain, and the design that's best because of the computer's limitations. The current exercise is to find the former. So you should pretend you have infinite memory and processing power. Often, you'll be able to use your preferred design without making any concessions (it's not like we're doing hardcore game development where we need to constantly worry about low-level issues). So while you're questions are good ones, I'd say it's premature optimization at this point.

Since that is not a satisfying answer, though, I'll say that your old school "script" above could be a perfectly valid implementation. All that's missing is a separation between the domain SocialCircle and the ORM SocialCircle (this might be a good time to think about the data mapper patter).

So just by way of a very handwavy demonstration:

function DomainSocialCircle(ormSocialCircle) {

    function addMember(member) {
        var count = ormSocialCircle.getMemberCount(); // no need for id, just assume we've been passed
                                                      // the right ormSocialCircle already.
        if ( count > 150 ) throw error....
        ormSocialCircle.addMember( member )
    }

    return {
        addMember: addMember
        // other methods left out
    };
}

The only point I wish to drive home is our entire goal is to get ourselves into a position where we're working with domain objects which are essentially code versions of concepts in our head. Now we can spend most of our time working with these very pleasant objects and not thinking about databases or computers. We tackle those issues separately. That is the key thing. Just as the frontend on your website hides the technical details of databases and code from your users, so your domain objects should hide that complexity from you. The big payoff here comes when your client code starts to read almost like English sentences....

bennadel commented 10 years ago

@jonahx Ah, very interesting. It's almost like an inverse of the Active-Record pattern - the object itself doesn't know how to persist itself; but, it does know who to call and the implementation of the persistent can change, somewhat independently.

Ok, I won't worry about any of this stuff just yet!

jonahx commented 10 years ago

Precisely!