At the outset, it’s important to establish why the techniques that we’re going to explore in this book are especially useful for web developers working on large web applications. We’ll begin by looking at some of the factors that contribute to the complexity of many large web applications. Then we’ll explore how modularity plays an important role in managing this complexity. Last, we’ll examine a list of tenets that will guide our discussions throughout the rest of the book.
If you consider how different the Internet is today from just 10 years ago, it’s clear how complicated web applications have become and just how quickly the changes have taken place. Far too often, this complexity makes large web applications difficult to maintain, less reliable, and more costly over their lifetimes. Let’s examine some factors that contribute to the complexity of many large web applications. Typically, large web applications have the following characteristics:
Large web applications usually have large numbers of users. This necessitates management of a large number of simultaneous connections or layers of caching. Web developers often need to write code to manage these situations.
Whereas many types of software are distributed as complete units, web applications have many parts delivered page by page, or connection by connection via Ajax. As a result, large web applications operate within an environment effectively shared by a huge number of users.
It’s hard to think of a business or service that doesn’t have at least some sort of web interface. For example, we see financial applications, ticketing sites, applications that organize massive amounts of data (e.g., search engines), media systems (e.g., news sites), and the list goes on. Web developers need to write code that may be reused in unexpected places.
The largest web applications today, even those that have been around many years, are just at the beginning of their lifetimes. Web developers need to write code under the assumption that it will have to stand up to years of changes and maintenance.
The Web is a fast-changing landscape littered with old browsers and other devices that can be difficult to support. Users access large web applications from all types of environments and with screens of wildly different sizes (including mobile devices). Web developers must write code that can handle the numerous idiosyncrasies that result from this.
Large web applications are not static; they are constantly fluctuating applications for which changes are typically pushed to servers regularly. Web developers need to write code to address this potential for moving parts.
Over time, web developers often end up addressing complexity in large web applications via one-off fixes and tweaks as their applications reach various breaking points. But there is a better way. This book will show you how to address challenges like the ones above head-on from the start. Mitigating the complexity from these challenges can often be attributed to one or more byproducts of modularity that we’ll examine in a moment. For example, I stated above that large web applications need to be available all the time. From the perspective of the web developer, this is an issue of reliability, which modularity plays a key role in addressing.
In a large web application, to address complexity with modular components, or modules, you need to encapsulate everything the component needs within small, well-defined pieces of the application. This allows you to divide a large application into more manageable pieces that you can build with a specific focus and reuse wherever needed. In addition, you hide (or abstract) the implementation details of each module and take steps to ensure each module can operate more or less independently of the others. Even relatively small web applications can benefit from such modularity. After all, the small web applications of today are the Googles, Yahoo!s, and Amazons of tomorrow. Building web applications in a modular way at the start provides a solid foundation for future growth.
You achieve modularity in large web applications, as in other types of software, through encapsulation, abstraction, and maintaining as much of a loose coupling as possible among an application’s modules.
Abstraction is the process of hiding details that should not be observable when working with a module from outside its implementation. Defining a good interface is the key to abstraction. Web applications present special challenges because HTML is not built for hiding information in the manner that many languages enforce and because CSS cuts across module boundaries, or cascades, and must therefore be managed rigorously. Chapter 7 shows how object-oriented PHP can be used to define interfaces that abstract the details of working with sections of HTML and CSS. Data managers, presented in Chapter 6, are good examples of interfaces that abstract working with dynamic data managed by the backend.
A loose coupling between modules means that one depends on the other as little as possible and only in clearly defined ways. In Chapter 2, you’ll see that it’s relatively easy to create a dependency graph that depicts the dependencies among objects in an object-oriented system. When object orientation is used to implement modules in a large web application, it’s easier to notice how changes to one part of a system may affect another. The techniques presented for modular HTML and CSS in Chapters 3 and 4 also promote loose coupling.
Once you create modules that take advantage of encapsulation, abstraction, and loose coupling, you’ll have better reusability, maintainability, and reliability across your entire web application. When a module is reusable, it’s clear how to make it operate and do new things. You can move it from place to place in the application with the confidence that everything it needs to work properly will come with it, and that you won’t experience unexpected consequences when you reuse the module. When a module is maintainable, it’s clear which area of the application you need to change to affect certain features and how to make the changes. Modules that are easy to maintain are more reliable because they reduce the risk of side effects when changes take place.
With an eye toward modularity, we’ll use the list of tenets in this section to guide our discussions in the chapters that follow. A tenet is a principle or belief that we will accept as true—that is, it’s an assertion. A quick read-through of this list will provide you with a high-level understanding of where we’ll be heading. Later, you may find this list to be a concise reminder of the concepts we’ve discussed. Each tenet is examined in the chapter with the corresponding number. For instance, Tenet 4 describes the robust use of CSS, and Chapter 4 shows how to apply this tenet when implementing your CSS.
Large-scale HTML is semantic, devoid of presentation elements other than those inherent in the information architecture, and pluggable into a wide variety of contexts in the form of easily identifiable sections.
Large-scale CSS forms a layer of presentation that is separate from the information architecture, applied in a modular fashion, and free of side effects as we reuse modules in various contexts.
Dynamic data exchanged between the user interface and the backend is managed through a clearly defined data interface. Pages define a single point for loading data and a single point for saving it.
Large-scale Ajax is portable and modular, and it maintains a clear separation between data changes and updates to a presentation. Data exchange between the browser and server is managed through a clearly defined interface.
The organization of files on the server for a large web application reflects the architecture of the application itself, including clearly demarcated scopes in which each file will be used.