Chapter 1. Change Begets Change

The entrepreneur always searches for a change, responds to it, and exploits it as an opportunity.

Peter Drucker

What kinds of changes encourage developers to adopt a client-server approach? Shifts in user behavior, technology, and software development process are the significant forces that have driven developers to change their patterns of design. Each of these factors, in a unique and significant way, makes established patterns obsolete. Together they have encouraged related innovations and a convergence in practice despite the absence of enforcement or mandated standardization.

Web users have changed. In the early days of the Web, users were satisfied with static pages and primitive user interfaces. The modern web user has come to expect a high-performance, interactive, well-designed, dynamic experience. These higher expectations were met with an explosion in new technologies and expansion of web browser capabilities. Today’s web developer needs to use tools and a development approach that are aligned with the modern web scene.

Technology has changed. Browsers and JavaScript engines are faster. Workstations and laptops are far more powerful, to say nothing of the plethora of mobile devices now being used to surf the Web. Web service APIs are the expectation for a modern web application rather than a rare additional feature. Cloud computing is revolutionizing the deployment and operation of web applications.

Software development has changed. The now popular “Agile Manifesto” values:

  • Individuals and interactions over processes and tools
  • Working software over comprehensive documentation
  • Customer collaboration over contract negotiation
  • Responding to change over following a plan

It is now possible to quickly spin up web applications that prove—at least on a small scale—the viability of a given technology. There is tremendous value to prototyping. As Fred Brooks, author of The Mythical Man Month (Addison-Wesley Professional), famously stated: “Plan to throw one away; you will, anyhow.” A prototype can allow for early customer or end user interaction that helps solidify requirements early in the process. It is no longer an insurmountable task to write a functional web application in a matter of minutes.

Web Users

Modern web application users have well-defined expectations about how they will be able to interact with a web application:

  • Web applications will be available across multiple platforms.
  • They will provide a consistent experience across devices.
  • They will respond with little or no latency.

The Gartner group claims that in 2014, the personal cloud will replace the PC at the center of users’ digital lives. There are many implications for web app development. Users are more technologically savvy and have high expectations for site responsiveness. They are less passive than in previous years and instead are interactive and engaged. Websites need to be designed in a way that suggests no limitations in the ability of a browser to mimic native application experience.

Users expect an application to be exposed in various ways and available in different situations. Responsive design and support for multiple browsers, platforms, and devices are the new norm. The use of JavaScript libraries and frameworks is essential to support the wide variety of target clients.

The New York Times recently reported on the impatience of web users. Among its findings: a company’s website will be visited less often than that of a close competitor if it is slower by more than 250 milliseconds. Performance needs to be a key consideration in web application development.

Technology

Java web application developers are typically familiar with server-side dynamic content. J2EE and JSP have been refined into JEE and JSF. Projects such as Spring provide additional capabilities geared toward server-side development. This mode of development made a great deal of sense in the early days of the Web, when web pages were relatively static, servers were relatively fast, JavaScript engines were slow, and there were few libraries and techniques to address browser incompatibilities.

By way of contrast, a modern client-server approach involves a server largely responsible for providing access to resources (typically communicated as messages in XML or JSON) in response to client requests. In the old server-driven approach, the browser requested an entire page and it was generated (along with relevant data) for rendering in the browser. In the client-server approach, the server initially serves pages with little data. The pages make asynchronous requests to the server as the user interacts with it and the server simply responds to these events with messages that cause the current page to be updated.

Initial web development efforts consisted of the creation of static HTML sites. Later, these sites were augmented with dynamic content using server-side processing (CGI, Java Servlets). Subsequently, more structured language integration emerged using server-side templating (ASP, PHP, JSP) and MVC frameworks. More recent technologies continue in the same tradition and provide additional abstractions of one sort or another.

Based upon a desire to shield developers from design concerns and the underlying architecture of the Web, component-based frameworks have emerged. Tag libraries were an early innovation, and now a component-based approach has been widely adopted in several popular frameworks:

  • Java Server Faces (JSF), an XML-based templating system and component framework with centralized configurable navigation.
  • The Google Web Toolkit is another component framework that leverages the abilities of Java programmers by letting them focus on Java coding with little need to directly modify HTML, CSS, or JavaScript.

Each of these frameworks has its place and has been used successfully in production systems. But like many solutions that try to hide underlying complexities, their usage is problematic in situations where you need greater control (such as the ability to integrate large amounts of JavaScript) or you do not conform to the framework assumptions (for instance, availability of server sessions). This is because these solutions attempt to hide the fundamental architecture of the Web, which uses an HTTP request-response protocol following the client-server computing model.

Browser innovations also led to a shift of responsibility from the server to the client. In the late 1990s, Microsoft developed the underlying technologies that led to Ajax (a term coined on February 18, 2005 by Jesse James Garrett). Ajax is an acronym for “asynchronous JavaScript and XML,” but is more generally applied to various technologies used to communicate with the server within the context of a given web page. This allowed small messages to be sent, which made better use of bandwidth when designing JavaScript-based web applications. Browser performance has increased significantly due to processor improvements and optimizations to JavaScript engines, so it has made sense to offload more work from the server to the browser. User interface responsiveness has evolved to a new level of sophistication.

