Frameworks not only save money, but also improve the quality of your software. Check out how OO-frameworks can be applied to networked applications, while comparing them to other popular software development techniques.

This chapter is from the book

Object-oriented frameworks help reduce the cost and improve the quality of
networked applications by reifying software designs and pattern languages that
have proven effective in particular application domains. This chapter
illustrates what frameworks are and compares them with other popular software
development techniques, such as class libraries, components, patterns, and
model-integrated computing. It then illustrates the process of applying
frameworks to networked applications and outlines the ACE frameworks that are
the focus of this book. These frameworks are based on a pattern language [POSA1,
POSA2] that has been applied to thousands of production networked applications
and middleware worldwide.

1.1 An Overview of Object-Oriented Frameworks

Even as computing power and network bandwidth increase dramatically, the
development of networked application software remains expensive, time consuming,
and error prone. The cost and effort stems from the growing demands placed on
networked software, as well as the continual rediscovery and reinvention of core
software design and implementation artifacts throughout the software industry.
Moreover, the heterogeneity of hardware architectures, diversity of OS and
network platforms, and stiff global competition makes it increasingly hard to
build high-quality networked application software from scratch.

The key to building high-quality networked software in a
time-to-market-driven environment is the ability to reuse successful software
designs and implementations that have already been developed. Reuse has been a
popular topic of debate and discussion for over 30 years in the software
community [McI68]. There are two general types of reuse:

Opportunistic reuse, in which developers cut and paste code from
existing programs to create new ones. Opportunistic reuse works in a limited way
for individual programmers or small groups. It doesn't scale up across
business units or enterprises, however, and therefore doesn't significantly
reduce development cycle time and cost or improve software quality. Worse,
opportunistic reuse can actually impede development progress since cut-and-paste
code often begins to diverge as it proliferates, forcing developers to fix the
same bugs multiple times in multiple places.

Systematic reuse, which is an intentional and concerted effort to
create and apply multiuse software architectures, patterns, frameworks, and
components throughout a product line [CN02]. In a well-honed systematic reuse
process, each new project leverages time-proven designs and implementations,
only adding new code that's spe-cific to a particular application. This
type of reuse is essential to increase software productivity and quality by
breaking the costly cycle of rediscovering, reinventing, and revalidating common
software artifacts.

Middleware [SS02] is a class of software that can increase systematic
reuse levels significantly by functionally bridging the gap between the
end-to-end functional requirements of networked applications and the underlying
operating systems and network protocol stacks. Middleware provides capabilities
that are critical to networked applications because they automate common network
programming tasks. Developers who use mid-dleware can therefore program their
networked applications more like stand-alone applications, rather than wrestling
with the many tedious and error-prone details associated with low-level OS event
demultiplexing, message buffering and queueing, marshaling and de-marshaling,
and connection management mechanisms. Popular examples of middleware include
Java virtual machines (JVMs), Enterprise JavaBeans (EJB), .NET, the Common
Object Request Broker Architecture (CORBA), and the ADAPTIVE Communication
Environment (ACE).

Detecting and recovering from transient and partial failures of networks
and hosts in an application-independent manner

Minimizing the impact of latency and jitter on end-to-end application
performance

Determining how to partition a distributed application into
separate component services

Deciding where and when to distribute and load balance
services in a network

Since reusable middleware is inherently abstract, it's hard to validate
its quality and to manage its production. Moreover, the skills required to
develop, deploy, and support reusable networked application middleware have
traditionally been a "black art," locked in the heads of expert
developers and architects. These technical impediments to systematic reuse are
often exacerbated by a myriad of nontechnical impediments [Hol97], such as
organizational, economic, administrative, political, sociological, and
psychological factors. It's therefore not surprising that significant
levels of software reuse have been slow to materialize in many projects and
organizations [Sch00].

While it's never easy to make reuse work universally, we've led the
development of powerful host infrastructure middleware called ACE
that's designed specifically with systematic reuse in mind. During the past
decade, we've written hundreds of thousands of lines of C++ code while
developing and applying ACE to networked applications as part of our work with
dozens of telecommunication, aerospace, medical, and financial services
companies. As a result of our experience, we've documented many patterns
and pattern languages [POSA2, POS00] that have guided the design of reuseable
middleware and applications. In addition, we've taught hundreds of
tutorials and courses on reuse, middle-ware, and patterns to thousands of
developers and students. Despite the many technical and nontechnical challenges,
we've identified a solid body of work that combines advanced research,
time-proven design knowledge, hands-on experience, and software artifacts that
can significantly enhance the systematic reuse of networked application
software.

At the heart of this body of work are object-oriented frameworks [FJS99b, FJS99a],
which are a powerful technology for achieving systematic reuse of networked
application software.1 Below, we describe the
three characteristics of frameworks [JF88] that help them to achieve the important
networked application qualities listed on page xi. Figure
1.1 (page 4) illustrates how these characteristics work together.

A framework provides an integrated set of domain-specific structures and
functionality. Systematic reuse of software depends largely on how well
frameworks model the commonalities and variabilities [CHW98] in application
domains, such as business data processing, telecom call processing, graphical
user interfaces, or distributed object computing middleware. Since frameworks
reify the key roles and relationships of classes in application domains, the
amount of reusable code increases and the amount of code rewritten for each
application decreases.

A framework exhibits "inversion of control" at run time via
callbacks. A callback is an object registered with a dispatcher that
calls back to a method on the object when a particular event occurs, such as a
connection request or data arriving on a socket handle. Inversion of control
decouples the canonical detection, demultiplexing, and dispatching steps within
a framework from the application-defined event handlers managed by the
framework. When events occur, the framework calls back to virtual hook
methods in the registered event handlers, which then perform
application-defined processing in response to the events.

Since frameworks exhibit inversion of control, they can simplify application
design because the frameworkrather than the applicationruns the
event loop to detect events, demultiplex events to event handlers, and dispatch
hook methods on the handlers that process the events. The use of virtual hook
methods in the handler classes decouples the application's classes from the
framework, allowing each to be changed independently as long as the interface
signature and interaction protocols aren't modified.

A framework is a "semi-complete" application that programmers
can customize to form complete applications by inheriting from and instantiating
classes in the framework. Inheritance enables the features of framework base
classes to be shared selectively by subclasses. If a base class provides default
implementations of its methods, application developers need only override those
virtual methods whose default behavior doesn't meet their needs.

Since a framework is a semi-complete application, it enables larger-scale reuse
of software than can be achieved by reusing individual classes or stand-alone
functions. The amount of reuse increases due to a framework's ability to
integrate application-defined and application-independent classes. In particular,
a framework abstracts the canonical control flow of applications in a domain
into families of related classes, which can collaborate to integrate customizable
application-independent code with customized application-defined code.