1.1. Software Development Paradigms and Processes

Time: 00:08:09 | Download: Large, Large (CC) Small | Streaming, Streaming (CC) | Slides (PDF)

Paradigms consist of "a set of assumptions, concepts, values, and practices that constitutes a way of viewing reality for the community that shares them, especially in an intellectual discipline." When applied to software development, paradigms guide how developers view a problem and organize its solution. Think of it as a language for describing a problem and designing and implementing a software solution. The term paradigm shift denotes "a fundamental change in [the] approach or underlying assumptions." Applied to software development, it means an abrupt change in the language between parts of the development process. Computer scientists have used various techniques to help manage the increasing complexity of software systems. They base each technique on a different paradigm, and each advancement caused or resulted in a paradigm shift.

To develop large, complex software systems, developers break the overall development process into smaller, more manageable steps or phases. Jurison1 notes that "The choice of the software development process has a significant influence on the project's success. The appropriate process can lead to faster completion, reduced cost, improved quality, and lower risk. The wrong process can lead to duplicated work efforts and schedule slips, and create continual management problems.".

The Software Development Process

Many software development processes have been proposed over time, each defining a specific set of phases or steps. There are typically some variations between the steps or how they are named, but three are common to most processes:

Analysis
Developers focus on understanding and modeling the problem during analysis. They form the initial model by abstracting its essential aspects or features and expressing them in a notation that all stakeholders, customers, domain experts, and implementors understand. Their primary goal is to create a model, independent of any programming language or system, that describes the real-world actors and their relationships. The object-oriented paradigm calls this phase object-oriented analysis (OOA), and its end product is a set of connected classes describing the original problem. We'll present our models using a notation specifically created for the task: the Unified Modeling Language.
Design
The design phase bridges the gulf between analysis and implementation by forming a solution architecture. The architecture reflects the domain knowledge discovered and recorded during the analysis phase and defines the framework upon which developers construct the final solution. Programs often require data structures and associated operations that don't exist in the original problem, and developers typically add them during the design phase. They also add details overlooked during analysis and remove irrelevant details during the design phase. The object-oriented paradigm calls this phase object-oriented design (OOD), and, significantly, its end product is the same, albeit refined, set of classes produced by OOA. Developers often partition these classes into sub-models focused on specific, related tasks. Some common groupings are:
Implementation
Developers build a usable system during the implementation phase. A software project ultimately delivers a program or system of programs or, in the case of software embedded in a physical product, a combination of hardware and software (e.g., a car or aircraft). CS 1410 focuses on the object-oriented paradigm's implementation phase or object-oriented programming (OOP). OOP builds systems based on the classes identified and refined in the previous phases.

A single individual or group may complete all three phases for a small project. Increasingly large projects often require different groups with specialized skills to complete each phase. Although analysis and design are distinct phases with distinct goals, they typically use the same language or paradigm. So, the following figures illustrate them together for simplicity and compactness.

Software Development Paradigms

Historically, Software developers have experimented with three major software development paradigms: procedural, data-driven, and object-oriented. Before adopting formal design processes, developers utilized "organic," ad hoc techniques (that is, programs "grew" in a haphazard way). Figure 1 illustrates that each technique can lead to a working program, but not in the same amount of time or with the same amount of effort.

A picture representing the four different software development paradigms as paths between the real world and a program solving a real-world problem. The ad hoc path is the longest and least direct path. The procedural paradigm represents a shorter and more direct path. The data-driven path is even shorter and even more direct. But the object-oriented path is the shortest and the most direct.
Four software development paradigms. Software developers responded to software systems' ever-increasing size and complexity by developing more sophisticated development paradigms. The figure illustrates the ad hoc, procedural, data-driven, and object-oriented paradigms as paths between the real world and a working program.

Procedural

The procedural paradigm focuses on how to solve a problem. Software developers using this paradigm list the steps needed to solve the problem and then successively decompose those steps into smaller and more simple sub-problems, which they ultimately represent with procedures, functions, or methods. Analysts often represent a procedural decomposition as a hierarchy - a list or a tree. The top or root of the tree represents the overall problem, and the leaves at the bottom denote the final procedures or functions. The nodes or branching points between the top of the tree and the bottom represent intermediate functions called from the functions above and calling functions below. There are no well-defined rules for performing a decomposition or determining when the functions are sufficiently simple to allow programming to begin. The absence of these rules suggests that decompositions are somewhat arbitrary.

Analysts observe the "real world" and translate their observations into procedural models. Designers refine the models, adding missed features while removing unnecessary ones. The functions composing the hierarchical models correspond well, if not precisely, with the final functions programmers created during implementation. Nevertheless, the procedural paradigm suffers from a paradigm shift between the real world and the analysis and design model.

The real world lacks neatly bounded and organized problem-solving steps or procedures. So, analysts synthesize them from their observations. While software professionals might understand the connections or articulations between the real-world elements and the model functions, customers and professionals in other disciplines might not. For example, accountants, buyers, and customers may understand their respective roles in managing accounts receivable and payable, stocking a store's shelves, and buying an individual product. However, they may not recognize their role in a decomposed model or program. There is an abrupt change between the problem and the procedural decomposition. This abrupt change is a paradigm shift. Nevertheless, the procedural model is still appropriate for small, simple programs, and what we learn while studying it will carry over to our study of the object-oriented paradigm.

