Showing posts with label SOLID. Show all posts
Showing posts with label SOLID. Show all posts

Thursday, April 8, 2021

SOLID | Dependency Inversion Principle (DIP)

 The dependency Inversion Principle, it states high level modules should not depend on low level modules. This is introduced by Robert C. Martin. 

Points to remember, 

  • High level and low level modules should depend upon abstractions 
  • and abstraction should not directly be dependent on the details but details should depend upon abstractions
  • Normally we have seen a project structure like
    • Presentation Layer - Business Layer - Data Access Layer (This is highly coupled) 
    • But introducing this principle suggests going with High Level Modules - Abstractions - Low Level Modules (This makes it loosely coupled)
    • So any changes to Low level should not affect directly to high level modules

Example,

will go first with Presentation Layer - Business Layer - Data Access Layer so,

public class BusinessLayer
{
        private DataAccessLayer dataAccessLayer;
        public BusinessLayer()
        {
                dataAccessLayer = new DataAccessLayer();
        }
        public void Save()
        {
                dataAccessLayer.Save();    
        }

public class DataAccessLayer
{
        public void Save()
        {
            //Method implementation
        }
}

Now, following the example, you see it is a strongly coupled and dependent architecture. Any change coming to DataAccessLayer would affect the existing implementation. 

In place, if we introduce another layer like Repository that acts as an abstraction to make this module a decoupled one. 

public class BusinessLayer
{
        //private DataAccessLayer dataAccessLayer;    This is commented to implement the abstraction
        private IRepositoryLayer repositoryLayer;
        public BusinessLayer(IRepositoryLayer repo)
        {
                repositoryLayer = repo;
        }
        public void Save()
        {
                repositoryLayer.Save();    
        }

public class DataAccessLayer : IRepositoryLayer        
{
        public void Save()
        {
            //Method implementation
        }
}

public interface IRepositoryLayer
{
        void Save();
}

Now, this works great to implement the Dependency Inversion Principle, We have inverted the dependency directly to an abstract layer, so both are loosely coupled, and if any change is coming up then it can be easily modified and even this makes unit testing the code more easily. 

In conclusion, as this is the last from SOLID principles, we have come across the basics of it and understanding with real world scenarios and examples. I hope anyone at glance would be able to grasp the foundation of principles. 

Any doubts or suggestions or thoughts are completely welcome, let me know if you want to know more in such simple language and examples. 

SOLID | Interface Segregation Principle (ISP)

Interface Segregation Principle (ISP), states "Clients should not be forced to depend upon interfaces that they do not use"

This is again introduced by Sir Robert D. Martin, while consulting at xerox.

Similar to the 

Single Responsibility Principle the goal of the Interface Segregation Principle is to reduce the side effects of frequent changes in the existing implementation. 

Points to remember,

  • No client needs to be forced to introduce with what is not necessary to them
  • Rather than using one fat interface, splitting into smaller and relevant interfaces are advisable

Case Study from Xerox,

  • Xerox created inhouse software to help printer system do tasks like stapling and faxing along with regular printer task
  • The whole system requires change from scratch up
  • That creates a whole lot of change and complexity

Example,

Below the interface is a one fat consisting of all the methods, now if something needs to introduce the whole implementation requires change and that is risky.

interface IPrint
{
        void Print();
        void Scan();
        void Fax();
}

We have solved this issue by separating SendEmail functionality from other classes to meet the Single Responsibility Principle.

The solution for the above example would,

interface IPrint
{
        void Print();
        void Scan();
}
interface IFax
{
        void Fax();
}

class Printer1: IPrint            //Only has the ability to Print 
{
        public void Print()
        {

        }
        public void Scan()
        {

        }

class Printer2: IPrint, IFax    //Printer ability to Print and Fax both
{
         public void Print()
        {

        }
        public void Scan()
        {

        }
         public void Fax()
        {

        }

We have separated the functionality by breaking it into interfaces rather than a single one. Now in Print1 that has the functionality of Print and Scan but not Fax so implementation, only IPrint interface will meet the goal. Printer2 is all in one so Print, Scan, and Fax functionality so along with IPrint we can have IFax interface to get the functionality of Fax in the same. 

Here we have separated the responsibilities as well as distributed the interface from a big fat to multiple interfaces and achieved a high level of abstraction.

SOLID | Liskov Substitution Principle (LSP)

Liskov Substitution Principle is introduced by Barbara Liskov. It is basically about the parent-child relationship (Inheritance) in Object-Oriented Design. the LSP states that if "When class S is a substitute of class T then an object of type T can be replaced by an object of type S without affecting the functionality of the existing implementation"

Points to remember,

  • Types can be replaced by their subtypes without altering the desirable properties of the program. 
  • It has often been related to a duck test, it says "If it is lookalike a duck, quacks like a duck, but needs batteries - you probably have the wrong abstraction"
  • Derived classes should be able to extend their base classes without altering the original implementation.

Example from previous posts,

public interface IEmployee
{
        void CalculateSalary(Employee employee);
}

public class PermenentEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class ContractEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class TemporaryEmployee: IEmployee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class InternEmployee: IEmployee                                    //InternType with Error
{
         public void CalculateSalary(Employee employee)
        {
            throw new NotImplementedException();                        //Violation of LSP 
        }
}

So here is a good example of the Open Closed Principle, but if we are talking about the Liskov then we are breaking our goal here. For example what if a new requirement suggests a new Employee type without the CalculateSalary method. Say we have an Intern type to be added in. Class InternEmployee needs to throw an exception as it does not have to do anything with that method. 

Modified example with Liskov Substitution Principle,

public abstract class Employee                                                    //Abstract class 
{
        public virtual void CalculateSalary(Employee employee)
        {
          
        }
}

public class PermenentEmployee: Employee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class ContractEmployee: Employee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}
public class TemporaryEmployee: Employee
{
         public void CalculateSalary(Employee employee)
        {
              //Salary calculation and print the same
        }
}

public class InternEmployee: Employee
{
         //public void CalculateSalary(Employee employee)        //Not required to implement the same.
}

This is the example can have much more use of object oriented programming and I am stretching the same with other design patterns going forward in further posts. I will be explaining the alternative for Virtual method in base class. 

Happy learning!

Monday, April 5, 2021

SOLID Design Principles

SOLID Design Principles

SOLID is an acronym for design principles, let's look at it
SOLID principles are a time-tested solution for software design problems. This principle helps to achieve loosely coupled code design.

Common problems in software architecture?

  • A poor architecture will develop bugs over time
  • the application requires to be altered for all the customization and future extensions
  • Once the application is ready and in production, over time it takes a lot of effort even for a simple task
  • Creating a single class with a lot of responsibility
  • Unnecessary dependency between classes
  • Redundant code

Why we should use SOLID design principles?

  • SOLID principles help to solve above listed common problems
  • Provides loosely coupled architecture
  • Classes can have their specific responsibility 
  • Rather than extending the one class using inheritance and abstraction, we can achieve the reusable environment
  • It stops affecting the existing functionality
  • It allows focusing more on abstraction 
We will go into detail in each dedicated post. Let me know if you have any suggestions or feedback.

C# Interview Prep: 100 Common Questions for 0-3 Years Experience

Common C# Interview Questions  Basics of C# Language: What is C#? C# (pronounced C sharp) is a modern, object-oriented programming language...