A set of guidelines that helps us to avoid having a bad design.
-
Rigidity (Hard to change)
The software / software-design is hard to change.
-
Changes propagate via dependencies to other modules
-
No continuity in the code.
-
-
Fragility (Easy to Break)
The design is easy to break.
- Fixing the problems causes new problems.
- Changes cause cascading effects to many places.
- The code breaks in unexpected places that have no conceptual relationship with the changed area.
- Developers are reluctant to change anything.
-
Immobility (Hard to reuse)
The design is hard to reuse.
- The code is so tangled that it is impossible to reuse anything.
-
Viscosity (Deviating from original design)
Changes or additions to the software are easier to implement by doing wrong thing.
- When a change is needed, you are tempted to hack rather than to preserve the original design.
-
Opacity (Difficult to understand/read)
The tendancy of a module to become harder to understand.
- Modules get more opaque over time.
-
Needless complexity (Much anticipated)
Design contains elements that are not currently useful.
- Too much anticipation of future needs.
-
Needless repetition (Duplication)
The same code appears over and over again, in slightly different forms.
- Overuse of cut-or-copy-and-paste.
-
Single Responsibility Principle (SRP)
There should never be more than one reason for a module (a class, a method, a library,..) to change.
-
Open-Closed Principle (OCP)
A module should be open for extension but closed for modification.
-
Liskov Substitution Principle (LSP)
Subclasses should be substitutable for their base classes.
If S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e. an object of type T may be substituted with any object of a subtype S) without altering any of the desirable properties of T.
-
Interface Segregation Principle (ISP)
Many client-specific interfaces are better than one general-purpose interface.
No client should be forced to depend on methods it does not use.
-
Dependency Inversion Principle (DIP)
Depend upon Abstractions. Do not depend upon concretions.
High-level modules should not depend on low-level modules, both should depend on abstractions. And abstractions should not depend on details. Details should depend on abstractions.
Guidelines for assigning responsibility to classes and objects in object-oriented design. Helps us in deciding which responsibility should be assigned to which object/class. Identify the objects and responsibilities from the problem domain, and also identify how objects interact with each other.
Principles are,
-
Creator
Who should be responsible for creating new instance for some class?
Decide who can be creator based on the objects association and their interaction.
Assign class B the responsibility to create an instance of class A iff, a) B contains or compositely aggregates A. b) B records A. c) B closely uses A. d) B have the initializing information for instances of A and pass it on creation.
-
Information Expert
Which responsibilities can be assigned to an object?
Assign those responsibilities to an object for which it has the information to fulfill that responsibility.
-
Low Coupling
How to support low dependency, low change impact, and increased reuse?
Reduce the impact of change in one class on other classes.
Coupling is a measure of how strongly one element is connected to, has knowledge of, or relies on other elements.
-
High Cohesion
How to keep objects focused, understandable, and manageable?
Assign a responsibility so that cohesion remains high.
Cohesion is a measure of how strongly related and focused the responsibilities of an element are.
-
Controller
What first object beyond the presentation layer receives and coordinates a system operation?
A controller may represent the overall system/root object, or use case scenario.
A controller object is a non-user interface object responsible for receiving and coordinating a system event/operation.
A use case controller should be used to deal with all system events of a use case, and may be used for more than one use case.
-
Indirection
Where to assign a responsibility, to avoid coupling between two or more things?
Assign the responsibility to an intermediate object to mediate between components/services so that they are not coupled directly.
-
Polymorphism
How to handle related but varying elements based on element type?
How to handle alternatives based on type?
How to create pluggable software components?
Assign responsibility for the behaviour using polymorphic operations to the types for which the behaviour varies.
-
Protected Variations
How to design objects, and systems so that the variations or instability in these elements does not have an undesirable impact on other systems?
Identify the points of predicted variation or instability, assign responsibilities to create an interface around them.
-
Pure Fabrication
What object should have the responsibility, when you don not want to voilate High Cohesion and Low Coupling?
Assign a set of responsibilities to an artificial (fabric) class that does not represent a problem domain.
-
Program to an Interface Not Implementation
-
Favor Composition over Inheritance
-
Strive for Loosely Coupled System
-
Law of Demeter (Least Knowledge Principle)
Only talk to your immediate friends.
Never call a method on an object you got from another call nor on a global object.
-
Keep it Simple and Sweet / Stupid (KISS)
-
Curly's Law: Do One Thing
-
One Responsibility Rule
-
Separation of Concerns
-
Don't Repeat Yourself (DRY)
-
Once and Only Once
-
Single Point of Truth
-
Write Everyting Twice (WET)
-
You aint gonna need it (YAGNI/YagNi)
Always implement things when you actually need them, never when you just foresee that you need them.
-
Encapsulate What Varies
-
Hollywood Principle
Don't call us, we'll call you.
-
Inversion of Control (IoC)
Custom-written (problem specific) portions of a computer program receive the flow of control from a generic framework.
The term is related to, but different from, the dependency inversion principle, which concerns itself with decoupling dependencies between high-level and low-level layers through shared abstractions.
Software frameworks, callbacks, schedulers, event loops and dependency injection are examples of design patterns that follow the inversion of control principle.
- Linguistic Modular Units
- Self-Documentation Principle
- Uniform Access Principle
- Open-Closed Principle
- Single Choice Principle
- Reuse-release Equivalence Principle (REP)
- Common Closure Principle (CCP)
- Common Reuse Principle (CRP)
- Acyclic Dependencies Principle (ADP)
- Stable Dependencies Principle (SDP)
- Stable Abstractions Principle (SAP)
-
Object-Oriented Software Construction - By Bertrand Meyer (https://sophia.javeriana.edu.co/~cbustaca/docencia/POO-2016-01/documentos/Object%20Oriented%20Software%20Construction-Meyer.pdf)
-
Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development - By Craig Larman
i) Second Edition PDF (https://www.utdallas.edu/~chung/SP/applying-uml-and-patterns.pdf)
ii) Third Edition (https://aanimesh.files.wordpress.com/2013/09/applying-uml-and-patterns-3rd.pdf)
-
Principles Of Object Oriented Design (http://wiki.c2.com/?PrinciplesOfObjectOrientedDesign)
-
The Principles of OOD (http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod)
-
Collections of Principles, Patterns, etc (http://principles-wiki.net/collections:start)
-
Slides based on Ref#4 (http://users.encs.concordia.ca/~sthiel/CC/uml-patterns.pdf)
-
Design Principles and Design Patterns By Robert Martin (http://www.cvc.uab.es/shared/teach/a21291/temes/object_oriented_design/materials_adicionals/principles_and_patterns.pdf)
-
http://staff.cs.utu.fi/~jounsmed/doos_06/slides/slides_060321.pdf
-
GRASP Design Principles by Danya Rao (https://www.cs.colorado.edu/~kena/classes/5448/f12/presentation-materials/rao.pdf)