Software Design

Agenda

  • Introduction

  • Design Process

  • Key Principles

  • Best Practices

  • Conclusion

Introduction

Software Design

Art and science of conceiving the structure of software systems.

The Designer

The designer is the one that simplifies, gives a strong and invisible personality to what he creates, prunes, purifies, clutters, and creates suitable products.
— Jasper Morrison

Design Approaches

There are two ways of designing software [Hoare]:
  • One way is to make it so simple that there are obviously no deficiencies

  • and the other way is to make it so complicated that there are no obvious deficiencies.

The first way is far more difficult to achieve!

Design Approaches

  • During domain analysis, we used abstraction to hide technical details and simplify models.

  • This abstraction was needed to understand the problem domain, without any influence from implementation details.

  • Conversely, during the detailed design, we will do either:

    • add details to domain models or

    • create models from scratch.

Software Design

design big picture

Different Activities

  1. Architecture.

  2. Preliminary Design (Component specification).

  3. Detailed design.

design process

Architecture

  • Strategic choices for system implementation.

  • More engineering than computer science.

  • Architectural patterns application.

Components Specification

  • High-level description of the collaboration between the system major components.

  • System boundaries definition.

  • Component desired behavior description.

Detailed Design

  • Component internal description.

  • Preparation of the target programming language projection.

  • Design pattern application.

Other Design Aspects

  • User interface design.

  • Protocol design.

  • Database design.

  • Algorithm design.

  • etc.

Agenda

  • Introduction

  • Design Process

  • Key Principles

  • Best Practices

  • Conclusion

Design Process

Design Process Activities

  1. Preliminary design

    1. Requirements/Domain decomposition into components.

  2. Detailed design

    1. Component specification

    2. Additional component decomposition, if needed.

Low-Level Activities

  1. List the hard decisions and decisions likely to change

  2. Design a component specification to hide each such decision

    1. Make decisions that apply to whole program family first

    2. Modularize most likely changes first

    3. Then modularize remaining difficult decisions and decisions likely to change

    4. Design the uses hierarchy as you do this (include reuse decisions)

  3. Treat each higher-level component as a specification and apply above process to each

  4. Continue refining until all design decisions:

    1. are hidden in a component

    2. contain easily comprehensible components

    3. provide individual, independent, low-level implementation assignments

Agenda

  • Introduction

  • Design Process

  • Key Principles

  • Best Practices

  • Conclusion

Key Principles

Design Principles

  1. Decomposition 

  2. Abstraction 

  3. Information concealment 

  4. Cohesion 

  5. Decoupling 

  6. Reusability

  1. Reuse. 

  2. Obsolescence anticipation 

  3. Portability 

  4. Testability 

  5. Simplicity 

  6. SOLID principles

Decomposition

  • Complexity control by the decomposition of problems into sub-problems. 

  • Divide and conquer approach, common to all design techniques. 

Abstraction

  • Complexity control by the amplification of the essential features and the suppression of the less important details. 

  • Allows to postpone design decisions. 

  • Types of abstraction: functional, structural, control, etc. 

Information Concealment

  • Important means to achieve abstraction.  

  • Design decisions that are likely to change should be hidden behind interfaces. 

  • Components should communicate only through well-defined interfaces. 

  • Interface should be specified by as little information as possible. 

  • If component internal decisions change, clients should not be affected. 

Typical Information Concealment

  • Data representation 

    • Data types, etc. 

  • Algorithms 

    • Data search and sorting  

  • Input and output formats 

    • Machine dependencies, e.g., byte-ordering, character codes 

  • Lower-level interfaces 

    • Ordering of low-level operations 

  • Policy/Mechanism separation 

    • Multiple policies for one mechanism. 

    • Same policy for multiple mechanisms. 

Cohesion

  • Cohesion should be increased where possible. 

  • Types of cohesion: functional, layer, de communicational, sequential, procedural, temporal, utility.

Keeping Together

  • All the code that performs a particular task (functional cohesion). 

  • All the code that provides or uses a set of related services (layer cohesion). 

  • All code that access or modify certain data (communicational cohesion). 

  • A sequence of operations, in which one operation provides input to the next (sequential cohesion). 

  • A set of operations that are used one after another (procedural cohesion). 

  • Operations that are performed at the same execution phase (temporal cohesion). 

  • Operations which cannot logically be placed in other cohesive units (utility cohesion). 

