note 11: software design - university of wisconsin...

58
Computer Science and Software Engineering University of Wisconsin - Platteville Note 11: Software Design Yan Shi Lecture Notes for SE 3330 UW-Platteville Based on Pressman Chapter 10 & 11

Upload: haanh

Post on 28-Jul-2018

218 views

Category:

Documents


0 download

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

Design

Architectural design

Component level design

Human Interface design

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)

Summary

Architectural Design— Key issues

— Tradeoff

— Architectural styles: repository, etc.

Component level design:— design principles such as SOLID,

— basic of good design: good modularity

— high cohesion, low coupling