The S.O.L.I.D. Foundation of System Design

The S.O.L.I.D. Foundation of System Design


S — Single Responsibility Principle

O — Open Close Design Principle

L — Liskov Substitution Principle

I — Interface Segregation Principle

D — Dependency Inversion Principle

Advantages

The SOLID principles are like a set of rules to help make computer programs better. Here’s how they help:

1. Easy to Change: If you need to update or fix something, it’s much easier because everything has its own job.

2. Easy to Grow: You can add new things to your program without messing up what you already have.

3. Less Breaking: When you add something new or change something, there’s less chance of breaking other parts of your program.

4. Easy to Check: It’s easier to test if each part of your program works right, so you can find and fix problems faster.

5. Less Mixing Up: Parts of your program talk to each other in a neat way, so there’s less confusion and mess.

6. Clear to Understand: Your program is easier to read and understand, like a well-organized book, so others can figure out how it works more easily.


1. Single Responsibility Principle (SRP)

A class should not have more than one reason to change. If there are multiple responsibilities help by a single class - it may lead to introducing bugs in existing piece of code and breaking one functionality while making changes in another functionality.

Version-1

class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total

    def pay(self, payment_type, security_code):
        if payment_type == "debit":
            print("Processing debit payment type")
            print(f"Verifying security code: {security_code}")
            self.status = "paid"
        elif payment_type == "credit":
            print("Processing credit payment type")
            print(f"Verifying security code: {security_code}")
            self.status = "paid"
        else:
            raise Exception(f"Unknown payment type: {payment_type}")


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
order.pay("debit", "0372846")        

Version-2

