Adam Howitt's Blog

Jan 09
2007

Help with OO Problem

I've studied OO at University in the shape of Eiffel, I've programmed OO somewhat lightly in Java and developed OO in CFCs but there are some classes of problem I just don't get.  If anyone reading this could offer insight from their own experience that would be great!  I'll offer problem 1 for now and dependent on the response I might hit you up for problem 2.

"is related to"

I've called this "is related to" because I'm talking about the modelling of relationships between classes.  This comes in the context of how to use objects in a Content Management System.

For example, lets say I have a website with an about us section and in that section, an programmer list with a list of the key skills of each programmer.  There is also a "key skills list" which has a list of programmers who are in posession of the skill.  Programmers own skills but they aren't necessarily composed of those skills e.g. "has a" and this isn't inheritance since programmers aren't a type of ColdFusion.

So, to make it real, under the list of programmers I have Ben Forta, DHH, Adam Howitt, Sean Corfield and Cameron Childress.  If you view the detail for each programmer you will see that all but DHH have ColdFusion experience.  All have MySQL experience and lastly Adam and DHH have dabbled in Rails.  If I navigate to the ColdFusion page I see a list: Adam, Ben, Cameron, Sean with a brief snippet of the full bio under each.

On the ColdFusion page I would fetch the ColdFusion object and dutifully write out each attribute before getting the related programmers:

<h1>#skillObj.getTitle()#</h1>
<p>#skillObj.getBody()#</p>
<h2>Related Programmers</h2>
<ul>
<cfset stProgrammers=skillObj.getProgrammers()>
<cfloop collection="#stProgrammers#" item="programmer">
<cfset currentProgrammer=stProgrammers[programmer]>
<li>#currentProgrammer.getFirstName# #currentProgrammer.getLastName#<br/>
<p>#currentProgrammer.getShortBio()#</p></li>
</cfloop>
</ul>


