4 December 2006
Good Application Design
The concept of an “include” is broken. I’ve skirted around the issue at least twice in the last year but it’s time to finally expose this misuse of technology.
HTML is not a programming language. This is a frequently contested assertion, but on it’s most basic level, HTML is not Turing complete. There’s no way to develop another programming language in it. While HTML is code, it is no more programming than a textual DOC file. Through certain extensions to generic web development, namely JavaScript and Server Side Includes, this distinction is blurred: JavaScript is Turing complete and includes enable rudimentary control over dynamic pages. And so many programmers adopt this style as their programming style.
As a programmer matures, they will move from raw HTML to JavaScript-reliant code for certain things like form validation. Eventually, however, a requirement on some project will push them to move that JavaScript validation to the server, and with PHP and ASP especially, they are likely to have a file which validates the data and then mails it or saves it to the database.
The first problem with non-abstracted code is exposed. While validation is a prerequisite for processing data, the two have no real relationship. There are inherently different tasks. “But that’s easy to fix! I’ll just make validation an include.” These are two of the most devastating sentences to an application’s development that can ever be uttered. By simply making a process, a critical process at that, an include, you are forming the entire application around that. You are insisting that certain variables be used, and certain expectations met. You are taking all the negative points of functions and marrying them to all the negative points of monolithic development. And each time your include is reused, you’ve made it that much harder for a future developer to fix your mistake.
If you need to re-use code, make it part of a function. Whether that function is part of a class or just a function, it is designed for your very purpose: to be re-used. It sets up its own namespace, it has discrete inputs and outputs, and as long as it works, programmers who are responsible for debugging your application in years to come can just ignore the inner workings and more quickly move to the source of the problem. Just don’t rely on global variables or try to interact directly with users in your function– then you’re incurring the trouble of setting up a function while neglecting its reusability benefits. And that is, perhaps, even worse than using an include.
By re-factoring your includes into functions and abstracting tasks into separate functions, you make your application faster (by eliminating duplicated code), easier to debug (by quickly determining what does and does not work, and more re-usable (by making each function do nothing more than what it is supposed to). If your application can include any non-content file without changing how the application works, then you’re well on your way to a well-architected system.

