Tuesday, September 26, 2023

SOLID Principle

 SOLID Principle

If I have to explain in one picture then I will use this one to illustrate what SOLID principle is.


SOLID is an acronym that stands for five key design principles that help software developers create code that is reusable, maintainable, and easy to understand. These principles are:

  • Single Responsibility Principle: This principle states that a class should have only one reason to change, meaning it should do only one thing. For example, a class that handles user authentication should not also handle logging or sending emails. This way, the code is easier to test, debug, and modify without affecting other functionalities.

// A bad example of SRP violation
class User {
  public:
    // Constructor, getters, setters, etc.
    void authenticate(); // Handles user authentication
    void log(); // Handles logging
    void sendEmail(); // Handles sending emails
};
// A good example of SRP compliance
class User {
  public:
    // Constructor, getters, setters, etc.
};
class Authenticator {
  public:
    void authenticate(User user); // Handles user authentication
};
class Logger {
  public:
    void log(User user); // Handles logging
};
class EmailSender {
  public:
    void sendEmail(User user); // Handles sending emails

};

 

  • Open-Closed Principle: This principle states that a class should be open for extension, but closed for modification. This means that the code should allow adding new features or behaviors without changing the existing ones. For example, a class that calculates the area of different shapes can be extended by adding new subclasses for new shapes, but the original class should not be modified to accommodate them. This way, the code is more flexible and less prone to errors.

// A bad example of OCP violation
class Shape {
  public:
    enum Type {circle, square};
    Type type;
};
class AreaCalculator {
  public:
    double calculateArea(Shape shape) {
      if (shape.type == Shape::circle) {
        // Calculate area of circle
      }
      else if (shape.type == Shape::square) {
        // Calculate area of square
      }
      // What if we want to add more shapes?
    }
};
// A good example of OCP compliance
class Shape {
  public:
    virtual double calculateArea() = 0; // An abstract method
};
class Circle : public Shape {
  public:
    double calculateArea() override {
      // Calculate area of circle
    }
};
class Square : public Shape {
  public:
    double calculateArea() override {
      // Calculate area of square
    }
};
// We can add more subclasses for different shapes without modifying the base class
class AreaCalculator {
  public:
    double calculateArea(Shape shape) {
      return shape.calculateArea(); // Polymorphism
    }
};

  • Liskov Substitution Principle: This principle states that a subclass should be able to replace its superclass without breaking the functionality of the program. This means that the subclass should follow the contract or specification of the superclass and not violate its assumptions or expectations. For example, a class that represents a rectangle should not inherit from a class that represents a square, because a rectangle is not always a square and may have different properties or behaviors. This way, the code is more consistent and reliable.

// A bad example of LSP violation
class Square {
  protected:
    int side;
  public:
    void setSide(int side) {
      this->side = side;
    }
    int getSide() {
      return side;
    }
};
class Rectangle : public Square {
  protected:
    int width;
    int height;
  public:
    void setWidth(int width) {
      this->width = width;
    }
    void setHeight(int height) {
      this->height = height;
    }
    int getWidth() {
      return width;
    }
    int getHeight() {
      return height;
    }
};
void process(Rectangle& r) {
  r.setWidth(5);
  r.setHeight(4);
  assert(r.getWidth() == r.getHeight()); // This will fail if r is a Square object
}
// A good example of LSP compliance
class Shape {
  public:
    virtual int getArea() = 0; // An abstract method
};
class Rectangle : public Shape {
  protected:
    int width;
    int height;
  public:
    void setWidth(int width) {
      this->width = width;
    }
    void setHeight(int height) {
      this->height = height;
    }
    int getWidth() {
      return width;
    }
    int getHeight() {
      return height;
    }
    int getArea() override {
      return width * height;
    }
};
class Square : public Shape {
  protected:
    int side;
  public:
    void setSide(int side) {
      this->side = side;
    }
    int getSide() {
      return side;
    }
     int getArea() override {
      return side * side;
     }
};
void process(Shape& s) {
  // Do something with the shape object
}



  • Interface Segregation Principle: This principle states that a class should not depend on methods or properties that it does not use. This means that the interface or contract of a class should be as small and specific as possible, and not include unnecessary or irrelevant details. For example, a class that implements a printer interface should not have methods for scanning or faxing if it does not support those features. This way, the code is more cohesive and less coupled.

// A bad example of ISP violation

