In theory, developing software applications that use concurrent and networked services can improve system performance, reliability, scalability, and cost-effectiveness. In practice, however, developing efficient, robust, extensible, and affordable concurrent and networked applications is hard, due to key differences between stand-alone and networked application architectures.
In stand-alone application architectures, user interface, application service processing, and persistent data resources reside within one computer, with the peripherals attached directly to it. In contrast, in networked application architectures, interactive presentation, application service processing, and data resources may reside in multiple loosely-coupled host computers and service tiers connected together by local area or wide area networks.
A network of X-terminals and `thin client NetPCs' is an example of a networked system architecture. In this environment, user interface presentation is handled by a display service on end-user hosts. The processing capabilities are provided by host computer(s) on which all or part of application services run. Access to persistent resources is mediated by one or more network file servers. Other services, such as naming and directory services, time services, HTTP servers, and caches and network management services, can run in the network and provide additional capabilities to applications.
There are three common reasons to adopt a networked architecture:
- Collaboration and connectivity. The explosive growth of the Web and e-commerce exemplify one of the most common reasons for networking: the ability to connect to and access vast quantities of geographically-distributed information and services. The popularity of the instant messaging and `chat rooms' available on the Internet underscores another common networking motivation: staying connected to family, friends, collaborators, and customers.
- Enhanced performance, scalability, and fault tolerance. The performance and scalability of a networked architecture may be enhanced by taking advantage of the parallel processing capabilities that are available in a network. For example, multiple computation and communication service processing tasks can be run in parallel on different hosts. Similarly, various application services can be replicated across multiple hosts. Replication can minimize single points of failure, thereby improving the system's reliability in the face of partial failures.
- Cost effectiveness. Networked architectures yield decentralized and modular applications that can share expensive peripherals, such as high-capacity file servers and high-resolution printers. Similarly, selected application components and services can be delegated to run on hosts with specialized processing attributes, such as high-performance disk controllers, large amounts of memory, or enhanced floating-point performance.
Although networked applications offer many potential benefits, they are harder to design, implement, debug, optimize, and manage than stand-alone applications. For example, developers must address topics that are either not relevant or are less problematic for stand-alone applications in order to handle the requirements of networked applications. These topics include:
- Connection establishment and service initialization
- Event demultiplexing and event handler dispatching
- Interprocess communication (IPC) and network protocols
- Primary and secondary storage management and caching
- Static and dynamic component configuration
- Concurrency and synchronization
These topics are generally independent of specific application requirements, so learning to master them helps to address a wide range of software development problems. Moreover, in the context of these topics many design and programming challenges arise due to several inherent and accidental complexities associated with concurrent and networked systems:
- Common inherent complexities associated with concurrent and networked systems include managing bandwidth [ZBS97], minimizing delays (latency) [SC99] and delay variation (jitter) [PRS+99], detecting and recovering from partial failures [CRSS+98], determining appropriate service partitioning and load balancing strategies [IEEE95], and ensuring causal ordering of events [BR94]. Similarly, common inherent complexities found in concurrent programming include eliminating race conditions and avoiding deadlocks [Lea99a], determining suitable thread scheduling strategies [SKT96], and optimizing end-system protocol processing performance [SchSu95].
- Common accidental complexities associated with concurrent and networked systems include lack of portable operating system APIs [Sch97], inadequate debugging support and lack of tools for analyzing concurrent and networked applications [LT93], widespread use of algorithmic--rather than object-oriented--decomposition [Boo94], and continual rediscovery and reinvention of core concepts and common components [Kar95].
By studying and applying patterns and pattern languages, developers can often resolve hard problems in their domain effectively and escape traps and pitfalls, such as accidental complexities, that have been avoided traditionally only via long and costly apprenticeship [PLoPD1].
Until recently [Lea99a] patterns for developing concurrent and networked software existed only in programming folklore, the heads of expert researchers and developers, or were buried deep in complex source code. These locations are not ideal, for three reasons:
- Re-discovering patterns opportunistically from source code is expensive and time-consuming, because it is hard to separate the essential design decisions from the implementation details.
- If the insights and rationale of experienced designers are not documented, they will be lost over time and thus cannot help guide subsequent software maintenance and enhancement activities.
- Without guidance from earlier work, developers of concurrent and networked software face the Herculean task [SeSch70] of engineering complex systems from the ground up, rather than reusing proven solutions.
As a result many concurrent and networked software systems are developed from scratch. In today's competitive, time-to-market-driven environments, however, this often yields non-optimal ad hoc solutions. These solutions are hard to customize and tune, because so much effort is spent just trying to make the software operational. Moreover, as requirements change over time, evolving ad hoc software solutions becomes prohibitively expensive. Yet, end-users expect--or at least desire--software to be affordable, robust, efficient, and agile, which is hard to achieve without solid architectural underpinnings.
To help rectify these problems, this book documents key architectural and design patterns for concurrent and networked software. These patterns can and have been applied to solve many common problems that arise when developing object-oriented middleware frameworks and applications. When used as a documentation aid, these patterns preserve vital design information that helps developers evolve existing software more robustly. When used as a design aid, the patterns help guide developers to create new software more effectively.
Of course, patterns, objects, components, and frameworks are no panacea. They cannot, for example, absolve developers from responsibility for solving all complex concurrent and networked software analysis, design, implementation, validation, and optimization problems. Ultimately there is no substitute for human creativity, experience, discipline, diligence, and judgement.
When used properly, however, the patterns described in this book help alleviate many of the complexities enumerated earlier. In particular, the patterns
- Direct developer focus towards higher-level software application architecture and design concerns, such as the specification of suitable service access and configuration, event processing, and threading models. These are some of the key strategic aspects of concurrent and networked software. If they are addressed properly, the impact of many vexing complexities can be alleviated greatly.
- Redirect developer focus away from a preoccupation with low-level operating system and networking protocols and mechanisms. While having a solid grasp of these topics is important, they are tactical in scope and must be placed in the proper context within the overall software architecture and development effort.