I've made a lot of progress in OOPhoto, my latest attempt at learning object oriented programming in ColdFusion, but I have a lot more to go. I think I have just barely begun to scratch the surface of object oriented programming and what it all means. Based on some different conversations that I've had, I believe that I have missed some of the most key concepts in what makes OO so great.
Last Thursday, I had dinner with Dan Wilson. Now, I don't want you to think that when two ColdFusion coders get together, all they can talk about is coding, but I'd be lying to say that we didn't talk a good amount about object orientation. While Dan appreciates all the effort I have put into this project, he is concerned that I am still treating objects too much like simple "Data Containers;" I am manually setting and getting data when I should just be getting things "processed." After all, a big part of object oriented programming is about "asking" objects to do things for you.
Unfortunately, we didn't have a pen and paper, so it took me quite a while to follow what he was saying. After the first few verbal explanations, I kept questioning what exactly was different between what he was saying and what I was doing. To me, our two approaches sounded very much the same. Ultimately, I think it all boils down to something I will refer to as the "Rule of Five." Don't try to look that up - I'm making it up right now. The Rule of Five states that if you Controller action is more than 5 lines of code, you're probably putting logic in the wrong layer of your application.
When you approach the code with the Rule of Five constraint in mind, the idea of processing data becomes quite different. You don't have a free line of code in your controller to create beans and move data into them - that's simply too much work. To keep with the 5 line limit, you can't mess with your form, you have to ask your form to be processed. In doing this, no only are we starting to get into the mind set of asking objects to do things for us, we are starting to think in terms of "Actions" rather than "Data." In stead of moving FristName, LastName, and Email address into a Contact object, we are simply asking our service layer to process the contact data form with a ProcessNewUser() action.
After moving more in that direction, what we end up with an extremely light weight Controller and a very rich Domain Model. When you look at the MVC/OOP dogma, this lines up nicely with its teachings. Your controller shouldn't really do anything - it should just take requests and hand them off to the Model. The controller doesn't really do any "processing."
That sounds good, but I just don't buy it yet. At least not hook, line, and sinker.
During my conversation with Dan, the idea of a night club bouncer kept coming up. To be honest, I don't fully remember the context in which it was brought up, or what exactly it was meant to symbolize, but I think it had to do with input points to an application. You go, you show your ID to the bouncer. He then process it, and decide whether or not to let you in.
I felt bad that I couldn't remember what Dan was talking about, so I kept going over it in my mind this weekend. That's when something dawned on me. Think about this situation as if it were a Form on a web site. Here, we have a user that needs to enter their ID in order to gain access. They then submit the ID to the bouncer, who processes it and returns True or False as to their ability to enter the club. Seems pretty straightforward, right? But think about what data is being passed around. If you take into account the Rule of Five described above, ideally, you would just hand over your wallet (FORM scope) to the bouncer and ask him to process it. He would then, in turn, open your wallet, rifle through it, probably get off a little on seeing pictures of your wife (the sleazy bastard), grab what he believes is your ID, scans it, and then lets you know if you can enter.
When you read it that way, I hope you get a strong guttural feeling that this is completely insane. You never hand your wallet over to someone and let them go through it. That's just bananas. What you do, in reality, it open your own wallet, select just the information that is needed, and hand that over. This way, the bouncer doesn't have to know about your wallet and you don't have to worry about him seeing half naked pictures of your wife. Your wallet (View) and the bouncer (Model) have, in object oriented terms, high cohesion and extremely low coupling.
If you follow my logic so far, the question then becomes, who opens the wallet, pulls out the ID, and hands it over to the bouncer? Obviously, it has to be something that liaises between your wallet and the bouncer. Is this the Controller? In my current OOPhoto application, the answer is Yes. The Controller is responsible for taking data out of the form, packaging it in an object, and handing it off to the service layer.
But it doesn't have to be. From what I discussed with Dan, it seems like one strategy would be to create a utility object that is designed to handle the form processing of a specific form. The controller could then instantiate one of these objects and then hand the FORM scope off to it, which would then take care of the processing. This would allow your primary Model the ability to process just the information needed without having to anything about the way in which the View is constructed; the hand off of data would be handled by the form processing utility object.
My biggest fear here is that all we are doing is adding another object and moving my current Controller logic into it. This feels like we are adding more complexity without any foreseeable benefit. Certainly, we don't really encapsulate changes; if the View changes, now I need to change the View and the utility object rather then the View and the Controller. Still two changes. Still a one-to-two ratio (one change, two affected places).
Uggg, I have some more thinking to do on this topic, but unfortunately, I need to get to work. To be continued.