Yesterday, I started taking my Exercise List domain model and converting it into code. Here is a little visual that I whipped together for the current Exercise object:
| || || |
| || |
| || || |
As you can see, the Exercise ColdFusion component has some simple properties, but then also has an array of these ExerciseJointRelationship ColdFusion components. Each one of these EJRs then had the ID and the Name value of all the different relationship characteristics (joint, joint action, movement plane, movement symmetry). I built it this way, of course, because I was trying to model the existing database structure. Remember, my join table was just a collection of foreign keys.
But, when I got through coding my Exercise.cfc and my ExerciseJointRelationship.cfc something just didn't feel right. I was setting Name values of the various parts of the Exercise-Joint relationship into the ExerciseJointRelationship.cfc. Something about this was just rubbing me the wrong way. The way this relationship exists in the database is as a collection of foreign keys, so why would I need names? For output. When I output the list of joint-aspects for an Exercise, I needed to output the names of the individual parts.
So, then I started to think about what Clark and Gareth were saying about what the objects in our problem domain really are. I was thinking very much in terms of what "queries" I would need and so, my view of objects we very limited. Again, my mentality is such that I am very tied to the data structure and to the procedural implementation.
Trying very, very hard NOT to think about the database, what is an Exercise? What are the relationships that exist. An Exercise IS an entity that has some simple properties such as Name and Description. But, more importantly, is has a collection of "Joint Aspects". I didn't want to say that it has a collection of Joints because, really, it doesn't. It has a collection of work that involves Joints. It is not a clean "Has-A" relationship. You could just as easily say that it has a collection of Joint Actions or Movement Planes; but these statements would also be equally incorrect. This is where understanding the domain is so critical.
So really, what an Exercise has is this collection of Joint Aspects. Each Joint Aspect then has a Joint, a Joint Action, a Movement Plane, and a Movement Symmetry. Each of these items (joint, joint action, etc.) would then be an additional object within the domain model. Here is a modified visualization of what I am talking about:
| || || |
| || |
| || || |
Something about this tells me that I am on a better track than I was before. This feels good, but at the same time, it is frustrating. With all these objects, I am going to need much more code just to model the domain on top of manipulating it. I feel like there's going to be almost as much "object code" as there is page controller / business logic code. This will be OK if much of the business logic is replaced by the object code, but I have this nagging feeling that it will not be.
But, I am not going to pass judgement just yet. Let me get through this next phase and then I can reevaluate.
Very Nice! Definitely takes a little bit to step back and think about how everything is related rather than how you would link them together in the dB (which was even more difficult as you had already created the dB and set everything up). I think where you will see the time saving and code minimizing will be when you actually use the objects (for output, or passing to dB, etc.). Once you've created them, you know exactly what you have in them and don't have to worry about whether you've got a joint, joint action, movement plane as all of that must be contained within them (as you've defined that when you created the objects). And, as you now have your joint aspect object, you have access to all of the objects within it whenever you need them. You definitely seemed to have defined what they are doing and how they're related rather than how the table structure sets them up. Once you've got all of your business objects created it will definitely make it easier to move them around to other projects (should that be necessary), and you've removed any tight coupling from them, making your life easier later. I am quite impressed :)
Thanks for the feedback. And, thanks for your help on the previous posts as well. This is such a movement away from the way I am used to thinking about applications. And, this is such a tiny application. I can't even imagine how someone would go about mapping out a massive application... but then again, I guess those aren't written over the course of a weekend :)
It seems like with this approach, you really need to know what you are doing up front. With a procedural approach, you can really wing it. Start with a page, code some, create a database table, code some more, add a database column. I feel like if you tried that mentality with an Object Oriented Approach, you would go crazy.
I'm right there with you Ben. I did a few small apps, but the amount of objects to support a large application is massive and overwhelming to be honest. I know that design patterns come into play to help this process along, but that's step 3 of an overall process.
These guys that do java programming have this sort of thing in the bag, but eventually, learning to do OO in CF with no real course material is really inefficient. Blogs are nice, but they are supplemental.
Have you ever perused Martin Fowler's catalog of enterprise design patterns?
I am by no means a design patterns junkie (as so many are in the CF world these days) but I have found this catalog to be a great source of ideas when thinking about web applications in an object-oriented way.
Might come in handy in your Exercise List project!
To not sound like an idiot, I wanted to point out that I have a collection of OO books, but without a Java background, some of them are cryptic.
The head first OOAD and then design patterns books were probably the best. The java was easy to understand as they didn't go beyond logic basics and what not.
The blogs make a lot more sense after reading those. However, there are still a lot of holes in my mind that need plugged.
I have read a few books on design patterns already, but it just seems to never quite stick. I read, own, and really like the HeadFirst Design Patterns book as it is an "easy" read and the examples are very accessible. I have tried reading the one on OOP (I can't recall the name off-hand), but I did not finish it; something just wasn't clicking.
I think I just learn best by trying / failing something with my own hands. That will drive the concepts home better.
You also have the massive advantage of a fan base that will aid you in your quest to learn OO. It's really a fitting reward.
Ben - you are right about the bulk of the code being in the model, this is as it should be. And, you are saving yourself a lot of time by thinking the modeling through before setting up the DB.
The good news is once the objects are modeled, you don't have to mess with them much. Then, your controller and display layers will be very thin. This is definitely the desired outcome of OOP: MVC separation, with the V and C layers as thin as possible.
I personally think that OOP and MVC rock the hizzy when it comes to GUIs. Once you've taken the time to model your business logic as objects, you can reuse it with a variety of UIs without any recoding. Does your Employee object care about layout and color schemes? Heck no!
But I am still skeptical about the advantages of using OOP in my ColdFusion apps. Think about how a CF template works: a page is requested, it processes stuff, it ends. That sounds an awful lot like procedural programming to me!
A GUI (desktop, browser, etc.) sits there for minutes or hours waiting for user events. Great! That sounds just like first MVC apps from back in the day, when Smalltalk walked the earth. Let's create a bunch of objects and get them talking to each other!
Why should we create all these objects for an app that will be finished running a few milliseconds later? Any thoughts?
One nice thing about OOP is that it's great to be able to code like so:
<cfif user.isInGroup(myGroup)> do whatever </cfif>
In other words, the code you're writing better expresses the intent of what you're trying to do.
It isn't how long the objects will be around that determines whether OOP is a good fit - it's how long the code base will be around, how complex it may become and how easy you want to make the maintenance.
The longer you plan on using the code, the more complex it is and the more maintainale you want it to be, the more OOP makes sense. We don't create objects to make things easy for the computer (it's quite happy with assembler bytecode, thank you very much). We do it to make it easier for us so we know where to look for each bit of code and we limit the potential collateral damage of changing functionality by encapsulating as much as possible behind objects with interfaces and limiting the knowledge in one of object of what is going on inside the next.
I dig what you're saying. Maintainability is key. Encapsulation, cohesion, coding to interfaces... it all makes sense even with a page request, if your system is complex enough.
I guess I've yet to fall in love with ColdFusion's implementation of OO concepts. It feels a little clunky after working in Java. The distinction between a class and an instance feels really vague in a CFC. Instead of using public/private to set access to variables, you have to scope members with "this" and "variables" (hardly self-documenting). And I definitely miss the Java's interface construct. :(