DEV Community

Cover image for SOLID, KISS, YAGNI and DRY Principles
Nguyen Khac Nghiem
Nguyen Khac Nghiem

Posted on

SOLID, KISS, YAGNI and DRY Principles

SOLID

This principle was given by Robert C. Martin and Michael Feathers to encourage us to create more maintainable, understandable, and flexible software. Including 5 sub-principles:

  • Single responsibility principle (SRP)
  • Open/Closed principle (OCP)
  • Liskov substitution principle (LSP)
  • Interface segregation principle (ISP)
  • Dependency inversion principle (DIP)

Single Responsibility Principle - SRP

This principle stipulates that each Class should have a single responsibility.
SRP

If a Class has many responsibilities, making changes to one of its responsibilities can affect the other ones.

❌ Violating SRP:



public class Animal {
    public void catSays() {
        System.out.println("I am a cat.");
    }

    public void lionSays() {
        System.out.println("I am a lion.");
    }

    public void hippoSays() {
        System.out.println("I am a hippo.");
    }
}


Enter fullscreen mode Exit fullscreen mode

✔️ Following SRP:



public abstract class Animal {
    public abstract void makeSound();
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("I am a cat.");
    }
}

public class Lion extends Animal {
    @Override
    public void makeSound() {
        System.out.println("I am a lion.");
    }
}

public class Hippo extends Animal {
    @Override
    public void makeSound() {
        System.out.println("I am a hippo.");
    }
}


Enter fullscreen mode Exit fullscreen mode

Open/Closed Principle - OCP

This principle stipulates that if there is a new function, you should not modify or add to the existing class, but should write another class that extends the existing class.

OCP

Class should be open for extension but closed for modification.

❌ Violating OCP:



public class Animal {
    private String type;

    public Animal(String type) {
        this.type = type;
    }

    public void draw() {
        if (type.equalsIgnoreCase("cat")) {
            System.out.println("Drawing a cat");
        } else if (type.equalsIgnoreCase("lion")) {
            System.out.println("Drawing a lion");
        }
        // More animals can be added here, violating OCP
    }
}


Enter fullscreen mode Exit fullscreen mode

✔️ Following OCP:



public abstract class Animal {
    public abstract void draw();
}

public class Cat extends Animal {
    @Override
    public void draw() {
        System.out.println("Drawing a cat");
    }
}

public class Lion extends Animal {
    @Override
    public void draw() {
        System.out.println("Drawing a lion");
    }
}

// You can add more animal classes without modifying existing code


Enter fullscreen mode Exit fullscreen mode

Liskov Substitution Principle - LSP

This principle stipulates that subclasses that inherit from a parent class can replace the parent class without affecting the correctness of the program.

LSP

The child Class should be able to process the same requests and deliver the same result as the parent Class or it could deliver a result that is of the same type.

❌ Violating LSP:



public class Animal
{
    public void run()
    {
        System.out.println("Run...");
    }

    public void fly()
    {
        System.out.println("Fly...");
    }
}

public class Bird extends Animal
{
    // Bird can fly and run...
}

public class Cat extends Animal
{
    // Cat can't fly...
}


Enter fullscreen mode Exit fullscreen mode

✔️ Following LSP:



public interface Flyable {
    public void fly();
}

public class Animal
{
    public void run()
    {
        System.out.println("Run...");
    }
}

public class Bird extends Animal implements Flyable
{
    @Override
    public void fly()
    {
        System.out.println("Fly...");
    }
}

public class Cat extends Animal
{

}


Enter fullscreen mode Exit fullscreen mode

Interface Segregation Principle - ISP

This principle stipulates that an interface should not have too many methods that need to be implemented. If an interface is too large, it should be split into many smaller interfaces that handle separate functions.

ISP

No code should be forced to depend on methods it does not use. A Class should perform only actions that are needed to fulfill its role.

❌ Violating ISP:



interface Animal {
    List<Animal> getAll();
    get(String id);
    save(Animal animal);
    update(String id, Animal animal);
    delete(String id);
    getAllWithPaginate(int page, int size);
    getAllWithSort(String sortCriteria);
    /* ... */
}


Enter fullscreen mode Exit fullscreen mode

✔️ Following ISP:



interface CrudAnimal {
    List<Animal> getAll();
    get(String id);
    save(Animal animal);
    update(String id, Animal animal);
    delete(String id);
}

interface PagingAndSortingAnimal {
    getAllWithPaginate(int page, int size);
    getAllWithSort(String sortCriteria);
}


Enter fullscreen mode Exit fullscreen mode

Dependency Inversion Principle - DIP

This principle stipulates:

  1. High-level modules should not depend on low-level modules. Both should depend on abstractions.
  2. Abstractions should not depend upon details. Details should depend upon abstractions.

DIP

The essence of this principle is to avoid dependence on modules, specific components that are easy to change during the coding process. Instead, it should depend on abstract components because these components are less likely to change. The way to apply and implement this principle is to have high-level modules define interfaces, then low-level modules will implement those interfaces.

