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

Getting Rid of "Friend" #3

Closed bennadel closed 10 years ago

bennadel commented 10 years ago

@jonahx I've been going through the code and going back through the book and I think I may want to ditch the "Friend" object. At first, I thought of the Friend as a "Role" within the relationship:

Actor (Person) -- Role (Friend)

... But, I think this gets awkward when it comes to the Friend -- SocialCircle relationship. In the book, there are really only a few aggregate-style types of relationships that this could be:

Outer Place -- Place Assembly -- Part Container -- Content Group -- Member

The SocialCircle doesn't feel like an outer place and the Friend is definitely not a place.

The Assembly -- Part relationship feels odd because a Friend cannot exist independently of a Social Circle (and a Part can exist independently from its Assembly).

The Container -- Content doesn't work either because the Content can only exist in one Container and while that would be true for Friend, it seems odd for "Person", which can be part of multiple social circles.

The Group -- Member relationship "feels" like the most accurate since the Member can be part of more than one group (such as the Person can be part of more than one Social Circle). But, the Group can exist without members... which is odd for a Social Circle... That said, if "Member" was the "Friend" object, then it would violate the "zero-or-more groups" constraint since a Friend can only be in one social circle (ie, context).

So, if I kept Friend, I think it would have to be a Container -- Content relationship. And, if I got rid of Friend, I think it would have to be a Group -- Member relationship.

There's something about the Group -- Member that just feels right, if only from a personification standpoint.

jonahx commented 10 years ago

Yep, I've been biting my tongue on this one :) -- glad you arrived at the same conclusion.

The main consideration for me is that in the problem as stated people and friends are essentially equivalent. It might make sense to introduce roles if the problem domain was bigger -- eg, if you were also modelling everyone's family life too, and they had responsibilities as mothers, father, wives, husbands, etc. But despite all the rules you've set up, the domain is actually small and well-defined here.

I agree that we have a pretty textbook case of Group -- Member.

As for Group existing without any members, here's some intuition for you: http://www.youtube.com/watch?v=wWJSt3b9pR8

bennadel commented 10 years ago

Yikes, that place is creepy :) Looks like it should be the location for some horror film.

The one thing that I wonder around with "relational" elements, like Friend, is that in the Database, this would probably be accompanied by time-delimiters like "startedAt" and "endedAt" for when a relationship to the social cricle started/ended. I wonder if those kinds of artifacts (and things like createdAt / updatedAt) are part of the domain model; or, if they are part of the database only (and any reporting that may be generated).

Anyway, my last code-push got rid of Friend and goes directly from people-to-socialcircle. Though, my "love triangle" logic isn't working for some reason. I didn't have time to debug before work.

Thanks!

jonahx commented 10 years ago

Good question about the timestamps.

If it is important to your domain, the you absolutely model it in your domain objects. The book discusses this in Principle 18: The History Principle, as well as other places I believe. Again, as you've written up the current example, I don't think these timestamps matter. But if you introduced a rule such as "If you've been a member of a SocialCircle for 1 year or more, you have to send everyone in that circle a card at Christmas," then you'd need to introduce them.

I think your feeling that this is usually a db thing comes from two places: 1) it's really easy to setup in a database (eg, add a column "createdAt" and give it a default value of NOW() ), so people are likely to use it and 2) You often aren't sure if you'll need createdAt and updatedAt columns, but you just throw them in there as insurance because it's so easy and why not? Nothing wrong really with either of these things, but they're orthogonal to the question of whether you need the info in your domain model. So if your example was a real application you were building for a client, it might make sense to leave it out of your domain for now -- since there is not current use for it -- but throw them in a database table anyway so they'd be there if requirements changed, at which point you could update your domain model.

bennadel commented 10 years ago

Ha ha, I definitely just throw them in the DB because, you never know :) Plus, it makes debugging a bit easier - not through the domain model, but look at the database and trying to figure out why someone has some weird data-state.

That makes sense, though, thanks.