Decoupling

  • Coupling should be reduced where possible. 

  • Interdependencies impacts maintainability, testability, and simplicity.

gnu eiffel compiler
Figure 1. The GNU Eiffel Compiler

Types of Coupling

Content

when a class (module) modifies the content of another class. Violates encapsulation, Law of Demeter. 

Common

when classes share global variables. 

Control

when a parameter controls the behavior of an operation.  

Stamp

when a class of a component becomes the parameter type of another component. 

Data

when parameter types are primitive types.

Operation call

when an operation calls another. 

Datatype use

when a component uses a datatype defined in another component. 

Merge or import

when a component includes another (merge) or when a class imports another. 

External

when a component depends on external artifacts: operating system, hardware, libraries, etc. 

Reducing Coupling

  • Dependencies among component should form a directed acyclic graph. 

  • Dependency between two components must follow the direction of stability (a component must always depend on a more stable one).

Reusability

  • Reusability should be increased where possible. 

  • Components should be designed to work on different contexts. 

  • Generalize design as much as possible: 

    • Use Frameworks, Patterns, and UML Collaborations. 

    • Design the system to contain hooks. 

  • Keep the design as simple as possible 

Reuse Analysis, Design, and Code

  • Reuse existing artifacts when possible, to take advantage of existing investment. 

  • Use Frameworks, Patterns, and UML Collaborations. 

  • Complementary to the principle of reusability.

Obsolescence Anticipation

  • Avoid: 

    • Immature technologies. 

    • Undocumented features. 

    • Software and Hardware without long-term support provision. 

  • Plan technology changes and adopt technologies that are supported by different vendors. 

Portability

  • Develop on and for different platforms. 

  • Avoid platform-specific frameworks or libraries. 

Testability

  • The internal state of a component should be accessible by external programs. 

  • Design components to be used directly by external clients, without user interfaces. 

Simplicity

  • The KISS principle [US Navy, 1960]: 

    • Keep it simple, stupid! 

  • Most systems work best if they are kept simple rather than made complicated 

  • Simplicity should be a key goal in design and unnecessary complexity should be avoided. 

SOLID

  • Acronym for Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion

Single responsibility [Robert Martin]

  • A class should have one and only one responsibility (i.e. only one potential change in the software’s specification should be able to affect the specification of the class).

  • The classes are abstractions of the real and not the different roles played by an object. 

swiss knife

Open/Closed principle [Bertrand Meyer]

  • Software entities should be open for extensions but closed for modification. 

Liskov substitution principle [Liskov 1994]

  • Class instances can be used throughout the superclass interface, without notifying its clients.

Interface-segregation [Robert Martin 2002]: 

  • Many client-specific interfaces are better than one general-purpose interface. 

Dependency inversion [Robert Martin 2003]

  • A client should depend upon abstractions and not upon concretions. 

Agenda

  • Introduction

  • Design Process

  • Key Principles

  • Best Practices

  • Conclusion

Design Best Practices

Best Practices

  • Separate interface from implementation. 

  • Separate orthogonal concerns: do not try to connect what is independent. 

  • The “what” before the “how”. 

    • First specify what a component should do, then how it does it. 

  • Work on different abstraction levels. 

  • Use rapid prototyping.

Distinguish specialization and aggregation

cd specialization aggregation
  • When the choice is possible, use aggregation instead of specialization. 

Avoid Large (God) Classes

large class 01 2x
Figure 2. System composed of a class that controls everything and of several data classes.

Avoid specialization  of concrete classes

  • Superclasses should be abstract. 

abstract classes

Super-classes should not know their subclasses

forbiden

Specialization hierarchies should be deep

cd java collection framework

Common Properties

  • If two classes share the same properties but not the same behavior, those properties should be moved to a third class. 

  • The behavior related to these properties will intuitively follow them.

Avoid Accessor/Mutator Methods

Attributes should be hidden:
  • Setter and Getter methods are not mandatory: they prevent good design choices. 

  • Prefer private attributes rather than protected and protected rather than public. 

Class Dependencies

Clients of a class must be dependent on its public interface, but a class should not be dependent on its clients. 

Define a minimal interface for all classes

