More Thoughts On MVC, OOP, And Form Submissions In ColdFusion
Posted July 3, 2008 at 6:29 PM by Ben Nadel
In my previous post on OOPhoto, my latest attempt at learning Object Oriented Programming in ColdFusion, I was finally able to codify some of the gut feelings that I have been having about a missing piece of the MVC puzzle. I understand MVC (model-view-controller) in theory; however, in practice, I am having a very hard time trying to wrap my head around it. I always felt like something was missing. Then, earlier today, when I was drawing parallels between ColdFusion and FLEX, I was finally able to formalize my thoughts into something tangible.
Take a look at the work flow (as denoted by pink arrows) in the following FLEX diagram. Please note that I am NOT a FLEX developer so this may not be 100% accurate:
| || || |
| || |
| || || |
In the above FLEX work flow, the user submits a form. This form submission triggers an event in the FLEX application (my OnSubmit() handler). This form submission handler then takes the form data and translates it somehow into a web service call which gets sent to the API or Controller of a ColdFusion application.
Assuming that this is even close to accurate, this makes a lot of sense to me; there needs to be something that translates the interface submission into a valid request and that translator, marked by the dotted outline above, is the submission event handler. My question then becomes, what is the equivalent of this method in the ColdFusion MVC model? In the comments of my previous post, it seemed that the general feeling was that the Controller should have no business savvy knowledge at all - it should simply take a request and hand stuff off to the service layer (I think). So is my OnSubmit() handler above not part of the Controller? Is it part of the service layer? Is that to be considered one of the service objects (or rather a method within it)? If this is part of the service layer, then that means that the service layer is coupled to the view since form names can be anything.... does that mean we need a different service layer for every type of interface or touch point in the application?
As you can see, I am very confused on this point. So, I think if someone could please explain to me where the OnSubmit() method above fits into the ColdFusion MVC world, it would have an enormous impact on my understanding of object oriented programming in ColdFusion.
What Other People Are Searching For
- Wanted: Full-Time ColdFusion Developer at Intoria Internet Architects
- Cold Fusion Senior Developer at Edge Information Management
- Back-End Web Developer-Information Technologist at Michigan State University
- ColdFusion Developer at Nonfat Media
- Mid-to-Senior Level Web Application Developer at SiteVision, Inc.
Ben the problem with your diagram is that you have the Flex application talking to a Controller on the server side. This isn't the case. The RemoteObject call from Flex would be to a *service layer* method, not a Controller method. The HTML Controller is concerned with exactly that, HTML controller and view. The Controller's job is only to invoke the model and render an HTML view. For a Flex app, the Controller is the Flex application, and the View is the Flex UI. Having Flex talk to an HTML controller on the server is only introducing unnecessary overhead and processing logic that has nothing to do with the Flex app.
This is the same reason why enforcing security in the Controller or at the framework event level is not a good idea. Security needs to be enforced at the Service layer. The same applies for web service calls.
Also, to answer your question, yes, the onSubmit handler is part of the Flex Controller. This is the whole reason why you *don't* need a separate service layer for each user interface. The whole point is that the service layer is totally agnostic to how it is called. HTML, Flex, web service, AJAX...the service layer should not care or have any knowledge of how it is being used.
The only problem with introducing Flex, is that you are now bringing in an MVC model, that is speaking to your CF MVC model :) At a recent Flex job, we had started a project using the MVC approach, but then due to (what felt like) duplication of the controller object for each of the views, we just ended up putting everything in a script block at the top of the view (something closer to an Active Record model). If we wanted to switch back to the MVC model, it would just mean putting the script block in a separate class, and referencing the view from the controller object. Anyway, back to your example...
I would usually put the handler methods in the controller class (as they are waiting for something like a "FORM_SUBMITTED" event to bubble back to it, once the user clicks on the submit button in the view). Once this is received, the controller passes that information to the model objects. I then have my ".save()" in the objects so it saves itself, and passes this off to a CF gateway page which also has a "save" function contained within the "mirrored" cf object on the server (as I said, it starts to get even more confusing once you try to introduce Flex + CF into the mix ;) ).
to summarize (only for the Flex side)
controller -> adds listeners -> instantiates view -> user submits form -> event bubbles to controller -> controller puts data into object(s) -> controller calls save method on object
I think in the previous post the controller would be akin to the service layer as that is taking the information from the view and passing it off to something else to handle doing something with the data (the factory or the model).
I think all of this service layer/factory/facade is only going to complicate your leap into the OOP world. I would say, rather than trying to learn all of it at once, just go with the basic MVC approach (you have a form which passes the information to a controller, which sets it in an object, which saves it to a dB), just as a start. Then, once you've got that nailed down, refactor it to use the service layers and factories. Sure, it would be easier to get it all done right off the bat, but the understanding usually comes once you have to change things and figure out why you are changing them that way.
Anyway, just my 2 cents :)
Heh, one more reply for the night. You said:
If this is part of the service layer, then that means that the service layer is coupled to the view since form names can be anything.... does that mean we need a different service layer for every type of interface or touch point in the application?
No, but it means you may need different kinds of Remote Proxy objects that act as a facade to the service layer, or looking at something like ColdSpring's AOP functionality to apply additional logic before or after the remote call is passed on from the proxy to the actual service layer objects. Since ColdSpring can automatically generate remote proxy objects for you, issues like this are easily addressed, but even if you wrote your proxy objects by hand all it would need to do is "translate" the incoming method arguments into names that the service layer can use.
In my opinion the "onSubmit() handler" would indeed be part of the controller in ColdFusion.
In the Flex world, your submission would be passed to a *service* on the server side, not a controller. Flex *is* the controller for that world.
Does that help?
Regarding this statement:
"If this is part of the service layer, then that means that the service layer is coupled to the view since form names can be anything"
Personally, I don't concern myself much with this issue. Admittedly, though, I'm no OO guru. If my service layer method expects form fields with certain names, I have no problem using those form field names in my view. True, you should aim for separation between the layers, but I think sometimes you have to be pragmatic about things. Of course, if someone gives me a good reason why I should absolutely not be doing it this way (and offers a way around it), I'll stand corrected
Guys, thanks so much for working through this with me; unfortunately, I think I did not explain myself as well as I could. I did not mean to start focusing on FLEX and its interaction with ColdFusion. I meant only to say that the OnSubmit() handler in FLEX made sense to me in a way that MVC in ColdFusion did not.
Really, what the main point / question for this post was, what was the OnSubmit() equivalent of the FLEX application in ColdFusion. By that, I mean, what part of the ColdFusion MVC strategy too the form fields and packaged them in a way that they could be used in the service / model layer.
It seems that both Sean and Brian agree that the ColdFusion "OnSubmit" handler would be part of the Controller in the Model-View-Controller setup. Ok, cool, that helps me out a bit. That is what I was assume, but have been having trouble wading through many different opinions.
I am not sure how this lines up or conflicts with the idea of asking objects to do things, rather than telling them, but I have to say, this makes more sense to me than that idea. I am just not there yet.
Going back to the FLEX for a moment, though, I am a bit confused on the idea of the FLEX calling a service layer in ColdFusion directly.... I had thought that all touch-points in an application where controlled by a Controller. I just assumed that web services would call a different controller, or be routed to a different sub-controller than the HTML, but a controller nonetheless. Afterall, without a controller, how do we "control" access? What would happen if we wanted to shut down our whole API for a while? Wouldn't we need a Controller to do that in a centralized manner? I feel like if we routed the API directly into a Service Layer, then we would have a hard time doing anything across the board.
Or, maybe we are talking about the same thing, just calling it different things for remote and local access??
Regardless, here are some points that I have taken away:
1. Model and Service layers are not view-specific.
2. Controllers or sub-parts of a controller (remote-proxy??) are view-specific and help to package requests into forms that can be used by the service layer and model.
I am a bit confused on the security stuff, but I am not going to worry about that at the moment since OOPhoto does not have any security issues.
In CF, your onSubmit() handler would be a controller method, such as index.cfm?event=handleForm or something. This controller handler would invoke the model the same way the Flex remote object call would.
Yes, most people seem to hold onto the idea that every request that comes into the application should go through a controller. This is why we have the Flash Remoting proxy controllers in ColdBox and Model-Glue, but the idea has some problems. ColdBox and Model-Glue are HTML Controllers. To use them to handle web service or Flash calls just complicates things and adds unnecessary overhead. I had a blog post on this idea, with an AJAX-specific slant, but the message is the same for Flash or web service calls as well: http://www.briankotek.com/blog/index.cfm/2007/7/25/AJAX-Data-Requests-vs-AJAX-Content-Requests
To answer your question about shutting down the API, you'd do this in your remote proxy components. If one is using ColdSpring this can be done simply by altering the configuration file. If one writes their own remote proxies, then that is where this would be handled. Either way, one simply removes the desired methods from the remote proxy and that part of the API is now gone. Make sense?
Good post; that makes sense to me. In the past, I have simply used the same controller for API requests as well as standard web requests. The controller path as a bit different. For example, if I had a "contacts" area, I might have a web request like this:
... and the API for it might be:
The difference is that any request whose "do" command starts with "api" gets routed through a different sub-section of the application and then returns JSON data through a standardized API protocol.
To me, these seem (mine and yours) like similar idea, with different implementation. And, seeing as I am trying to learn more, I will try my best to wrap my head around your way, with the remote facades as it makes sense to me as well.