class Printer {
  public:
    virtual void print() = 0;
    virtual void scan() = 0;
    virtual void fax() = 0;
};
class LaserPrinter : public Printer {
  public:
    void print() override {
      // Print using laser
    }
    void scan() override {
      // Scan using laser
    }
    void fax() override {
      // Fax using laser
    }
};
class InkjetPrinter : public Printer {
  public:
    void print() override {
      // Print using ink
    }
    void scan() override {
      // Scan using ink
    }
    void fax() override {
      // Fax using ink
    }
};
class DotMatrixPrinter : public Printer {
  public:
    void print() override {
      // Print using dot matrix
    }
    void scan() override {
      // Do nothing, this printer does not support scanning
    }
    void fax() override {
      // Do nothing, this printer does not support faxing
    }
};

// A good example of ISP compliance

class Printer {
  public:
    virtual void print() = 0;
};
class Scanner {
  public:
    virtual void scan() = 0;
};
class FaxMachine {
  public:
    virtual void fax() = 0;
};
class LaserPrinter : public Printer, public Scanner, public FaxMachine {
  public:
    void print() override {
      // Print using laser
    }
    void scan() override {
      // Scan using laser
    }
    void fax() override {
      // Fax using laser
    }
};
class InkjetPrinter : public Printer, public Scanner, public FaxMachine {
  public:
    void print() override {
      // Print using ink
    }
    void scan() override {
      // Scan using ink
    }
    void fax() override {
      // Fax using ink
    }
};
class DotMatrixPrinter : public Printer {
  public:
     void print() override {
       // Print using dot matrix
     }
};


 

  • Dependency Inversion Principle: This principle states that a class should depend on abstractions, not concretions. This means that the high-level modules or classes should not depend on the low-level ones, but rather on their interfaces or abstract classes. For example, a class that performs some business logic should not depend on a specific database implementation, but rather on an abstract data access layer. This way, the code is more decoupled and easier to change.

// A bad example of DIP violation

class MySQLConnection {
  public:
     void connect();
     void executeQuery();
     // Other methods related to MySQL connection
};

class BusinessLogic {
  private:
     MySQLConnection connection; // A concrete dependency
  public:
     BusinessLogic(MySQLConnection connection) {
       this->connection = connection;
     }
     void doSomeWork() {
       connection.connect();
       connection.executeQuery();
       // Other business logic operations
     }
};

// A good example of DIP compliance

class DatabaseConnection { // An abstract class or interface
  public:
     virtual void connect() = 0;
     virtual void executeQuery() = 0;
     // Other abstract methods related to database connection
};

class MySQLConnection : public DatabaseConnection { 
  public:
     void connect() override {
       // Connect to MySQL database
     }
     void executeQuery() override {
       // Execute query on MySQL database
     }
};

class BusinessLogic {
  private:
     DatabaseConnection connection; // An abstract dependency
  public:
     BusinessLogic(DatabaseConnection connection) { 
       this->connection = connection;
     }
     void doSomeWork() { 
       connection.connect();
       connection.executeQuery();
       // Other business logic operations
     }
};

Wednesday, September 13, 2023

How to install systemd in WSL linux

 Systemd is officially supported in the wsl from windown 11 onwards. Follow this instruction.

What is systemd?

It is one of the first questions that came up to mind when discussing systemd. To find the answer, we have to first know a bit about the sysvinit. If we forget about systemd and the other similar systems, then it’s safe to say that sysvinit is the first process started by the kernel when you boot up any Linux or Unix computer. This means that all the other processes are their child in one way or the other.


Once the system is successfully booted, the sysvinit process continues to run and waits for special commands like ‘shutdown’, which are used to shut down a Linux system. That means now the task of the sysvinit process is to gracefully shutdown the system. For many years, the sysvinit remained a perfect system to bring up and shutdown Linux-based systems. But as time passed by, the system became slow and inflexible, especially for modern-day computers.


So, in 2010 systemd was proposed to replace the widely used sysvinit system. Both systems have their own advantages but at last, it was decided to use systemd in place of sysvinit system.


Follow the instructions from the official website:

Set the systemd flag set in your WSL distro settings:

Open the file: /etc/wsl.conf in vi/vim editor

If the file does not exist, then create it.

vi /etc/wsl.conf


Add these two lines in it:

[boot]

systemd=true


These two lines can be added anywhere in the existing file. Else in the top if creating a new file.

Save the file.


Go to windows powershell with admin mode then below command:

wsl.exe --shutdown

systemd should be working now.