Is Your MVC MIA When it Comes to 404s?
Dealing with missing pages in Web applications.
For those of you who know me, you know that I don't like the term MVC in Web applications and Web frameworks. MVC doesn't really work for stateless HTTP, but that's another story. Sometimes it looks like anybody who uses a template system and a database layer in the same app is suddenly "MVC".
But this post is not about the overuse or misuse of any particular terms. This post is about the consistency of frameworks. Consistency is key to a low learning curve. If all parts of a framework behave the same way, then a developer is less likely to be surprised by behaviors in the framework. Also, I feel that they are less likely to rely on a manual every couple of minutes to look up method names, directory names, etc.
Yesterday, my brother asked me how he could capture 404 errors in Cognifty, as he was building an app that relied on dealing with random URL patterns. He said he tried to use htaccess files and mod_rewrite, but that wouldn't cut it. Given the fact that most, if not all, MVC frameworks use a front-controller pattern, there is never a missing file error (404) at the Apache level. Apache is always finding the index.php file that kicks off the MVC application.
Usually, a request into a PHP framework is something like this
... which gets re-written by mod_rewrite into
The index.php uses the remaining "/some/thing" as instructions for which bit of logic to run. Failing to find the requested code can be akin to not finding a regular page in the traditional Web world, which would result in a 404 error. But, shouldn't we expect a bit more from an advanced Web framework nowadays?
After talking for a bit, we decided that handing off the request to a standard service (or controller) was the best way to handle this type of "error". He started searching to see if other frameworks had a consistent, or at least documented, way of dealing with missing controllers. Some of the frameworks (ZF in particular) treat the missing controller as an error. Whether or not this situation is actually an error depends on your point of view.
If your application is designed to act upon any inbound URL, regardless of whether or not it matches any particular controller file, then treating this condition as an error has its downsides. Triggering an error condition disrupts the regular flow of code, requiring that the end-developer do some more tracing or searching to figure out how to handle this error. Also, the error might trigger a path of execution in the framework that doesn't have all the benefits of a traditional MVC request... events, pre- and post- method handlers, logging, tracking, permissions, templating....
If your application is not designed to handle any random inbound URL, well you might be inclined to treat this sort of condition as a regular error. And that's fine, but treating it as an error only disrupts the flow of code and puts a burden on the programmer to switch mental modes and deal with the error in a new "silo" of thinking.
In Cognifty, when the request runner cannot find a module or service (controller in other systems) that matches the incoming request, it simply adds a new, standard service to the execution stack. That service can do any error handling or reporting that it chooses, but it has the exact same feel as all the other business logic in the system. So, if you choose not to modify it there are no downsides, it will behave just like traditional error handling. But, if you do choose to modify the default behavior, you can do it just like any other business logic in the system; no need to catch errors, or listen for error signals.
This level of consistency reminds me of how Cognifty (and LogiCreate before it) handled 301 and 302 redirects. In most PHP systems you see something like this.
I've always felt that this is horrible. The execution dies right then and there, no clean up can happen by the system if you exit the code in 10 different places in your app. It also makes it hard to profile and refactor.
The LogiCreate/Cognifty way of performing a redirect is to simply change your presentation handler. Displaying the location header is treated the same way as displaying an HTML template:
$this->presenter = 'redirect'; $t['url'] = 'some/thing/else'; return;
Earth-shattering? No. Different from the rest? Definitely.
These micro-revelations about how easy code should be are always what keep me from truly enjoying coding in other frameworks. I'll do it for money if the job requires it, but I can't seem to devote any free time to anything but Cognifty.
Anyone have any insight into how their favorite framework handles 404s?