Forcing Cross-Layer Dependencies? You're Doing it Wrong.
There are a few things that frustrate me more as a web developer than finding cross-layer coupling in frameworks. I'm not just refering to 'view' or 'model' layers here… Front-facing parameters, module logic, and data storage structure are all unique layers of an application and should be treated as such. Tightly coupled systems are difficult to maintain, potential security concerns, and expose a deep level of ignorance to contextual logic. Yes, this is going to be a rant.
First, an example to illustrate what a tightly coupled routing system looks like. Here is a particularly nasty snippet of code (slightly modified) that a coworker showed me a few days ago.
// assumes a path like http://domain.com/foo/bar
$uri = $_SERVER['REQUEST_URI'];
$uri = explode('/', $uri);
call_user_func($uri[0], $uri[1]);
With this code you basically are allowing any visitor the ability to run any function and pass in anything they want. If you have a function that calls your database connection, you just allowed all visitors the ability to really mess with your data storage. Sure, this might work if you have some simple logic like domain.com/display_article/5, and your function display_article accepts article IDs, but you are still allowing the visitors full access to your application. You can't just assume things will work the way you want them to.
CakePHP has the same idea, although not as blatent, for their default routing.
// this url
http://domain.com/controller/action/param1/param2/param3
// will trigger this action
Controller::action(param1, param2, param3)
Again, you are allowing full access to your system, even if controllers are a subset of your application. If you want to change your URLs, you need to change your entire controller class. From a SEO level this url does not make sense... param3 is not a subset of param2. This is wrong on so many layers (pun intended).
Security Risks
What's the easiest way to hack a system? Simple: know it. This is the exact reason why I stay away from open source frameworks. If a malicious visitor knows your site uses wordpress than all they know every line of code in your primary structure. The more abstracted out your layers are, especially between front-facing and server-side, the better you mask vulnerabilities. If your URLs and logic structure are a one-to-one match you are asking to be hacked.
Difficult to Maintain
The closer the dependency between layers the more difficult it is to maintain and effectively test either section. Just like the CakePHP example above, if you decided to tweak your URL structure you now need to update your application in several locations. If your database logic is scattered around in the view layers (you pass in models or, even worse, raw mysql results) into view logic and want to change a column name you end up in a world of hurt. In today's world of agile processes and changing development teams each section of logic needs to be flexible and easy to change without worrying about your changes rippling through the entire system.
Semantically Wrong
This reason annoys me the most. Each layer within your application serves a specific purpose within its context. Column names in a database should reflect the value names relative to the table name. Class structure should make sense in regards to their level in the application. Nodes in the HTML should add semantic value to your content, not be structured in such a way that it's easier for CSS and Javascript to interact with it. Each layer in a web application serves a unique and obvious purpose and should be written as such. Enforcing dependencies on one layer because another layer needs it 'to work that way' and you break the natural flow and rhythm.
The Solution
There's no reason why layers need to be tightly coupled. Call it functional design, low coupling, or straight-up mapping, applications can and should be written in such a way that each section exists independent of each other and communicate via standard interfaces. URLs should be interpreted and passed into an appliation through routing systems. Data should be read and passed into views through simple models or even translators. Even small applications can be built with low levels of dependency with basic mappers. If you ever get to the point where you realize that you're writing functionality 'just because this other area needs it like that', take a step back and try to visualize the context of your logic. Don't force it.
Comments (0)