Fundamental Programming Principles I
System Experiments Laboratory
Software of good quality is intended as software that responds
to some specified quality criteria, such as correctness,
maintainability, robustness, etc. It follows that to develop
software of good quality, it is necessary to have discipline, to
apply a coherent system of techniques through the whole life cycle
of a program, and to apply well-known principles to all phases of
software development and maintenance. In synthesis, we can say that
the two fundamental programming principles are abstraction
Abstraction, in the programming context, is a generalization
process where the developer concentrates on similarities pertaining
to a set of objects, excluding other aspects that diversify these
objects, arriving in this way at the construction of a new object
that generalizes them. In designing programs the developer can
proceed describing initially, in abstract way, the algorithm and
the data on which it operates, then proceeding to refinements of
the abstract description in terms of more and more detailed and
There are three types of abstractions:
- The Functional Abstraction, is used when a set
of instructions or complex operations are complessively expressed
with a procedure or function.
- The Data Type Abstraction, is used with
abstract data types and their related operations, ignoring aspects
pertaining the low-level data representation and the related
- The Control Abstraction, consists in using
high-level instructions without specifying the exact mechanism of
Structuration means subdividing programs in modules. The
fundamental mechanism by which structure can be given to a program
consists in using functional abstraction. Here I use the
general term module to indicate both a procedure or a
function. The criteria by which the set of instructions of a
program can be subdivided and structured in a set of modules are
functional independence, hierarchical
decomposition, information restriction, and data
- Functional Independence, consists in giving
the maximum independence to the modules of which the program is
composed. More each module executes a well-defined program feature,
distinguished and independent from the features executed by other
modules, more the program is complessively understandable.
Functional independence can in turn be expressed in terms of two
criteria: the maximization of cohesion of computations
internal to each module, and the minimization of coupling
between modules due to shared state (shared data between modules,
global variables). Functional independence is often called
"separation of concerns", it is one of the key factors that enables
reusability of modules. Less frequently we see the term "separation
of duty", which seem to have approximately the same conceptual
meaning as "separation of concerns".
- Hierarchical Decomposition, consists in
decomposing a program in modules that realize simple features local
to a particular aspect of the problem to solve. In a program
decomposed into a set of modules that call themselves
hierarchically, following a tree structure, the feature executed by
each module is easier to understand and can be easily identified
relatively to the features of other modules.
- Information Restriction, basically signify
that each module communicates with other modules by means of a
restricted non-shared data flow in the form of a well-defined
set of parameters, restricting in this way the visibility of
the underlying mechanisms by which local computations are executed
internally to each module.
- Data Type Abstraction, by which some
particular modules can be seen as representations of abstract data
types. Other modules interact with these particular modules only by
means of the operations defined on the represented abstract data
Abstraction and Structuration: A Twofold Principle
Guaranteeing the good modularity of a program, allows attainment
of other properties, such as readability,
maintainability, and correctness. On the basis of
what said above, proceeding by levels of abstraction, and
structuring a program in modules, are two different views of the
same general principle:
- On one hand, by proceeding from the abstract to the concrete,
development of highly structured programs is generally
- On the other hand, to guarantee good modularity of a program,
the developer must have at each moment a global vision of the
program, that can be obtained more easily by proceeding with
structuration in successive refinements.
The design strategy inspired directly to the abstraction
principle introduced above is called top-down strategy.
Using the top-down strategy, the developer decomposes a problem
iteratively into smaller subproblems, the combined solution of
which constitutes the solution of the initial problem. Using the
abstractions seen above, the developer proceeds in the
decomposition of the problem until each single subproblem has a
simple structure that can be expressed directly by instructions of
the programming language.
In practice, the first decomposition of a program, can be seen
as a functional abstraction, while the successive decompositions
are applications of data type abstration and control
- The functional decomposition is used each time
the developer establishes that some program feature responds to a
significative modularity criteria.
- The sequential decomposition is used when in
the analysis of a problem the developer sees that the problem can
be decomposed in a set (or serie) of elementar actions that must be
executed one after the other.
- The alternative decomposition is used when the
problem can be decomposed in terms of choices between different
- The iterative decomposition is used when the
developer sees a refinement of the problem where some actions must
be executed many times.
The inverse strategy, called bottom-up strategy, is
used sometimes to integrate preexisting modules into a program, or
to integrate a small program into a bigger one.
Code has a number of properties. In no particular order:
- Correctness, intended as adhesion of the
program's implementation to the problem specification. Correctness
of a program should be verifiable, so correctness leads us to the
next fundamental property: verifiability.
- Verifiability, it should be reasonably easy to
verify the correctness of a program.
Locality - the verifier shouldn't have to refer to
many separate pieces of code to prove correctness. It occurs that
locality is connected to functional independence as it promotes
cohesion of code.
- Robustness, intended as capacity of the
program to operate predictably, despite the introduction of input
data incoherent with its specification.
- Maintainability, intended as ease of
adaptation and transformation of the program when the specification
changes. A program that is easy to modify shouldn't be fragile. A
small modification shouldn't make it fail in unexpected ways.
It occurs that the robustness and maintainability
properties are somehow connected.
- Simplicity, intended as the possibility to
identify easily the program starting from the corresponding
- Efficiency, intended as the capacity of the
program to execute with small use of resources (CPU, RAM,
stack/heap, disk, etc.). An additional requirement for real-time
programs is to execute within bound space and time.
- Modularity, intended as the degree of internal
organization and structuration of the program, that must allow the
ability to understand how the various parts of the program
cooperate to the general scope.
- Readability, intended as the ability, of the
designer or other persons, to understand the program at each
moment. For a program to be easy to read and understand, it should
not be obscured by non-essential coding forms. It should be easy
for the person reading it to assimilate one concept at a time.
- Portability, intended as the possibility to
execute the program in various computing environments without
- Generality, intended as the degree of
generality that the program provides in the resolution not only of
a single problem, but rather of a class of problems, so that it is