Front Controllers Should NOT Extend Application.cfc

I've been playing with FW/1 a bit on a personal app, and it has proven incredibly frustrating due to multiple manifestations of a single problem: your Application.cfc HAS to extend the framework in order to use the framework.  My complaint really has nothing to do with FW/1 in particular, the exact same argument could be made against Fusebox's Application.cfc integration (but FB at least provides a "normal" way to use it).  And just to be clear, I'm also not railing against Sean Corfield, even though he happens to be the author of both FW/1 and Fusebox's Application.cfc integration.

The first problem is due to Adobe's seemingly mindless choice to require the use of Application.cfc for per-request settings (datasource, mappings, ORM config, etc.), rather than doing it the right way with tags (in the style of the CFAPPLICATION tag).  With Application.cfc being the only place you can define any of this, you cannot use Application.cfc for an individual frontend, since it has to be shared across ALL frontends.

Consider a prototypical blog.  It has a public side (where the public reads), and an admin side (where authors write).  Two separate front ends; one single application.  If your front controller is bound to Application.cfc, you're forced to either run two separate applications or a single dual-purpose frontend.  Either one is a mess, either reducing encapsulation or increasing duplication.  At the very least.

Now consider a different example: an app with a single frontend that also needs one, single, solitary, standalone page for something.  Maybe even just for a quick one-off test script.  You create 'test.cfm' in your directory (so it gets the proper Application.cfc context so you can do your ORM magic), and hit it in the browser.  Oops, your framework decided with it's onRequest handling that it's going to just do it's thing, completely ignoring your template.  Different manifestation, same problem, though this one can be mostly addressed by overriding onRequest with custom behaviour that conditionally invokes super.onRequest.