❌ Violating DIP:



// Abstraction
interface Animal {
    void makeSound();
}

// Low-level Module
class Cat implements Animal {
    @Override
    public void makeSound() {
        System.out.println("I am a cat");
    }
}

// Low-level Module
class Lion implements Animal {
    @Override
    public void makeSound() {
        System.out.println("I am a lion");
    }
}

// Low-level Module
class Hippo implements Animal {
    @Override
    public void makeSound() {
        System.out.println("I am a hippo");
    }
}

// High-level Module
class AnimalFactory {
    // High-level modules depend on low-level modules
    private final Cat animal;

    public AnimalFactory() {
        this.animal = new Cat();
        this.animal.makeSound();
    }

    public Cat getAnimal() {
        return this.animal;
    }
}

public class Main {
    public static void main(String[] args) {
        AnimalFactory factory = new AnimalFactory();
    }
}


Enter fullscreen mode Exit fullscreen mode

✔️ Following DIP:



// Abstraction
interface Animal {
void makeSound();
}

// Low-level Module
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("I am a cat");
}
}

// Low-level Module
class Lion implements Animal {
@Override
public void makeSound() {
System.out.println("I am a lion");
}
}

// Low-level Module
class Hippo implements Animal {
@Override
public void makeSound() {
System.out.println("I am a hippo");
}
}

// High-level Module
class AnimalFactory {
// High-level modules depend on abstractions
private final Animal animal;

public AnimalFactory(Animal animal) {
    this.animal = animal;
    this.animal.makeSound();
}

public Animal getAnimal() {
    return this.animal;
}
Enter fullscreen mode Exit fullscreen mode

}

public class Main {
public static void main(String[] args) {
Animal animal = new Cat();
AnimalFactory factory = new AnimalFactory(animal);
}
}

Enter fullscreen mode Exit fullscreen mode




Keep It Simple, Stupid - KISS

This principle was given by Kelly Johnson with the meaning of emphasizing the importance of simplicity in coding. The simpler the code, the faster the ability to read and understand that code, the simpler it is, the easier it is to maintain and change in the future, this will help save a lot of time.

The ways to approach KISS:

  • Do not abuse design patterns or libraries if not necessary.
  • Divide big problems into smaller problems to handle.
  • Name variables and methods clearly.

You Aren't Gonna Need It - YAGNI

This principle was coined by Kent Beck. It focuses on not complicating a requirement with future assumptions. In other words, don't assume and build the functionality of software before you need to use it.

Don't Repeat Yourself - DRY

DRY is a familiar and core principle in the programming industry that emphasizes reusing code as much as possible. Principles were formulated by Andrew Hunt and David Thomas.

This principle makes parts of the code less repetitive, making it easier and faster to change code segments.

To approach this principle, whenever there is a piece of code that is used twice in different places, you should repackage that piece of code (create functions, create classes, ...) so that it can be called later.

Reference

  1. SOLID Principles
  2. The Principles of Clean Code: DRY, KISS, and YAGNI

Top comments (14)

Collapse
 
alexmario74 profile image
Mario Santini • Edited

About the DRY principle, I think you put it in a too simplistic way. Actually DRY is not about code repetition, the principle rather refers on information, and knowledge in the system.
When you find duplicated code in your system, you should check if all the different part with that code are actually working on the same piece of information.
In that case you can try to find an abstraction, and you can refactor your code base in a way that this logic is placed in one place and just used where it is needed, getting rid of the duplicated code.
If the code is the same, but is working on differen business entities, you may better to leave it duplicated, as it may will diverge in the future.
If you change it and then you have to implement a new requirement that change the behaviour in one place, but not in the other, then you are forced to introduce complexity to handle the feature.

Collapse
 
nknghiem profile image
Nguyen Khac Nghiem

Thanks for your feedbacks!

Collapse
 
__junaidshah profile image
Junaid

Great share and welcome to dev.

Collapse
 
nknghiem profile image
Nguyen Khac Nghiem

Thank you so much!!!

Collapse
 
aatmaj profile image
Aatmaj

Nicely explained. The examples make it clear to understand👍🏻

Collapse
 
nknghiem profile image
Nguyen Khac Nghiem

Thank you so much!!!

Collapse
 
bogomil profile image
Bogomil Shopov - Бого

Useful! Thanks!

Collapse
 
nknghiem profile image
Nguyen Khac Nghiem

You're welcome.

Collapse
 
shoptinhyeuvn profile image
Shop tình yêu shoptinhyeu.vn

Excellent. You're really good.

Collapse
 
nknghiem profile image
Nguyen Khac Nghiem

You are too kind.

Collapse
 
__masashi__ profile image
Masashi

Amazing post. Keep it up buddy!

Collapse
 
nknghiem profile image
Nguyen Khac Nghiem

Thank you so much!!!

Collapse
 
dolphin profile image
Olavi Jokela

I have learned so much. Thanks.

Collapse
 
asyncnavi profile image
Navraj Sandhu

Amazing 💝