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

31 October 2015

interface segregation principle

Interface segregation principle is one of the SOLID design principles. It stands for letter "I" in the "SOLID" acronym.

It states that Interface shouldn't be combined together which could lead to the fat interface, instead interfaces should be segregated or separated based on their real-world meaning closeness. If a behavior of a real-world object can exist as a separate entity in real world, consider defining an interface just alone for that set of behaviors.

Let’s consider an example to explain Interface Segregation Principle

Assume you are developing a vehicle which flies in the air, runs on water and run in the road. Then probably your interface looks like below:

interface IHybridVehicle
{
 void RunOnRoad();
 void Fly();
 Void RunOnWater();
}

Then any class implementing the IHybridVehicle will implement all the methods.

public class HyBridVehicle : IHyBridVehicle
{
  // Implementation for IHyBridVehicle methods
}

The problem with the above single fat interface approach:

When you have Hybrid Vehicle instance with you and just need the ability to run them on the road, even then you still end up having reference to an instance of IHyBridVehicle type. This happens because the current design is lacking an interface catering to each independent capability of the hybrid vehicle you are building.

The disadvantage of this fat interface design is that, when you want to remove /add/update methods/ behaviors, you have to consider the regression effort of the places wherever you got a reference to IHybridVehicle Interface. Definitely, such an effort will be huge because wherever you just need flying, traveling on road or sailing on water, you would have referred the single, big, fat interface IHybridVehicle.

Solving the problems having with fat Interface by using Interface Segregation Principle

Let’s separate the methods in IHybridVehicle to each interface whose implementation can have real-world independent existence and this time lets IHybridVehicle interface inherit from 3 interfaces.

interface IRoadVehicle
{
 void RunonRoad();
}

interface IWaterVehicle
{
 void FloatonWater();


interface ISkyVehicle
{
 void FlyinSky();
}
interface IHybridVehicle: IRoadVehicle, IWaterVehicle, ISkyVehicle
{
}

Advantage of applying Interface segregation principle:

  1. Now, if u want to just refer to just the ability of vehicle instance which runs on road, use it as IRoadVehicle, no need to refer to the big fat interface all over the places.
  2. And whenever you want IHybridVehicle as whole you can still do.

Hope you understood interface segregation principle. As always your comments are welcome!

02 October 2015

single responsibility principle

SOLID principles play an important role in designing your classes during low-level design. Last time we discussed about DRY principle, this time let's discuss on SRP principle (Single Responsibility Principle). Single Responsibility Principle is one of the SOLID design principles. It stands for letter "S" in the "SOLID" acronym.

What is SRP principle

The single responsibility principle states that, a class, a method, etc should have only one responsibility OR should be doing only one thing. In essence a class or method should have only one reason to change.

Let's consider an example:

Class not following SRP

public class EmailSender
{
  public void SendEmail(string customerID, 
                       string emailNotificationType)
  {
    //STEP1: load customer details
    //STEP2: get email content
    //STEP3: send email (using SmtpClient class)
  }

  public string GetEmailContent(Customer customer, 
                 string emailNotificationType)
   {
    // Build the email notification content
   }
}

If you look at EmailSender class, it is doing three things in it:

  1. Loading customer details from database, which is REPOSITORY responsibility.
  2. Building the content of the email to be send, its not a responsibility of email sender class.
  3. Sending email. Ideally sending email should only be the sole responsibility of the email sender class.

OK, but what is the problem with above class design?. EmailSender class is working as expected!

Problems with not following SRP

The EmailSender class can go under changes because any of the below reasons:

  1. Changes in the way, you are loading customer details.
  2. Changes to the email content because of requirement enhancements / changes.
  3. If there any change in the way you are sending the email instead of using SmtpClient class or something like that.

So in essence, the EmailSender class will have to undergo changes if any the above three changes, which leads to regression efforts which are going to involve the other two responsibilities as well.

Code re-factoring using SRP

