As a CF developer, I can appreciate the need for a framework. I have been working with the Fusebox methodology for years. I was introduced to it back in '99 when I took at job at Breckenridge Communications in downtown Denver. I have been using it ever since. Most recently, I've had the opportunity to embrace and implement the latest incarnation, FB 5. For the most part, I'm very happy with it.
There are things about it, however, that rub me the wrong way.
In most cases, it isn't because something was implemented incorrectly, or is technically inferior to other solutions...most of my pet peeves stem from a philosophical standpoint. Essentially, they bug me because they cause FB 5, as a framework, to be impractical or unintuitive to a developer, or are hypocritical in respect to what a framework should represent and be responsible for (which I expect is unintentional, and not necessarily a limitation of ColdFusion).
I was going to list my top three pet peeves but the post quickly became epic. So, I'll pick one for today, and go into the others later. Today's FB 5 pet peeve is:
No fall-through support for "No-XML" Implicit Circuit Detection
The Problem
I'm extremely anal when it comes to laying out folders and files, and obtaining some semblance of consistency and form. At my present company, our projects use a standard MVC structure:
/controller
/model
/view
Since we have chosen to focus on No-XML implementations for our FB apps, we use CFCs as circuits in controller, and the ColdSpring services are delegated to the model folder, along with Value Objects. Views, as you have no doubt surmised, reside as templates in /view. Having said all of that, I would expect to be able to create the following structure encapsulating functionality for an "Article" business object like so:
/controller/article.cfc
/model/article/article.cfc
/model/article/articleService.cfc
/view/article/dsp_article_detail.cfm
In implicit circuit or "No-XML" mode, FB must guess where the circuit and fuseaction reside. It does this by walking down a predefined path of the /controller, /model, and /view files and folder, as well as similar aliases.
So, when you do this:
<cfset myFusebox.do( action="article.show" )>
It first checks /controller/article.cfc, sees that it is indeed a circuit, and tells the framework "SUCCESS!" The guessing on FB's part ends there...
...but what if you want to do this?
<cfset myFusebox.do( action="article.dsp_article_detail" contentvariable="bodyContent" )>
A CF developer new to the framework might expect FB to go into /view/article and says, "Oh! I found your dsp_article_detail.cfm file, so let's display that!"
It, sadly, does not.
Instead, it does this:
"Well, I'm not sure what 'article' is, so...better get searching, let's have a look in /controller...ah, I see your circuit right here, it's 'article.cfc', now I'll just go ahead and find your dsp_article_detail fuseaction...oh, whoops! Sorry, you don't have one! ERROR".
It finds your controller CFC, assumes that it is the correct circuit, and throws a horrible error as it attempts to execute the fuse (which it thinks is a function), when what the developer really wanted to do was call a display template.
Why This Is
FB 5 uses a "find-once-and-forget" mentality about implicit circuit detection. Once it walks your /controller, /model, and /view path, and finds a circuit...any circuit...that matches the naming convention you use when calling the circuit.fuseaction, it considers the first circuit found to be correct, and prevents any further dynamic detection. I assume this approach was used for speed and/or efficiency to save CPU cycles in implicit circuit mode. Or, perhaps the FB team decided to play the Occam's razor card.
Workaround
Change your folder structure to:
/controller/article.cfc
/model/article/article.cfc
/view/varticle/dsp_article.cfm
"/varticle"? Really?? I'm sorry, but this is all kinds of lame. I shouldn't have to categorize my specific business object's views with yet another categorization. That's why the dsp_article.cfm's top-most parent folder is /view in the first place...it's a view! Adding another folder with a 'v' prefix should be totally unnecessary and, as it stands, completely unintuitive for new FB developers.
Philosophical Argument
If it was done this way for speed/efficiency, why should this be a concern when you are in production mode? If it was the simplest solution, why force new developers to have to understand the "nuances" of implicit circuit detection when, with a little more work, you can make it robust enough to be intuitive for new developers to pick up and understand? Remember, one of the benefits of a framework should be to enforce a standardized approach to developing an application, with a set of rules and best practices to follow. If the framework conveys those rules like this: "In order to accomplish A, you must do B, C, or D. Oh, but also don't forget that sometimes X, Y, Z won't work so in those cases you have to change things around a bit". That sounds less like a framework and more like what Dr. Evil described as, "the sort of general malaise that only the genius possess and the insane lament".
Solution
Change the way FB introspects for circuits. Instead of a "find-once-and-forget" method of detecting circuits, why not cache a map of the existing circuits/fuses found (create the map on every request in dev mode, and store/cache the map in production), and when a myFusebox.do() occurs, refer to the map's look-up table before assuming the "first-found" circuit is God? That way, it doesn't blindly assume the first circuit found is correct, and has a backup set of circuits/fuses to check before throwing a final "Undefiend Fuseaction in Circuit X" error.
The intended detection should execute as described in the following use-case:
1. myFusebox.do() calls with an action parameter of "article.dsp_article_detail"
2. FB validates that there is a circuit in /controller named article.
3. FB scans the map, and finds no dsp_article_detail() function.
4. FB validates that there is a circuit in /model named article.
5. FB scans the map, and finds no dsp_article_detail() function.
6. FB validates that there is a circuit in /view named article (in this case, a sub-folder)
7. FB scans the map, and finds no function, but does find a dsp_article_detail.cfm, which satisfies the implicit circuit.fuseaction requirement, and fires.
No-XML mode is cool. Except for this.
There are things about it, however, that rub me the wrong way.
In most cases, it isn't because something was implemented incorrectly, or is technically inferior to other solutions...most of my pet peeves stem from a philosophical standpoint. Essentially, they bug me because they cause FB 5, as a framework, to be impractical or unintuitive to a developer, or are hypocritical in respect to what a framework should represent and be responsible for (which I expect is unintentional, and not necessarily a limitation of ColdFusion).
I was going to list my top three pet peeves but the post quickly became epic. So, I'll pick one for today, and go into the others later. Today's FB 5 pet peeve is:
No fall-through support for "No-XML" Implicit Circuit Detection
The Problem
I'm extremely anal when it comes to laying out folders and files, and obtaining some semblance of consistency and form. At my present company, our projects use a standard MVC structure:
/controller
/model
/view
Since we have chosen to focus on No-XML implementations for our FB apps, we use CFCs as circuits in controller, and the ColdSpring services are delegated to the model folder, along with Value Objects. Views, as you have no doubt surmised, reside as templates in /view. Having said all of that, I would expect to be able to create the following structure encapsulating functionality for an "Article" business object like so:
/controller/article.cfc
/model/article/article.cfc
/model/article/articleService.cfc
/view/article/dsp_article_detail.cfm
In implicit circuit or "No-XML" mode, FB must guess where the circuit and fuseaction reside. It does this by walking down a predefined path of the /controller, /model, and /view files and folder, as well as similar aliases.
So, when you do this:
<cfset myFusebox.do( action="article.show" )>
It first checks /controller/article.cfc, sees that it is indeed a circuit, and tells the framework "SUCCESS!" The guessing on FB's part ends there...
...but what if you want to do this?
<cfset myFusebox.do( action="article.dsp_article_detail" contentvariable="bodyContent" )>
A CF developer new to the framework might expect FB to go into /view/article and says, "Oh! I found your dsp_article_detail.cfm file, so let's display that!"
It, sadly, does not.
Instead, it does this:
"Well, I'm not sure what 'article' is, so...better get searching, let's have a look in /controller...ah, I see your circuit right here, it's 'article.cfc', now I'll just go ahead and find your dsp_article_detail fuseaction...oh, whoops! Sorry, you don't have one! ERROR".
It finds your controller CFC, assumes that it is the correct circuit, and throws a horrible error as it attempts to execute the fuse (which it thinks is a function), when what the developer really wanted to do was call a display template.
Why This Is
FB 5 uses a "find-once-and-forget" mentality about implicit circuit detection. Once it walks your /controller, /model, and /view path, and finds a circuit...any circuit...that matches the naming convention you use when calling the circuit.fuseaction, it considers the first circuit found to be correct, and prevents any further dynamic detection. I assume this approach was used for speed and/or efficiency to save CPU cycles in implicit circuit mode. Or, perhaps the FB team decided to play the Occam's razor card.
Workaround
Change your folder structure to:
/controller/article.cfc
/model/article/article.cfc
/view/varticle/dsp_article.cfm
"/varticle"? Really?? I'm sorry, but this is all kinds of lame. I shouldn't have to categorize my specific business object's views with yet another categorization. That's why the dsp_article.cfm's top-most parent folder is /view in the first place...it's a view! Adding another folder with a 'v' prefix should be totally unnecessary and, as it stands, completely unintuitive for new FB developers.
Philosophical Argument
If it was done this way for speed/efficiency, why should this be a concern when you are in production mode? If it was the simplest solution, why force new developers to have to understand the "nuances" of implicit circuit detection when, with a little more work, you can make it robust enough to be intuitive for new developers to pick up and understand? Remember, one of the benefits of a framework should be to enforce a standardized approach to developing an application, with a set of rules and best practices to follow. If the framework conveys those rules like this: "In order to accomplish A, you must do B, C, or D. Oh, but also don't forget that sometimes X, Y, Z won't work so in those cases you have to change things around a bit". That sounds less like a framework and more like what Dr. Evil described as, "the sort of general malaise that only the genius possess and the insane lament".
Solution
Change the way FB introspects for circuits. Instead of a "find-once-and-forget" method of detecting circuits, why not cache a map of the existing circuits/fuses found (create the map on every request in dev mode, and store/cache the map in production), and when a myFusebox.do() occurs, refer to the map's look-up table before assuming the "first-found" circuit is God? That way, it doesn't blindly assume the first circuit found is correct, and has a backup set of circuits/fuses to check before throwing a final "Undefiend Fuseaction in Circuit X" error.
The intended detection should execute as described in the following use-case:
1. myFusebox.do() calls with an action parameter of "article.dsp_article_detail"
2. FB validates that there is a circuit in /controller named article.
3. FB scans the map, and finds no dsp_article_detail() function.
4. FB validates that there is a circuit in /model named article.
5. FB scans the map, and finds no dsp_article_detail() function.
6. FB validates that there is a circuit in /view named article (in this case, a sub-folder)
7. FB scans the map, and finds no function, but does find a dsp_article_detail.cfm, which satisfies the implicit circuit.fuseaction requirement, and fires.
No-XML mode is cool. Except for this.

