The process of design

Initially, object-oriented software development was language-driven. The motivation to adopt an object-oriented approach came first from the need to cope with increasingly complex software systems. Research in object-oriented programming was primarily concerned with the development of language mechanisms to support the new approach. Only recently, has the attention shifted from language support mechanisms and the pragmatics of program development to issues of analysis and design. Research concerning language mechanisms, however, is still important, for example in the area of concurrent/distributed programming and the support of persistent objects. See part II.

Object-Oriented Development

OOD/P -- will be in the 90s what structured programming was in the 70s.

Criterion for decomposition: \fbox{object}

Abstractions of the problem space


slide: Object-oriented development

The common denominator in both analysis and design in an object-oriented approach may be characterized as a decomposition into objects. See slide 3-development. Objects, according to  [Booch86], are crisp entities, that suffer and require actions, which (must) have a clear relation to concepts or entities of the problem domain. Ideally, we have a seamless transition between the phases of analysis, design and implementation. Seamless in the sense that the various phases employ a common object model, that is gradually refined as the project progresses. In other words, such a transition presupposes a notion of objects that may unify the activities in the respective phases. The central imperative of the object-oriented movement, namely to provide a model of reality, still betrays the conception of object-oriented programming as simulation, as originally expressed by  [DaNy66]. The initial motivation underlying this approach is the idea that a natural representation of the problem domain in a software system may reduce the complexity of understanding the system implementing a solution. The presupposition here is that modeling involves the use of objects to represent the entities in the problem domain. Assuming the presupposition to hold, our task then reduces to identifying the right objects and showing that that particular decomposition is valid with respect to the original problem. The goal of design may then be stated as arriving at an architectural structure that adequately reflects the relevant properties of the problem domain.

The architecture of object-oriented systems

The process of software development has often been compared to the process of constructing buildings, usually in the context of defending a traditional software development method. The argument comes down to the statement that it takes a solid plan and sufficient time to lay the foundations and erect the building. The conclusion, generally, is a plea for a science of software engineering/programming, or an engineering discipline of software design. See for example  [Gries] or  [Potter91] for a similar argument in defense of formal specification methods. The line of reasoning exemplified by the building metaphor is defective in two respects. Firstly, the presupposition of a rigid ordering in time is clearly contradicted by the many attractive old city centers, which have often evolved over time without a plan. Secondly, the presupposition of a fixed method of development is clearly demonstrated to be false by modern building techniques, employing prefabricated components. Hence, neither temporal order nor procedures of construction are as fixed as they at first seem. The view expressed in the building metaphor also fails for the software life-cycle. Both throwaway and incremental prototyping have come to be accepted as viable methods for developing software. Nevertheless, when we speak of design, we think of some architectural blueprint of the system, the layout of its structure. What, we may ask, is the role of the design in the software life-cycle? And what is the function of its product, the design document?

Software Development Process -- transition

Aspects

Alternative styles


slide: Software development process

In  [Jacobs92], a detailed account is given of a method of object-oriented software engineering based on elementary architectural notions, such as (object) components and (use) relations, and strong convictions with respect to design guidelines and process management issues. See slide 3-process. An explicit distinction is made between the {\em architectural concepts}, which provide the means with which to construct various models, the method, which is a bag of guidelines telling us how to employ the architectural notions, the process, which details what steps to take to complete the software life-cycle, and the tools, which provide the software support either for the construction of models or for managing the actual process of software development, or both. In  [Jacobs92], both the method and issues of process development are spelled out in great detail, illustrated by a number of examples. These issues are clearly important in actual production environments (business or industrial), but seem to be dependent to a large extent on non-technological factors. From the perspective of software technology, we are primarily interested in the architectural notions underlying the various methods and, to a lesser extent, in the tool support for these methods. Also, apart from the architectural structure per se, we are interested in what properties a design model must have in order that we may verify that a model satisfies its initial requirements.

Perspectives of modeling

