Jc-alt logo
jc
Interviews: Object Oriented Design

Interviews: Object Oriented Design

··
3 min read
·interviews

Intro

Refresher on basic ood fundamentals, design patterns, concurrency, etc.

based on: https://github.com/ashishps1/awesome-low-level-design

OOP Fundamentals

Classes and Objects

Enums

Interfaces

Encapsulation

Abstraction

Inheritance

Polymorphism

Class Relationships

Association

Aggregation

Composition

Dependency

Design Principles

SOLID

5 principles intended to make source code more understandable, flexible, and maintainable

S: Single Responsibility

A class should have a single responsibility

O: Open-Closed

Classes should be open for extension, but closed for modification.

L: Liskov Substitution

If S is a subtype of T, then objects of type T in a program may be replaced with objects of type S, without altering any of the desirable properties of that program.

I: Interface Segregation

Clients should not be forced to depend on methods that they do not use.

D: Dependency Inversion

High level modules should not depend on low level modules. Both should depend on the abstraction.

Abstractions should not depend on details. Details should depend on abstractions

YAGNI (You Aren't Gonna Need It)

Don't add features or functionality to our software that we currently don't need.

from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int
    # Future-proofing for possible new features
    address: str | None = None
    phone_number: str | None = None


def create_user(name: str, age: int) -> User:
    # Simplified for current needs
    return User(name=name, age=age)

instead of

from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int

def create_user(name: str, age: int) -> User:
    return User(name=name, age=age)

KISS (Keep It Simple Stupid)

Don't add unnecessary complexity to our software

def get_even_numbers(numbers: list[int]) -> list[int]:
    even_numbers: list[int] = []

    for i in range(len(numbers)):
        if numbers[i] % 2 == 0:
            even_numbers.append(numbers[i])

    return even_numbers
def get_even_numbers(numbers: list[int]) -> list[int]:
    return [number for number in numbers if number % 2 == 0]

DRY (Don't Repeat Yourself)

Don't duplicate code or data in our software

from dataclasses import dataclass

@dataclass
class Product:
    id: int
    name: str
    price: float


def sort_by_name(products: list[Product]) -> list[Product]:
    return sorted(products, key=lambda p: p.name)


def sort_by_price(products: list[Product]) -> list[Product]:
    return sorted(products, key=lambda p: p.price)


def sort_by_id(products: list[Product]) -> list[Product]:
    return sorted(products, key=lambda p: p.id)

instead of

from dataclasses import dataclass
from operator import attrgetter
from typing import Literal

ProductField = Literal["id", "name", "price"]


@dataclass
class Product:
    id: int
    name: str
    price: float


def sort_products(products: list[Product], field: ProductField, descending: bool = False) -> list[Product]:
    return sorted(products, key=attrgetter(field), reverse=descending)

ARY (Always Repeat Yourself)

Find a pattern and stick to it

Consistency across code greatly helps ease of reading. Do not copy & paste the same code all over the place, but do copy & paste class skeletons, reuse variable naming conventions, etc.

Rule Of 3

Don't factor out shared code between two classes, wait until you have at least 3

Design Patterns

Creational Patterns

Structural Patterns

Behavioral Patterns

Concurrency and Multi-threading Concepts

Concurrency 101

Synchronization Primitives

Concurrency Challenges

Concurrency Patterns