100 Days of Code - Day 18 Object Oriented Programming

100 Days of Code - Day 18 Object Oriented Programming

Hello! My name is Rick and I am in search for gig as a developer :)

This past December I finished up a year long study with a full-stack school in NYC called [Codeimmersives] (codeimmersives.com). We explored HTML, CSS, JavaScript, and how to build applications using the MERN stack. I learned about class-based components, passing props around (prop-drilling) and utilizing the component lifecycle(componentWillMount, componentDidMount, etc). After learning class based components, we moved on to functional based components using hooks, custom hooks, and different ways to manage state, such as the useContext and Redux APIs. (This is just a brief overview of the technologies I studied over the past year). Currently I am enrolled at devCodeCamp learning Python and solving problems. I am documenting my journey by sharing these blog posts. Please help me out by dropping a comment below on what you think!

SOLID

SOLID is an acronym for the first five object-oriented design (OOD) principles by Robert C. Martin (also known as Uncle Bob).

These principles can apply to various programming languages and were established as a guide for programmers to follow in order to avoid code smells, refactoring code, and supports Agile and Adaptive software development.

SOLID stands for:

  • S - Single-responsiblity Principle
  • O - Open-closed Principle
  • L - Liskov Substitution Principle
  • I - Interface Segregation Principle
  • D - Dependency Inversion Principle

Single Responsibility Principle

A class, function, etc should only have ONE responsibility. It is important to follow this principle because quite often as an application grows, the code will need to be updated or changed. Following this principle also makes the code easier to read by someone else.

Below is an example of bad practice. Notice the function has multiple responsibilities.

Screen Shot 2022-03-08 at 9.55.25 PM.jpg

Instead, each function has ONE responsibility

Screen Shot 2022-03-08 at 9.56.58 PM.jpg

Screen Shot 2022-03-08 at 9.57.14 PM.jpg

Screen Shot 2022-03-08 at 9.59.26 PM.jpg

Screen Shot 2022-03-08 at 9.58.57 PM.jpg

Open-closed Principle

The functionality in code should be OPEN to extension and CLOSED to modification. You do not want to change the existing code, but you can add to it as the application grows. Again, practicing this principal avoids a mess and bugs in your code. For example, if we have a class that calculates the area of a circle and would want to add the ability to calculate the area of a different shape, then we could add an if statement. On the other hand, what about making a 'shape' class and adding children to that class that have their own methods.
Screen Shot 2022-03-09 at 8.53.54 AM.jpg

Why is open-close important?

  • When you modify a class or method, there may be unexpected outcomes and bugs.
  • If you work for a larger company, they may have features set in place that have been throughly tested.
  • When you add an extension there is confidence that the existing code will be safe!

Liskov Substitution Principle

  • Ability to replace any instance of a parent class with an instance of one of its child classes without negative side effects. If the child class does not have the same variables and methods as the parent then the principal is not adhered to and the code will have bugs. However, you can make a new class that is a child and add functionality (modify)

Screen Shot 2022-03-09 at 8.28.32 PM.jpg

Interface Segregation Principle

  • Interfaces should be granularly split and be as small as possible.
  • Code should not depend on methods it doesn't use.

Check out the code below. We have a parent Vehicle class and because a motorcycle class can not use auto drive, it breaks the principal. Methods can not be unused that are inherited from parent classes.

class Vehicle():
  def accelerate(self):
    raise NotImplementedError

  def brake(self):
    raise NotImplementedError

  def impliment_auto_drive(self):
    raise NotImplementedError


class TeslaSelfDriving(Vehicle):
  def accelerate(self):
    print('implimentation to accelerate') 

  def brake(self):
    print('implimentation to brake')

  def impliment_auto_drive(self):
    print('implimentation to auto drive')


class MotorCycle(self):
  def accelerate(self):
    print('implimentation to accelerate') 

  def brake(self):
    print('implimentation to brake')

  def impliment_auto_drive(self):
    raise NotImplementedError

solution below where interfaces are split

from abc import ABC, abstractclassmethod

class Accelerate(ABC):
  @abstractclassmethod
  def accelerate(self):
    pass
class Brake(ABC):
  @abstractclassmethod
  def brake(self):
    pass
class AutoDrive(ABC):
  @abstractclassmethod
  def impliment_auto_drive(self):
    pass


class TeslaSelfDriving(Accelerate, Brake, AutoDrive):
  def accelerate(self):
    print('implimentation to accelerate') 

  def brake(self):
    print('implimentation to brake')

  def impliment_auto_drive(self):
    print('implimentation to auto drive')


class MotorCycle(Accelerate, Brake):
  def accelerate(self):
    print('implimentation to accelerate') 

  def brake(self):
    print('implimentation to brake')

Dependency Inversion Principle

  • Entities must depend on abstractions, not on concretions. It states that the high-level module must not depend on the low-level module(implementations), but they should depend on abstractions.

Example:

You are a CEO of Coka-Cola with many responsibilities

You wouldn't:

drive a truck

do tax stuff

package bottles

etc..

You would only manage

More to follow on Dependency Inversion Principle with examples.