Mobile device browsers have also provided an additional incentive to further isolate client-side code from the server. In some cases, a well-designed application leveraging responsive design principles can be created. If this is not an option, a single consistent API available for all device clients is very appealing.

Roy Fielding’s doctoral dissertation in 2000 led Java EE 6 to new APIs that deviated from the previous component-based trajectory. JAX-RS (Java API for RESTful Web Services) and Jersey (a “production quality reference implementation”) are designed to create applications reflecting a client-server architecture with RESTful communications.

Software Development

In the past, setting up a new Java project was a rather monumental task. A vast array of configuration options made it tedious and error-prone. Very little was automated, as the assumption was that each project would have unique characteristics that developers would want to account for to meet their specific requirements.

Later influences led to innovations that made setting up a project much simpler. “Convention over configuration” was an influential mantra of the Ruby on Rails community. Maven and other Java projects also chose sensible defaults and target easy setup for a subset of popular use cases.

The availability of scripting languages on the JVM makes it possible to speed development by bypassing the somewhat rigorous type checking of Java. Languages like Groovy, Python (Jython), and Ruby are loosely typed and constructed in a manner that requires less code to accomplish equivalent functionality. So-called microframeworks like Sinatra or Play provide minimal Domain Specific Languages (DSLs) to quickly write web applications and services. And so today, it is a trivial task to set up a minimal set of web services in a development environment.

The failure of enough large-scale waterfall-style software projects has also made it clear that there are many advantages to producing a small-scale version of the final product. A prototype (or prototypes) of the final product can serve many purposes:

  • Verify technical foundation of the project
  • Create constructs that bridge disparate technologies to be used together
  • Allow end user interaction to clarify intended usage and user interface design
  • Allow system designers to clarify the interfaces and data structures to be passed between systems
  • Allow programmers to work on different parts of the application in parallel

Prototypes have numerous benefits:

  • They are a specific, tangible asset representing the final system to be designed. As such, they incorporate information that is otherwise stored in design documents, diagrams, and other artifacts (and frequently in more informal locations like email and people’s memories of water-cooler conversations).
  • Prototypes are concrete implementations. As such, they present the requirements in a much more tangible form. This can lead to a better understanding of the extent and quality of the requirements gathered, and can suggest areas where there is need of clarification.
  • Prototypes can immediately expose potential points of failure that are not apparent before attempting a specific implementation.
  • The preceding benefits can lead to better estimates and scheduling due to a more comprehensive understanding of what is intended.

Prototyping can be leveraged extensively in client-server web application development because of the clear and unambiguous separation between the client and server. Prototypes of the server can be provided to the client developers (and vice versa) while development proceeds in parallel. Or if development is not proceeding in parallel, server-side calls can be quickly stubbed out so that client-side code can be developed.

What Has Not Changed

The fundamental nature of the Web (a client-server architecture transmitted over HTTP) has not changed.

New technology does not change everything. High-level programming languages have not removed the need to understand operating system specifics. Object-relational mapping frameworks have not removed the need to understand relational databases and SQL. In like manner, there have been consistent attempts to ignore the underlying architecture of the Web in an effort to emulate the experience of desktop applications.

The Nature of the Web

The essence of the Web has not changed. It is still made up of servers that serve HTML documents to clients via the HTTP protocol. See Figure 1-1.

HTTP request and response
Figure 1-1. HTTP request and response

A client-server web architecture more closely maps to the underlying architecture of the Web itself. Although not technically protocol-specific, REST was developed based upon and in conjunction with HTTP. REST essentially defines constraints on the usage of HTTP. It seeks to describe a well-designed web application: a reliable application that performs well, scales, has a simple elegant design, and can be easily modified (Figure 1-2).

REST request and response
Figure 1-2. REST request and response

In fact, to more accurately emphasize the challenges in the modern web environment, we need to consider multiple devices and cloud deployments. See Figure 1-3.

Multiple devices and cloud deployments
Figure 1-3. Multiple devices and cloud deployments

The specific area of “medium specificity” that has been ignored in web development in general (and in component frameworks in particular) is the stateless, client-server nature of the Web itself.

Server-Driven Web Development Considered Harmful

Just because a given feature is available does not mean that it should be used. In many cases, a server-driven, component-based approach to web development should be replaced with a client-server one. Server-driven approaches obscure the nature of the Web itself, which is a client-server technology built on the HTTP protocol. Ignoring or obscuring the fundamental underlying architecture of the Web makes development, debugging, and support of software systems more difficult. The intention, to make the Web somehow simpler or easier to understand, breaks down rather quickly in any nontrivial system where there needs to be a clear understanding what functionality is available and how the system actually works.

Why Client-Server Web Applications?

There are a number of advantages to a client-server approach to web development.

Code Organization/Software Architecture

