The document discusses software design and modularity. It emphasizes that software should be designed for maintainability in addition to performance. Modularity principles like high cohesion and loose coupling are presented, including the benefits of strong cohesion through functional grouping and loose coupling through small, flexible interfaces. Examples of good and bad modularity in code are provided.
2. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 2
About this module
Software should be designed not just for performance, but also for
maintainability! Why?
⢠Save on maintenance costs
Post-release defect removal
Minor adjustments
⢠Save on verification costs
Higher pre-release fault detection and removal rate
⢠Save on development costs
Lower fault injection rate
⢠Facilitate teamwork
Software that is more maintainable is also easier to understand
Design for maintainability requires special techniques
⢠Message of the textbookâs cover picture?
3. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 3
Basic concept: modularity
A software system should be split into modules
⢠To facilitate future change
By minimizing the scope of change
⢠To avoid need for future change
By containing change within isolated modules
⢠To reduce development time and effort
By simplifying the system
By postponing design decisions until optimal time, and avoiding some
expensive optimizations
By allowing comprehension and reasoning on modules and interfaces
4. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 4
Modularity
Two main criteria:
⢠Cohesion: a measure of tightness of relationships within a module
⢠Coupling: a measure of tightness of relationships among modules
Tradeoff:
⢠Strong cohesion:
Focused modules
More granularity
⢠Loose coupling:
Isolated modules
Less granularity (to avoid split dependencies)
⢠Optimum: around 7+-2 modules at each level of abstraction
This holds for large modules (subsystems) and small modules (individual
objects or routines) alike
This is just an estimate, not an absolute rule
5. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 5
Cohesion
âSingle-minded functionalityâ: operations in a module should be strongly
related
Types of cohesion:
(HIGH)
⢠Functional: perform one function only
⢠Communicational: use the same data
⢠Sequential: an incomplete sequence of causally-related actions
⢠Procedural: sequence of non-causally-related actions
⢠Temporal: actions that are performed at the same time
⢠Logical: decision branches
⢠Coincidental: no discernable relationship
(LOW)
6. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 6
Strong cohesion
Heuristics
⢠Partition the system according to dependency clusters
⢠Isolate presentation, data management, and processing
MVC architectures
⢠Isolate control from work
Focus on control-only or work-only
High-cohesion âcontrol-onlyâ modules
Dispatching events
Startup and shutdown routines (delegate the individual tasks)
⢠Isolate main functionality from auxiliary functionality
Exception throwing
Garbage collection
⢠A complex name usually indicates poor cohesion
Split âgetAndSetâ routines
7. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 7
Example of strong cohesion
From [BD]:
Alternative
Decision
Criterion
subtasks
*
SubTask
ActionItem
DesignProblem
Task
assesses
solvableBy
resolvedBy
based-on
* * *
implementedBy
DecisionSubsystem
RationaleSubsystem
PlanningSubsystem
8. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 8
Decoupling
âAversion to interactionâ: different modules should be detached
Types of coupling:
⢠Simple-data ("normal"): non-structured parameter list
⢠Data-structure ("stamp"): structured parameter
⢠Control: select a callee task by a flag parameter
Logical cohesion
⢠External: the program is tied to a particular device or environment
=> non-portable
⢠Global-data ("common"): two routines access the same global data
At least make it read-only
⢠Pathological ("content"): use internal data of a different module
E.g. via pointers
9. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 9
Loose coupling
Heuristics:
⢠Small interfaces: few parameters
⢠Adapted interfaces: convenient for the callee
⢠Flexible interfaces: convenient for many callers
Orthogonality
⢠Visible interfaces: no direct access to protected data
⢠Avoid pathological coupling: pass parameters through interfaces
float[][] A;
x = det(A);
⢠Avoid stamp coupling: decompose bundles of parameters into basic
types or very-high-cohesion parameters (e.g. events)
⢠Avoid external coupling: use IDEs that produce portable code
⢠Avoid global-data coupling: In object-oriented programs, use âgetâ
and âsetâ methods to read and modify object attributes
10. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 10
Example of loose coupling
Adapted from [BD]: change from binary tree to linked list
⢠Parse tree for a + b + c
add1:Node
add2:Node
c:Nodeb:Node
a:Node
add:Node
c:Nodeb:Nodea:Node
Sharing through attributes
class Node {
Node left;
Node right;
String name;
}
Sharing through operations
class Node {
Enumeration getArguments();
String getName();
}
Sharing through attributes
class Node {
Node next;
String name;
}
Sharing through operations
class Node {
Enumeration getArguments();
String getName();
}
11. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 11
Example of bad modularity
/* If 'direction' is 0, input n rows
into array 'lines';
otherwise output n rows from array 'lines'.
Pre: 0 <= n <= length(lines).
*/
in_out (
int n, /* number of rows, input or output */
int direction /* control flag: 0 = in, 1 = out */
) {
int i;
for (i = 0; i < n; i ++) {
if (direction == 0) {
read one input row into lines[i];
} else {
write lines[i];
}
}
}
/* Read n lines of input.
Output the lines in sorted order.
Pre: 0 <= n <= length(lines).
*/
input_sort_echo(
int n /* number of rows to be sorted */
) {
int i, j;
in_out(n, 0);
for (i = 0; i < n - 1; i ++) {
for (j = i + 1; j < n; j ++) {
if (lines[j] <= lines[i] alphabetically) {
copy string lines[j] into string temp;
copy string lines[i] into string lines[j];
copy string temp into string lines[i];
}
}
}
in_out(n, 1);
}
12. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 12
Improving modularity
Global-data coupling:
⢠Both routines access array lines
⢠Fix: the access to array lines and string temp can be made explicit in
the routine interfaces
Logical cohesion:
⢠The same routine (in_out) performs unrelated operations
⢠Fix: split into an input routine and an output routine
Communicational or temporal cohesion:
⢠The same routine (input_sort_echo) controls the flow and does the
sorting
⢠Fix: call sorting as a sub-routine
13. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 13
Example of improved modularity
/* Input n rows to 'lines';
Pre: 0 <= n <= length(lines). */
in(
int n, /* number of rows to be input */
StringArray lines /* storage */
) {
int i;
for (i = 0; i < n; i ++) {
input lines[i]; /* read one row */
}
}
...
sort(
int n, /* number of rows to be input */
StringArray lines /*
) { ...
...
out(
int n, /* number of rows to be input */
StringArray lines /*
) {...
/* Read n rows and output them sorted.
Pre: n >= 0
*/
input_sort_echo(
int n /* number of rows to handle */
) {
Declare and allocate StringArray lines;
in(n, lines);
sort(n, lines);
out(n, lines);
}
14. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 14
Design process
Design: blackbox model full-detail (clearbox, whitebox, glassbox)
⢠Choose among several alternatives
Consider solutions permitted by the analysis model
Heuristics, patterns
Constraints, invariants
Optimize design goals tradeoffs
Select and prioritize goals: maintainability, usability, performance, etc.
⢠Iterate through the design
Why?
Brainstorming and consolidation
Prototypes to clear out technical risks
Several levels of abstraction
Several viewpoints, design goals
Fixing defects
Know where to stop
Review criteria
15. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 15
Overview of software design
System-level
⢠Using the analysis model as a starting point, take high-level decisions
to optimize the selected design goals
Object-level
⢠âClose the gapâ between the architecture model and the deployment
platform
Detailed
⢠Organize and build code in a way that supports change and reasoning
Specialized design
⢠UI design
⢠Function-oriented design
⢠Real-time, etc.
16. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 16
System-level design
System-level design typically comprises the following activities:
⢠Identifying design goals and constraints
⢠Defining the architecture
Decomposing the system into subsystems
Selecting system-wide conventions and policies:
Persistency
Security
Global control flow
Boundary conditions: start-up, shut-down, error handling
⢠Selecting reusable components, libraries, etc.
⢠Mapping to hardware
17. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 17
Object design
The following activities are typically performed at this level:
⢠Identifying design objects: implementation-specific classes
⢠Service specification: precisely describe interfaces
⢠Component selection: find pre-made parts that are suitable for the
functionality of the system
⢠Object model restructuring: optimize maintainability
Reduce multiplicity
Implement binary associations as references
Merge similar classes
Collapse trivial classes into attributes
Split complex classes
⢠Object model optimization: optimize performance
Use different algorithms / data structures
Add or remove redundant associations
Add derived attributes
âOpen upâ the architecture
18. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 18
Design goals
First thing: determine goals and priorities
⢠Include viewpoints of several stakeholders
⢠See [BD, sect.6.4.2] for a comprehensive list of software design goals
⢠Relative importance varies depending on the nature of the application
19. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 19
Design goals
End-user / customer / sponsor Developer / maintainer
scope x
low cost/effort x x
low dev. time x x
low defect rate x x
modifiability x
comprehensibility x x
reliability x
robustness x
user-friendliness x
documentation x x
reusability x
adaptability x
portability x
backward compatibility x
performance x
memory efficiency x
20. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 20
Performance measures
Running time is not a single, well-defined measure
⢠Consider all input data and internal non-determinism
⢠Worst-case: maximum value
E.g. car airbag controller: worst-case is critical
Polling: time = (#sensors) * (time per sensor) + (alarm time)
Interrupts: time = (interrupt path length) * (hub delay) + (alarm time)
⢠Average-case : weighted by operation frequency (operational profile)
E.g. text editor: average-case is more important than worst-case
E.g. videophone image compression: both worst-case and average-case are
important
⢠Amortized: mean taken over an operating cycle
E.g. the average number of bit flips in an n-bit number
Answer: 2! (Why?)
21. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 21
Performance measures
Many performance measures
⢠Latency vs. throughput
E.g., an IDE that does background compilation performs more work to
improve average latency
E.g., a web service might have a fixed limit on the response time (latency),
and optimize the maximum number of simultaneous requests (throughput)
⢠Memory requirements
Data storage: scalability, garbage collection
⢠Number of expensive operations (function calls, multiplications, etc.)
⢠Number of accesses to communications, external storage, or I/O
resources
E.g. a trip planner might allow increased response time to minimize wireless
communication time
22. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 22
Design tradeoffs
Typical design tradeoffs:
⢠Rapid development vs. scope
⢠Performance vs. maintainability
Orders of growth
⢠Performance vs. portability
⢠Backward compatibility vs. comprehensibility
⢠Cost, delivery time vs. robustness, reusability
Not to be confused with cost vs. other quality parameters
⢠Space vs. speed
Why operating systems, IDEs, etc. will fill up hard drives of any sizes?
Not easily traded:
⢠Quality vs. effort
Low defect rate, maintainability, comprehensibility, documentation
Early in the project: non-tradeable
Late in the project: tradeable to a small extent
⢠Delivery time vs. staffing
Only early in the project
Brooksâ law: adding people to a late project only makes it later
23. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 23
Software architecture
Architectural design should address:
⢠Subsystem decomposition
⢠System-wide policies
Data organization
Control flow
Communication protocols
Error handling
Mapping to hardware
Security
⢠NOT development methodology issues, such as object-orientation vs.
function-orientation
24. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 24
Basic definitions
Subsystems
⢠Parts of a system
⢠Can be developed and changed independently (more or less)
⢠Example: UI evolves independently from business logic
Services
⢠A service provided by a subsystem = a set of operations of that
subsystem that share a common purpose
⢠Examples: download, upload, notification, management, âŚ
Interfaces
⢠An interface of a subsystem = a black-box view of that subsystem
As seen by an actor or by another subsystem
⢠API: operations, signatures, and specifications
Signature = parameter types, return type
Example: doGet method of HttpServlet class
SURWHFWHG YRLGSURWHFWHG YRLGSURWHFWHG YRLGSURWHFWHG YRLG GR*HWGR*HWGR*HWGR*HW+WWS6HUYOHW5HTXHVW+WWS6HUYOHW5HTXHVW+WWS6HUYOHW5HTXHVW+WWS6HUYOHW5HTXHVW UHTUHTUHTUHT +WWS6HUYOHW5HVSRQVH+WWS6HUYOHW5HVSRQVH+WWS6HUYOHW5HVSRQVH+WWS6HUYOHW5HVSRQVH UHVSUHVSUHVSUHVS
29. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 25
Defining the architecture
Decomposition into subsystems
⢠Heuristics
Use variants of Abbottâs lexical rules: nouns, verbs
Identify groups of objects involved in use cases
Encapsulate functionally related classes - Facade pattern
Isolate scope overlaps among use cases
Create dedicated subsystems for moving data among subsystems
Create a separate subsystem for the user interface
Encapsulate legacy code - Adaptor pattern
30. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 26
Layers and partitions
Different ways of decomposing the system:
⢠Layering: each subsystem provides a level of abstraction
Closed architecture: each layer can access services from the layer
immediately below it. E.g. ISO OSI
Open architecture: each layer can access services from any layers below it
E.g. Motif toolkit for X11
⢠Partitioning: peer subsystems with as few dependencies as possible
⢠Not a clear distinction between layering and partitioning
A B C
D E
F G H
31. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 27
Common architectures
Design the data first, then the control
⢠During analysis, may assume objects run whenever needed
⢠During design, the object behavior should be determined so that the
object does indeed run whenever needed
Types of data organization schemes:
⢠Repository
⢠Model-view-controller (âarchitectureâ, âframeworkâ, âpatternâ)
⢠Client/server
⢠Peer-to-peer
⢠Pipe-and-filter / data flow
Types of control flow:
⢠Centralized
⢠Event-driven
⢠Thread-based
32. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 28
Repository architecture
Subsystems interact by sharing data in a central repository
The repository may also implement control flow
⢠Serialize concurrent accesses of processing subsystems
⢠Activate subsystems depending on state of data (âblackboardâ)
E.g. DBMS, compilers [BD], various CAD tools
LexicalAnalyzer
SyntacticAnalyzer
SemanticAnalyzer
CodeGenerator
SourceLevelDebugger SyntacticEditor
ParseTree SymbolTable
Compiler
Repository
Optimizer
33. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 29
Repository architecture
Pros:
⢠Decoupled subsystems; easy to add new ones
Cons:
⢠Repository may become a bottleneck
⢠Strong coupling between each subsystem and the repository
34. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 30
Model-view-controller
A.k.a. MVC
Partition data representation (model), presentation (view), and control
⢠One of the first design patterns: model state updates are reported to
all views
Refined to âobserver patternâ (will see later)
May use âListenerâ objects in Java
⢠Special case of the repository architecture, if the model is considered
to be the data repository
Controller
Model
subscriber
notifier
initiator
*
repository1
1
*
View
35. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 31
Model-view-controller
Pros:
⢠Allows independent change of model, view, and controller
⢠Allows subscription at runtime
⢠Isolates variability, as the views are less stable than the model
Cons:
⢠The model may become a performance bottleneck
36. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 32
Client-server
Servers provide services to clients
⢠E.g. central database
⢠E.g. communication systems
Web server; DNS
Mail server; news server; ...
⢠Suitable for distributed systems that process large amounts of data
Why?
37. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 33
Client-server
Three-tiered architecture:
Browser
WebServer
Servlet
DataBase
JDBC
http request
service
query
SQL query table
result set
string
web page
38. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 34
Peer-to-peer
Peer-to-peer:
⢠Generalize client-server systems
⢠Each subsystem can request and provide services
E.g. a database that can also notify the application
⢠More difficult to design
Many possible interleavings of messages/service requests
Many possible modes of failure in concurrent/distributed systems
Deadlock
Unfairness/starvation
Livelock/divergence
...?
Process1
Resource1
Resource2
Process2
1:req
5:req 3:req
4:ack
2:ack
6:req
39. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 35
Pipe-and-filter
Filters: processing subsystems
⢠Executing concurrently
Pipes: associations between filters
⢠Data transfer
⢠Synchronization
E.g. UNIX shell [BD]
ps grep sort more
40. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 36
Centralized control
Two types
⢠Call-return (procedure-driven): sequential subroutine calls
Rigid = easy to debug, but locks resources
⢠Manager: one component is designated to control a concurrent
system
E.g.: a repository database that can signal changes
Flexible = Better real-time response, efficiency
More difficult to design = interleaving, modes of failure
41. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 37
Event-driven control
Two types
⢠Interrupt-driven
Interrupts are serviced immediately (according to priority)
Offers execution time bounds, hence good for real-time systems
⢠Broadcast
Events are broadcast to several listeners, who will handle them when they
can
Better modularity, but no time bounds
Usually combined with the MVC architecture
42. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 38
Broadcast events example
Events are key to implementing graphical user interfaces
⢠The broadcast method of the source may be invoked automatically
upon occurrence of an event
Example: ActionEvents are emitted by Button objects
addActionListener(
ActionListener)
removeActionListener(
ActionListener)
...
ActionListener
actionPerformed(
ActionEvent)
MyListener
actionPerformed(
ActionEvent e)
ActionEvent
getActionCommand()
getSource()
e
* 1
1
*
1 *
Button
43. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 39
Broadcast events example
Example: Mouse events are emitted by a Component object
⢠Applets and other subclasses of Component inherit its methods
⢠Mouse movement events are sent to a different listener
(MouseMotionListener)
MouseListener
mouseClicked(
MouseEvent)
mousePressed(
MouseEvent)
...
MyListener
MouseEvent
Point getPoint()
setPoint(Point)
* 1
1
*
1 *
mouseClicked(
MouseEvent)
mousePressed(
MouseEvent)
...
addMouseListener(
MouseListener)
addMouseMotionListener(
MouseMotionListener)
âŚ
Component
...
Applet
1 *
MouseMotionListener
44. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 40
Using events
Events ensure communication between source and listener while
effectively decoupling the functionality of source and listener
⢠None needs to know the details of the other
⢠The connection can be made and cancelled dynamically
Event queues may be added to further decouple the timing of source and
listener
⢠Source and listener may operate at different rates
45. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 41
Thread-based control
Thread-based
⢠Several streams of execution that respond to different users, different
stimuli, different events, etc.
⢠Example: servlets
Service method
⢠Issue: mutual exclusion
Communication through shared variables
âsynchronizeâ
46. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 42
Threads example
class MyThread extends Thread {
int k = 0; // the data managed by the Thread
int m_id; // unique ID for each Thread
public MyThread(int id) {
m_id = id;
}
// print and update the data, i.e., integer k
// invoked whenever the system executes the Thread
public void run() {
for(;;) { // forever
System.out.println(Thread + m_id + : + k);
k++;
}
}
}
47. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 43
Thread-based control
⢠May use queues to further decouple request generation from request
handling
*
Stimulus Thread
**
Event
Stimulus Thread
*
Event queue
Event
*
1
*
1
Stimulus Thread
* *
48. McGill University ECSE 321 Š 2003 Radu Negulescu
Introduction to Software Engineering Software designâSlide 44
Using threads
Threads are used for modularity, not performance
⢠(Unless the OS scheduler is clever enough to map them to separate
processors)
⢠Decouple different user workflows
Different users
Different applications of same user
⢠Tracking different actors
⢠Mapping to different hardware
⢠Avoid concurrency
⢠Handle concurrency with mutual exclusion (synchronize)