The picture depicts the procedural software development process. Specifically, it illustrates the product of analysis and design as a hierarchy or tree and the implementation as short, skeletal functions. Analysis and design are logically close to the implementation, but there is a large gap between the real-world problem and the analysis and design. The fault of the procedural paradigm is the large logical separation between the real-world problem and the analysis and design phases, which the picture illustrates with a person leaping over the gap.
The procedural paradigm. Procedures and functions are the consistent language running from analysis through design and into implementation. Software developers follow the same paradigm in all three phases. However, analysis introduces a significantly new language transitioning from the original, real-world problem to the functional decomposition. The resulting paradigm shift does not help the analyst build domain understanding and makes the results of analysis and design (decomposition diagrams) hard for non-software developers to understand.

Data-Driven

An element in a data flow diagram: data (arrows) entering and leaving a process (a circle or bubble).

Software developers created and used numerous data-driven paradigms from the mid-1970s through the mid-1990s. Data-driven models follow data throughout the system. They begin following it when it enters the system, continue following it as it passes through transforming processes, and stop when it leaves. Analysis and design model the data flowing through the system as arrows entering and leaving process bubbles. Sometimes, multiple arrows entered a bubble where the system merged them into a single exiting flow; sometimes, a single flow entered, only to be separated into multiple flows leaving the process. The result was a web of data and processes that described a given problem.

An analysis based on a data-driven paradigm facilitates developer understanding of the problem domain, and the results are easier for non-professional stakeholders to understand. The data-driven models are also more useful than hierarchical models for software testing, validation, and documentation.

While a data flow's bubble-and-arrow diagrams match the real world, there is a large gap between the data flow diagrams and the programs written during the implementation phase. The gap is a paradigm shift resulting from changing the underlying language from data flows that focus on what to procedures that focus on how.

The picture represents the data-driven software development process. Analysis and design produce a web of data-flow arrows and process bubbles. Skeletal functions still represent the functions created during the implementation phase. Data-driven models still suffer from a paradigm shift, but one between analysis and design and implementation. The large gap makes it difficult for developers to transition from the model to a functioning system, illustrated by a person jumping between design and implementation.
The data-driven paradigm. The analysis and design phases are logically close to the real-world problem. Data-driven analysis helps developers gain domain understanding. Furthermore, the resulting data-flow graphs are easier for non-software developers to understand than the decomposition trees created by the procedural technique. However, the data flow diagrams are more difficult to convert to running programs than decomposition trees because of the paradigm shift from data to functions.

Object-Oriented

The object-oriented paradigm encapsulates data and the procedures or operations that may access and operate on that data into an entity called an object. In that way, the object-oriented paradigm simultaneously focuses on what and how. A class describes a group of similar objects. It is often easier for developers to understand classes and how they are connected using a graphical notation; the illustration below includes four classes arranged in a class diagram using the Unified Modeling Language (UML) notation. A common metaphor for classes and the objects created or instantiated from them is cookie cutter and cookies. A cookie-cutter determines a cookie's size, shape, and decorations, but we can't eat the cookie-cutter. But we can roll out some dough and stamp out as many cookies with the cookie cutter as we like. If we use the same cookie cutter, all cookies will be identical. A class is like a cookie-cutter, and the objects created or instantiated from it are like cookies: objects instantiated from the same class will also be the same.

Objects in the real world are identified during analysis and abstracted into classes. During the design phase, developers add detail to the classes, add new classes, and sometimes remove classes. Still, for the most part, software development carries the classes discovered during analysis into design. The design phase refines the classes and passes them into the implementation phase. When software developers implement the classes, they translate the UML class diagrams into an appropriate programming language. Significantly, the concepts of classes and objects do not change from one phase to another. Classes bring a conceptual consistency to software development that bridges the real world, analysis, design, and implementation.

A picture illustrating the object-oriented software development process. The analysis and design phases produce a set of classes. Developers translate these classes into a working program during the implementation phase. The figure depicts object orientation as forming a bridge between each phase of the software development process with a person walking easily between phases on the bridges.
The object-oriented paradigm. The object-oriented paradigm evenly spreads the development phases without any large gaps. That is, there are no inter-phase paradigm shifts. Developers identify classes during analysis, refine them during design, and implement them during the programming phase. But the paradigm or language of classes remains consistent throughout the development process. This consistent use of classes forms the object-oriented bridges between each phase of the software development process. Classes effectively eliminate the gaps or paradigm shifts inherent in other development techniques.

The ability of the object-oriented paradigm to bridge the gaps between the phases, smoothing the development process, is only one of its many strengths. It retains the best characteristics of the procedural and data-driven paradigms while overcoming or minimizing their worst features. For example, the models created during analysis help developers understand the problem domain similarly to data-driven models because classes represent data. But classes also denote operations or procedures, so the transition from design to implementation is similar to the procedural paradigm. Furthermore, as each class defines a new, intermediate scope (the region of a program where a variable is visible and accessible), the object-oriented paradigm also allows some but not all of the procedures in a program to access the data. Controlling data access reduces the functional coupling that practically limits the size and complexity of software created with the procedural paradigm. The many strengths of the object-oriented paradigm make it the current best practice for creating large, complex software systems.

Paradigms: Java Versus C++

Java is a pure object-oriented language that only supports the object-oriented paradigm. For this reason, Java programs necessarily define everything, including library methods and symbolic constants, inside classes. Alternatively, C++ is a hybrid language supporting the procedural and object-oriented paradigms. C++ allows developers to choose the paradigm most appropriate for a given problem: the object-oriented paradigm for large, complex problems and the procedural paradigm for smaller, less complex problems.


1 Jurison, J. (1999). Software project management: The manager's view. Communications of the Association for Information Systems, 2, Article 17, 1-57.