By Sherri Wheeler (Originally published by Zend.com in 2005)
Note: This article does not describe an MVC architecture, but rather an example multi-tiered design.
This article is for experienced web developers and development companies who are looking for a way to move from small applications up to medium to large projects, and are interested in improving the quality of their application design. Any developers currently using a set of distinct web pages for each application function will find in this article a discussion of why a better methodology is needed and how it can be accomplished.
Traditional PC software development has had the benefit of several decades of experimentation, research, and improvement. There is a wealth of literature on how to develop applications based on time-tested principals and methodologies. However, web development is often seen as the immature kid brother of application development and hasn’t been given as much quality attention.
Web programmers are often seen as ‘junior developers’ or amateurs. A big reason for this is that until recently web applications were of a smaller scale, and many web projects are approached in a hack-together fashion without proper pre-planning. This used to be acceptable, but the growing size and scope of today’s web applications demands a more mature and robust approach. The time is fast approaching when web applications will match the scale of PC applications and many inexperienced web developers (and companies) will be left behind.
In this article I will discuss the need for web developers to adopt a more mature design strategy, and an example of an architecture that can form a solid foundation for medium to large scale web applications.
Many medium to large web development projects suffer from one or more of several pitfalls:
- Under-developed or non-existent design paradigm.
- Ad-hoc development strategy.
- Web/HTML dependent business logic.
- Poor scalability.
- Exponential growth of program complexity and maintenance costs.
- Poor or no code re-use within a project or between projects.
- No significant overall improvement from one project to the next.
In my experience using PHP, web development traditionally follows the pattern of creating one ‘page’ for each major action that a program needs to have performed. In the case of a news article manager, at minimum there will be the following pages:
- Form for adding an article.
- Process new article input and save to database.
- Form to edit news.
- Process article edit.
- View a news article.
- View a list of news articles.
- Process the deletion of a news article.
- Multiple pages for login, logout, home, etc.
When a client’s needs for their site are modest… what’s wrong with this ‘set of pages’ approach? With small admin areas for things like news articles or galleries, it’s almost always faster and easier to take the traditional approach or reuse the pages created for a past project. But then the developers get trapped. When a client decides they love this new found control over their online empire, they often want to expand. Manage web-polls? Sure. A database of contacts? No problem. The developers just add the small set of pages needed for each new functionality, easy right? But soon you end up with a monster application, dozens or even hundreds of pages, that form an utterly unmaintainable, unscalable mess. Each of these pages performs it’s own tasks, sometimes taking input and sometimes saving to the database. Each page contains it’s own business logic. There is no separation or encapsulation of any kind. What if they want to grow up to a CMS, CRM or other enterprise scale application? From customer relationship management and analysis tools, to corporate resource systems, the size of online applications is growing fast.
Companies with separate design and development teams, will face the additional problem that if the programmer is working on the business logic and the designer needs to change the interface, they will both be vying for the same file or files. One side will have to wait, and both sides run the risk of editing something they shouldn’t have. A situation like this is a perfect example of the need for separation of presentation and business logic.
Unfortunately, many developers are of the mindset that “it’s only a website”, and that full-blown development strategies don’t need to be applied or aren’t worth the initial overhead, but development companies that are still developing projects the same way they have been for years or even months are falling behind. Each project could potentially bring to the company codebase some new reusable code, and, a learning experience that can improve the way that future projects are developed. However, if each project starts from scratch rather than from an evolving base structure, then the development team is losing productivity by repeating past actions and potentially repeating past mistakes.
The rapid growth of the size of online applications brings concerns of program integrity, expandability, security, and stability, that the old one-page-per-action paradigm can’t address. This is where a multi-tiered system with complete data encapsulation becomes necessary. While it requires a greater amount of pre-planning and setup work, the benefits far outweigh the initial overhead.
Developers first need to build a base structure that can optimize repeated tasks. What really changes from project to project? What can be reused? Each development project often has similarities to past projects and all of the features such as login authentication, database interaction, error handling, debugging, application profiling, function libraries, etc. should form the base structure that each development project grows out of. Even your project directory structure should already be created for you, and common website functions like contact-forms, galleries, article managers, forums, polls, etc can be reused from past projects in a simple plug and play fashion. Developing your reusable codebase involves more than just hunting through past projects to find anything that could be handy. Developers should actively design functions and modules to be reusable; don’t hard-code client specific data, design functions to perform useful rather than specific tasks, etc. Further information on developing code for reuse is available online and discussed in several books.
Once the existing codebase has been pruned, cleaned, tested and organized, it has to be assembled. It has to work together in a common structure. The form this structure will take depends on the design paradigm that the company or developer decides to go with. Object oriented? Multi-tiered? Do your research and know what you’re doing before you invest the time to put it all together. This is where a style guide is a must to ensure your programmers are following the same coding formats and standards.
This base structure will be the starting point of most new projects, and in each situation you may find ways to improve or expand it. The collection of useful modules available will grow and the system should continuously become more efficient, elegant, and error free. Soon you will find that your development time for each project drops significantly as the development team becomes familiar with the new system, and time wasted redeveloping existing functionality is eliminated.
In addition to the benefits of code reuse, improvement and ease of maintenance and growth, there is another concern that many web developers overlook but application developers have been dealing with and studying for decades. Data encapsulation and multi-tiered design go hand in hand. If you can separate your user interface interaction code from your data storage and business logic code, you’ll have a more robust, stable system that is capable of handling major changes.
Still don’t know where to start? Follow your chosen design paradigm, but keep in mind that you are developing for the web. HTML is NOT data. It’s the formatting of data. Don’t store it in your database, and don’t let your business logic touch it. How you encapsulate your data and how you develop your interfaces will again depend on your design strategy and personal preference. Below I will briefly explain a design model as an example.
There have been many, many papers and books written on various design paradigms and models, and here I will describe one that I have used to great benefit. It is an evolution of existing paradigms that has been adapted for web applications in PHP and has evolved on it’s own from project to project.
+============================+ | User Interface (Browser) | +============================+ ^ | output| | | |input | v +------------------------------+ | User Interaction Handler | | (UI Model Layer) | +------------------------------+ ^ | | Interaction (Encapsulation Boundary) | v +------------------------------+ | Data Controller | | (Business Logic Layer) | +------------------------------+ ^ | output| | | |input | v +............................+ | Abstraction Layer(s) | +============================+ | Data Store(s) | | (Database/Filesystem) | +============================+
As shown in diagram 1, this model creates a separation of the web-dependent concerns from the business logic and data storage. All interaction with the user interface is handled by the User Interaction Handler via HTML pages. These pages are generated dynamically from HTML templates that are free of any business logic. There are several templating engines available for PHP. The User Interface Handler presents the HTML templates and populates them with data as needed. All handling of HTML or web-dependent data structures happens here. When a user performs a specific action, the correct UI Handler is called. It sanitizes the HTML input and creates a data object defined as a class in the Data Controller Layer. The UI Handler converts all data from the HTML forms into their correct data types, performs some minor data checks and passes the data to the data object, or receives data from the data object.
The data object does not handle HTML. Each object has specific, typed, input variables that it is expecting and will perform error checking based on this. Your form data for “age” should already be an integer before it is passed to the data object. The data object checks for required fields or performs other business logic, and stores the information or retrieves it from the database though a database abstraction layer (again several are available for PHP). Errors are populated back to the UI Handler which formats data into HTML and presents it to the user via an HTML template.
The key concerns here are that the User Interaction Handler never touches the database. It doesn’t know or care how or in what representation the data is stored. The data object never touches HTML. It doesn’t use the GET or POST arrays either. These should be converted as needed to be passed to the object, or the whole GET or POST array can be passed in which case the data object should expect an array of strings. The data object is ignorant of the fact that it is doing it’s work for a website.
Each time a new module is added to the system such as a news manager, a new data object class is created (such as NewsArticle) and a set of functions in the UI Handler are created for each action on that News object (for example create, edit, view, sort, delete, etc.). Each action will have one or more corresponding methods in the NewsArticle class.
I have shied away from providing source code or a more detailed explanation for a very important reason. Copying someone else’s model will not help you. A system like this should be researched and evolved to match your specific needs. It should be VERY well documented, and should evolve with your company. A knowledge of design paradigms is a must, and a commitment to the initial overhead of developing such a codebase will be required. In the end it will pay off with a streamlined development process and a continuously improving business model.
The paradigm described previously is just one of many that can be adopted. The important concern is to find one that’s best for you and mold it to your needs. From one project to the next, the basic framework can be improved and evolved, reusable code can be added to libraries available in the framework, and development time will speed up drastically while maintenance time drops. Bugs found in one project can quickly and easily be identified in other projects; and future projects won’t suffer from bugs that have already been addressed.
A sound design paradigm and a serious commitment to code reuse is a must if companies plan to stay competitive. PHP lends itself perfectly to this philosophy, and can be scaled to larger applications easily through sound programming practices. It’s popular association with only simple projects is a symptom of it’s ease of use, and the failure of the web development industry to push itself to improve. The key goal is to bring the maturity and experience of application design to the rapidly growing area of web development.
The traditional approach to web development involves programmers creating a PHP/HTML page for each ‘function’ that their application will perform. Each page might perform input, business logic, or output in any combination. This design paradigm suffers from many problems including poor scalability, non-reusable code, and no logic separation.
This presents a problem for companies and developers interested in moving to larger projects. It traps developers into starting each new project from scratch, or reusing the ‘pages’ from past projects in an application that can quickly grow to a large unmanageable collection of unrelated files. Maintenance and scalability suffers and development doesn’t improve from one project to the next.
Implementing a design methodology that will create a modularized, and encapsulated base code structure that can be re-used and improved for each new application is an important concern that has been studied in the context of PC applications but seems to be getting only passing attention from web developers.
The need to apply mature design principles that are currently used in other areas of software development is a growing concern for the web development industry, and will play a major role in companies who plan to tackle the larger web applications that are increasingly demanded by today’s clients.