I’m looking to improve my OOP code design as far as I can, but I’m stuck on this issue.
For example, I want to get the profiles of all friends of a user, in a social networking site. So I have tables Friendships and Profiles. And I have classes Friends and Profile.
Let Friends be the class that handle a user’s friendships and Friends::getFriendsProfiles() be the function that fetches and returns all the user’s friends’ profiles.
So inside my function Friends::getFriendsProfiles() I can either do a
-
A table join
(e.g.SELECT * FROM Friends LEFT JOIN Profiles ON Friends.user2 = Profile.userId WHERE Friends.user1 = :userid), or -
I can just fetch the user ids of the friends, create a
Profileobject for each friend id, and call$profile->getProfile($friendid)which runs a query (SELECT * FROM Profiles WHERE userId = $friendid) to fetch a friend’s profile. Then return the set of all the friends’Profileobject.
Option 1 Disadvantage: My Friendship class knows about Profiles. And when I need to make a change on the way a profile is returned (e.g. I want to add another property to each profile object), I need to change it in 2 different places.
Option 2 Disadvantages: Instead of making 1 query (which I think should run in O(1) ?), it is now O(n) where n is the number of the user’s friends.
But Option 2 is so much cleaner and loosely coupled. Which option should I take?
Domain objects are naturally going to have some coupling. This is just the reality of the system you are modelling. This is not so much a coupling problem between friendship and profile its a problem of tight coupling between your business layer and your data layer. If you had a datamapper, finder class etc and made your business object persitance ignorant then changes like this should not matter too much.
If you use the second option you run into the n+1 select problem. In this instance I would not sacrifice performance when there are more important areas that you could consider decoupling.