For instance:
  • copy()

  • deepCopy()

  • equals()

  • fromString()

  • toString()

  • etc. 

Classes are not Actions

Be suspicious with classes whose names are verbs:
  • they may be an operation. 

  • in some cases, they are indeed an operation (see Command and Strategy patterns). 

Operations

  • Feature envy: operations of a class should use properties (and other operations) of this same class. 

  • Common behavior of public operations should be placed in private methods. 

Bad Practices

  • Depth-first design 

  • Requirement direct refinement. 

  • Potential changes misunderstanding. 

  • Design too detailed. 

  • Ambiguous design. 

  • Undocumented design decisions. 

  • Inconsistent design. 

Agenda

  • Introduction

  • Design Process

  • Key Principles

  • Best Practices

  • Conclusion

Conclusion

Conclusion

  • Design is a creative activity that goes beyond diagrams drawing: design is not source code with boxes and arrows

  • Design is not a trivial task: a good design requires experience.

Design is about making choices:
  • Choices about the hardware, programming language, network, user interfaces, etc.

  • Identify the quality factor(s) that will drive the design

Component partitioning requires several iterations:
  • it’s hard to find the adequate partitioning at first time.

  • design experience is required.

  • Interfaces should be designed to be stable.

Takeaways

  • Separate interface and implementation.

  • Separate what is common from what is variable.

  • Use a common interface to allow variable implementations to be replaced.

  • Use design patterns for ensuring variability and extensibility.

Further Readings

References

  • [] Bruce Powel Douglass. Real-Time Design Patterns: Robust Scalable Architecture for Real-Time Systems. Broché, 23 septembre 2002.

  • [] Bruce Powel Douglass. Doing Hard Time: Developing Real-time Systems with UML, Objects, Frameworks, and Patterns. Addison-Wesley Professional, 1999.

  • [] Martin Fowler. UML Distilled: A Brief Guide to the Standard Object Modeling Language (3rd Edition). Addison-Wesley Professional, 2003.

  • [] Arthur J. Riel. Object-Oriented Design Heuristics. May 10, 1996. Addison-Wesley Publishing Company.

References

  • [] Bruce Powel Douglass. Real-Time UML: Developing Efficient Objects for Embedded Systems. Addison-Wesley Professional, 1998.

  • [] James Coplien. Software Patterns. SIGS Books. New York, 1996.

  • [] Kent Beck. Smalltalk Patterns: Best Practices. Prentice Hall, 1997, 256 pp., ISBN 0-13-476904-X

  • [] Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. October 1994.

References

  • [] Craig Larman. Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development. Prentice Hall, 2004.

  • [] Desmond D’Souza and Alan Wills. Objects, components, and frameworks with UML: the Catalysis Approach, by Addison Wesley, 1998.

  • [] Schmidt et al. Pattern-Oriented Software Architecture: Patterns for Concurrent & Networked Objects. Wiley and Sons, 2000, ISBN 0-471-60695-2.

  • [] Buschmann, Muenier, Rohnert, Sommerlad, and Stal, John. Pattern-Oriented Software Architecture — a System of Patterns”. Wiley & Son, 1996.

References

  • [] James D. Mooney. Bringing Portability to the Software Process. Technical Report, West Virginia University. 1997.

  • [] Douglas C. Schmidt, Michael Stal, Hans Rohnert, Frank Buschmann. Pattern-Oriented Software Architecture, Patterns for Concurrent and Networked Objects. John Wiley & Sons, 22 avr. 2013.

  • [] Clements, Paul; Felix Bachmann; Len Bass; David Garlan; James Ivers; Reed Little; Paulo Merson; Robert Nord; Judith Stafford. Documenting Software Architectures: Views and Beyond, Second Edition. Boston: Addison-Wesley., 2010. ISBN0-321-55268-7.

  • [] Christine Hofmeister, Robert Nord, Dilip Soni. Applied Software Architecture. Addison-Wesley, 1999.

References

  • [] Henry Muccini. SA Styles, Patterns, and Tactics. DISIM, University of L’Aquila. (Advanced Software Engineering Course).

  • [] Nick Rozanski and Eoin Woods. Software Systems Architecture: Working With Stakeholders Using Viewpoints and Perspectives. Addison Wesley, October 2011.