Comments (10)
Maybe I'm missing something, but why would you want to do article.dsp_article_detail?
Check out the following and see if they are adding some functionality to your liking: http://tech.groups.yahoo.com/group/fusebox5/message/3769
I would think personally that going back to something like ColdFusion's variable handling would work nicely here. Where CF allows you to omit the scope from some variables, FB could be seen as simply allowing you to omit the scope from some actions, i.e. if you wanted to explicitly scope the action it would look like this:
myFusebox.do( action="view.article.dsp_article_detail" contentvariable="bodyContent" )
That may be an approach that's actually better suited to FuseBox than it is to ColdFusion as a core language. And this would also help to reduce ambiguity since you can tell from the code if you're going to deliberately bypass a controller circuit. The down side is more typing although it seems like a reasonable balance.
re: joshua
Explain to me your alternate method of calling a display template in FB 5?
re: anonymous
I'm on that group and monitoring, though I have yet to see that functionality on a to-do list.
re: ike
I'm actually perfectly comfortable with your proposed solution and would be happy to use this method, which, from a naming convention standpoint, is (at the very least) consistent and intuitive.
That is...if it were supported.
@hanzo - has anyone suggested that as an enhancement request for 5.6?
"It finds your controller CFC, assumes that it is the correct circuit"
It does not assume it is the correct circuit it IS the correct circuit. You have always be able to define a circuit alias 1 time and point to one place. Implicit circuits do not and will not change that precedence that has existed in fusebox for years.
"assume this approach was used for speed and/or efficiency to save CPU cycles in implicit circuit mode."
Did you ever even read my response on the Yahoo group??? Seriously this is ludicrous.
"If it was the simplest solution, why force new developers to have to understand the "nuances" of implicit circuit detection when"
Think about this for a second and how crazy this sounds. Simplest? All the bleedin logic is there it would be easy to implement. Nuances? How about a developer trying to follow code and look in multiple places (about 6) for where the hell a fuseaction might have been defined. Let alone if heaven forbid someone makes a fuseaction by the same name which one is actually being called.
I have no problems with suggestions but I already offered an explanation once prior for this.
@Issac you should be able to do that already. Just put everything under the view directory and you could call view.dsp_*.cfm (I think can't say I've tried it).
"It does not assume it is the correct circuit it IS the correct circuit."
Except that it isn't. Or, to be more specific, it *is* the correct circuit, but it is *not* the circuit that would you expect to perform the do() on.
When a developer has a folder structure like the example given, she would expect that she should be able to call 'article.dsp_article' as the action, because after all, she placed the dsp_article file in the /view folder, which is an honest assumption, is it not?
I mean, after all, if you had a /view/varticle/dsp_article.cfm and called do() with an action parameter of 'varticle.dsp_article', you would achieve the expected result, right?
So, the original point stands: Why not article.dsp_article? The answer of course is it FB *thinks* your circuit you're calling is /controller/article.cfc, because it was the first one it found.
Technically: First one found is correct
Intuitive: First one found is not very flexible, and will cause new programmers to become frustrated with "Error: Undefined Fuseaction in Circuit XYZ".
"Did you ever even read my response on the Yahoo group??? Seriously this is ludicrous."
I apologize, but I have not yet found that exact post explaining why the current process of implicit circuit detection is the way that it is, but I would very much like to read it.
"Think about this for a second and how crazy this sounds."
So, are you arguing that it is more intuitive and approachable as a framework to have documentation that states that you may (and should organize your business objects into
/controller
/model
/view
and that implicit circuit detection should be smart enough to also examine:
/controller/(alias)
/model/(alias)
/view/(alias)
Which would therefore indicate to the new FB developer that could achieve the following structure:
/controller/article.cfc
/model/article/article.cfc
/view/article/dsp_article.cfm
Because as it stands, that is the message that the documentation conveys, but that is not the end-result. /controller/article.cfc becomes the default (assumed) circuit when attempting to call article.dsp_article.cfm, when the intention was to have FB look at /view/article/.
Remember, I'm not arguing that FB isn't technically sound...there are clearly defined rules and regulations to follow.
I'm arguing that it isn't intuitive and that some rules don't have clearly defined "exceptions", which cause approachability issues for new developers.
"Let alone if heaven forbid someone makes a fuseaction by the same name which one is actually being called."
I'm *all for* a fixed ruleset that prevents this kind of behavior, which in turn would further govern and guide a new FB developer into a better way of thinking about site structure and how fuses are called.
What I'm *not* for is the assumption that the first circuit found is the one I'm referring to, when you still have additional alias-walking that could be done before a final Undefined Fuseaction is thrown (and would be done anyway if the /controller/(circuit).cfc didn't exist!)
Remember: I don't hate FB. I love it, actually. I'm pro FB all the way. I just hate to see new developers trying to use it and struggle with parts that are unintuitive.
And, I'm sorry but I stand firm on the grounds that you should (in some way) be able to have:
/controller/article.cfc
/model/article/article.cfc
/view/article/dsp_a_silly_view.cfm
Be able to call 'article.dsp_a_silly_view', and not have it throw an Undefined Fuseaction.
"you should be able to do that already. Just put everything under the view directory and you could call view.dsp_*.cfm (I think can't say I've tried it)."
If this is the case, **fantastic**, I am on board and support it. I thought that I had tried this once before in our first project's early dev and it failed, but I would be happy to give it another go and report back.
@hanzo
in the end a circuit name is a variable that holds path information. You expect to have one variable named "article" that holds two different values during one request. And not only that, you expect it to auto-magically detect which one is the correct value.
And, no offense, but this approach is anything but intuitive. Try to look at this from the perspective of a developer that gets handed such an app in order to enhance or maintain it. You'd have to check a number of possible locations every time you want to track down a request. This could easily turn into a developer's nightmare.
I mean, you don't specify a list of possible datasources in one variable and let CF (or the developer) guess which one is intended to be used in CFQuery either. ;-)
You propose that you should be able to call your model, view, and controllers with the same name (article.cfc) and FB should determine which one you are requesting? From the perspective of someone maintaining this code it would be a nightmare to have to go through all of those files to determine which 'article' you were referring to… Given a MVC structure I have never had a problem calling my cfc's article.cfc (controller), mArticle.cfc (model) and vArticle.cfc (view) AND it makes it much easier for future developers to see a map of my application simply by looking at the controller rather than guessing WHICH article.cfc I am calling . . .
@ike
I tried a view various combinations of view.article.dsp*, view.layout.article.dsp*, layout.article.dsp*, etc, but none of them seem to pick up. It would seem that you are restricted to a 'scope.variable' naming convention for circuit.fuseaction.
That is a shame, because 'view.article.dsp_header' would be acceptable and perfectly clear, without being a maintenance nightmare.
@chris
I'm 'pro' maintainable, easy-to-understand code. Anything that expedites the learning process for a new developer is "A Good Thing" imo, which is one of the great things about No-XML mode.
Part of my original pet peeve stems from hands-on experience with training, however. I've actually been over the shoulder of new FB developers whom have embraced FB 5 and are in the learning process, have a solid grasp on their circuit being in /controller/article.cfc, while their model and view are delegated to /model and /view, and physically witnessed their frustration as the ask me:
"Why isn't my dsp template being found?"
And when I explain that their circuit was already detected in /controller/article.cfc, that they are no longer 'allowed' to use that naming convention for any of their views, they are perplexed.
You see, it's easy to understand why FB is the way that it is in regards to implicit circuit detection, and it's also relatively easy to come up with a standardized naming convention that will allow you to conform to those rules (such as Seth's suggestion to go with /view/vArticle).
And, as all the passionate posters have been on this blog so far (and I thank you all!) it is also very easy to explain why the alternate could lead to some honest maintenance headaches, forcing a developer to have to look in multiple places, and even leave FB guessing far more than it should be.
That's why as part of my original blog post, I included a section on 'Why This Is', to make an attempt to explain to the layman why their thought process needs to change when they discover this issue with their file/folder structure.
However, with all of these facts in play, the end result is still the same: A new developer to FB will open up the documentation, read about No-XML mode, see the rules on /controller, /model, and /view, begin to build a file/folder structure for a new site, and inevitably hit this road block.
They *will* have a /controller/article.cfc
They *will* have a /view/article/dsp_header.cfm
They *will* get an undefined fuseaction 'dsp_header' in circuit 'article' when they try to load a display template.
And they will become frustrated as to why that is.
--
I'm going to throw out an alternate proposition, because I am truly passionate about this particular issue and I want new CF developers to embrace FB.
1. Amend the FB documentation in the implicit circuit detection section so that it very *clearly* and *precisely* describes how, once your /controller/circuit.cfc is detected by FB, that if you have a model and (most importantly) a view folder that match the naming convention, they will be occluded, which may be unintentional on the developer's part, and could lead to frustration.
I would also provide an example of that layout in the documentation, and a proposed /model/mObject and /view/vObject alternate.
2. Introduce a more descriptive error message for 'Undefined Fuseaction in Circuit XYZ'. If possible, include the full path to the circuit, which (to a new struggling developer) would offer new insight as to why their view is failing.
If we assume the developer has /controller/article.cfc and is attempting to call /view/article/dsp_header.cfm, and see:
Error: Undefined Fuseaction 'dsp_header' in Circuit 'article'
they may still be inclined to think their problem somehow lies in /view/article/dsp_header.cfm
However, if the error were to display
Error: Undefined Fuseaction 'dsp_header' in Circuit 'controller.article'
Or even
Error: Undefined Fuseaction 'dsp_header' in Circuit 'article' (implicitly in controller)
I would be comfortable with it providing enough clues to a new developer to help track down the issue and begin to wrap their head around why things work the way that they do in FB 5.