View
119
Download
0
Category
Preview:
Citation preview
2
Design bridges that gap between knowing what is needed
(software requirements specification) to entering the code
that makes it work (the construction phase).
Design is both a verb and a noun.
3
During the design phase, software engineers apply their
knowledge of the problem domain and implementation
technologies in order to translate system specifications
into plans for the technical implementation of the
software.
The resulting design expresses the overall structure and
organization of the planned implementation. It captures
the essence of the solution independent of any
implementation language.
4
There is a famous cartoon showing
two professors at a chalkboard
examining a proof that includes the
step “then a miracle occurs”.
At times it seems like this is the
most that can be hoped for during
software design.
5
There is a process for design but not an algorithm.
Software design is a heuristic rather than deterministic
process.
No reliable process for conjuring up a design
6
Poorly designed programs are difficult to understand and
modify.
The larger the program, the more pronounced are the
consequences of poor design.
Cost of adding the ith feature to a well-designed and poorly designed program
7
To better understand how good design can minimize
technical complexity, it’s helpful to distinguish between
two major types of complexity in software:
Essential complexities – complexities that are inherent in
the problem.
Accidental/incidental complexities – complexities that are
artifacts of the solution.
The total amount of complexity in a software solution is:
ESSENTIAL COMPLEXITIES + ACCIDENTAL COMPLEXITIES
8
Design is the primary tool for managing essential and
accidental complexities in software.
Good design doesn't reduce the total amount of essential
complexity in a solution but it will reduce the amount of
complexity that a programmer has to deal with at any
one time.
A good design will manage essential complexities
inherent in the problem without adding to accidental
complexities consequential to the solution.
9
MODULARITY – subdivide the solution into smaller
easier to manage components. (divide and conquer)
INFORMATION HIDING – hide details and complexity
behind simple interfaces
10
ABSTRACTION – use abstractions to suppress details in
places where they are unnecessary.
HIERARCHICAL ORGANIZATION – larger components
may be composed of smaller components. Examples: a
complex UI control such as tree control is a hierarchical
organization of more primitive UI controls. A book
outline represents the hierarchical organization of ideas.
12
The term wicked problem was first used to describe
problems in social planning but engineers have
recognized it aptly describes some of the problems they
face as well.
A wicked problem is one that can only be clearly defined
by solving it.
Need two solutions. The first to define the problem, and
the second to solve it in the most efficient way.
Fred Brooks could have been talking about wicked
problems when he advised: “Plan to throw one away;
you will anyhow.”
13
Any product that is an aggregate of more primitive
elements, can benefit from the activity of design.
15
Non-deterministic – A deterministic process is one that
produces the same output given the same inputs. Design
is non-deterministic. No two designers or design
processes are likely to produce the same output.
Heuristic – because design is non-deterministic design
techniques tend to rely on heuristics and rules-of-thumb
rather than repeatable processes.
Emergent – the final design evolves from experience and
feedback. Design is an iterative and incremental process
where a complex system arises out of relatively simple
interactions.
16
Good design reduces software complexity which makes the
software easier to understand and modify. This facilitates
rapid development during a project and provides the
foundation for future maintenance and continued system
evolution.
It enables reuse. Good design makes it easier to reuse
code.
It improves software quality. Good design exposes defects
and makes it easier to test the software.
Complexity is the root cause of other problems such as
security. A program that is difficult to understand is more
likely to be vulnerable to exploits than one that is simpler.
17
1. Understand the problem (software requirements).
2. Construct a “black-box” model of solution (system specification).
System specifications are typically represented with use cases
(especially when doing OOD).
3. Look for existing solutions (e.g. architecture and design patterns)
that cover some or all of the software design problems identified.
4. Design not complete? Consider using one or more design techniques
to discover missing design elements
Noun-verb analysis, CRC Cards, step-wise refinement, etc.
Take final analysis model and pronounce a first-draft design
(solution) model
5. Consider building prototypes
6. Document and review design
7. Iterate over solution (Refactor) (Evolve the design until it meets
functional requirements and maximizes non-functional
requirements)
18
User requirements and system specification (including
any constraints on design and implementation options)
Domain knowledge (For example, if it’s a healthcare
application the designer will need some knowledge of
healthcare terms and concepts.)
Implementation knowledge (capabilities and limitations
of eventual execution environment)
20
Methods and patterns are the principle techniques for
dealing with the challenges of design
They are useful for:
Creating a design
Documenting and communicating a design
Transferring design knowledge and experience between
practitioners
21
A design pattern is a reusable solution to a commonly
occurring design problem
Design patterns are adapted for the unique
characteristics of the particular problem
Just as there are levels of design, there are levels of
design patterns:
Architecture Styles/Patterns
Design Patterns
Programming Idioms
24
Design is generally
“THE DECISIONS WE TAKE TO BUILD SOMETHING”
Design + implementation = Product
If we apply this to software:
DESIGN
+
PROGRAMMING / CODING
=
SOFTWARE PRODUCT
27
Increased difficulty to adapt and maintain
Causes
Communication/Documentation breakdown
• Maintainers not fully familiar with the original design
principles -> change works, but…
Design is not resilient in the face of change
28
Characteristics of a bad design:
RIGIDITY - It is hard to change because every change affects
too many other parts of the system.
FRAGILITY - When you make a change, unexpected parts of
the system break.
IMMOBILITY - It is hard to reuse in another application
because it cannot be disentangled from the current
application.
VISCOSITY: The law of least resistance when faced with a
choice
• Design viscosity: Hacks are easier/faster than preserving the
design
• Environment viscosity: Slow cycle time -> fastest choice
29
SOLID
Single Responsibility Principle
Open Closed Principle
Liskov Substitution Principle
Interface Segregation Principle
Dependency Inverison Principle
Code becomes more Testably (remember TDD is not only
about testing, more important its about Design)
30
"There should never be more than one reason for a class
to change." — Robert Martin, SRP paper linked from The
Principles of OOD
My translation: A class should concentrate on doing one
thing and one thing only
31
Two resposibilities
Connection Management + Data Communication
interface Modem {
public void dial(String pno);
public void hangup();
public void send(char c);
public char recv();
}
32
Separate into two interfaces
interface DataChannel {
public void send(char c);
public char recv();
}
interface Connection {
public void dial(String phn);
public char hangup();
}
33
"Software entities (classes, modules, functions, etc.)
should be open for extension, but closed for
modification." — Robert Martin paraphrasing Bertrand
Meyer, OCP paper linked from The Principles of OOD
My translation: Change a class' behavior using
inheritance and composition
34
// Open-Close Principle - Bad example
class GraphicEditor {
public void drawShape(Shape s) {
if (s.m_type==1)
drawRectangle(s);
else if (s.m_type==2)
drawCircle(s);
}
public void drawCircle(Circle r) {....}
public void drawRectangle(Rectangle r) {....}
}
class Shape {
int m_type;
}
class Rectangle extends Shape {
Rectangle() {
super.m_type=1;
}
}
class Circle extends Shape {
Circle() {
super.m_type=2;
}
}
35
Impossible to add a new Shape without modifying
GraphEditor
Important to understand GraphEditor to add a newShape
Tight coupling between GraphEditor and Shape
Difficult to test a specific Shape without involvingGraphEditor
If-Else-/Case should be avoided
36
// Open-Close Principle - Good example
class GraphicEditor {
public void drawShape(Shape s) {
s.draw();
}
}
class Shape { //super class
abstract void draw();
}
class Rectangle extends Shape {
public void draw() {
// draw the rectangle
}
}
37
"Functions that use pointers or references to base
classes must be able to use objects of derived classes
without knowing it." — Robert Martin, LSP paper linked
from The Principles of OOD.
My translation: Subclasses should behave nicely when
used in place of their base class
38
// Violation of Liskov's Substitution Principle
class Rectangle
{
int m_width;
int m_height;
public void setWidth(int width){
m_width = width;
}
public void setHeight(int ht){
m_height = ht;
}
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;
}
}
39
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.
}}
40
"Clients should not be forced to depend upon interfaces
that they do not use." — Robert Martin, ISP paper linked
from The Principles of OOD
My translation: Keep interfaces small
41
Don’t force classes so implement methods they can’t
(Swing/Java)
Don’t pollute interfaces with a lot of methods
Avoid ’fat’ interfaces
42
//bad example (polluted interface)
interface Worker {
void work();
void eat();
}
ManWorker implements Worker {
void work() {…};
void eat() {30 min break;};
}
RobotWorker implements Worker {
void work() {…};
void eat() {//Not Appliciable
for a RobotWorker};
}
43
Solution
- split into two interfaces
interface Workable {
public void work();
}
interface Feedable{
public void eat();
}
44
"A. High level modules should not depend upon low
level modules. Both should depend upon abstractions.
B. Abstractions should not depend upon details. Details
should depend upon abstractions." — Robert Martin, DIP
paper linked from The Principles of OOD
My translation: Use lots of interfaces and abstractions
45
//DIP - bad example
public class EmployeeService {
private EmployeeFinder emFinder //concrete class, not abstract. Can access a SQL DB for instance
public Employee findEmployee(…) {
emFinder.findEmployee(…)
}
}
46
Now its possible to change the finder to be a
XmlEmployeeFinder, DBEmployeeFinder,
FlatFileEmployeeFinder, MockEmployeeFinder….
//DIP - fixed
public class EmployeeService {
private IEmployeeFinder emFinder //depends on an abstraction, no an implementation
public Employee findEmployee(…) {
emFinder.findEmployee(…)
}
}
47
http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod
http://www.oodesign.com
http://www.slideshare.net/enbohm
49
In software engineering, a design pattern is a general
repeatable solution to a commonly occurring problem in
software design.
A design pattern isn't a finished design that can be
transformed directly into code. It is a description or
template for how to solve a problem that can be used in
many different situations.
50
A design pattern
Design Patterns are time-tested common solutions to
recurring design problems.
Are the answer to a question that commonly arises “How
can I … ?”
Abstracts a recurring design structure
Comprises class and/or object
• Dependencies
• Structures
• Interactions
• Conventions
Names & specifies the design structure explicitly
Distils design experience
52
Can reuse solutions
Gives us a head start (mostly design, but implementation
too)
Avoids unanticipated results as we are using time-tested
solutions
No need to reinvent the wheel
Establish common terminology
Design patterns provide a common point of reference
53
Design patterns gained popularity in computer
science after a certain book was published in
1994 by four authors, commonly know as Gang
of Four or GOF
Gang of Four (GoF) Gamma, Helm, Johnson,
Vlissides, - founders of movement.
Gamma et al, Design Patterns: Elements of
Reusable Object-Oriented Software,
Addison Wesley, 1995.
They offer advice and help for developing
quality software
An object-oriented design pattern
systematically names, explains and evaluates
an important and recurring design in object-
oriented systems.
54
A design pattern has 4 basic parts:
1. Pattern Name
2. Problem
3. Solution
4. Consequences and trade-offs of application
Language- and implementation-independent
A “micro-architecture”
Adjunct to existing methodologies (Unified, OMT, etc.)
No mechanical application
The solution needs to be translated into concrete terms in the
application context by the developer
55
Codify good design
Distil and disseminate experience
Aid to novices and experts alike
Abstract how to think about design
Give design structures explicit names
Common vocabulary
Reduced complexity
Greater expressiveness
Capture and preserve design information
Articulate design decisions succinctly
Improve documentation
Facilitate restructuring/refactoring
Patterns are interrelated
Additional flexibility
59
There must be exactly one instance of a class, and it
must be accessible to clients from a well-known access
point.
When the sole instance should be extensible by
subclassing, and clients should be able to use an
extended instance without modifying their code.
60
Controlled access to sole instance.
Reduced name space.
Permits refinement of operations and representation
Permits a variable number of instances.
61
Hayes
Modem
USR Modem
Zoom
Modem
Modem< ? >
File Sync
Dedicated Modem
Send ()
Receive()
Dial () {}
Hangup () {}
Send ()
Receive()
Dial ()
Hangup ()
62
Hayes
Modem
USR Modem
Zoom
Modem
Modem
File Sync
Send ()
Receive()
Dial ()
Hangup ()
Dedicated Modem
Send ()
Receive()
Dedicated Modem
Adapter
Send ()
Receive()
Dial () {}
Hangup () {}
ADAPTER(wrapper)
Convert the interface of a class into
another interface clients expect. Adapter
lets classes work together that couldn't
otherwise because of incompatible
interfaces.
65
Applicability:
You want to use an existing class, and its interface does
not match the one you need
Consequences:
The amount of adapting is needed
Conceptual distance between adapter and adaptee can
cause undesirable side effects
Observer(Publish-Subscribe)
Define a one-to-many dependency between
objects so that when one object changes
state, all its dependents are notified and
updated automatically.
68
Motivation:
Maintain consistency between collaborating objects
while maintaining loose coupling
Structure:
69
Applicability:
When an abstraction has two aspects, one dependent on
the other.
When a change to one object requires changing others,
and you don't know how many objects need to be changed.
When an object should be able to notify other objects
without making assumptions about who these objects are.
Consequences:
Abstract coupling between Subject and Observer
Support for broadcast communication
Unexpected updates
Dangling References
Memory Issues
Recommended