0% found this document useful (0 votes)
11 views23 pages

SOLID Principles

Uploaded by

akhilendert
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
11 views23 pages

SOLID Principles

Uploaded by

akhilendert
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 23

👨‍💻About the Instructor

=======================

Pragy
Senior Software Engineer + Instructor @ Scaler

https://linktr.ee/agarwal.pragy

💎 Key Takeaways
================

✅ In-depth understanding of SOLID principles


✅ Walk-throughs with examples
✅ Practice quizzes & assignment

❓ FAQ
======
▶️Will the recording be available?
To Scaler students only

✏️Will these notes be available?


Yes. Published in the discord/telegram groups (link pinned in chat)

⏱️ Timings for this session?


7.30pm - 10.30pm (3 hours) [15 min break midway]

🎧 Audio/Video issues
Disable Ad Blockers & VPN. Check your internet. Rejoin the session.

❔ Will Design Patterns, topic x/y/z be covered?


In upcoming masterclasses. Not in today's session.
Enroll for upcoming Masterclasses @ [scaler.com/events]
(https://www.scaler.com/events)

🖥️ What programming language will be used?


The session will be language agnostic. I will write code in Java.
However, the concepts discussed will be applicable across languages

💡 Prerequisites?
Basics of Object Oriented Programming

Important Points
================

💬 Communicate using the chat box


🙋 Post questions in the "Questions" tab
💙 Upvote others' question to increase visibility
👍 Use the thumbs-up/down buttons for continous feedback
⏱️ Bonus content at the end
-----------------------------------------------------------------------------

>
> ❓ What % of your work time is spend writing new code?
>
> • 10-15% • 15-40% • 40-80% • > 80%
>

< 15%

⏱️ Where does the rest of the time go!?

- thinking & planning


- discussions with others
- requirements gathering
- reading other peoples' code
- read the documentation
- google stuff
- go through stackoverflow
- maintainance
- fixing bugs
- adding new features
- changing small things
- writing documentation
- writing unit tests
- meetings

- playing TT / snooker / chai / ...

How to minimize my work time while maximizing my salary?


Whatever code I write is near-perfect from the start

✅ Goals
========

We'd like to make our code

1. Readable
2. Extensible
3. Maintainable
4. Testable

#### Robert C. Martin 🧓🏻 Uncle Bob

===================
💎 SOLID Principles
===================

- Single Responsibility Principle (SRP)


- Open Closed Principle (OCP)
- Liskov's Substitution Principle (LSP)
- Interface Segregation Principle (ISP)
- Dependency Inversion Principle (DIP)
💭 Context
==========

Cannot start with a full blown problem.


Toy problem that demonstrates the various SOLID principles properly
Programming language: pseudocode
syntax highlighting of Java
concepts will be applicable to any modern programming
language that supports Object Oriented Programming

- simple Zoo Game 🦊


- characters - visitors, zoo staff, animals
- structures - cages, feeding bowls, doors

-----------------------------------------------------------------------------

🎨 Design a Character
======================

Concept in mind => class in code

```java

class ZooEntity {

// attributes (properties)
// staff
String visitorAddress;
String visitorName;
Integer age;
Gender gender;
Boolean isVegetarian;
// animals
String name;
Integer age;
Gender gender;
Boolean isVegetarian;
Boolean canFly;
String species;
// visitors
String address;
String name;
String ticketID;
Gender gender;

// methods (behavior)
// staff
void checkInToWork();
void feedAnimals();
void poop();
void eat();
void getPaid();
// animals
void eat();
void poop();
void fly();
void swim();
void attackVisitors();
// visitors
void eat();
void litter();
void buyTicket();

```

Major Issues: name collisions! So, I need to rename the attributes and
methods. Simple fix

🐞 Problems with the above code?

❓ Readable
This code looks readable - I can totally read and understand it!
(for now)

But as the complexity and requirements grow, the code will very quickly
become unreadable.
There's a lot of code in a single class - if I wish to understand how this
class works, I need to read all these (potentially) thousands of lines of
code

❓ Testable
I can totally write testcases for each individual method
```java
class ZooEntityTester {
void testAnimalEat() {
...
}
}
```
Behavior of staff, animals, visitors is thightly coupled - because everything
is in 1 class.
Changing 1 can adversely effect the other.

Therefore this code is hard to test - any changes can have unintended side
effects

❓ Extensible
(will come back to this later)

❓ Maintainable
If there are 3 devs - each working on 1 type of character (animal, staff,
visitor)
All these 3 devs are modifying the same class/file
PR - merge conflicts
Difficult to maintain

🤔 What is the main reason for all these issues?


This code is too complex becuase it is doing too much!

🛠️ How to fix this?


==================================
⭐ Single Responsibility Principle
==================================

- any class/function/module (unit-of-code) should have a single, well-defined


responsibiity
- single: it should not do more than 1 things
- well-defined: the respobsibility should be clear to anyone who is
reading the code - it should not be vague

- another way to state it: any piece of code should have only 1 reason to
change

- if some piece of code has more than 1 responsibility - split it into


multiple pieces

```java
// make use of inheritance (from OOP)

// extract out the common behavior into a parent class


class ZooEntity {
Integer id;
String name;
Gender gender;

void eat();
void poop();
void speak();
}

// separate out the different responsibilities into different child


classes

class Animal extends ZooEntity {


String species;
Boolean canFly;
Boolean canBreatheUnderwater;

void attackVisitors();
void fly();
}

class Visitor extends ZooEntity {


String ticketID;
Boolean isVIP;

void litter();
void registerForNightShow();
}

class Staff extends ZooEntity {


String department;
Integer salary;

void cleanPremises();
void feedAnimals();
}

```

Have the name conflicts gone?


Yes

❓ Readable
We have way too many classes now!
Earlier: 1 class Now: 4 classes

As a dev (experience level doesn't matter) you will always be working on 1


feature at any given time
You need to read and understand 1 or a handful of classes at any given time

The number of classes is more


However, each class now is much smaller, and easier to read & understand!

❓ Testable
Can any changes made to `class Animal` effect the behavior of `class Staff`?
No!
Thus, the code is decoupled - it is easier to test (lesser side effects)

❓ Extensible
(will come back to this later)

❓ Maintainable
Merge conflict - if diff devs are working on different features - most likely
they will be working on diff classes (files)
Less merge conflicts

-----------------------------------------------------------------------------

🐦 Design a Bird
================

```java
class Animal extends ZooEntity {
String species;
}
class Bird extends Animal {
// species is inherited by the class Bird

Integer beakLength;
Integer wingSpan;

void fly() {
print("flap wings")
}
}
```

🕊️ different birds fly differently!

```java
class Bird extends Animal {
// species is inherited by the class Bird
void fly() {
if (species == "pigeon")
print("flap wings, make noise, poop on people below, fly")
else if (species == "eagle")
print("spread wings and glide elegantly")
else if (species == "penguin")
print("bro I can't fly")
}
}
```

🐞 Problems with the above code?

- Readable
- Testable
- Maintainable

1. This has if-else ladder which is bad!


Why is if-else bad?
2. Violates the Single Responsibility principle
This code is currently responsible for multiple types of birds
But this time, let's focus on extensibility.

- Extensible - FOCUS!
Extensibility = being able to add new features/functionality "easily"

❓ How can I add a new type of Bird - peacock

I will need to modify the `class Bird` and add a new else-if condition inside
it

```java
// class Bird extends Animal {
// // species is inherited by the class Bird
// void fly() {
// if (species == "pigeon")
// print("flap wings, make noise, poop on people below, fly")
// else if (species == "eagle")
// print("spread wings and glide elegantly")
// else if (species == "penguin")
// print("bro I can't fly")
else if(species == "peacock")
print("female (pehens) can fly, but the males cannot")
// }
// }
```

❓ Do we always write all code ourselves from scratch?


NO - often use other people's code
1. copy-paste
2. import external libraries/packages

```java

[PublicZooLibary] // found this library on github


{
class Bird extends Animal {
// species is inherited by the class Bird
void fly() {
if (species == "pigeon")
print("flap wings, make noise, poop on people below, fly")
else if (species == "eagle")
print("spread wings and glide elegantly")
else if (species == "penguin")
print("bro I can't fly")
}
}
}
[MyCustomGame] {
// first import the external library
import PublicZooLibary.Bird;

// now use it
class MyZooGame {
static void main() {
Bird b = new Bird(...);
b.fly();
}
}
}

```
❓ How can we add a new type of Bird?
You still need to modify the Bird class to add peacock

❓ Do we always have modification access?


No.
- A lot of time we import public libraries - and we don't have modification
access to it.
- A lot of times, libraries/packages are shipped as compiled files - you
don't even have the source code (.dll .exe .com .so .jar .ext .pyc .war)

🛠️ How to fix this?

========================
⭐ Open/Closed Principle
========================

- your code should be closed for modification, but still, remain open to
extension!
- modification: changing existing code
- extension: not changing existing code, but adding new code in a separate
file

Seems impossible! How on earth can we add new features if we cannot modify
existing code!?

❔ Why is it bad to modify existing code?

# Code lifefycle in large companies (like Google)

- dev writes code on local machine


- test locally
- commit the code
- make a Pull Request (PR)
- that PR is reviewed by others in the team
- give you feedback
- suggest improvements
- make changes
- (iterative process)
- PR gets merged
- Quality Assurance (QA) team
- write additional unit tests
- manual testing
- integration testing
- QA clears this code
- Deployment
+ Staging servers
- check if everything works fine
- any build / deployment errors
- all the enviornment variables are being read properly
- logs are being outputted
+ Production
* A/B testing
- deploy the code to only 5% of the users
- monitor
- number of exceptions
- server health
- custom satisfaction & ratings
- revenue
- ...
* Deploy to 100% of the userbase

If a piece of code has already gone through this extensive process, you do
NOT want to repeat this
Only new code should go through this process

To fix the previous code, once again, we should use inheritance

```java

[PublicZooLibary] // found this library on github


{
// what if the library author had use SOILD principles
abstract class Bird extends Animal {
// species is inherited by the class Bird
abstract void fly();
}

class Pigeon extends Bird {


void fly() {
print("flap wings, make noise, poop on people below, fly")
}
}
class Eagle extends Bird {
void fly() {
print("spread wings and glide elegantly")
}
}
class Peguin extends Bird {
void fly() {
print("bro I can't fly")
}
}
}

[MyCustomGame] {
// first import the external library
import PublicZooLibary.Bird;
import PublicZooLibary.Pigeon;
import PublicZooLibary.Eagle;
import PublicZooLibary.Penguin;

// what if I need to add a new type of Bird


class Peacock extends Bird {
void fly() {
print("Only the females can fly")
}
}
// now use it
class MyZooGame {
static void main() {
Pigeon p = new Pigeon();
p.fly();
}
}
}

```

- Extension
If I need to add a new type of Bird what should I do?
I just just implement another class

Did I have to modify existing code?


No!
But didn't I modify the library?
I did not - I expected the library author to write good code from the
get go!

Max salaries of developers in India (Bangalore/Hyderabad/Chennai/Pune)


3Cr (base) + stocks (for senior positions like Architect with 10+ YOE)

Why would a company pay this much to a developer?


Good developer don't just develop for today - they develop for the
future.
Good devs are able to anticipate future changes in requirements
And they write code today that doesn't need to change when the
requirements change!

❔ Isn't this the same thing that we did for Single Responsibility as well?
Yes! In both cases, we split the large class into multiple smaller classes!

❔ Does that mean that OCP == SRP?


No! The solution was same, but the intent was different!

🔗 All the SOLID principles are linked to one another. They come as a
package.

-----------------------------------------------------------------------------

To demand high salaries like these, master the following topics

Data Structures & Algorithms (DSA)


- everyone focusses on this
- as a fresher you main focus should be here

How computer works internally


- Operating Systems: memory managment, disk access, process, threads &
synchronisation
- Computer Networks: protocols, IP, subnetting, ...
- Databases: indexes, SQL, query optimization, normalization

Low Level Design (LLD)


- Object Oriented Programming (OOP)
- SOLID principles
- Design Patterns (creational/structural/behavioral)
- builder pattern
- python: never implement builder pattern in a language like
Python/Kotlin/Ruby/Javascript
- Case studies (Splitwise/Bookmyshow/Parking Lot/Chess/Snake Ladder)
- Database Schema Design (ER diagram)
- REST API design

Projects

(Seniors) High Level Design

-----------------------------------------------------------------------------
9:04 PM - 9:20 PM (15 mins break)
-----------------------------------------------------------------------------

Zoo game - designing the animals, especially birds


- Single Responsiblity
- Open Closed

```java
class ZooEntity {
...
}

class Animal extends ZooEntity {


String species;
...
}

abstract class Bird extends Animal {


abstract void fly();
}

class Pigeon extends Bird {


void fly() {
print("flap wings, make noise, poop on people below, fly")
}
}
class Eagle extends Bird {
void fly() {
print("spread wings and glide elegantly")
}
}

```

🐓 Can all the birds fly?


=========================

```java

abstract class Bird extends Animal {


abstract void fly();
}

class Pigeon extends Bird {


void fly() {
print("flap wings, make noise, poop on people below, fly")
}
}

class Kiwi extends Bird {


void fly() {
// what should I do here?
}
}
```

There are certain birds that cannot fly!


Kiwi, Penguin, Emu, Ostrich, Dodo, (male) Peacock, ...

>
> ❓ How do we solve this?
>
> • Throw exception with a proper message
> • Don't implement the `fly()` method
> • Return `null`
> • Redesign the system
>

🏃‍♀️ Run away from the problem - simply don't implement the `void fly()` method

```java

abstract class Bird extends Animal {


// Integer beakLength;

abstract void fly();


}

class Kiwi extends Bird {


// no void fly

void poop() {
...
}
}
```

🐞 Compiler Error: either Kiwi should be an abstract class as well


(incomplete), or Kiwi should implement all abstract methods (void fly)

⚠️Throw an proper exception

🐞 Violates expectations!

✅ Before extension

Code works
Properly tested
devs are happy
users are happy

```java
abstract class Bird extends Animal {
abstract void fly();
}

class Pigeon extends Bird {


void fly() {
print("flap wings, make noise, poop on people below, fly")
}
}
class Eagle extends Bird {
void fly() {
print("spread wings and glide elegantly")
}
}

class Main {
Bird getBirdTypeFromUserChoice() {
// shows the different types of birds to the user
// lets the user pick one class
// creates an object of that class
// and returns that object

if(userChoice == "pigeon")
return new Pigeon(...)
else if (...)
return new ...
...
// instead of if-else, use factory pattern
}

void main() {
Bird b = getBirdTypeFromUserChoice();
b.fly();
}
}
```

❌ After extension
The code doesn't work!

```java
class Kiwi extends Bird {
void fly() {
throw new FlightlessBirdException("bro, Kiwi's don't fly")
}
}
```

Inside void main, we get an exception when we encounter `b.fly()`

Q1: did they change existing code?


No - I just added a new file
Old code was written by a senior dev
A new intern comes to the company and adds Kiwi.java
The old dev doesn't even know that someone has added a new file

Q2: was the code working before this extension?


Yes, your code was working before

Q3: is the code working now?


No, your code is not working now
Your code breaks without touching your code!

==================================
⭐ Liskov's Substitution Principle
==================================

Barbara Liskov

- Any object of a `class Child extends Parent` should be able to replace any
object of a `class Parent` without any issues.
- anywhere you expect to see a parent class object, you should be able to
use a child class object without breaking anything!

- child classes should NOT violate expectations set by the parents


- typing Indian parent mentality

🎨 Redesign the system!

```java
/**
* INCORRECT
abstract class Bird extends Animal {
abstract void fly(); // enforcing that all Birds should be able to fly
}
*/
class Bird {
// not all birds can fly
// so we will not enforce any void fly here

abstract void peck();


abstract void poop();
}

interface ICanFly {
void fly();
}

class Pigeon extends Bird implements ICanFly {


void fly() {
print("flap wings, make noise, poop on people below, fly")
}
}
class Eagle extends Bird implements ICanFly {
void fly() {
print("spread wings and glide elegantly")
}
}

class Main {
Bird getBirdTypeFromUserChoice() {
...
}

void main() {
Bird b = getBirdTypeFromUserChoice();

// b.fly(); // compiler error, not a runtime error


// existing code won't break

if(b instanceof ICanFly) {


ICanFly flyingBird = (ICanFly) b;
flyingBird.fly();
}
}
}

// adding this extension now does not break existing code!

class Kiwi extends Bird {


// Kiwi is a Bird, but it cannot fly, so it will NOT implement the ICanFly
interface
// no compiler error if we don't implement void fly()
}
```

```py
from abc import ABC, abstractmethod

class Bird(ABC):
...

class FlightMixin(ABC):
@abstractmethod
def fly(self):
raise NotImplementedError

class Eagle(Bird, FlightMixin):


def fly(self):
print("fly high")

class Kiwi(Bird):
# no need to implement fly() method
...
```

Q: didn't we modify existing code for this change to happen?


No. We expect code to follow all SOLID principles from day 1
We're saying that a good dev won't write the previous bad code at all - they
will write the later code from the get go.

Q: aren't we violating the OCP?


Again, no.

-----------------------------------------------------------------------------

✈️What else can fly?


=====================

```java

class Bird {
...
}

interface ICanFly {
void fly();

void flapWings();
}

class Pigeon extends Bird implements ICanFly {


void fly() {
print("flap wings, make noise, poop on people below, fly")
}
}

class Eagle extends Bird implements ICanFly {


void fly() {
print("spread wings and glide elegantly")
}
}

class Shaktiman implements ICanFly {


void fly() {
print("put finger up, and spin really fast")
}

void flapWings() {
// SORRY Shaktiman!
}
}

```

❓ Are there things apart from Birds that can fly?


Aeroplanes, insects, Superman, Papa ki Pari, Drones, Patang (kite), Dragons,
Pegasus, Shaktiman, Mom's Chappal, Udta Punjab, ...

❓ How does a Bird typically fly? What steps does it take?


1. kickOffGround() to make a small jump
2. spreadWings()
3. flapWings()
4. start gliding

>
> ❓ Should these additional methods be part of the ICanFly interface?
>
> • Yes, obviously. All things methods are related to flying
> • Nope. [send your reason in the chat]
>

No - these should NOT be part of ICanFly interface, because not all the
things that can fly can support these

==================================
⭐ Interface Segregation Principle
==================================

- Keep your interfaces minimal


- The clients of your interface (other pieces of code that implement your
interface) should not be forced to implement methods that they don't need

❓ Isn't this similar to LSP? Isn't this just SRP applied to interfaces?

Single Responsibility - general principle


Liskov Substitution - type hierarchy (mathematical principle)

SRP vs ISP => ISP can apply to APIs as well, not just classes

🔗 All SOLID principles are tightly linked to each other. You see view them
together, not as individual principles

How will you fix `ICanFly`?

Split it into multiple interfaces


`ICanFly`, `IHasWings`, ...

-----------------------------------------------------------------------------

we've been designing a lot of characters - animals, birds, staff, ..


we've improved our code quite a lot to meet future requirement changes

Let's now design some structures

🗑️ Design a Cage
================

```java
abstract class Animal { ... } // High Level Abstraction
class Tiger extends Animal { ... } // Low Level Implementation
class Doggy extends Animal { ... } // Low Level Implementation
class Bird extends Animal { ... } // Low Level Implementation

interface IBowl { // High Level Abstraction


void feed(Animal animal); // tells you that you need to feed
// but doesn't tell you how to feed
}
class MeatBowl implements IBowl { // Low Level Implementation
void feed(Animal animal) {
// measure meat
// put in bowl // tells you exactly how to
// add enzymes for easier digestion // feed
// add multivitamins
// make sure the food is at the correct temp
// serve it
}
}
class FruitBowl implements IBowl { ... } // Low Level Implementation
class GrainBowl implements IBowl { ... } // Low Level Implementation

interface IDoor { // High Level Abstraction


void resistAttack(Attack attack);
}
class WoodenDoor implements IDoor { ... } // Low Level Implementation
class IronDoor implements IDoor { ... } // Low Level Implementation

class Cage1 { // High level controller


// a cage for tigers

// dependencies
IronDoor door = new IronDoor();
MeatBowl bowl = new MeatBowl();

List<Tiger> kitties = new ArrayList<>();

public Cage1() {}

public feed() {
// delegate the task to the dependency // delegates tasks
for(Tiger t: this.kitties)
this.bowl.feed(t)
}

public resistAttack(Attack attack) {


// delegate the task to the dependency
this.door.resistAttack(attack)
}
}
class Cage2 {
// a cage for small birds

// dependencies
WoodenDoor door = new WoodenDoor();
FruitBowl bowl = new FruitBowl();

List<Bird> birdies = new ArrayList<>();

public Cage2() {}

public feed() {
// delegate the task to the dependency
for(Bird b: this.birdies)
this.bowl.feed(b)
}

public resistAttack(Attack attack) {


// delegate the task to the dependency
this.door.resistAttack(attack)
}
}

// Cage3 for doggies, Cage4 for snakes, ...

class Game {
void main() {
Cage1 tigerCage = new Cage1();
...
Cage2 birdCage = new Cage2();
...
}
}

// if I wish to add a new cage


// I would need to add a new class - write more code

class Cage3 {
// for xmen
// ...
}
```

🐞 A lot of code repetition


- violates the Don't Repeat Yourself (DRY) principle
- I literally copy pasted the code
- the different classes are basically the same
- to add a new cage, I need to once again copy paste code

High Level Code


- Abstractions
- pieces of code that tell you what to do, but not how to do it
- declare the function, but don't define the implementation
- abstract classes / interfaces
- Controllers
- managerial code
- pieces of code that don't do the task themselves, instead, delegate
the task to dependencies

Low Level Code


- code that tells you exactly how to do something
- implementation details
- classes
```

interface abstract class interface


------- --------- -------
IBowl Animal IDoor High level abstractions
------- --------- -------
║ ║ ║
║ ║ ║
┏━━━━━━━━━━┓ ┏━━━━━━━┓ ┏━━━━━━━━━━┓
┃ MeatBowl ┃ ┃ Tiger ┃ ┃ IronDoor ┃ Low level implementations
┗━━━━━━━━━━┛ ┗━━━━━━━┛ ┗━━━━━━━━━━┛
│ │ │
╰───────────────╁───────────────╯

┏━━━━━━━┓
┃ Cage1 ┃ High level controller
┗━━━━━━━┛

```

In the above code, the class `Cage1` depends on low level implementation
details `MeatBowl`, `Tiger`, `IronDoor`

=================================
⭐ Dependency Inversion Principle - what do achieve
=================================

- any code (high/low level) should NEVER depend on low level implementation
details
- should ONLY depend on high level abstractions

```
------- --------- -------
IBowl Animal IDoor High level abstractions
------- --------- -------
│ │ │
╰───────────────╁──────────────╯

┏━━━━━━┓
┃ Cage ┃ Code
┗━━━━━━┛
```

But how?

=======================
💉 Dependency Injection - how to achieve it
=======================

- Don't create your dependencies yourself


- Let your clients (code that uses your code) create the dependency for you,
and inject it into you

```java
interface IDoor { ... } // High Level Abstraction
class IronDoor implements IDoor { ... } // Low Level Implementation Detail
class WoodenDoor implements IDoor { ... } // Low Level Implementation Detail
class AdamantiumDoor implements IDoor { ... } // Low Level ...

interface IBowl { ... } // High Level Abstraction


class MeatBowl implements IBowl { ... } // Low Level Implementation Detail
class GrainBowl implements IBowl { ... } // Low Level Implementation Detail
class FruitBowl implements IBowl { ... } // Low Level Implementation Detail

class Cage { // High level controller


// a generic cage

// dependencies
IDoor door;
IBowl bowl;

List<Animal> animals;

// dependency injection via constructor

public Cage(IDoor door, IBowl bowl, List<Animal> animals) {


this.door = door;
this.bowl = bowl;
this.animals = Arrays.copy(animals);
}

public feed() {
// delegate the task to the dependency // delegates tasks
for(Animal a: this.kitties)
this.bowl.feed(a)
}

public resistAttack(Attack attack) {


// delegate the task to the dependency
this.door.resistAttack(attack)
}
}

class Game {
void main() {
Cage tigerCage = new Cage(
new IronDoor(...),
new MeatBowl(...),
Arrays.asList(new Tiger(...), new Tiger(...))
);
Cage birdCage = new Cage(
new WoodenDoor(...),
new FruitBowl(...),
Arrays.asList(new Eagle(...), new Peacock(...))
);

// if I want a cage for XMen


Cage forXMen = new Cage(
new AdamantiumDoor(...),
new MeatBowl(...),
Arrays.asList(new Wolverine(...), new Cyclops(...))
);
}
}

```
All the fancy frameworks use dependency inversion & injection! They also use
SOLID principles
- backend
- Rails (ruby)
- Spring (java)
- Django / Flask / FastAPI (python)
- Laravel (php)
- .Net (C#, F#, ...)
- Express (Nodejs)
- frontend
- React
- Vue
- Angular
- Svelte
- Fullstack
- Dart + Flutter

IoC - Inversion of Control


- you don't have control over the event loop - the framework does
- you write handlers, and the framework calls those handlers
- you write controller, and for every request, the framework creates an
object of that controller and calls the handle() method
- when creating the object of the controller, the framework will do
dependency injection

Enterprise Code
===============

If you go to large companies (Like Google) - you will find "over-engineered"


code!

Startups care about


- moving fast
- product-market fit
- fundraising
- failing fast
- iteration speed
Startups don't care about
- code quality
- CTO changing
- projects getting shelved

Enterprises care about


- devs joining and leaving teams
- projects that run for 10+ years
- teams that involve 100+ devs
- massive documentations
- code quality

Design Patterns / Principle / .. all these are heavily hammered into every
piece of code

```java
class StripePaymentGatewayServiceStrategyFactory implement
IPaymentGatewayServiceStrategyFactory {
StripePaymentGatewayServiceStrategyFactory instance;

// extra long variable names


// logging everywhere
// patterns everywhere
}
```
Not good at LLD
- code doesn't make any sense
- everything is too complex
- soooo much hierarchy of function calls

If you're good at LLD


- you won't even have to read 90% of the code
- just the class name will tell you exactly what the code will do!

================
🎁 Bonus Content
================

>
> We all need people who will give us feedback.
> That’s how we improve. 💬 Bill Gates
>

-------------
🧩 Assignment
-------------

https://github.com/kshitijmishra23/low-level-design-
concepts/tree/master/src/oops/SOLID/

----------------------
⭐ Interview Questions
----------------------

> ❓ Which of the following is an example of breaking


> Dependency Inversion Principle?
>
> A) A high-level module that depends on a low-level module
> through an interface
>
> B) A high-level module that depends on a low-level module directly
>
> C) A low-level module that depends on a high-level module
> through an interface
>
> D) A low-level module that depends on a high-level module directly
>

