6 Object Oriented Design Principles

Presentation built from:

  1. Head First Design Patterns, Bert Bates et al, 2009
  2. The Pragmatic Programmer, Andrew Hunt, 1999,
  3. Principles of OOD, Robert C. Martin, 2003 (SOLID Principles)

...to improve code architecture and higher-level code structure

The one constant in software development is change. No matter how well you design an application, over time an application must grow and change or it will die.

Often more time is spent on code after initial development is complete. So design should focus on making maintenance and extensibility easier.

EVOLVE OR DIE

Source: http://skyteach.ru/wp-content/uploads/2017/08/evolve-or-die-366x315.png

6 Design Principles are "heuristics" to follow, that increase your chances of creating flexible, reusable, and maintainable code.

Source: https://www.shutterstock.com/image-illustration/businessman-front-huge-maze-121706023

OO Basics

Inheritance

Abstraction

Polymorphism

Better Code

flexible

reusable

maintainable

OO Principles

(DRY, OCP, ...)

OO Design Patters

(Template Method,..)

1st Principle

Don't Repeat Yourself (DRY)

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.

modification of any single element of a system (knowledge) does not require a change in other logically unrelated elements

simplifies maintenance, extensibility ☺

"It isn't a question of whether you'll remember: it's a question of when you'll forget."

- the pragmatic programmer

class Line {
public:
  Point start;
  Point end;
  double lenght;
};
class Line {
public:
  Point start;
  Point end;
  double length() 
  { 
    return start.distanceTo(end); 
  };
};

extract common code to functions and reuse

combine functions to classes and reuse (e.g. inheritance, composition)

void runningController() 
{
    readSensorData();
    calculateTorqueWithMethod1();
    setCommands();
}

void safetyController() 
{
    readSensorData();
    calculateTorqueWithMethod2();
    setCommands();
}
class A {
public:
  int a_, b_;

  A()      { a_=0; b_=5; };
  A(int a) { a_=a; b_=5; };
}
class A {
public:
  int a_, b_;

  A() : A(0) {};
  A(int a)   { a_=a; b_=5; }
}

one place to modify, one place to maintain

Examples: Don't Repeat Yourself (DRY)

e.g. Template Method

2nd Principle

Identify the aspects of your application that vary and separate them from what stays the same

Take what might vary (in the future!) and encapsulate it so it won’t affect the rest of your code.

(way more easily said than done!)

3rd Principle

Classes should be open for extension, but closed for modification

If your needs or requirements change, just go ahead and make your own extensions, through e.g. inheritance, composition, ...

We spent a lot of time getting this code correct and bug free, so we can’t let you alter the existing code. This reduces the chances of introducing bugs or causing unintended side effects in pre-existing code.

...a more specific way to separate the code is

Design Pattern: Template Method

"...defines the program skeleton of an algorithm in an operation, deferring some steps to subclasses."

void advanceControlLoop() 
{
    readSensorData();
    calculateTorqueValues();
    setCommands();
}

void calculateTorqueValues() = 0;

Dario's Walking Controller Class

void calculateTorqueValues() override
{
  // Dario's implementation
}
void calculateTorqueValues() override
{
  // Christian's implementation
}

Marko's Skating Controller Class

This part never has to be touched again, closed, no more bugs can be introduced!

()

()

4th Principle

Single Responsibility Principle

A class should have only one reason to change (be rewritten)

Want to avoid changing a class like the plague because bugs creep. And when a class has two reasons to change, instead of one, it is more likely to.

...so how to write a "closed" class

2 > 1
2>12 > 1

So how can we see that a class has only a single responsibility?

Cohesion

measure of how strongly related and focused the various responsibilities of a software module are.

  • all member variables used by most functions
  • functions similar in what they do

Example: Do these classes have only a single responsiblity / reason to change?

5th Principle

Program to an interface, not an implementation

...since there will always be coupling to other classes (even if just one), most flexible way is through an interface

Example: Program to an Interface

Dog d = Dog(); 
d.bark();
Animal* animal      = new Dog();
animal->makeSound();

Why is this better?

  • Client code doesn't have to change when new animal is added ("loose coupling" between client and dog")
  • Can load different implementations during runtime

"Client"

6th Principle

Favor composition over inheritance

"HAS-A" can be better/more flexible than IS-A

Example: Favor Composition over Inheritance 

void RubberDuck::fly() {
  // override to do nothing
}

Disadvantages of Subclassing:

  • Hard to generalize all duck behaviours into one interface (e.g. not all ducks should be able to fly)
  • Changes can unintentionally affect other ducks (adding non-virtual method to base)
  • Runtime behaviour changes are difficult

 

Squeaking and flying duck?

Code reuse :-)

"Strategy Pattern"

has-a

has-a

Composition:

  • add new functionality by writing new code rather than altering existing code, e.g. RubberDuck (open closed principle).
  • done dynamically at runtime.

The one constant in software development is change. More time is spent on code after initial development process is complete, or it will die.

  • design should focus on making maintenance and extensibility easier.
  • Following well-known design principles/heuristics increase chances of writing code with these characteristics.

Summary: Software Development Guidelines

Source: https://www.shutterstock.com/image-illustration/adapt-vs-fail-toggle-switch-change-176572736

(You yourself will be the most frequent user/client of your code. So you will be the one that will benefit most from proper code design.)

Outlook/Extensions: Design Patterns

Shared vocabulary for communication to convey ideas more concisely  (meetings, documentation, ...)

Think at pattern level, not at nitty-gritty object level

Reuse tested code as much as possible to reduce likelihood to introduce new bugs.

Goal is to write code once, and then never have to touch it again.

End of presentation

Made with Slides.com