note 11: software design - university of wisconsin...
TRANSCRIPT
Computer Science and Software Engineering
University of Wisconsin - Platteville
Note 11: Software
Design
Yan ShiLecture Notes for SE 3330
UW-Platteville
Based on Pressman Chapter 10 & 11
Architectural Design
http://www.google.com/imgres?q=house+blueprint&hl=en&sa=X&biw=1366&bih=624&tbm=isch&prmd=imvns&tbnid=NthnyVrUQDxK-M:&imgrefurl=http://house-blueprints.net/blueprint_7728.htm&docid=URmpMpw_gJrljM&imgurl=http://house-blueprints.net/images/mf/7728_house_mf_plan_blueprint.jpg&w=600&h=446&ei=wk2OT5SgO5Kk8ASK7vG1Dg&zoom=1&iact=hc&vpx=275&vpy=309&dur=753&hovh=193&hovw=260&tx=152&ty=112&sig=106647714582772815655&page=1&tbnh=120&tbnw=160&start=0&ndsp=21&ved=1t:429,r:8,s:0,i:152
Software architecture
Architectural Design is the design process for identifying
— the structure of data and sub-systems making up a system;
— the framework for sub-system controls and communications
The output of this design process is a description of the software architecture.
Software Architectural Design
An early stage of the system design process.
Represents the link between specification and design processes.
Often carried out in parallel with some specification activities.
It involves identifying major system components and their communications.
Keys to Making Architectural
Design Decisions
NON FUNCTIONAL REQUIREMENTS!
Performance— Localize critical operations and minimize communications. Use large
rather than fine-grain components.
Security— Use a layered architecture with critical assets in the inner layers.
Availability— Include redundant components and mechanisms for fault tolerance.
Maintainability— Use fine-grain, replaceable components.
Architectural Design Tradeoffs
Using large-grain components improves performance but reduces maintainability.
Introducing redundant data improves availability but makes security more difficult.
Compromise solution must be found:Use different architectural styles for different parts of a
system!
Common Software Architectures
Data flow: Pipe and Filter
Data centric: Repository (discussed in SE2730)
Layered (discussed earlier)
Client-server (discussed in SE2730)
Object-Oriented
Service-Oriented
Data Flow Architecture
Application as a collection of pipes and filters.— Data enter the system and then flows through the components one at
a time until finally the data is assigned to some final destination (output or a data store).
Key: each filter works independently of others Typically have simple protocols between components
— ASCII text files— Comma-separated values (CSV) files— XML
http://www.dossier-andreas.net/software_architecture/pipe_and_filter.html
Repository Model
Data Centered:
central database accessed by multiple, independent software systems ("clients")
Repository Model Advantages
An efficient way to share large amounts of data— no need to transmit data directly between subsystems
— one data scheme shared by all client subsystems
Easy to add new clients— don't have to modify existing clients
— often can add new functionality without bringing whole system down
Uniform, centralized maintenance of data— one set of tools for backup, recovery
— relatively easy to monitor access
Repository Model Disadvantages
Must make performance compromises: what might be ideal for one subsystem may not be optimal for another
Security/backup policies can't be specialized to needs of particular subsystems
Making whole-sale changes to data model is difficult— must update a large number of clients simultaneously— typically must take whole system off-line
Distributing data becomes difficult— copying from one repository to another introduces
consistency problems
Layered Model
Each layer: an abstract machine with its own interface and services— Typically: some control on how different layers can
access others can only interface with layers on both sides, or can only
interface with "inner" layers
Examples— GUI apps: GUI+policy+domain
— OSI model for network communications
Layer model characteristic
Advantage:
— Supports the incremental development of sub-systems in different layers.
— When a layer interface changes, only the adjacent layer is affected.
— Easier to provide multi-platform implementations of an application system: only the inner, machine-dependent layer need to be re-implemented.
Disadvantage:
— Multiple levels of command interpretation may jeopardise system performance.
Client Server Model
Components:— a set of stand-alone servers providing services
— a set of clients which access and use the services
— communication network Often a simple bus or the internet
This is a key component!
ClientsServers Network
Applications Resources: files, devices, computation power
Thin Client and Fat Client
Software application functions are usually divided into three tiers:
Data Management
Business Logic
PresentationThin
Client
Fat
Client Application Servers
Client and Server Pros and Cons
Advantages: — servers don't need to know about clients (identities
or numbers) — can add new servers/upgrade existing servers
without having to modify all clients
Problems: — network can become a bottleneck — no shared data model so sub-systems use different
data organization. Data interchange may be inefficient Same data may have to be saved on multiple servers
Object-Oriented Architecture
An object-oriented design views a system as a series of cooperating objects, instead of a set of routines or procedural instructions.
Key Principles:— Abstraction— Composition— Inheritance— Encapsulation— Polymorphism— Decoupling
Service Oriented Architecture
Service-oriented architecture (SOA) enables application functionality to be provided as a set of services, and the creation of applications that make use of software services.
SOA key principles:— Services are autonomous. — Services are distributable. — Services are loosely coupled. — Services share schema and contract, not class. — Compatibility is based on policy.
Policy in this case means definition of features such as transport, protocol, and security.
Service Oriented Architecture (SOA)
http://techaffinity.com/blog/service-oriented-architecture-soa/
IaaS— Google Compute
Engine
PaaS— Google App Engine
Google Compute Engine vs App Engine
SaaS— Gmail
Daas— Homeowner and
credit score data
Service Oriented Architecture
Mohamed Marwan Selim, “An Empirical Analysis on the Microservices Architecture Pattern and Service-Oriented Architecture”, May 2016, Thesis
Component-Level Design
What is a component?
The conventional view: a functional element that incorporates — processing logic, — the internal data structures and — an interface
The object-oriented view: a set of collaborating classes.
Component-Level Design
After the first iteration of architectural design
For each component, define
— the internal data structures
— algorithms
— interface and communication mechanisms
at a level of abstraction close to code.
Effective Component Design
Functional Independence
— modules are single-minded; each module addresses specific set of requirements
— each module has a simple interface
How?
High Cohesion (single task) and Low Coupling (low communication)
Review: Cohesion and Coupling
Cohesive module: performs single task with minimal interaction with the rest of the system
Levels of cohesion:— coincidental < logical < temporal <= procedural <
communicational < functional (best)
Coupling: measurement of interconnections between modules
Levels of coupling:— content > common > control > stamp > data (best)
Cohesion
For simple systems, cohesion is not a significant problem.
For large, complex systems, low cohesion generally means more maintenance and testing costs; it can also lead to security problems.
The evolution of cohesion includes: — Coincidental cohesion (worst)— Logical cohesion— Temporal cohesion— Procedural cohesion— Communicational cohesion— Functional cohesion (best)
Coincidental Cohesion
Parts of a module are grouped arbitrarily (randomly).
Parts have no significant relationship.
Example: put all code in the main function
Causes:
— lack of creativity and/or experience
— rigid rules about module lengths
— maintenance without a design process can destroy structure, (for example we need to add this someplace, let’s just put it in here. )
Coincidental Cohesion (2)
Problems created by low cohesion:
— maintenance nightmares: cannot find defects or good places to extend functionality,
— hard to reuse such pieces,
— low efficiency,
— lots of data passing,
— harder to test, etc.
Logical Cohesion
Parts of a module are grouped because they are logically categorized to do the same thing, even if they are different by nature.
Example: group all I/O handling into one class (diskIO(), screenIO(), etc.)
At least this is predictable and one can generally find a function when needed!
Logical Cohesion (2)
Sometimes it is used to isolate code that is platform dependent and will need to be rewritten or seriously modified when ported to another platform. — Example: put all device drivers in one module.
Problems:
— interfaces hard to understand
— may lose efficiency due to data passing
— hard to scale up/distribute across multiple processors or computers.
— hard to reuse pieces
— may be nearly impossible to follow the flow.
Temporal Cohesion
Parts of a module are grouped by when they are processed. The parts are processed at a particular time in program
execution.
Example: a function which is called after catching an exception which closes open files, creates an error log, and notifies the user.
There use to be a need for this: — When memory was very small (32K or smaller) and virtual
memory was not common, programs had to be overlaid — We wanted to minimize the number of times needed to save
state, roll a chunk of program out of memory, and roll in a new chunk of program.
Problems: not any better than logical cohesion.
Procedural Cohesion
Parts of a module are grouped because they always follow a certain sequence of execution
Example: a function to check file permissions and then open the file
Problem: no better than temporal cohesion
— it is essentially temporal cohesion with added restriction that all the parts of the module correspond to a related action sequence in the program
Communicational Cohesion
Parts of a module are grouped because they operate on the same data.
Example:— Combine multiple calculations in a loop like mean,
min, max and standard deviation computed in the same loop.
— Functions that calculate and print based on the same data: addScoresComputeMeanPrintMean().
Benefit: Sometimes this is done to improve efficiency (avoid multiple data passing).
Problem: low reusability.
Functional Cohesion
Parts of a module are grouped because they all contribute to a single well-defined task of the module.
Example: I/O— One directory structure for each device, within which
a class for Input and a class for Output, who are children of abstract I/O class.
Functional cohesion is the ultimate goal!— Methods are short and to the point.— Ones related are grouped together locally in a file.
Advantages: — high reusability, — extensibility, and — maintainability
Exercise
class Areas { double circleArea() { ... }double rectangleArea() { ... }double triangleArea() { ... }
} class Plane {
double speed, altitude; takeoff() { ... }void fly() { ... }void land() { ... }
} class MyFunctions {
void initPrinter() { ... }double calcInterest() { ... }Date getDate() { ... }
} class Init {
void initDisk() { ... }void initPrinter() { ... } void initMonitor() { ... }
}
// logical cohesion
// communicational cohesion:// they all work on speed and altitude
// coincidental cohesion
// temporal cohesion
Coupling
Coupling is a measure of interconnection and dependency between modules/classes.
Given two classes A and B:— If A knows B through its interface only
— If A interacts with B also via non-interface stuff of B
Goal: low coupling — This gives simple connections between modules.
Loosely coupled
Tightly coupled
Different Types of Coupling
Content coupling (Worst/highest)
Common coupling
Control coupling
Stamp coupling
Data coupling (Best/lowest)
Content Coupling
Module A modifies or relies on the internal workings of another module B (e.g. accessing local data of another module).
Therefore changing the way B produces data (location, type, timing) will lead to changing the dependent module A.
Example:
— no get/set methods, all data are public.
— goto statement
Identify a content coupling issue if you are:
— using pointer to access private data of other classes (C++)
— branching into the middle of a subroutine (multiple entry points)
Common coupling
Two modules have read/write access to the same global data. Changing the shared resource implies changing all the
modules using it.
Example: global variables.
— Single module with write access where all other modules have read access is not common coupling
Problem:— Hard to track down who made the change and who is changing.
Always try your best to avoid using global variables!
Control Coupling
One module A controls the logic of another module B, by passing B information on what to do.
Example: passing a control flag or switches.
Problem: — often generalize a function beyond their original purpose,
adding unnecessary complication. — Module A and B are not independent: hard to reuse code.
Class B{
public void Do(int what){
if (what == 1)
do_wow;
else if ( what == 2 )
do_blabla;
}
}
Class A{
void ControlDo( )
{
…
B.Do(1);
}
}
Stamp Coupling
Also known as Data-structured coupling. Modules share a composite data structure and use only a part of it,
possibly a different part.
Example: passing a whole record to a function which only needs one field of it.
employee = { age = 24,
compensation = 2000 }
def age_range(employee)
range = 1 if employee.age < 10
range = 2 if employee.age > 10 && < 20;
...
return range
end
def compensation_range(employee)
... only relies on employee.compensation
end
Problem: • Efficiency?• Reusability?• maintenance?
Data Coupling
Modules share data through parameters.— Just the data needed are passed between the calling and
called modules through parameters. — A simple argument list and every item is used.— Parameters are not passed several levels deep.
Variables are not reused.
Example:// In Class A:
B.add(num1,num2);
Parameter based communications: GOOD!a parameter has one and only one purpose in life.
Basic OO Design Principles
Single Responsibility Principle (SRP)
Open-Closed Principle (OCP)
Liskov Substitution Principle (LSP)
Interface Segregation Principle (ISP)
Dependency Inversion Principle (DIP)
Release Reuse Equivalency Principle (REP)
Common Closure Principle (CCP)
Common Reuse Principle (CRP)
SOLID
Single Responsibility Principle
“A class should have one and only one reason to change.”
Each responsibility should be a separate class.
// single responsibility principle - bad example
interface IEmail {
public void setSender(String sender);
public void setReceiver(String receiver);
public void setContent(String content);
}
class Email implements IEmail {
public void setSender(String sender) {// set sender; }
public void setReceiver(String receiver) {// set receiver; }
public void setContent(String content) {// set content; }
}
http://www.oodesign.com/single-responsibility-principle.html
Single Responsibility Principle
“A class should have one and only one reason to change.”
Each responsibility should be a separate class.
// single responsibility principle - good example
interface IEmail {
public void setSender(String sender);
public void setReceiver(String receiver);
public void setContent(IContent content);
}
interface IContent {
public String getAsString(); // used for serialization
}
class Email implements IEmail {
public void setSender(String sender) {// set sender; }
public void setReceiver(String receiver) {// set receiver; }
public void setContent(IContent content) {// set content; }
}
http://www.oodesign.com/single-responsibility-principle.html
Open-Closed Principle
"A module should be open for extension but closed for modification.“
How? Create abstractions as a buffer between the functionality
that is likely to be extended and the design class itself.
Example: sensor detector<<interfcae>>
Sensorread()
enabel()disable()
test()Detector
DoorSensorSmokeSensorHeatSensorMotionSensor
Liskov Substitution Principle
"Subclasses should be substitutable for their base classes.“
Any derived class must satisfy the contract for the base class.— contract: precondition and post condition of using a base
class.
— We must make sure that the new derived classes just extend without replacing the functionality of base classes.
Example: Is an apple a fruit? Is a queue a list?
Liskov Substitution Example
// Violation of Liskov's Substitution Principle
class Rectangle {
protected int m_width, m_height;
public void setWidth(int width){ m_width = width; }
public void setHeight(int height){ m_height = height; }
public int getWidth(){ return m_width; }
public int getHeight(){ return m_height; }
public int getArea(){ return m_width * m_height; }
}
class Square extends Rectangle {
public void setWidth(int width){
m_width = width; m_height = width;
}
public void setHeight(int height){
m_width = height; m_height = height;
}
}
Liskov Substitution Example
class LspTest {
private static Rectangle getNewRectangle() {
// it can be an object returned by some factory ...
return new Square(); }
public static void main (String args[]) {
Rectangle r = LspTest.getNewRectangle();
r.setWidth(5); r.setHeight(10);
// user knows that r it's a rectangle.
// It assumes that he's able to set
// the width and height as for the base class
System.out.println(r.getArea());
// now he's surprised to see that
// the area is 100 instead of 50.
}
}
Interface Segregation Principle
"Many client-specific interfaces are better than one general purpose interface“
Example: multiple servers can be better than one general purpose server
— one specialized interface for each major category of clients
— avoid “fat/polluted” interface
Interface Segregation Example
// interface segregation principle - bad example
interface IWorker {
public void work();
public void eat();
}
class Worker implements IWorker{
public void work() {// ....working}
public void eat() {// ...... eating in launch break}
}
class SuperWorker implements IWorker{
public void work() {//.... working much more}
public void eat() {//.... eating in launch break}
}
class Manager {
IWorker worker;
public void setWorker(IWorker w) { worker=w; }
public void manage() { worker.work(); }
}
Interface Segregation Example
// interface segregation principle - good example
interface IWorker extends Feedable, Workable {}
interface IWorkable { public void work();}
interface IFeedable{ public void eat();}
class Worker implements IWorkable, IFeedable{
public void work() {// ....working}
public void eat() {//.... eating in launch break}
}
class Robot implements IWorkable{
public void work() {// ....working}
}
class SuperWorker implements IWorkable, IFeedable{
public void work() {//.... working much more }
public void eat() {//.... eating in launch break}
}
class Manager {
Workable worker;
public void setWorker(Workable w) { worker=w;}
public void manage() { worker.work(); }
}
Dependency Inversion Principle
"Depend on abstractions. Do not depend on concretions."
Components should depend on abstractions such as defined by an interface.
Why?
OCP welcomes extension. The more a component depends on other concrete components, the more difficult it will be to extend.
Portability issue: if high level classes depend on low level classes, what happened if we need to change low level classes?
Release Reuse Equivalency Principle
Reusability
“The granule of reuse is the granule of release.”
Either all of the classes inside the package are reusable, or none of them are.
In order to effectively reuse code it must arrive in a complete, black-box package that is to be used but not changed.
Common Reuse Principle
Reusability "Classes that aren't reused together should not
be grouped together.“
Again, high cohesion! Grouping classes/modules unnecessarily can lead
to spurious integration, testing efforts.
group reusable classes of the same purpose into packages
Common Closure Principle
Maintainability
"Classes that change together belong together.“
High cohesion!
Classes in the same package should address the same functional or behavioral area.
— If later changes in the area is necessary, only those classes within the package will require modification.
Design Principle Summary
5 class design principles: SOLID— Single Responsibility Principle (SRP)— Open-Closed Principle (OCP)— Liskov Substitution Principle (LSP)— Interface Segregation Principle (ISP)— Dependency Inversion Principle (DIP)
3 package cohesion principles: — Release Reuse Equivalency Principle (REP)— Common Closure Principle (CCP)— Common Reuse Principle (CRP)