Object-Oriented Application Frameworks
Mohamed Fayad
Douglas C. Schmidt
The following is the guest editorial for the Communications of the ACM, Special Issue on
Object-Oriented Application Frameworks, Vol. 40, No. 10,
October 1997.
Computing power and network bandwidth have increased dramatically over
the past decade. However, the design and implementation of complex
software remains expensive and error-prone. Much of the cost and
effort stems from the continuous re-discovery and re-invention of core
concepts and components across the software industry. In particular,
the growing heterogeneity of hardware architectures and diversity of
operating system and communication platforms makes it hard to build
correct, portable, efficient, and inexpensive applications from
scratch.
Object-oriented (OO) application frameworks are a promising
technology for reifying proven software designs and implementations in
order to reduce the cost and improve the quality of software. A
framework is a reusable, ``semi-complete'' application that can be
specialized to produce custom applications
[Johnson:88]. In contrast to earlier OO reuse
techniques based on class libraries, frameworks are targeted for
particular business units (such as data processing or cellular
communications) and application domains (such as user interfaces or
real-time avionics). Frameworks like MacApp, ET++, Interviews, ACE,
Microsoft's MFC and DCOM, JavaSoft's RMI, and implementations of OMG's
CORBA play an increasingly important role in contemporary software
development.
The primary benefits of OO application frameworks stem from the
modularity, reusability, extensibility, and
inversion of control they provide to developers, as described
below:
- Modularity -- Frameworks enhance modularity by
encapsulating volatile implementation details behind stable
interfaces. Framework modularity helps improve software quality by
localizing the impact of design and implementation changes. This
localization reduces the effort required to understand and maintain
existing software.
- Reusability -- The stable interfaces provided by
frameworks enhance reusability by defining generic components that can
be reapplied to create new applications. Framework reusability
leverages the domain knowledge and prior effort of experienced
developers in order to avoid re-creating and re-validating common
solutions to recurring application requirements and software design
challenges. Reuse of framework components can yield substantial
improvements in programmer productivity, as well as enhance the
quality, performance, reliability and interoperability of software.
- Extensibility -- A framework enhances extensibility
by providing explicit hook methods [Pree:94] that
allow applications to extend its stable interfaces. Hook methods
systematically decouple the stable interfaces and behaviors of an
application domain from the variations required by instantiations of
an application in a particular context. Framework extensibility is
essential to ensure timely customization of new application services
and features.
- Inversion of control -- The run-time architecture
of a framework is characterized by an ``inversion of control.'' This
architecture enables canonical application processing steps to be
customized by event handler objects that are invoked via the
framework's reactive dispatching mechanism. When events occur, the
framework's dispatcher reacts by invoking hook methods on
pre-registered handler objects, which perform application-specific
processing on the events. Inversion of control allows the framework
(rather than each application) to determine which set of
application-specific methods to invoke in response to external events
(such as window messages arriving from end-users or packets arriving
on communication ports).
Developers in certain domains have successfully applied OO application
frameworks for many years. Early object-oriented frameworks (such as
MacApp and Interviews) originated in the domain of graphical user
interfaces (GUIs). The Microsoft Foundation Classes (MFC) is a
contemporary GUI framework that has become the de facto
industry standard for creating graphical applications on PC platforms.
Although MFC has limitations (such as lack of portability to non-PC
platforms), its wide-spread adoption demonstrates the productivity
benefits of reusing common frameworks to develop graphical business
applications.
Application developers in more complex domains (such as
telecommunications, distributed medical imaging, and real-time
avionics) have traditionally lacked standard ``off-the-shelf''
frameworks. As a result, developers in these domains largely build,
validate, and maintain software systems from scratch. In an era of
deregulation and stiff global competition, however, it has become
prohibitively costly and time consuming to develop applications
entirely in-house from the ground up.
Fortunately, the next generation of OO application frameworks are
targeting complex business and application domains. At the heart of
this effort are Object Request Broker (ORB) frameworks, which
facilitate communication between local and remote objects. ORB
frameworks eliminate many tedious, error-prone, and non-portable
aspects of creating and managing distributed applications and reusable
service components. This enables programmers to develop and deploy
complex applications rapidly and robustly, rather than wrestling
endlessly with low-level infrastructure concerns. Widely used ORB
frameworks include CORBA, DCOM, and
Java
RMI.
Although the benefits and design principles underlying frameworks are
largely independent of domain to which they are applied, we've found
it useful to classify frameworks by their scope, as follows:
- System infrastructure frameworks -- These
frameworks simplify the development of portable and efficient system
infrastructure such as operating system
[Campbell-Islam:93] and communication frameworks
[Schmidt:97], and frameworks for user interfaces and
language processing tools. System infrastructure frameworks are
primarily used internally within a software organization and are not
sold to customers directly.
- Middleware integration frameworks -- These
frameworks are commonly used to integrate distributed applications and
components. Middleware integration frameworks are designed to enhance
the ability of software developers to modularize, reuse, and extend
their software infrastructure to work seamlessly in a distributed
environment. There is a thriving market for Middleware integration
frameworks, which are rapidly becoming commodities. Common examples
include ORB frameworks, message-oriented middleware, and transactional
databases.
- Enterprise application frameworks -- These
frameworks address broad application domains (such as
telecommunications, avionics, manufacturing, and financial engineering
[Birrer:93]) and are the cornerstone of enterprise business activities
[Fayad-Hamu:97]. Relative to System infrastructure
and Middleware integration frameworks, Enterprise frameworks are
expensive to develop and/or purchase. However, Enterprise frameworks
can provide a substantial return on investment since they support the
development of end-user applications and products directly. In
contrast, System infrastructure and Middleware integration frameworks
focus largely on internal software development concerns. Although
these frameworks are essential to rapidly create high quality sofware,
they typically don't generate substantial revenue for large
enterprises. As a result, it's often more cost effective to buy
System infrastructure and Middleware integration frameworks rather
than build them in-house [Fayad-Hmau:97].
Regardless of their scope, frameworks can also be classified by the
techniques used to extend them, which range along a continuum from
whitebox frameworks to blackbox frameworks.
Whitebox frameworks rely heavily on OO language features like
inheritance and dynamic binding to achieve extensibilty. Existing
functionality is reused and extended by (1) inheriting from framework
base classes and (2) overriding pre-defined hook methods using
patterns like Template Method [Gamma:95]. Blackbox
frameworks support extensibility by defining interfaces for components
that can be plugged into the framework via object composition.
Existing functionality is reused by (1) defining components that
conform to a particular interface and (2) integrating these components
into the framework using patterns like Strategy
[Gamma:95] and Functor.
Whitebox frameworks require application developers to have intimate
knowledge of the frameworks' internal structure. Although whitebox
frameworks are widely used, they tend to produce systems that are
tightly coupled to the specific details of the framework's inheritance
hierarchies. In contrast, blackbox frameworks are structured using
object composition and delegation more than inheritance. As a result,
blackbox frameworks are generally easier to use and extend than
whitebox frameworks. However, blackbox frameworks are more difficult
to develop since they require framework developers to define
interfaces and hooks that anticipate a wider range of potential
use-cases [Johnson:95].
Frameworks are closely related to other approaches to reuse,
including:
- Patterns --
Patterns represent recurring solutions to software development
problems within a particular context. Patterns and frameworks both
facilitate reuse by capturing successful software development
strategies. The primary difference is that frameworks focus on reuse
of concrete designs, algorithms, and implementations in a particular
programming language. In contrast, patterns focus on reuse of
abstract designs and software micro-architectures.
Frameworks can be viewed as a concrete reification of families of
design patterns that are targeted for a particular application-domain.
Likewise, design patterns can be viewed as more abstract
micro-architectural elements of frameworks that document and motivate
the semantics of frameworks in an effective way. When patterns are
used to structure and document frameworks, nearly every class in the
framework plays a well-defined role and collaborates effectively with
other classes in the framework.
- Class libraries --
Frameworks extend the benefits of OO class libraries in the following
ways:
- Frameworks define ``semi-complete'' applications that
embody domain-specific object structures and functionality --
Components in a framework work together to provide a generic
architectural skeleton for a family of related applications. Complete
applications can be composed by inheriting from and/or instantiating
framework components. In contrast, class libraries are less
domain-specific and provide a smaller scope of reuse. For instance,
class library components like classes for Strings, complex numbers,
arrays, and bitsets are relatively low-level and ubiquitous across
many application domains.
- Frameworks are active and exhibit ``inversion of control''
at run-time -- Class libraries are typically passive,
i.e., they perform their processing by borrowing threads of
control from self-directed application objects. In contrast,
frameworks are active, i.e., they control the flow
of control within an application via event dispatching patterns like
Reactor and Observer. The ``inversion of control'' in the run-time
architecture of a framework is often referred to as The Hollywood
Principle, i.e., ``Don't call us, we'll call you.''
In practice, frameworks and class libraries are complementary
technologies. For instance, frameworks tyically utilize class
libraries like the C++ Standard Template Library (STL) internally to
simplify the development of the framework. Likewise,
application-specific code invoked by framework event handlers can
utilize class libraries to perform basic tasks such as string
processing, file management, and numerical analysis.
- Components --
Components are self-contained instances of abstract data types (ADTs)
that can be plugged together to form complete applications. Common
examples of components include VBX controls and CORBA Object Services.
In terms of OO design, a component is a blackbox that defines a
cohesive set of operations, which can be reused based solely upon
knowledge of the syntax and semantics of its interface. Compared with
frameworks, components are less tightly coupled and can support
binary-level reuse. For example, applications can reuse components
without having to subclass from existing base classes.
The relationship between frameworks and components is highly
synergistic, with neither subordinate to the other. Frameworks can be
used to develop components, whereby the component interface provides a
Facade for the internal class structure of the framework.
Likewise, components can be used as pluggable strategies in blackbox
frameworks. In general, frameworks are often used to simplify the
development of infrastructure and middleware software, whereas
components are often used to simplify the development of end-user
application software. Naturally, components are also effective for
developing infrastructure and middleware, as well.
When used in conjunction with patterns, class libraries, and
components, OO application frameworks can significantly increase
software quality and reduce development effort. However, a number of
challenges must be addressed in order to employ frameworks
effectively. Companies attempting to build or use large-scale
reusable framework often fail unless they recognize and resolve
challenges such as development effort, learning
curve, integratability, maintainability,
validation and defect removal, efficiency, and
lack of standards, which are outlined below:
- Development effort -- While developing complex
software is hard enough, developing high quality, extensible, and
reusable frameworks for complex application domains is even harder.
The skills required to produce frameworks successfully often remain
locked in the heads of expert developers. One of the goals of this
theme issue is to demystify the software process and design principles
associated with developing and using frameworks.
- Learning curve -- Learning to use an OO application
framework effectively requires considerable investment of effort. For
instance, it often takes 6-12 months become highly productive with a
GUI framework like MFC or MacApp, depending on the experience of
developers. Typically, hands-on mentoring and training courses are
required to teach application developers how to use the framework
effectively. Unless the effort required to learn the framework can be
amortized over many projects, this investment may not be cost
effective. Moreover, the suitability of a framework for a particular
application may not be apparent until the learning curve has
flattened.
- Integratability -- Application development will be
increasingly based on the integration of multiple frameworks
(e.g. GUIs, communication systems, databases, etc.) together
with class libraries, legacy systems, and existing components.
However, many earlier generation frameworks were designed for internal
extension rather than for integration with other frameworks developed
externally. Integration problems arise at several levels of
abstraction, ranging from documentation issues [Fayad-Hamu 97], to the
concurrency/distribution architecture, to the event dispatching model.
For instance, while inversion of control is an essential feature of a
framework, integrating frameworks whose event loops are not designed
to interoperate with other frameworks is hard.
- Maintainability -- Application requirements change
frequently. Therefore, the requirements of frameworks often change,
as well. As frameworks invariably evolve, the applications that use
them must evolve with them.
Framework maintenance activities include modification and adaptation
of the framework. Both modification and adaptation may occur on the
functional level (i.e., certain framework
functionality does not fully meet developers' requirements), as well
as on the non-functional level (which includes more
qualitative aspects such as portability or reusability).
Framework maintenance may take different forms, such as adding
functionality, removing functionality, and generalization. A deep
understanding of the framework components and their interrelationships
is essential to perform this task successfully. In some cases, the
application developers and/or the end-users must rely entirely on
framework developers to maintain the framework.
- Validation and defect removal -- Although a
well-designed, modular framework can localize the impact of software
defects, validating and debugging applications built using frameworks
can be tricky for the following reasons:
- Generic components are harder to validate in the
abstract -- A well-designed framework component typically
abstracts away from application-specific details, which are provided
via subclassing, object composition, or template parameterization.
While this improves the flexibility and extensibility of the
framework, it greatly complicates module testing since the components
cannot be validated in isolation from their specific instantiations.
Moreover, it is usually hard to distinguish bugs in the framework from
bugs in application code. As with any software development, bugs are
introduced into a framework from many possible sources, such as
failure to understand the requirements, overly coupled design, or an
incorrect implementation. When customizing the components in
framework to a particular application, the number of possible error
sources will increase.
- Inversion of control and lack of explicit control
flow -- Applications written with frameworks can be hard to
debug since the framework's ``inverted'' flow of control oscillates
between the application-independent framework infrastructure and the
application-specific method callbacks. This increases the difficulty
of ``single-stepping'' through the run-time behavior of a framework
within a debugger since the control flow of the application is driven
implicitly by callbacks and developers may not understand or have
access to the framework code. This is similar to the problems
encountered trying to debug a compiler lexical analyser and parser
written with LEX and YACC. In these applications, debugging is
straightforward when the thread of control is in the user-defined
action routines. Once the thread of control returns to the generated
DFA skeleton, however, it is hard to trace the program's logic.
- Efficiency -- Frameworks enhance extensibility by
employing additional levels of indirection. For instance, dynamic
binding is commonly used to allow developers to subclass and customize
existing interfaces. However, the resulting generality and
flexibility often reduce efficiency. For instance, in languages like
C++ and Java, the use of dynamic binding makes it impractical to
support Concrete Data Types (CDTs), which are often required for
time-critical software. The lack of CDTs yields (1) an increase in
storage layout (e.g., due to embedded pointers to virtual
tables), (2) performance degradation (e.g. due to the
additional overhead of invoking a dynamically bound method and the
inability to inline small methods), and (3) a lack of flexibility
(e.g., due to the inability to place objects in shared
memory).
- Lack of standards -- Currently, there are no widely
accepted standards for designing, implementing, documenting, and
adapting frameworks. Moreover, emerging industry standard frameworks
(such as CORBA, DCOM, and Java RMI) currently lack the semantics,
features, and interoperability to be truly effective across multiple
application domains. Often, vendors use industry standards to sell
proprietary software under the guise of open systems. Therefore, it's
essential for companies and developers to work with standards
organizations and middleware vendors to ensure the emerging
specifications support true interoperability and define features that
meet their software needs.
Over the next several years, we expect the following framework-related
topics will receive considerable attention by researchers and
developers:
- Reducing framework development effort --
Traditionally, reusable frameworks have been developed by generalizing
from existing systems and applications. Unfortunately, this
incremental process of organic development is often slow and
unpredictable since core framework design principles and patterns must
be discovered ``bottom-up.'' However, since many good framework
exemplars now exist, we expect that the next generation of developers
will leverage this collective knowledge to conceive, design, and
implement higher quality frameworks more rapidly.
- Greater focus on domain-specific enterprise frameworks --
Existing frameworks have focused largely on system infrastructure and
middleware integration domains (such as user interfaces
[Gamma:95,Pree:94] and OS/communication systems
[Schmidt:97,Johnson:95,Cambell-Islam:93]). In
contrast, there are relatively few widely documented exemplars of
enterprise frameworks for key business domains such as manufacturing,
banking, insurance, and medical systems. As more experience is gained
developing frameworks for these business domains, however, we expect
that the collective knowledge of frameworks will be expanded to cover
an increasing wide range of domain-specific topics and an increasing
number of Enterprise application frameworks will be produced. As a
result, benefits of frameworks will become more immediate to
application programmers, as well as to infrastructure developers.
- Blackbox frameworks -- Many framework experts
[Johnson:88] favor black-box frameworks over
white-box frameworks since black-box frameworks emphasize dynamic
object relationships (via patterns like Bridge and Strategy
Gamma:95) rather than static class relationships.
Thus, it is easier to extend and reconfigure black-box frameworks
dynamically. As developers become more familiar with techniques and
patterns for factoring out common interfaces and components, we expect
that an increasing percentage of black-box frameworks will be
produced.
- Framework documentation -- Accurate and
comprehensible documentation is crucial to the success of large-scale
frameworks. However, documenting frameworks is a costly activity and
contemporary tools often focus on low-level method-oriented
documentation, which fails to capture the strategic roles and
collaborations among framework components. We expect that the advent
of tools for reverse-engineering the structure of classes and objects
in complex frameworks will help to improve the accuracy and utility of
framework documentation. Likewise, we expect to see an increase in
the current trend [Johnson:95,Schmidt:97] of using
design patterns to provide higher-level descriptions of
frameworks.
- Processes for managing framework development --
Frameworks are inherently abstract since they generalize from a
solution to a particular application challenge to provide a family of
solutions. This level of abstraction makes it difficult to engineer
their quality and manage their production. Therefore, it is essential
to capture and articulate development processes that can ensure the
successful development and use of frameworks. We believe that
extensive prototyping and phased introduction of framework technology
into organizations is crucial to reducing risk and helping to ensure
successful adoption.
- Framework economics -- The economics of developing
framework includes activities such as the following:
- Determining effective framework cost metrics --
which measure the savings of reusing framework components vs. building
applications from scratch;
- Cost estimation -- which is the activity of
accurately forecasting the cost of buying, building, or adapting a
particular framework;
- Investment analysis and justification -- which
determines the benefits of applying frameworks in terms of return on
investment;
We expect that the focus on framework economics will help to bridge
the gap among the technical, managerial, and financial aspects of
making, buying, or adapting frameworks
[Hamu-Fayad:97].
The articles in this theme issue describe how OO application
frameworks provide a powerful vehicle for reuse, as well as a way to
capture the essence of successful patterns, architectures, components,
policies, services, and programming mechanisms. The feature articles
lead off with ``Framework Development for Large Systems'' by Dirk
Baumer, Guido Gryczan, Rolf Knoll, Carola Lilienthal, Dirk Riehle, and
Heinz Zullighoven. These authors draw on their experience developing
large-scale industrial banking projects to present concepts and
techniques for domain partitioning, framework layering and framework
construction. The second feature article on "Evolving Custom-Made
Applications into Domain-Specific Frameworks" by Wim Codenie, Koen De
Hondt, Patrick Steyaert, Arlette Vercammen discusses solutions to
common framework development challenges such as avoiding the
proliferation of versions, estimating effort, and alleviating the
tendency towards ``architectural drift.''
The Theme section also contains several short articles, starting with
"Frameworks = (Patterns + Components)/2" by Ralph Johnson, which
compares and contrasts frameworks with other object-oriented reuse
techniques such as patterns and components. The second short article
is "An Adaptive Framework for Developing Multimedia Software
Components" by Edward Posnak, Greg Lavender, and Harrick Vin describes
a framework that simplifies the development of dynamically adaptive
multimedia software components by promoting the reuse of code, design
patterns, and domain expertise. The next short article is "Frameworks
Design by Systematic Generalization with Hot Spots and Patterns" by
Hans Albrecht Schmid, which presents a systematic method for designing
frameworks based on identifying "hot spots," which capture key sources
of variation in an application domain. Serge Demeyer, Theo Meijler,
Oscar Nierstrasz, and Patrick Steyaert also focus on hot spots in
their article on "Design Guidelines for Tailorable Frameworks," which
presents design guidelines to develop frameworks for open systems.
Several case studies are also covered in the theme issues, including
"The Framework Life Span: a Case Study for Flexible Manufacturing
Systems" by A. Aarsten, Davide Brugali, and G. Menga, which highlights
the relationships between application frameworks, patterns, and
pattern languages in the domain of manufacturing systems. Likewise,
the SEMATECH CIM Framework, by David Doscher and Robert Hodges
describes the structure of a framework for computer integrated
manufacturing of semiconductors. In addition, Adele Goldberg, Steve
Abell, and David Leibs describe LearningWorks, which is a framework
for exploring ideas about computing and software system
construction.
Finally, the theme section contains three sidebars: "Achieve
Bottom-Line Improvements with Enterprise Frameworks" by Hamu and
Fayad, "Framework Integration problems, Causes, and Solutions by
M. Mattsson et al., and "Lessons Learned Building Reusable OO
Frameworks for Distributed Software" by Schmidt and Fayad.
The articles in this theme issue reinforce our believe that
object-oriented application frameworks will be at the core of
leading-edge software technology in the twenty-first century. As
software systems become increasingly complex, object-oriented
application frameworks are becoming increasingly important for
industry and academia. The extensive focus on application frameworks
in the object-oriented community offers software developers an
important vehicle for reuse and a means to capture the essence of
successful patterns, architectures, components, and programming
mechanisms.
The good news is that framework are becoming mainstream and developers
at all levels are increasingly adopting and succeeding with framework
technologies. However, OO application frameworks are ultimately only
as good as the people who build and use them. Creating robust,
efficient, and reusable application frameworks requires development
teams with a wide range of skills. We need expert analysts and
designers who have mastered patterns, software architectures, and
protocols in order to alleviate the inherent and accidental
complexities of complex software. Likewise, we need expert middleware
developers who can implement these patterns, architectures, and
protocols within reusable frameworks. In addition, we need
application programmers who have the motivation, skills, and training
to learn how to use these frameworks effectively. We encourage you to
get involved with others working on frameworks by attending
conferences, participating in online mailing lists and newsgroups, and
contributing your insights and experience.
Acknowledgements
We would like to thank the staff of CACM for their help in producing
this theme issue. We'd also like to thank Ralph Johnson and Bryan
Doerr for suggestions on improving this introduction. In addition, we
are grateful to all the reviewers for valuable and useful reviews on
all the submissions for this theme section.
References
[Birrer:93] Eggenschwiler T. Birrer "Frameworks in
the Financial Engineering Domain: An Experience Report" ECOOP '93
Proceedings, Lecture Notes in Computer Science nr. 707,
Springer-Verlag, 1993.
[Johnson:88] Ralph Johnson and Brian Foote.
``Designing Reusable Classes.'' Journal of Object-Oriented
Programming. SIGS, 1, 5 (June/July. 1988), 22-35.
[Campbell-Islam:93] Roy H. Campbell and Nayeem Islam
"A Technique for Documenting the Framework of an Object-Oriented
System", Computing Systems, Vol. 6, No. 4, Fall 1993
[Fayad-Hamu:97] Mohamed E. Fayad and David S. Hamu
"Object-Oriented Enterprise Frameworks: Make vs. Buy Decisions and
Guidelines for Selection", The Communications of ACM, 1997, to appear.
[Gamma:95] Erich Gamma, Richard Helm, Ralph
Johnson, and John Vlissides, "Design Patterns: Elements of Reusable
Software Architecture", Addison-Wesley, 1995.
[Hamu-Fayad:97] David S. Hamu and Mohamed E. Fayad,
"Achieve Bottom-Line Improvements with Enterprise Frameworks," The
Communications of ACM, October 1997.
[Johnson:95] Herman Hueni and Ralph Johnson and
Robert Engel, ``A Framework for Network Protocol Software,''
Proceedings of OOPSLA, Austin, Texas, October 1995.
[Pree:94] Wolfgang Pree, Design Patterns for
Object-Oriented Software Development, Addison-Wesley, Reading, MA,
1994.
[Schmidt:97] Douglas C. Schmidt, ``Applying Design
Patterns and Frameworks to Develop Object-Oriented Communication
Software,'' Handbook of Programming Languages}, Volume I, edited by
Peter Salus, MacMillan Computer Publishing, 1997.
Back to
ACE home page.