class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor:
    def pay_debit(self, order, security_code):
        print("Processing debit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"

    def pay_credit(self, order, security_code):
        print("Processing credit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = PaymentProcessor()
processor.pay_debit(order, "0372846")        

The original version of the Order class was doing too much. It was keeping track of items in the order, calculating the total price, and also handling the payment process. This is like having a chef in a restaurant who also serves the food and handles the cash register—all by themselves!

Applying the Single Responsibility Principle, we made a big change: we split the jobs. Now, the Order class only takes care of the order itself, like keeping track of items and calculating how much they cost. It's like the chef focusing on cooking only.

Then, we created a new class called PaymentProcessor. This class has one job: handling payments. Whether it's paying by debit or credit, this class takes care of checking the payment details and updating the order status to "paid." This is like having a cashier who handles all the money stuff, separate from the chef.

By doing this, each class has its own responsibility. The Order class focuses on the order, and the PaymentProcessor class focuses on payments. This makes the code easier to understand, manage, and change in the future because each part does one specific thing.

2. Open/Closed Principle (OCP)

We should not make changes/ modifications in existing classes to provide new functionality. Instead we should extend the existing classes to support add-on features/ functionalities.

O stands for Open for extension and closed for Modifications.

Version-1

class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor:
    def pay_debit(self, order, security_code):
        print("Processing debit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"

    def pay_credit(self, order, security_code):
        print("Processing credit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = PaymentProcessor()
processor.pay_debit(order, "0372846")        

Version-2

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):

    @abstractmethod
    def pay(self, order, security_code):
        pass


class DebitPaymentProcessor(PaymentProcessor):
    def pay(self, order, security_code):
        print("Processing debit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):
    def pay(self, order, security_code):
        print("Processing credit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = DebitPaymentProcessor()
processor.pay(order, "0372846")        

In the newest version of the code, there's a special rule being followed called the Open/Closed Principle. This principle says that a piece of software (like a class in programming) should be open for extension but closed for modification. In plain language, it means you should be able to add new features without changing the existing code.

Before:

Previously, the PaymentProcessor class didn't exist. The Order class had methods to handle payments directly, and if we wanted to add a new payment method, we'd have to change the Order class itself. That's like having a toolbox where you need to change the toolbox itself every time you get a new tool.

After:

  1. Abstract Base Class: We introduced an abstract class named PaymentProcessor. This class is like a blueprint or a contract. It says, "If you want to be a payment processor, you must have a pay method." But it doesn't say how to do it. This allows for different types of payment processors to be created in the future without changing the blueprint.
  2. Specific Payment Processors: We then created DebitPaymentProcessor and CreditPaymentProcessor classes that extend the PaymentProcessor class. This is like saying, "Here are specific tools (debit and credit processors) that follow the blueprint (PaymentProcessor) on how to process payments." Each of these classes has its own way of handling payments, according to the blueprint.

What Changed for Open/Closed Principle:

  • Open for Extension: We can easily add more payment methods (like PayPal or cryptocurrency) by creating new classes that follow the PaymentProcessor blueprint. We don't need to touch the existing classes to add these new features.
  • Closed for Modification: The original Order class and the abstract PaymentProcessor class don't need to be changed when adding new payment types. They're closed for modification, meaning you don't mess with them once they're set up and working.

3. Liskov Substitution Principle (LSP)

Every Parent Class should be replaceable by it’s sub-class. If a class B extends a class A - then it should be possible to replace object of class A will object of class B without breaking any of the client’s behavior. In simple words, child class should extend the capability of parent class and not narrow it down.

Version-1

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):

    @abstractmethod
    def pay(self, order, security_code):
        pass


class DebitPaymentProcessor(PaymentProcessor):
    def pay(self, order, security_code):
        print("Processing debit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):
    def pay(self, order, security_code):
        print("Processing credit payment type")
        print(f"Verifying security code: {security_code}")
        order.status = "paid"


class PaypalPaymentProcessor(PaymentProcessor):
    def pay(self, order, security_code):
        print("Processing paypal payment type")
        print(f"Using email address: {security_code}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = PaypalPaymentProcessor()
processor.pay(order, "[email protected]")        

Version-2

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):

    @abstractmethod
    def pay(self, order):
        pass


class DebitPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code

    def pay(self, order):
        print("Processing debit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code

    def pay(self, order):
        print("Processing credit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class PaypalPaymentProcessor(PaymentProcessor):

    def __init__(self, email_address):
        self.email_address = email_address

    def pay(self, order):
        print("Processing paypal payment type")
        print(f"Using email address: {self.email_address}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = PaypalPaymentProcessor("[email protected]")
processor.pay(order)        

What is the Liskov Substitution Principle (LSP)?

The LSP is like saying you can replace something with a version of it, and everything should still work fine. Imagine you have a favorite app you use all the time. If an update for the app comes out, you expect it to do all the things the old one did, maybe with some extra features or fixes. You don't want the update to break the app or remove something you rely on.

How Does It Apply Here?

In the provided code, there's a PaymentProcessor class that acts like a general idea of "paying for an order." It says, "If you want to be a payment processor, you need to have a pay method that takes an order."

Then, there are specific versions of this idea: DebitPaymentProcessor, CreditPaymentProcessor, and PaypalPaymentProcessor. Each of these is like an update or a special version of the PaymentProcessor. According to LSP, you should be able to use any of these payment processors in place of just a general PaymentProcessor, and they should all work properly—they should all be able to pay for the order without causing problems.

The Practical Example:

  • Before: You just had an order and wanted to pay for it. There wasn't much flexibility in how the payment was processed.
  • After: Now, you can choose how to pay—debit, credit, or PayPal. No matter which method you choose, the process works the same way from the order's perspective: it gets paid. You don't need to change how the order works depending on the payment method; you just swap out one PaymentProcessor for another.

Why It's Cool:

This is great because it lets the rest of your code (like where you handle orders) be simple and not worry about the details of payment processing. Whether it's a debit card, a credit card, or PayPal, your order code doesn't need to change. This makes your code more flexible and easier to extend with new payment methods in the future without messing with existing functionality.

4. Interface Segregation Principle (ISP)

Clients should not be forced to implement methods that they don’t use. Try to make your interfaces narrow enough that client classes don’t have to implement behaviors they don’t need.

Version-1

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):

    @abstractmethod
    def auth_sms(self, code):
        pass

    @abstractmethod
    def pay(self, order):
        pass


class DebitPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code
        self.verified = False

    def auth_sms(self, code):
        print(f"Verifying SMS code {code}")
        self.verified = True

    def pay(self, order):
        if not self.verified:
            raise Exception("Not authorized")
        print("Processing debit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code

    def auth_sms(self, code):
        raise Exception("Credit card payments don't support SMS code authorization.")

    def pay(self, order):
        print("Processing credit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class PaypalPaymentProcessor(PaymentProcessor):

    def __init__(self, email_address):
        self.email_address = email_address
        self.verified = False

    def auth_sms(self, code):
        print(f"Verifying SMS code {code}")
        self.verified = True

    def pay(self, order):
        if not self.verified:
            raise Exception("Not authorized")
        print("Processing paypal payment type")
        print(f"Using email address: {self.email_address}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = DebitPaymentProcessor("2349875")
processor.auth_sms(465839)
processor.pay(order)        

Version-2

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class PaymentProcessor(ABC):

    @abstractmethod
    def pay(self, order):
        pass


class PaymentProcessorSMS(PaymentProcessor):

    @abstractmethod
    def auth_sms(self, code):
        pass

    @abstractmethod
    def pay(self, order):
        pass


class DebitPaymentProcessor(PaymentProcessorSMS):

    def __init__(self, security_code):
        self.security_code = security_code
        self.verified = False

    def auth_sms(self, code):
        print(f"Verifying SMS code {code}")
        self.verified = True

    def pay(self, order):
        if not self.verified:
            raise Exception("Not authorized")
        print("Processing debit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code

    def pay(self, order):
        print("Processing credit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class PaypalPaymentProcessor(PaymentProcessorSMS):

    def __init__(self, email_address):
        self.email_address = email_address
        self.verified = False

    def auth_sms(self, code):
        print(f"Verifying SMS code {code}")
        self.verified = True

    def pay(self, order):
        if not self.verified:
            raise Exception("Not authorized")
        print("Processing paypal payment type")
        print(f"Using email address: {self.email_address}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
processor = PaypalPaymentProcessor("[email protected]")
processor.auth_sms(465839)
processor.pay(order)        

Applying ISP in Our Code:

We've applied the Interface Segregation Principle by developing two distinct interfaces (abstract classes in Python): PaymentProcessor and PaymentProcessorSMS.

  • PaymentProcessor Interface: Aimed at basic payment processing, it includes a single method pay(self, order), serving as a foundational layer for any payment type.
  • PaymentProcessorSMS Interface: Building upon PaymentProcessor, it introduces auth_sms(self, code) for payment methods requiring SMS authentication. This separation allows for focused functionality tailored to specific requirements.

Before ISP:

Initially, a singular, bulky interface might have been used, demanding all payment methods to support SMS authentication, even when unnecessary. This approach could lead to superfluous implementations, cluttering the codebase.

After ISP:

The introduction of specialized interfaces ensures:

  • Specificity: A clear distinction is made where DebitPaymentProcessor and PaypalPaymentProcessor implement PaymentProcessorSMS for SMS verification necessity. Conversely, CreditPaymentProcessor aligns with PaymentProcessor, suitable for scenarios without SMS authentication need.
  • Flexibility and Maintainability: With the advent of new payment methods, extending the appropriate base class becomes straightforward, without mandating irrelevant functionalities. For instance, should a need arise for an online payment-specific method, introducing a new interface can be done seamlessly, preserving the integrity of existing processors.
  • Code Clarity: Each payment processor is confined to relevant functionalities, eliminating unnecessary complexity and enhancing code readability and maintainability.

5. Dependency Inversion Principle (DIP)

High-level classes shouldn’t depend on low-level classes. Both should depend on abstractions. Abstractions shouldn’t depend on details. Details should depend on abstractions.

In short, Class should depend on interfaces rather than concrete classes.

Version-1

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class SMSAuthorizer:

    def __init__(self):
        self.authorized = False

    def verify_code(self, code):
        print(f"Verifying SMS code {code}")
        self.authorized = True

    def is_authorized(self) -> bool:
        return self.authorized


class PaymentProcessor(ABC):

    @abstractmethod
    def pay(self, order):
        pass


class DebitPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code, authorizer: SMSAuthorizer):
        self.security_code = security_code
        self.authorizer = authorizer

    def pay(self, order):
        if not self.authorizer.is_authorized():
            raise Exception("Not authorized")
        print("Processing debit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code

    def pay(self, order):
        print("Processing credit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class PaypalPaymentProcessor(PaymentProcessor):

    def __init__(self, email_address, authorizer: SMSAuthorizer):
        self.email_address = email_address
        self.authorizer = authorizer

    def pay(self, order):
        if not self.authorizer.is_authorized():
            raise Exception("Not authorized")
        print("Processing paypal payment type")
        print(f"Using email address: {self.email_address}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
authorizer = SMSAuthorizer()
authorizer.verify_code(465839)
processor = PaypalPaymentProcessor("[email protected]", authorizer)
processor.pay(order)        

Version-2

from abc import ABC, abstractmethod


class Order:

    def __init__(self):
        self.items = []
        self.quantities = []
        self.prices = []
        self.status = "open"

    def add_item(self, name, quantity, price):
        self.items.append(name)
        self.quantities.append(quantity)
        self.prices.append(price)

    def total_price(self):
        total = 0
        for i in range(len(self.prices)):
            total += self.quantities[i] * self.prices[i]
        return total


class Authorizer(ABC):
    @abstractmethod
    def is_authorized(self) -> bool:
        pass


class AuthorizerSMS(Authorizer):

    def __init__(self):
        self.authorized = False

    def verify_code(self, code):
        print(f"Verifying SMS code {code}")
        self.authorized = True

    def is_authorized(self) -> bool:
        return self.authorized


class AuthorizerGoogle(Authorizer):

    def __init__(self):
        self.authorized = False

    def verify_code(self, code):
        print(f"Verifying Google auth code {code}")
        self.authorized = True

    def is_authorized(self) -> bool:
        return self.authorized


class AuthorizerRobot(Authorizer):

    def __init__(self):
        self.authorized = False

    def not_a_robot(self):
        self.authorized = True

    def is_authorized(self) -> bool:
        return self.authorized


class PaymentProcessor(ABC):

    @abstractmethod
    def pay(self, order):
        pass


class DebitPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code, authorizer: Authorizer):
        self.security_code = security_code
        self.authorizer = authorizer

    def pay(self, order):
        if not self.authorizer.is_authorized():
            raise Exception("Not authorized")
        print("Processing debit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class CreditPaymentProcessor(PaymentProcessor):

    def __init__(self, security_code):
        self.security_code = security_code

    def pay(self, order):
        print("Processing credit payment type")
        print(f"Verifying security code: {self.security_code}")
        order.status = "paid"


class PaypalPaymentProcessor(PaymentProcessor):

    def __init__(self, email_address, authorizer: Authorizer):
        self.email_address = email_address
        self.authorizer = authorizer

    def pay(self, order):
        if not self.authorizer.is_authorized():
            raise Exception("Not authorized")
        print("Processing paypal payment type")
        print(f"Using email address: {self.email_address}")
        order.status = "paid"


order = Order()
order.add_item("Keyboard", 1, 50)
order.add_item("SSD", 1, 150)
order.add_item("USB cable", 2, 5)

print(order.total_price())
authorizer = AuthorizerRobot()
authorizer.verify_code(465839)
authorizer.not_a_robot()
processor = PaypalPaymentProcessor("[email protected]", authorizer)
processor.pay(order)        

## Changes Made:

1. Before DIP Implementation: Initially, the payment processors directly depended on a specific type of authorization (SMSAuthorizer), making the system less flexible. If we wanted to introduce a new authorization method, we would have to modify the payment processors directly, which goes against the open/closed principle.

2. After DIP Implementation:

- An Authorizer abstract class (interface) was introduced, representing the abstraction for authorization mechanisms. This abstraction defines what it means to be an authorizer without specifying how the authorization is performed.

- Concrete classes like AuthorizerSMS, AuthorizerGoogle, and AuthorizerRobot implement this interface, each providing a specific authorization mechanism. This setup allows for new authorization mechanisms to be added without modifying existing payment processors.

- Payment processors (`DebitPaymentProcessor`, CreditPaymentProcessor, PaypalPaymentProcessor) now depend on the Authorizer abstraction rather than concrete implementations. This means any object that implements the Authorizer interface can be used, increasing flexibility and enabling the system to easily adapt to new requirements or changes.

### Impact of DIP:

- Flexibility: The system can now support various authorization mechanisms without changing the payment processing logic. This makes it easy to introduce new authorization methods in the future.

- Decoupling: Payment processors are no longer tightly coupled to a specific authorization method. This reduces dependency on specific implementations, making the system more robust and easier to maintain.

- Scalability: It's easier to scale the system by adding new authorization methods or payment processors, as the core architecture doesn't need to change.

By adhering to the Dependency Inversion Principle, the updated design improves the system's ability to evolve and adapt, ensuring that changes in authorization mechanisms or payment processing strategies can be accommodated with minimal impact on the existing codebase.


Thank you for reading the Article!

要查看或添加评论,请登录

Sourabh Ligade的更多文章

  • How I Built a Production-Ready RAG Chatbot: A Comprehensive Technical Guide

    How I Built a Production-Ready RAG Chatbot: A Comprehensive Technical Guide

    1. Introduction to Retrieval-Augmented Generation (RAG) Retrieval-Augmented Generation (RAG) is an advanced natural…

  • Difference between Stack and Queue Data Structures

    Difference between Stack and Queue Data Structures

    Stack: A stack is a linear data structure in which elements can be inserted and deleted only from one side of the list,…

  • What is Queue Data Structure?

    What is Queue Data Structure?

    A Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific…

  • What are Stacks?

    What are Stacks?

    Stacks are the simplest of all data structures, yet they are also among the most important. They are used in a host of…

  • What is Insertion Sort Algorithm?

    What is Insertion Sort Algorithm?

    Insertion sort is a simple sorting algorithm that works by iteratively inserting each element of an unsorted list into…

  • What is Recursion?

    What is Recursion?

    Recursion explained to an 8-year-old: Imagine you have a set of nesting dolls, each doll containing smaller dolls…

  • What is a HashMap?

    What is a HashMap?

    HashMaps explained to an 8-year-old: Imagine you're in a giant toy store with hundreds of shelves filled with different…

  • How I Built a Full-Stack Book Review Website Using Django??

    How I Built a Full-Stack Book Review Website Using Django??

    In this article, we will make a book application from installation to the final product using Django. I hope to make a…

社区洞察

其他会员也浏览了