Skip to content

Latest commit

 

History

History
393 lines (287 loc) · 7.33 KB

slides.md

File metadata and controls

393 lines (287 loc) · 7.33 KB
css theme drawings highlighter lineNumbers layout info
unocss
geist
persist
true
shiki
false
cover
## Software Design and Architecture

Software Design and Architecture

Part II

Open slides here: https://sda.np-overflow.club


Installation

Due to certain language limitations of Python, we'll be using ✨ Typescript ✨ for this workshop!

Please install the following:

  1. NodeJS & NPM Install here
  2. Your favorite code editor or VSCode

To run a file: open a terminal window and type:

npx tsx /path/to/file

Tech support

  • Don't panic, find help

Head over to #tech-support on our Discord server

<style> a:hover { text-decoration: underline; } </style>

Recap from last week

  • Object-Oriented Programming (with Python 🐍)
  • Creation patterns
    • Singleton
    • Abstract classes
  • Structural patterns
    • Decorators
    • Bridges

⁉ ️How can we use this in our code ⁉️


Deep dive into OOP

  • SOLID - 5 principles that compliments OOP
    • Also helps you write good code 👍 (maintainable, readable, understandable, flexible... developers good code)
Character Idea Important
S Single responsibility principle
O Open closed principle
L Liskov substitution principle
I Interface segregation principle
D Dependency inversion principle

Single responsibility principle

  • Each class should only manage a single thing

keyboard.ts

class Keyboard {
  type() {
    console.log('clang clang')
  }
}

mouse.ts

class Mouse {
    scroll() {
        console.log('wheeeeee')
    }
}

accessories.ts

class Accessories {
    type() {
        // ...
    }
    scroll() {
        // ...
    }
}

Open closed principle

  • Clases should be open for extension but closed for modification

keyboard.ts

class Keyboard {
  type() {
    console.log('clang clang')
  }
}

rgb-keyboard.ts

class RGBKeyboard extends Keyboard {
    colors = ['red', 'green', 'blue']
    
    showFancyLights() {
        console.log(colors)
    }
}

keyboard.ts

class Keyboard {
    colors = ['red', 'green', 'blue']
    
    type() {
        console.log('clang clang')
    }
    showRGB() {
        console.log('beep boop')
    }
}

Liskov substitution principle

  • If class RGBKeyboard is a subclass of Keyboard:
    • RGBKeyboard should be able to replace Keyboard without any side effects

developer.ts

class Developer {
    keyboard: Keyboard
    constructor(keyboard: Keyboard) {
      this.keyboard = keyboard
    }
    
    writeCode() {
        this.keyboard.type()
    }
}

main.ts

const logitechKeyboard = new Keyboard()
const qinguan = new Developer(logitechKeyboard)
qinguan.writeCode() // Writes code with `Keyboard`

const razerKeyboard = new RGBKeyboard()
const jimmy = new Developer(razerKeyboard)
jimmy.writeCode() // Writes code with `RGBKeyboard`

Interface segregation principle

  • Interfaces (methods/properties of a class) should be split into their logical concerns
  • For example, read vs writes to a database can be 2 interfaces, instead of a huge interface

keyboard.ts

interface KeyboardDatabaseWriter {
    create(keyboard: Keyboard)
    update(keyboard: Keyboard)
    delete(keyboard: Keyboard)
}

interface KeybaordDatabaseReader {
  findByName(name: string)
  findByBrand(brand: string)
  findByPrice(price: string)
}

keyboard.ts

interface KeyboardDatabase {
  create(keyboard: Keyboard)
  findByName(name: string)
  findByBrand(brand: string)
  findByPrice(price: string)
  update(keyboard: Keyboard)
  delete(keyboard: Keyboard)
}

Dependency inversion principle

  • Dependencies should be on abstractions and not concretions
  • Instead of depending on classes, which are "concrete" and contain implementation, use interfaces which only define methods & not implementation

developer.ts

// Anything that I can type on is a keyboard!
interface Keyboard {
  type()
}
class Developer {
    keyboard: Keyboard // Depend on an interface
    constructor(keyboard: Keyboard) {
      this.keyboard = keyboard
    }
    writeCode() {
        this.keyboard.type()
    }
}

main.ts

// Any class that has a `type()` method can be used

const logitechKeyboard = new Keyboard() 
const qinguan = new Developer(logitechKeyboard)
qinguan.writeCode() // Writes code with `Keyboard`

const razerKeyboard = new RGBKeyboard()
const jimmy = new Developer(razerKeyboard)
jimmy.writeCode() // Writes code with `RGBKeyboard`

Applying SOLID with Clean Architecture

  • Separate your program into layers
  • Achieve a few objectives
    • Independent of framework
    • Independent of user interface
    • Independent of database
    • Independent of external interfaces
    • Highly testable

Layers of Clean Architecture

Layer Purpose
Entity Entities and their corresponding rules
Use case Service/business functions
Interface adapter Mapping/connecting our use cases to frameworks/drivers
Frameworks/drivers Databases, HTTP handlers, user interfaces, etc

Activity time!

Duration: 10 minutes

Task: Find a real life application which you can apply Clean Architecture to

Once done: Submit to sli.do on the right!


Practical time!

  • Let's rewrite a program with Clean Architecture
  • The program
    • Has an HTTP API endpoint we can interact with
    • Shows the keyboards in our collection
    • When new keyboards arrive, add them to our collection
  • Before we begin, we need a few things:
    1. Starter code here
    2. API tester here

Open them on your laptop!


layout: center

⚠️ Demo on screen! ⚠️

Open the downloaded file in your editor