There are clear advantages to being able to decouple logical sections of code and promote higher cohesion both in the original construction and ongoing support of any system. The clear separation between client and server tiers makes for manageable, modular sections of code. In addition, data and display markup can be more clearly separated. The data can be delivered in JSON rather than inline. This is consistent with the modern JavaScript notion of unobtrusive JavaScript where a page’s behavior, structure, and presentation are separated.

Flexibility and code reuse are a logical outcome of good code organization. There is flexibility at many stages in the application life cycle when sections of code can be developed in relative isolation (APIs can be exposed, mobile device clients created, new versions of sections of the application tested and released independently). Code reuse is more likely when there are clear components. At minimum, the same RESTful APIs can be used to serve data to a wide variety of browsers and mobile devices.

Component approaches tend to introduce brittle coupling and are less adaptable. There is no way to plug in a different frontend easily.

Flexibility of Design/Use of Open Source APIs

Component-based approaches include tightly integrated server-side code that requires specific JavaScript technology. They also generate HTML and CSS that limits the options available from a design and behavior perspective. A distinct client running JavaScript can take advantage of the latest libraries that ease browser compatibility, standardize DOM manipulation, and provide complex widgets.

Prototyping

Prototyping works well with client-server web applications due to the clear separation between tiers. As previously mentioned, prototypes can test and verify initial ideals. They help clarify vague notions and facilitate clear communication regarding requirements. They can inspire and generate new ideas as people interact with something more concrete than a long text description or a series of pictures. Bad ideas and inconsistencies can be quickly recognized and eliminated. Used correctly, prototypes can save time, money, and resources and result in a better final product.

Developer Productivity

Besides the ability to prototype either the client portion or the server component (or both), work can be split clearly, and development can progress in parallel. The separation allows sections of code to be built in isolation. This prevents the problem in component approaches where a server build is required every time a page is changed during development. Development tasks require less time and effort, changes are less complex, and troubleshooting is simplified.

This is especially evident when a need arises to replace, upgrade, or relocate server-side code. Such changes can be done independently, without affecting the client. The only limitation is that the original interface, specifically the URL and message data structure, must remain available.

Application Performance

User experience is greatly impacted by the perceived performance of a page in the browser. Faster JavaScript engines allow the client to perform computationally intensive operations so server workload can be effectively offloaded to the client. Ajax requires relatively small amounts of data to be retrieved when needed so full page reloads can occur infrequently and less data is sent in the intervening requests. Users perceive a snappier, more immediate response as they interact with an application.

There are many benefits to stateless design that ease the lives of developers and support staff. Resources dedicated to session management can be freed up. This simplifies load-balancing and configuration that would otherwise be required. Servers can be easily added to accommodate increased load allowing for horizontal scalability. This replaces the unwieldy process of hardware upgrades traditionally used to increase throughput and performance.

The benefits even extend to the simplification of the overall architecture of a system. For instance, problems related to maintaining state are extremely challenging in a cloud-based environment. When using traditional stateful sessions, it is challenging to efficiently persist data so that it is readily available across multiple requests within a user’s session. If data is stored on a backend server, subsequent requests directed to different servers will not have access to it. Possible solutions include:

  • Use an application server that supports clustering and failover. Weblogic uses the concept of managed servers, for instance. These solutions require additional management and vary in each application server implementation.
  • Use session affinity or sticky sessions. In this scenario, all requests within a user session are sent to the same backend server. This does not provide automatic failover.
  • Utilize a separate centralized data store. Typically this involves persisting data in a database. This option may not provide the best performance.
  • Store the data on the client side. This avoids the performance problems associated with storing session data in a database as well as the failover issues with sticky sessions. This is because any backend server can handle each client’s request.

The move toward avoiding server-side state management is becoming more prevalent. Even a framework like JSF, which is designed for the traditional server-side management of user sessions, is adding features to allow for stateless functionality.

There are a few inherent challenges with creating client-server applications. It is necessary to embrace JavaScript as a first-class development language in its own right. This means learning the language in some depth, utilizing available libraries, and adopting mature development techniques. Areas of application architecture that were previously generally accepted require a different design, such as standard practices regarding session management. There is no carefully defined standard for client-server web applications. Certain parts of JEE, such as JAX-RS, provide some clarification; others such as JSF do not apply.

Beyond the initial learning (and unlearning) curve, a client-server approach for building web applications is extremely effective and stable. The clear separation of responsibilities between client and server allow for easy modification extension to a code base. A recognition of the essential nature of the Web reduces problems that result from attempting to obscure its design. The capacity for horizontal scalability far exceeds what is possible using other patterns of design.

Conclusion

New challenges and developments afford new opportunities. A client-server web application design is a natural response that recognizes and accounts for the changes to the Web and web development. And it does so in a way that recognizes what has not changed, and so can allow for development of stable, enduring solutions that are well-positioned for future enhancements.

Get Client-Server Web Apps with JavaScript and Java now with the O’Reilly learning platform.

O’Reilly members experience live online training, plus books, videos, and digital content from nearly 200 publishers.