> ❓What is the main goal of the Interface Segregation Principle?


>
> A) To ensure that a class only needs to implement methods that are
> actually required by its client
>
> B) To ensure that a class can be reused without any issues
>
> C) To ensure that a class can be extended without modifying its source code
>
> D) To ensure that a class can be tested without any issues

>
> ❓ Which of the following is an example of breaking
> Liskov Substitution Principle?
>
> A) A subclass that overrides a method of its superclass and changes
> its signature
>
> B) A subclass that adds new methods
>
> C) A subclass that can be used in place of its superclass without
> any issues
>
> D) A subclass that can be reused without any issues
>

> ❓ How can we achieve the Interface Segregation Principle in our classes?
>
> A) By creating multiple interfaces for different groups of clients
> B) By creating one large interface for all clients
> C) By creating one small interface for all clients
> D) By creating one interface for each class

> ❓ Which SOLID principle states that a subclass should be able to replace
> its superclass without altering the correctness of the program?
>
> A) Single Responsibility Principle
> B) Open-Close Principle
> C) Liskov Substitution Principle
> D) Interface Segregation Principle
>

>
> ❓ How can we achieve the Open-Close Principle in our classes?
>
> A) By using inheritance
> B) By using composition
> C) By using polymorphism
> D) All of the above
>

# ============================ That's all, folks! ===========================

You might also like