  • Create a separate class to load the Customer details.
  • Create a separate class to build the email content.
  • With that, the EmailSender will have only one responsibility, i.e. just deal with sending email out.
public class CustomerRespository
{
  public Customer GetCustomer(string id)
  {
    // logic load customer from Database
  }
}
public class EmailContentBuilder
{
  public string getEmailContent
               (Customer customerDetails)
  {
    // logic to build email content
  }
}
public class EmailSender
{
 public void SendEmail(string emailaddress, 
            string subject, string bodycontent)
  {
    //logic to send email out
  }
}

Advantages of following SRP

If they are any changes to the above three class, then only that class will have code changes and the testing efforts just isolated to that class alone.

Which means you don't need to worry about regressing other two class responsibility, as they have not undergone any code changes. So single responsibility principle leads to better class design to ensure less regression effort in case of a class responsibility/functionality changes.

Hope you got the gist of single responsibility principle. As always your comments are welcome!

02 December 2012

DRY (Do not repeat yourself) design principle

As a software developer when we are working on a project, the natural tendency is to Create logic whenever and wherever we want. i.e. we duplicate the same code all across the project.

The disadvantage of repeating the same code is maintenance overhead in terms unit testing the code, defects fixing, etc. and also not but not least, the size of the code base grows bigger!!!, which we don’t want.

So, don't repeat the same code. That is what DRY principle says.

DRY principle article with an example:


Problem statement:

In one of the windows application project we had a requirement to put the cursor to the next/previous control On the form with the Down arrow/up arrow keys. This was got assigned to a naive developer. This windows application project was being developed on .NET 3.5; to achieve this behavior we had to write code for this.

The naive developer started coding. He got the required functionality of changing the control focus with the Down/up arrow keys but only for the single form. He had spent a day of effort for the same. The windows form application had over 30 forms. So he might need another 30 days to achieve the functionality across All the forms in the windows application.

Definitely that is not acceptable.

Solution by using the DRY principle:

Here the behavior expected is the same for all the 30 forms in the windows application project. Can we not move create a code which a single place and which will be applicable in all the places?

Yes. Definitely, we can do that. Let's see how DRY principle helps:

  1. By making use of the inheritance we can achieve this. Create a class which derives from the System.Windows.Forms.Form Class
  2. Move all the code for achieving the desired functionality into it. And derive all the 30 forms in the app from the base class.

Here by following DRY principle helps to reduce the time required to get the functionality and future changes will be applicable to all the forms by making changes in just one place. So don't duplicate the code in your project. Always try to write a code in a reusable manner, so that it can be applied in different places.

If you are adding new code, check you are not violating DRY principle:

  • The new code does not already exist anywhere in the project. If exists, reuse it.
  • If the new code does not already exist, make sure you write it in a reusable manner.
  • 06 May 2012

    Why Inversion of control is called so?

    In most of the interviews this is the question one asks and most of us don’t know what is the straight answer to this question.

    Not just from the interview perspective, it necessary to know why IOC (Inversion of control) is called so. Let’s start without much ado:

    Whenever we start thinking of any application we do follow in the lines of high-level modules and low-level modules. High-level modules depend on low-level modules to get of functionality. That's how its start is not?

    Yeah, that's good design, because it has some kind of modularity because each low-level component shall provide some specific functionality.

    But the issue is high-level modules is directly dependent on the low-level modules. So there is tight coupling, hence we cannot easily replace low-level module if we wish to use some other module which provides the same functionality. It’s not flexible design.

    So point here is, high level module depends on low level module.

    Now how can we bring flexibility into the system?

    Let’s introduce a layer of abstraction in between the high-level modules and low-level modules; such that high modules depend on the abstraction and whereas low-level modules implement functionality as per the abstraction.

    So point here is, high-level modules no longer depend on the low-level modules (which now providing the implementation) instead they just depend on the abstraction.

    That means to say that, whenever we need to replace the lower level component with the other component which implements the given abstraction, it doesn't involve much change (minor changes in configuration file in well-designed application) and hence system becomes flexible.

    But still not clear as, why it’s called Inversion of Control. Is not?

    Yes that right. Still, low-level components are not depending on high-level components instead they follow the abstraction to implement the functionality.

    Now let’s make this abstraction is owned by high-level modules. It’s also making sense they are the ones which use implementation (low-level modules) as per the required abstraction. So abstraction is dictated by the high-level modules as they own them.

    So with this approach of designing, high-level modules no longer depend on the low-level modules. Instead, low-level modules depends on high-level modules.

    So the point here is, dependency has been inverted and hence the name, Inversion of Control (IOC).

    This way lLow-level modules depends on high-level modules making the system flexible.

    Ref: More on Inversion of control on wikipedia.