Like the majority of places where inheritance is used, the proper solution is composition.  Rather than having your Application.cfc extend the framework, let your application compose the framework into itself.  That way it happens on the application's terms, rather than the framework's terms.  I understand that just extending the framework is desirable for ease of initial setup, so I'm not saying you can't do that, just you (as a framework author) should provide an alternative (like Fusebox's fusebox5.cfm).  Then I (as the application developer) can decide how the framework should be used.

Just to be clear, the problem with using inheritance where composition is the correct choice rests on both the shoulders of Adobe (for making request settings part of Application.cfc, rather than composed in with tags), and framework authors (for requiring Application.cfc to extend the framework).  Addressing either of these problems would handle the first manifestation (paragraph 3), but only the framework authors can deal with the second manifestation (paragraph 4).

Bottom line, don't wire yourself in so you can self-invoke, let me invoke you when and where I want you.

34 responses to “Front Controllers Should NOT Extend Application.cfc”

  1. Raymond Camden

    I'm a bit confused. Well, I'm a lot confused. But I want to focus on one thing. You repeatedly make the argument that Adobe made a mistake by saying request level settings had to be made in App.cfc, and that they should be made in tags instead. Can you explain to me what you mean by that? If I use App.cfc to say that application.bgcolor=red, how would I do something like that in a tag based form? Or I guess I'm saying – can you give a concrete real example of how files would make use of global settings w/o one place to set them?

  2. Brian Meloche

    I thought I'd jump on, since LightFront framework development is a bit quiet these days, but it is being actively used. Since FW/1, FB3Lite and LightFront are all designed to be "light" frameworks, I thought I'd point this fact out.

    Although it's LightFront's default for the Application.cfc to extend lightfront.cfc, and the examples currently show it that way, there's nothing stopping you from developing a LightFront application where Application.cfc DOES NOT extend lightfront.cfc. It's not documented, yet, but it absolutely does work if you need it to be configured that way.

    It also does not need to process every request. In fact, an application I'm building these days for a client does not use LightFront throughout the entire application, only the pages I tell it to. LightFront can also be used in the pages that do not call the framework directly. It's pretty flexible that way. In fact, it's more flexible in that regard than either FW/1 or FB3Lite.

    I have a lot of documentation left to write for LightFront, and I will get to it soon, but I'm too busy these days! :-)

  3. Justin Carter

    Could you just put your unrelated test code in it's own folder with it's own application.cfc and inherit and override parts if you need to?

    Multiple inheritence could be a problem but I doubt many application frameworks would place nicely together if you tried to stick them into the same space anyway…

    Or perhaps I'm still missing your point as to what can't be worked around :)

  4. Raymond Camden

    I'm afraid I still don't quite get it Barney. You would want a function to specify ormSettings, but you wouldn't want to use it in App.cfc. So I'm not sure _where_ you would use it, and if you didn't use it in one particular file, wouldn't you run the risk of having 2-N copies of the same settings that would need to be updated?

    It almost sounds like you are saying that because of App.cfc, you can only build evangelist demos, which I'm sure you really don't mean. There are probably millions of apps out there that go beyond simple demos.

    Maybe I'm coding "wrong" – but I've never run into a problem with the use of Application.cfc. I've never felt like I couldn't do what I need to do.

  5. Martijn van der Woud

    100% agree with Barney here. By imposing that per-request settings be specified in the Application.cfc pseudoconstructor, the SRP design principle is violated. Application.cfc now has too many possible reasons for change.

    Also, I agree with Barney that developers should have as much choice as possible, as to when and how to invoke frameworks. Forcing developers to extend a framework Application.cfc makes this unneccesarily difficult. Frameworks should not dictate how we write our apps, they should just do work for us when requested. Stick to the http://en.wikipedia.org/wiki/Hollywood_Principle ! ;)

  6. John Allen

    I love your blog and what you write, but the prototypical blog example isn't showing a problem that can't be solved by using different view and controllers. For example the public sees '/views/blog/post' and the admins would see '/views/blogadmin/editpost'. No code duplication and its 100% DRY. For one off scripts just make another view dir and view. All my projects usually have a '/views/scribble/default/' for development.

    Inheritance vs composition for Application.cfc… not really getting the point. Since Application.cfc is the FIRST thing that happens on every request how would composition for Application.cfc work?

    Interesting post and your blog rocks.

  7. Martijn van der Woud

    @John "Since Application.cfc is the FIRST thing that happens on every request how would composition for Application.cfc work?"

    I think that is exactly the point. Because you are forced to put per-request settings and in Application.cfc you cannot use composition to handle those settings more flexibly. Instead you're stuck with inheritance if you want to overrule something. If you could handle per-request settings outside Application.cfc, this would allow for greater flexibility, as well as adjusting settings at runtime.

  8. Raymond Camden

    @Martin – So taking one setting, like mappings – how would you do it if you didn't have App.cfc? I mean given that we know it runs first, it is an excellent way to define pre-request settings, but it sounds like you are saying this is a bad thing. I'm getting really confused here. Can you provide some pseudo-code perhaps – ie your ideal world scenario? Again, we can focus on one thing, like

    cfset this.mappings["/root"] = "this path"

    That's a common mapping I use now.

  9. Martijn van der Woud

    @Ray I am not saying we should not have App.cfc, just that I would prefer the possibilty of defining per-request setttings where ever I choose.

    Given this App.cfc

    If you could specify mappings with a tag, you could have your mappings specified in a seperate CFC, maybe like this:

    I personally would prefer this possibility for two reasons:

    1) I allows for great flexibility: Suppose my app detects that a shared network drive is broken, and I want to redirect all uploads to a failover network drive so that my app can continue to run while I fix the problem. All I would have to do is this:

    But since we are stuck with App.cfc, I would have to edit the App.cfc mappings code manually on a running production server. Yuck! Alternatively I could check for availability of the network drive in the App.cfc pseudo constructor and specify mappings conditionally but I think you will agree that it would not be a very elegant or maintainable solution.

    2) In my opionion, mappings config need not be parsed on every request. In general, mappings do rarely change during the lifetime of an application. In the above scenario the mappings would be cached, only to be refreshed when application.mappingsConfig.init() is called. It might not make a very large difference, but I know little things like this can add up (I work on an application that sees up to 7.5 million daily page views). If you want the settings refreshed per request, you can put application.mappingsConfig.init() in onRequestStart(). Again this choice we do not have since we are stuck with the App.cfc pseudo-constructor.

    One more thing to note is that in Railo, you can specify per-webcontext settings (including mappings) using the tag.

  10. Martijn van der Woud

    Hmmm… Seems the code has been stripped out. Hold on a sec.

  11. Martijn van der Woud

    Application.cfc: http://pastebin.com/f44bb4038
    MyMappingsConfig.cfc: http://pastebin.com/f3107ed1

  12. Martijn van der Woud

    Code for switching to different set up mappings at runtime: http://pastebin.com/d7d005b8f

  13. Sami Hoda

    Subscribing…

  14. Raymond Camden

    Martin, thanks for the code samples. It is a lot clearer to me now. It seemed to me as if Barney was saying the entire concept of App.cfc was broken. I may have misunderstood him. I can see how what you propose would give additional flexibility, although you have to admit it is a good bit more complex. But I can agree with the idea that mappings should not need to be defined on every request.

  15. Martijn van der Woud

    Hi Ray,

    Glad the code samples provided more clarity. As for my understanding Barney correctly, only he can tell. :)

    Regarding the increased complexity: this is definitely true for my example. On the other hand if we DID have a tag that could be used anywhere, I suppose you could still put it in the App.cfc pseudoconstructor if you like to keep things simple.

  16. Brian Meloche

    I like the idea, Martin. A cfmapping tag would allow for added flexibility. Has this been submitted to Adobe as an enhancement request?

  17. Martijn van der Woud

    Open BlueDragon has a cfmapping tag since version 6.2.1 (see http://wiki.openbluedragon.org/wiki/index.php/CFMAPPING and http://www.creative-restraint.co.uk/blog/post.cfm/per-application-mappings) Railo has a complete and seperate administrator and cfadmin tag for every web-context (including mappings) and ColdFusion has this.mappings in the App.cfc constructor (Railo has this as well, dunno about OpenBD)

    So we have three different implementations, of which the paid engine has only the sloppiest one. Starting to sound familiar, Adobe? ;)

  18. Thomas Messier

    Subscribing too…

  19. dave wheelock

    just listening in…

  20. Ben Nadel

    I think we are forgetting one *extremely* crucial point here and that is that the Application.cfc IS really a framework unto itself; it's the ColdFusion Framework. So yes, when you choose to use the ColdFusion Framework (you can quite easily choose NOT to use it and still build applications), there is some coupling that your application does have to make to it.

    I don't see this as a problem, and, in fact, it has made building applications much easier, at least in my experience. If anything, I with there was *more* stuff I could define in the App.cfc, such as per-application JAR paths for a app-specific class loader.

    Also, I am confused on how you would go about creating centralized settings withOUT a centralized point of entry? Or, are you staying that we should be creating explicit front-controllers with index.cfm (and apply all the per-request settings there via tags + methods)?

  21. John Allen

    @Martijn van der Woud – thanks for the clarification.

    @Ben – Exactly. Application.cfc is a framework. This is a crucial point. A super simple front controller like FW/1 really just adds some more expected behavior for HTML requests.

  22. James Morrow

    @Ben, @John – good point – application.cfc is definitely a base framework, but I think it's also not unreasonable to ask for more flexibility in the way it's used, especially when considering the case Barney/Martin describe (ORM, multi-headed, etc.)

  23. Sean Corfield

    Ben's point is important: when Application.cfc was introduced, it was as a front controller. It has onRequest() to intercept every request – the very definition of Front Controller! Application.cfc IS a framework.

    If you don't like that, don't use it: stick with Application.cfm!

    Personally, I like the way Application.cfc works. I don't have any problems with its per-request nature. Application.cfm was per-request too, so I don't really get what you're complaining about anyway…

  24. Raymond Camden

    I have to echo Sean here. While I saw an interesting ideas here (re: setting up mappings differently), but I've yet to see any proof/reason why App.cfc is "broken".

  25. Martijn van der Woud

    I never stated that App.cfc was 'broken'. And I do not think that Barney was trying to assert that either.

    Two points that are important as I see it:
    1) It would (sometimes) be practical if per-request settings could be defined anywhere, instead of being restricted to the App.cfc pseudoconstructor

    2) Framework authors should provide their users with as much flexibility as possible, regarding the way their framework is invoked. If two frameworks force me to extend their base App.cfc, then it is impossible for me to use both frameworks together. It is all a matter of perspective I guess: is the framework running my application? Or is my application using the framework? I personally personally prefer the latter.

    @Sean
    "Personally, I like the way Application.cfc works. I don't have any problems with its per-request nature. Application.cfm was per-request too, so I don't really get what you're complaining about anyway… "

    It is not the per-request nature of Application.cfc I have a problem with, but the restriction that per-request settings be defined there and nowhere else.

    Also, we are trying to exchange technical opinions here, so that we all may learn from each other. If we don't agree with each other, that's for the best. If we all agreed nobody could learn from this discussion. I must say that I find your labeling this as "complaining" a bit demeaning. Please keep it positive!

  26. Raymond Camden

    Ok, not broken, but "evil". Come on – you have to admit thats a strong term. ;)

    1) I concur.

    2) I guess I just don't see the concern in this – I'd never use FW/1 and Model-Glue in the same app.

    As for being positive and not complaining, again, I'll point out Barney's words here – "evil", and "The first problem is due to Adobe's seemingly mindless choice". Those are strong statements and not very constructive I think.

  27. Martijn van der Woud

    @Raymond you are right about "evil" – and "mindless choice". Compared to that, Sean was being polite. Point taken.

  28. Sean Corfield

    @Martijn, you know you can still use the cfapplication tag with Application.cfc-powered apps? And on Railo, you can use cfapplication to modify existing settings (as well as simply overwrite them) and I think you can do everything via the tag that you can set via Application.cfc (mappings, custom tag paths, default datasource etc).

    Like Ray, I can't imagine trying to use multiple MVC frameworks in a single app so that's a straw man argument.

    As for "Framework authors should provide their users with as much flexibility as possible, regarding the way their framework is invoked." – absolutely not true. The framework runs the application by definition. Ruby on Rails is successful because it is opinionated software. cfWheels, ColdBox, Fusebox, FW/1, Mach-II, Model-Glue all dictate how your application runs. They all "force" you to do certain things in particular ways.

    You mentioned the "Hollywood Principle" earlier but you got it the wrong way round: the frameworks all follow that principle in that you do not "call" the framework, it calls you. You write CFCs and .cfm pages and the *framework* calls methods on those CFCs and includes those pages.

    Now, it's perfectly fair comment if you don't like that approach but I don't think there are any (application) frameworks in the CFML world where your code acts as the controller and invokes the framework…

  29. Martijn van der Woud

    @Sean, it is good to know that we can still use the cfapplication tag in App.cfc-powered apps. I did not know that. But I guess there are still many things you cannot do with this tag, like mappings and ORM settings. With the cfadmin tag on Railo (I mentioned that one earlier) you can indeed do anything you can do in the App.cfc pseudo-constructor. Actually I believe that Railo's admin GUI is using this tag internally for managing datasources, mappings, archives, cache settings and all the other Railo awesomeness.

    Railo is a good example of providing the flexibility and choice that I personally like so much. For instance I have four ways to define a datasource:
    - this.datasource in App.cfc (http://www.railo.ch/blog/index.cfm/2010/2/19/Random-Friday-Railo-tip-thisdatasource) – datasource is Application-specific
    - the web administrator GUI – datasource is web-context specific
    - the server administrator GUI – datasource is server-wide
    - the cfadmin tag – datasource is either web-context specific or server-wide, depending on tag attributes

    That said, I think I see your point of frameworks being successful because they do NOT provide flexibility and are built from the perspective of running an app instead of being run by it. I do not particularly like it from a design standpoint. But I guess it makes working together more easy if everyone is forced to do things the same way. And honestly that might be more important than losing some flexibility. And maybe most people find it comfortable to be forced to do things in some standard way. It's just one more thing you don't have to think about, which is a legitimate line of thought of course. I guess I am not like most people ;-)

    As for your comment that "cfWheels, ColdBox, Fusebox, FW/1, Mach-II, Model-Glue all dictate how your application runs." True. But some frameworks are more restrictive than others. For example, ColdBox forces my App.cfc to extend their coldbox.system.coldbox cfc. And the framework is loaded in the onApplicationStart event handler. ModelGlue does not force my App.cfc to extend anything, and is loaded by a cfinclude in index.cfm Personally I think the latter is more elegant and allows for greater flexibility, like having .cfm templates in the same app that do NOT use the framework.

  30. Mitch Rose

    Purists begone! Sean, really, it's not a straw man argument. Sometimes you have barely enough time to get the job done, nevermind rewrite all that accumulated spaghetti or consolidate existing framework based code. The lesson: don't inherit from multiple frameworks and drive.

  31. Micky Dionisio

    @Barney,

    You took the words right out of my mouth man. I agree with every single point you've made as its totally in line with the golden rule to always favor composition over inheritance. Excellent post man!

    When you have a chance, we're working on a project called cfcommons, created by Brian Carr. There will be a Part 2 follow up from Part 1 in which we will implement SimpleMVC to build it into a proper web application where we use composition in Application.cfc instead of inheritance.

    We'd love your thoughts, thanks man!

  32. Sean Smith

    So, I have a question:

    If you have a front controller which in order:
    1) Fires application.cfc (by way of being a CF page) which defineds app data/settings)
    2) Defines a request.context object (session, security login, other global per request stuff)
    3) Cfincludes the application page (cfm controller file)
    and
    4) Each controller gets it's page specific stuff (form data. etc.) by instantiating an object specific to that page, an object which extends a base class (object).

    Then, either the page object or the base class (object) can redefine any application settings it needs to, on a per request basis. The application only defines default mappings, data sources, etc., but the page object never reads the application scope directly. Rather, a page object (or controller cfm if controllers aren't object based) would always read app settings from the context object, which gets created at every request by the front controller. The context object overrides settings created in application.cfc as the situation (the context) requires.

    Or this kind of arrangement not the way to go?