720 likes | 1.74k Views
Modular Design. What are modules? Good modules Criteria for evaluating modularity Hierarchy Modules and Classes Namespaces Other tricks and techniques. Modularity -- What does it look like?. Modularity packages abstractions into discrete units. What are Modules?.
E N D
Modular Design • What are modules? • Good modules • Criteria for evaluating modularity • Hierarchy • Modules and Classes • Namespaces • Other tricks and techniques sd
Modularity -- What does it look like? Modularity packages abstractions into discrete units. sd
What are Modules? • Modules are just another name to software units: • Pieces of code • They should have “building block” properties: • Independent • Well-defined interface • Examples: • Routines • AKA procedures, functions, subprograms, subroutines, etc. • Files • as in C • Packages • as in ADA • Modules • as in Modula • Objects • Classes sd
Good Modules • Two aspects to a module: • interface • specification in Ada • *.h in C “One must provide the intended user with all the information needed to use the module correctly, with nothing more.” David Parnas [1972]: • implementation • called a body in Ada • *.c in C “One must provide the implementer with all the information needed to complete the module, and nothing more.” David Parnas [1972]: sd
Good Modularity • “Modularity - the property of a system that has been decomposed into a set of cohesive and looselycoupled modules.” [G. Booch, OODwA, '91, p. 52] • Cohesion • Loose coupling • Criteria for evaluating the quality of modularity in a system or a design methodology [Meyer, OOSC ‘88]: • Global Criteria • Decomposability • Composability • Continuity • Local Criteria • Continuity • Understandability • Protection sd
Decomposability • Divide a problem into several sub-problems, and work on each sub-problem individually. • Examples: • Top-down design • Automobile systems: • Transmission • Brake • Electricity • Operating System: • File system • Processes • Timer • Counter Examples: • Initialization module • The C++ Programming Language: There is no decent sub-language other than C! • MS-Windows: No simple uninstall strategy. sd
Composability • Build a new system from existing components • Examples: • Good Procedure Libraries • C stdio • C strings • IMSL • Common Data Format (usually weakly typed) • RTF: Rich Text Format. • Lisp: the nested list metaphor. • UNIX filters: text files. • ML: Hyper Text Markup Language. • IMSL: Numerical computation library: real vectors/matrices. • OLE/VBX Controls. • Counter Examples: • Most DOS applications • Pre-processors sd
Continuity • Small change in problem specification leads to a small change in the module/system • Examples: • #define MAX_ELEMENTS 50 • Counter Examples: • Changes in data formats • Top-down design • Dependency on implementation: function/variable • if (f.eof) • if (f.eof()) sd
Understandability • Understand a module by examining at most few of its neighbours • Examples: • Smalltalk containers library • Counter Examples: • Most current applications sd
Protection • Modular Protection • Effects of errors limited to one module, or at most few of its neighbours. • Examples: if (!(p = calloc(MAX_ELEMENTS, sizeof *p))) { printf(stderr, ”cannot allocate...\n”); ...} • Counter Examples: f(){char s[100]; gets(s); ....} sd
Achieving Good Modular Design • The Main Technique: • Hierarchy • A person can usually understand • the magical number seven plus minus one or two. • In order to deal with large system, one must be able to organize it in a hierarchy of abstractions. • Even finding good names and identifiers become a problem, e.g.,dbg_dbg_std_open() sd
Hierarchy • Example: Computer Organization: • Pascal virtual machine downto microcode. • Mechanisms for building a hierarchy: • Conceptual layers (e.g., ISO communication model). • User discipline. • Lingual Mechanisms: • routine • class (only in OOP languages) • file/cluster of classes • -- missing link! • nested procedures? • nested modules? • namespaces? • directories? • categories? sd
Modules and Classes • Simple and pure OOP approach: • Class = Module • Module = Class Difficulty: need higher level structures • More sophisticated approach: • Classes and objects are implemented in modules to produce the architecture of a system. • Independent design decisions: • Logical design: Finding the classes and objects. • Physical design: Organizing the classes and objects into modules. sd
Classes as Namespaces • In C++ each class forms a namespace, in which one can make enum, typedef and even class and struct definitions. • Let class specific definitions belong in its namespace • Example: enumerated typed as symbolic constants class Stack { enum {DEFAULT_SIZE = 1000 }; ...}; The alternate ways for defining symbolic constants, #define DEFAULT_SIZE 1000 and constint DEFAULT_SIZE = 1000; are much less modular. sd
Classes as Namespaces (cont.) • Example : Type definitions class String{private: typedef char* pchar; ...}; class Date{public: typedef enum { Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec } Month;...}; sd
More on Classes as Namespaces Static class variables can be used to define class specific variables class Complex {public: static Complex Infinity; enum {DEFAULT_SIZE = 1000 };}; f(Complex c){if (c == Complex::Infinity) { ... } ... } sd
Nested Classes Class nesting can be used to group together related classes: class Stack {public: class Overflow { }; // May be thrown from push()class Underflow { }; // May be thrown from pop() ...}; class Tree23{private: class Node { ... }; class InternalNode: public Node {...}; class ExternalNode: public Node {...}; ...}; sd
Namespaces namespace TurboWindows { class Window {... }; Window *display;} • Define • Use single element by explicit qualification TurboWindows::display.clear(); • Incorporate a single element via ausing-declaration using TurboWindows::display; ... display.clear(); • Incorporate an entire namespace via a using-directive usingnamespace TurboWindows; ... display.clear(); sd
Nested Namespaces namespace Technion {namespace Base {namespace Math {class Complex { ... }; ... }namespace Types {class String { ... };class Date { ... }; Date today; ... } }namespace DataStructures {class Stack { ... };class Queue { ... }; ... }namespace Windows {class Window { ... }; ... }} sd
Adding Elements to Namespaces namespace Technion {namespace Windows {class Window { ... }; }} ... #include <stdio.h>... namespace Technion {namespace Windows { Window *display; }} sd
Manipulating Namespaces // Alias to a namespacenamespace Math = Technion::Math; // Composing namespacesnamespace My {usingnamespace Technion::Base::Types;usingnamespace HebrewUniversity::Math;usingnamespace GNU::String; // Overloads Technion::Base::Types::String}; sd
Decisions in Modular Design • Grouping of logically-related classes together • Example: tree, tree-node, and tree-iterator • Rule of thumb: • 5 or so classes • 10-15 or so functions • Concerns: • Work is partitioned by modules • Machine architecture constraints • Reuse of modules across applications • Isolate machine dependencies • Isolate configuration dependencies • Partitioning of each module into interface and implementation parts • Recall Parnas’ rules. • Visibility graph among modules These decisions are a creative and inventive process. They can never be made in any disciplined order! sd
Techniques for Good Modularity Bertrand Meyer [OOSC ‘88] enumerates five principles that “ensure proper modularity”: • Creativity is Dangerous: • Linguistic modular units • Must use proper language constructs • Totalitarian Regime Communication: • Few interfaces • You may talk with only few others! • Small interface • You may use only few words in your conversation! • Explicit interface • All conversations. • Paranoid Approach: • Information Hiding • Everything is secret unless explicitly declared otherwise. sd
Linguistic Modular Units • Demand • Modules must correspond to syntactic units in the languages used. • Rationale • Global • Decomposability: There should be a clear boundary between modules. • Composability: Dispersed modules cannot be conveniently recomposed. • Local • Understandability: Dispersed modules are difficult to understand. • Protection: The best protection is that of the compiler. Programmers tend to break non enforceable rules. • Conclusion • It is foolish to make a modular design for Cobol! sd
Few Interfaces • Demand • Every module should communicate with as few others as possible. • Rationale • Global: • Continuity: changes less likely to affect other modules. • Local: • Understandability: small neighbourhood to consider. • Protection: less likely to affect others. sd
Module Architecture #1/4 • Complete Graph • Maximal number of interfaces: n(n-1)/2 • Worst case! sd
Module Architecture #2/4 • Shallow Tree (Star) • Minimal number of interfaces n-1 • Best case in terms of the total number of connections, but there is a node of a very high degree n-1 sd
Module Architecture #3/4 • Binary (Low Degree) Tree • Minimal number of interfaces n-1 • Best case in terms of • total number of connections. • maximal number of connections. • usually three. • Try to keep the diameter small. • More generally, low expansion property is desired. sd
Module Architecture #4/4 • Planar Graph • Reasonable number of interfaces: 3n-6 • Relatively simple to draw (can use straight lines only...) • Typical in OOP • Try to keep the degree small sd
Cycles in the Interfaces Graph Buffer Handle Chunk Hanoi Node List • Recall that the graph is directed. • Cycles are usually a bad sign. • Large cycles are unacceptable! • Small cycles are in many cases OK: sd
Mutually Recursive Routines Peano North Peano West Peano East Peano South Peano Curve: sd
Biconnected Components • Biconnected Components are usually candidates for higher level clusterization: sd
Small Interface (Weak Coupling) • Demand • If two modules communicate at all, they should exchange as little information as possible. • Rationale • Global • Continuity: changes less likely to affect other modules • Local • Understandability: small neighbourhood to consider • Protection: less likely to affect others • Conclusion (also from “few interfaces”): • Ban • C global variables • Fortran global garbage block sd
Coupling StrongCoupling WeakCoupling Classical Levels of Coupling [Myers ‘78], [Stevens, Constantine, Myers ‘81] • Content - A module refers directly to the contents (source code) of another. • Examples: Modify statement, jump to internal label, refer to local data through numerical offset, etc. • Common - Access to the same global data. • Examples: C’s global variables, Fortran’s common block. • Control - Directly affect the control of another module. • Examples: pass control flag, request one module to print an error message for another, prescribed order among modules. • Parameter - AKA signature coupling, occurs when a data structure is used to pass information between modules. • Hardly a concern in strongly typed languages. • Data Coupling - Occurs when all parameters are either simple, or, data structures all of whose elements are used. Irrelevant in modern languages, replaced by: • Subtype Coupling - Inheritance. sd
Explicit Interfaces • Demand • Whenever modules A and B communicate, this must be obvious from the text of A and B or both. • Dynamic tool (e.g. run-time system) or, better yet, static tool (e.g., compiler) should be able to check that the communication is done according to that interface. • Rationale • Global • Composability: Must know which modules are connected. • Local • Understandability: We should be able to know which modules are dependent on, and affect the one we try to understand. • Counter Examples: • Shared variables, files, etc. • Pointers. • Shared types. sd
Information Hiding • Demand: • All information about a module should be private unless it is specifically declared public. • Rationale: • Global: • Continuity: Changes to private parts will not affect other modules. • Local: • Protection: Protection from changes to internal data format. • Understandability: Gives two levels of understanding the module. • Counter Examples: • C’s struct • Pascal main Program • Examples: • Turbo/Borland Pascal’s units • C++’s class sd
Criteria & Principles Relationships Decomposability LinguisticModular Units Composability Few Interfaces Understandability Small Interfaces Continuity Explicit Interfaces Protection Information Hiding Hierarchy Principles Criteria SimpleInterfaces Cohesion sd
Cohesion WeakCohesion StrongCohesion Classical Levels of Cohesion [Myers ‘78] • Coincidental - Occurs when carelessly trying to satisfy style rules. • print_prompt_and_check_parameters • Logical - Related logic, but no corresponding relation in control or data. • Library of trigonometric functions, in which there is no relation between the implementation of the functions. • Temporal - Series of actions related in time. • Initialization module. • Sequential - Series of actions related to a step of the global processing. • read_inputs, check_all_inputs, output_result. • Communication- Series of actions related to a step of the processing of a single data item. May occur in the attempt to avoid control coupling. • clear_window_and_draw_its_frame • Functional - Execute a single, well-defined function or duty. • Data - Collection of related operations on the same data. sd