My question is how do you implement getProgrammers and what do the classes look like?  My initial thought is that there is a Programmer class and a Skill class.  Now for the chicken and the egg: does a programmer has a struct of skills (order isn't important) or does the skill have a struct of programmers (again, order not important).  Or both?  What do I store? The struct of class instances (programmer objects) or the struct of ids?  If I use a struct of objects, the call getProgrammers has all the information it needs to print this page.

If I store the ids of the objects then I increase cohesiveness by requiring the method to call a function to instantiate the skill class for each id. Storing the ids creates a new issue - I have to load each skill one by one, making multiple database calls for each page request instead of a single database call to load all related skills.  In the current system, I load all skilll attributes with one query, all related programmers with another then display them to the screen.  

The biggest issue I am having trouble understanding is what gets stored in memory.  We don't really have a Programmer or a Skills page, but model the employee structure and skills profiles of clients in the service industry.  Some clients have over a thousand employees with experience or skills selected from a list of over a hundred.  Adding up the potential number of objects, some clients may have over 5,000 content objects which may be called by any number of pages at a given time.  The current procedural approach works but we're trying to see if there is a better OO design to fit the purpose.

Comments (Comment Moderation is enabled. Your comment will not appear until approved.)
[Add Comment] [Subscribe to Comments]
  1. I am not formally versed in OO so take this for what its worth, but this is the way I see it.

    If, in the situation you are currently describing, all you need to know about a skill is its name, I don't really see justification of creating an object for each skill for each programmer object. That just seems overkill and not particularly useful (that is assuming though that all you need to know about a skill is its name).

    So with that out of the way, I do see use in creating an object for each programmer, although I would implement lazy loading, only creating the object as needed, and doing it through a service, making each object static, only one instance of it.

    Now, as far as the relationship, I do believe that description of the relationship would be that a programmer is composed of skills, giving it a "has-a" relationship. So I would give the programmer object a private property structure of skills, and giving different methods of accessing them (you *could* if you wanted to, create an object called skills, being an interator object, one for each programmer that holds all the skills for that programmer and allowing you to iterate over them). But I would say that a programmer is composed of their skills, they definitely are not of type of their skills.

    To be able to list out skills and the programmers that have them, I would somehow store a list of skills (get them from a query, however you want to do it) and then loop over the programmers for that client and call a method to see if that programmer has that skill (again the iterator could handle this), and if so then print their name. This may not be as efficient as having a skills object that has programmers, but I dont think the relationship works nearly as well that way.

    again, just my 2cents.

  2. I'm kind of with Ryan on this. What you're describing is aggregation, a "has-a" relationship between objects. What that generally means is you would ask a programmer for its skills, and internally it would invoke any objects it holds as instance variables handle the task.

    That said, I also agree with Ryan that in this case it seems like overkill to actually have individual Skill objects. Unless you have some need for this, I would think holding an array or query orfskills as an instance variable inside the Programmer would probably be fine.

  3. I always approach things like this moving from the base classes to relationships to methods.

    - Programmer is a class - obviously - Skill is a class - I have to disagree with the others. Whenever I've felt that something is "too basic to be an object," I've regretted it. I only avoid it if the structural overhead is too great (and it rarely is).

    - programmer-to-skills is a relationship - As in database design, this is best stored elsewhere as in a many-to-many table (usually called PROGRAMMER_SKILL).

    - ProgrammerPool is a class - This is the, otherwise tacit, class that provides the list of available Programmers, the list of available Skills, and the relationship between those two.

    The methods for the two basic objects are obvious: Programmer.getName(), Skill.getName(), Programmer.getBio(), etc.

    You would obtain the list of all Programmers or all Skills through ProgrammerPool.getProgrammers() and ProgrammerPool.getSkills(). You could obtain filtered lists via ProgrammerPool.getProgrammersForSkills(List<Programmer>), or ProgrammerPool.getSkillForProgrammer(List<Skill>), or some such method. ProgrammerPool is a singleton that contains all three tables of data.

    I think that the important point is that Programmers, Skills, and their relationships are all part of a higher-level object called ProgrammerPool. That was missing in the original discussion--the two lists of programmers and skills just appeared magically--and so access to the relationship information was missing.

  4. I think the programmers->skills problem is a matter of composition. A programmer most certainly "has a" skill such as ColdFusion. ColdFusion "is a" skill so it would inherit from its abstract Skill parent (and perhaps a "Compilable" or "Scriptable" interface). If you made a request to something like Programmer.getSkills() it would be expected to return an array of Skill objects (or maybe just an array list of Skills). Likewise, Skills.getProgrammers() would return programmers who "have a" skill of various types. It's like a "linked list" where every programmer can have more than one skill and every skillset can have more than one programmer. In this case, you could store the serialized objects into the database and you'd only have to make one DB call to unserialize them which would retain their instantiated state. Or if you don't need to save object state you could store Class IDs and defer instantiation until the last possible moment (which is usually a good idea).

  5. Ryan and Brian, thanks for the comments. I see your point but from a content management perspective I can't eliminate just the skill title since there may be a request for adamSkillList=programmer.getSkills() for a collection and then as part of the iteration I ask for adamSkillList['ColdFusion'].getShortDescription() I want to use this to create more than just relationships between programmers - at this point a programmer is a concrete example of the generic I am trying to build...

    Scott, Happy New Year and long time no speak! It seems like yesterday we were celebrating New Year at the Dark Horse. On the matter at hand I think your explanation of a pool makes the most sense to me. The pool necessarily tightly coupled to both the programmer and the skill but the programmer and skill remain reusable.

  6. Why wouldn't this be a has and belongs to many relationship?

    Programmers are objects and skills are objects. I think anything less than discrete objects for each of these can be limiting and potentially create highly coupled and clunky code down the road.

    What happens when you want to implement a skills.accreditation_courses method down the road and want to access this from the programmer or find all of the programmers that might be interested in this course?

    Each programmer object has several related skill objects. Each skill object has several related programmer objects. If you call the programmer.skills method there would be an array of skills objects. If you call the skill.programmers method there would be an array of programmer objects. In the database you would use a join table to link programmers to skills. That's the rails way.

  7. This is definitely an aggregation relationship. And I have no problem actually having a Skill class. I was under the impression this was a simple string value, which is why I said "Unless you have some need for [individual Skill objects]...". If Skill is more than just a string then it is certainly viable to use an object for this as long as there aren't thousands of skills for a given Programmer (performance would be an issue at that point and lazy loading of Skills would need to be implemented).

  8. Do none of us have jobs?!?

    Adam, you should post weekly questions like this. Herb Sutter used to do a Guru of the Week question in comp.lang.c++.moderated (http://www.gotw.ca/gotw/). Those were always fun.

    Happy New Year!

  9. The relationship between Programmers and Skills may be aggregation if you can make the argument that a Programmer can exist without Skills. ;)

    I think the relationship between Skills and Programmers is one of composition - once the Programmer dies so does the Skill. The Skill is wholly contained within a Programmer. (one may argue that the skill is abstract and can exist without any Programming object containing it, but now we're getting into the area of philosophy and not OOP - if a Programmer falls in the forest...).

  10. Great thread and thanks for everyone participating to this point. If the skill is wholly contained within a programmer then it suggests no other programmer has that skill. So each skill relates to many programmers as each programmer relates to many skills. If one programmer with the skill dies, the skill lives on in the remaining programmers. If the last programmer dies, the skill may still be acquired from books :-)

  11. Jough, yes exactly. In my mind, a Skill can exist independent of a Programmer, and a Programmer could exist that does not have any Skills (or at least has not got any Skills defined). If either of those suppositions are incorrect, you're right that this would be composition instead of aggregation. The difference is subtle but can be important in certain situations. However, when I said earlier "this is definitely aggregation" I didn't mean in the aggregation vs. composition way, but rather that this is definitely a "has-a" relationship.

  12. I would agree in this case it would be composition. You would want to use a collection cfc that would simply have an array of objects. So when you call getProgrammers() it would return a collection object with each element in the array being an instance of the programmer cfc.

    I never thought much of composition but the more I have worked with OOP in CF the more I see how useful it is. With CF8 it will only get better since the performance enhancements made to createObject and cfobject.

  13. Well, Javier re-opened the door on this discussion so I'll follow-up on why I think this is a problem that would require composition rather than aggregation.

    In the OOP world, we're looking at things from more of an Aristotlian perspective rather than a Platonic one. Yes, if you deconstruct a Programmer the skill that they had still exists in the world - the difference is that it's not *their* skill, it's "a" skill - an abstract.

    When you kill a programmer their skills die with them. It's easier if you think of things that are more concrete. A programmer "has-a" heart as well as skills. If you make a programmer disappear into the ether, their heart also disappears, because it's part of the programmer object.

    Same thing with skills. Yes, you can have skills without anyone to be composed of them, but they're abstract and can't be instantiated - can't perform work in the world - without a programmer object to use them.

    Skills will never create code. Programmers will.

    The programmer -> skills relationship may not be the best example for discussing aggregation and composition, but from a practical perspective, what happens to a particular programmer object's skills when you disinstantiate the programmer object? Can you discorporate a person object's skills from their instance?

    I would say no, but I'd be interested in further discussion, since I don't think we really arrived at consensus previously.

  14. Jough, I think you might be getting lost in the details here. Yes, there is a subtle theoretical difference between the terms "aggregation" and "composition". However, in the context of what Adam was asking about, I don't see how the distiction will matter in practice. His Programmer CFC will hold an instance variable pointing to one or more Skill CFC instances. No one is disputing that this is a "has-a" relationship. While I agree with you that this is technically composition rather than aggregation, I haven't seen many situations where the subtle difference between the two definitions matters in practice. Am I missing something or were you just interested in determining the difference for theoretical reasons?

[Add Comment]