Understanding a problem domain may be quite demanding. Understanding is even more difficult when the description of the domain is cast in some representation pertaining to the solution domain. An object-oriented approach is said to require less translation from the problem domain to the (software) solution domain, thus making understanding easier. Many proponents of an object-oriented approach, however, seem to be overly optimistic in their conception of the modeling task. From an epistemological point of view, modeling may be regarded as being essentially colored by the mechanisms that are available to express the model. Hence, rather than opposing the functional and object-oriented approach by claiming that an object-oriented approach aims at modeling reality, I would prefer to characterize the distinction in terms of (modeling from) a different vernacular, a different perspective due to different modeling mechanisms. In other words, a model is meant to capture some salient aspects of a system or problem domain. Dependent on what features are considered as most important, different means will be chosen to construct a model. Even within the confines of an object-oriented approach, there appear to be radically different perspectives of the modeling required in the various phases of the software life-cycle.

Modeling reality -- vernacular

  • requirements -- use cases
  • analysis -- domain concepts
  • design -- system architecture
  • implementation -- language support >

    Design model {\em -- system oriented}

    • provides a justification of the architecture

    slide: Perspectives of modeling

    An important contribution of  [Jacobs92] is the notion of use cases that describe the situations in which a user actually interacts with the system. Such a (use case) model is an important constituent of the requirements document, since it precisely describes what the system is intended for. For the purpose of analysis, it may be helpful to develop a more encompassing (conceptual) model of the problem domain. The advantage of such an approach is that the actual system may later easily be extended due to the generality of the underlying analysis model. In contrast to the model used in analysis, both the design model and the implementation model are more solution oriented than domain oriented. The implementation model is clearly dependent on the available language support. Within a traditional life-cycle, the design model may be seen as a transition from analysis to implementation. The notion of objects may act as a unifying factor, relating the concepts described in the analysis document to the components around which the design model is built. However, as we have noted, object-oriented development does not necessarily follow the course of a traditional software life-cycle. Alternatively, we may characterize the function of the design document as a justification of the choices made in deciding on the final architecture of the system. This remark holds in so far as an object-oriented approach is adopted for both design and implementation. However, see  [Hend90] for a variety of combinations of structured, functional and object-oriented techniques.

    Dimensions of modeling

    When restricting ourselves to design models, we may again distinguish between different modeling perspectives or, which is perhaps more adequate in this context, dimensions of modeling. In  [Rum91], it is proposed to use three complementary models for describing the architecture and functionality of a system. See slide 3-dimensions.

    Dimensions of modeling {\em -- OMT}

    • object model -- decomposition into objects
    • dynamic model -- intra-object state changes
    • functional model -- object interaction (data-flow)

    Model of control

    • procedure-driven, event-driven, concurrent

    slide: The OMT method

    The OMT method distinguishes between an object model, for describing the (static) structure of object classes and their relations, a dynamic model, that describes for each object class the state changes resulting from performing operations, and a functional model, that describes the interaction between objects in terms of a data-flow graph. An important contribution of  [Rum91] is that it identifies a number of commonly used control models, including procedure-driven control, event-driven control and concurrent control. The choice for a particular control model may deeply affect the design of the system. See section duality for a further discussion. The OMT approach may be called a hybrid method since it employs non object-oriented techniques for describing intra-object dynamics, namely state-charts, and a functional approach involving data-flow diagrams, for describing inter-object communication.

    Coherent models

    The OMT object model, however, only captures the static structure of the system. To model the dynamic and functional aspects, the object model is augmented with a dynamic model, which is given by state diagrams, and a functional model, which is handled by data flow diagrams. From a formal point of view this solution is rather unsatisfactory since, as argued in  [Hayes91], it is hard to establish the consistency of the combined model, consisting of an object, dynamic and functional model.

    Model criteria -- formal approach

    • unambiguous -- single meaning
    • abstract -- no unnecessary detail
    • consistent -- absence of conflict

    slide: Coherent models -- criteria

    Consistency checking, or at least the possibility to do so, is important to increase our belief in the reliability (and reusability) of a model. To be able to determine whether a model is consistent, the model should be phrased in an unambiguous way, that is, in a notation with a clear and precise meaning. See slide 3-coherent. Also, to make the task of consistency checking manageable, a model should be as abstract as possible, by leaving out all irrelevant details. To establish the consistency of the combined model, covering structural, functional and dynamic aspects, the interaction between the various models must be clearly defined. Currently, to my knowledge, there is no completely developed method encompassing the structural, functional and dynamic aspects of a system in a manner that is amenable to a rigorous formal approach. However, there is an emerging understanding of how to deal with these various aspects. Moreover, there are attempts towards a standardization of the notions employed in the various methods. See sections OMG and methods.

    Functional versus object-oriented development

    The functional approach is a relatively well-established method of software development. In essence, a functional approach amounts to decomposing a task into the steps that must be taken to complete it. For instance, when describing a compiler in a functional manner, a first decomposition can be made as follows: lexical scan -> parser -> code generation Each of these steps can be regarded as transforming its input to a representation suitable for the next step, finally resulting in an executable program. See slide 3-functional. Obviously, the method of functional decomposition lends itself to a structured approach, since each step (in the example above) may be decomposed into a number of smaller steps. Graphically, a functional decomposition may be pictured as a tree with the elementary steps as its leaves. A functional decomposition may be augmented by a data flow diagram that depicts the nature of the data transformations effected by each step. Basically, a data flow diagram is a graph with nodes labeled by the (intermediate) data representations and edges that are labeled by the functional components identified in the function decomposition tree.

    Functional development methods

    • each module represents a major step in the process

    Disadvantages

    • no data abstraction / information hiding
    • not responsive to changes
    • inadequate for natural concurrency

    slide: Functional development methods

    In contrast, the components that result from an object-oriented approach do not represent actual steps toward a solution, but rather may be seen as (abstract) entities that contribute to the solution on the basis of their assigned responsibilities. Correspondingly, the flow of control is far less regular than in a functional decomposition. The equivalent of the combined data flow and functional decomposition diagram for an object-oriented system is a message-passing diagram depicting the actual interaction between objects. This diagram is a graph with objects as nodes, and edges labeled by requests to execute a method. In general, this graph will be too complex to be represented pictorially. It is possible, however, to divide up an object interaction graph into meaningful related pieces, which is the approach taken for Fusion, for example. See section Fusion. Moreover, the complexity of object-interaction is compensated for by the opportunities for a more tight definition of the semantics, that is the responsibilities and obligations, of each (object) component participating in the computation. The major drawback of a functional approach, as observed in  [Booch86], is the absence of data abstraction and information hiding. Typically, the functional approach is not concerned with issues of data representation, although it does allow additional procedural abstractions to access and modify the data. However, the functional approach does not in itself provide any support for a tight coupling between the functional components and data representations or the procedural abstractions that are used for the purpose of information hiding. Hence, changes in the data representation or the structure of the algorithm may ripple across the system in an unforeseen manner.

    Object-oriented development -- design for change

    • localized changes

    Advantages

    • improved maintainability
    • improved understandability

    Support for concurrency {\em -- active objects}

    • no modifications needed for concurrency

    slide: Support for change

    In contrast, object-oriented development is neither data nor procedure oriented, but strives to encapsulate both data and procedures acting on these data in objects. Instead of a detailed description of the steps that need to be taken to solve a problem or complete a task, the required functionality is distributed among the objects that may later be assembled (in a rather straightforward way) to actually perform the task. Perhaps the most important advantage of encapsulating data and procedures, from the perspective of design, is that (in many cases) changes may be kept strictly local to the classes defining the relevant objects. See slide 3-OO. Ideally, object-oriented design is design for change, in other words the development of an architecture that is adaptable to changing requirements or changes in the underlying software and hardware support. However, to achieve this adaptability generally requires a non-trivial effort during design, in order to find stable abstractions with a well-defined semantics that determines their role in the system. Obvious potential spin-offs from the effort to design for change are improved maintainability of the system and a better understanding of its architectural structure. Another benefit of an object-oriented approach, mentioned in  [Booch86], is the possibility of introducing concurrency in a later stage. Starting from a functional decomposition, the introduction of concurrency would generally incur a total restructuring of the algorithm. With an object-oriented approach, however, concurrency may be introduced by employing active objects. In principle, clients of an object need not be aware of whether the object is passive, that is merely responding to messages, or active, which means that the object in addition to answering messages has (autonomous) behavior of its own. However, employing active objects imposes a number of additional constraints, on an implementation level but also on a design level. We will explore these issues in chapter \ref{Distribution and concurrency}.