Professional Documents
Culture Documents
4.1 Modular Design Review: Provide Simple Interfaces
4.1 Modular Design Review: Provide Simple Interfaces
related functions that can benefit from a common implementation or that are used in
many parts of a system,
Notice that we do not say that a module should contain functions that are logically related
because, for example, they solve the same part of a problem. This sort of decomposition does not
normally facilitate maintenance or promote code reuse.
Use appropriate tools.
While modular designs can in principle be implemented in any programming language,
implementation is easier if the language supports information hiding by permitting the
encapsulation of code and data structures. Fundamental mechanisms in this regard include the
procedure (or subroutine or function) with its locally scoped variables and argument list, used to
encapsulate code; the user-defined datatype, used to encapsulate data; and dynamic memory
allocation, which allows subprograms to acquire storage without the involvement of the calling
program. These features are supported by most modern languages (e.g., C++ , Fortran 90, and
Ada) but are lacking or rudimentary in some older languages (e.g., Fortran 77).
Design checklist.
The following design checklist can be used to evaluate the success of a modular design. As
usual, each question should be answered in the affirmative.
1. Does the design identify clearly defined modules?
2. Does each module have a clearly defined purpose? (Can you summarize it in one
sentence?)
3. Is each module's interface sufficiently abstract that you do not need to think about its
implementation in order to understand it? Does it hide its implementation details from
other modules?
4. Have you subdivided modules as far as usefully possible?
5. Have you verified that different modules do not replicate functionality?
6. Have you isolated those aspects of the design that are most hardware specific, complex,
or otherwise likely to change?
Example
Database search:
We use a simple example to illustrate how information hiding considerations can influence
design. To search a database for records matching a specified search pattern, we must read the
database, search the database, and write any matching records found. One possible
decomposition of this problem defines input, search, and output modules with the following
interfaces.
input(in_file, database)
An examination of what must be done to read a database, perform a search, and so on could then
lead us to define the procedures that comprise the input, search, and output modules.
This design provides simple interfaces. However, all three modules depend on the internal
representation used for the database, and hence must be modified if this representation is
changed. In addition, each module probably duplicates database access functions.
An alternative decomposition, driven by information hiding concerns, focuses on the internal
representation of the database as something potentially complex, likely to change, and common
to many components. Hence, this information is hidden in a single database module that provides
operations such as the following.
read_record(file, id, record)
The rest of the program can now be written without knowing anything about how the database is
implemented. To change the internal representation of the database, we need simply to substitute
a different implementation of the database module, which furthermore is ideally suited for reuse
in other applications.