Solid Dry Kiss Yagni

17 Jul 2020 ⏱️ 8 min
Solid Dry Kiss Yagni

Confused? Well, this is no where related to actual real life kiss 😂

“Solid, DRY, KISS. YAGNI” are few of the software engineering principles we will be discussing today.

Preparing for Interviews? I highly recommend Mastering System Design course on Educative.

Why should I learn these?

These principles are set of guidelines which help you write better, robust and clean code. Once, you start applying them, you’ll start seeing the results on the overall process of developing products. Here are some advantages which will be visible in your code -

  • Robustness
  • Efficiency
  • Clean Code
  • Delivering high quality softwares
  • Flexible, Easy to refactor

Writing code is easy but writing good and quality code is hard

In this post, I’ll be introducing a few I have learnt in my past year of professional software development career.


  • KISS
  • DRY
  • Tell, Don’t Ask!

Simplicity is prerequisite for reliability. — Edsger Dijkstra


KISS is an acronym for “Keep It Simple Stupid” This principle literally means to keep your code as simple code as possible.

You might think - “But, I always keep it simple only !?”

Well, that is not the case with a lot of engineers. You start with something basic but soon add unwanted complexity as the code grows.

Engineers like to complicate things!

The simpler the code, the easier it is to understand and maintain it.

A very basic example of this would be adding a complex sort function when simple library sort would cater your need! Don’t optimize unless there is an requirement.

Another common violation of KISS is using a new framework or adding a new npm module in your code which can be easily avoided. Eg. There is a npm package to convert string to camel case. Think, do you actually need this or a simple function would solve your task?

As soon as you add a new dependency, you are basically increasing the overall code complexity which will be problamatic in future.

Key to following this principle is learn to break your problem into as simple and small steps as possible, then write minimal code to implement them.


DRY stands for “Don’t Repeat Yourself”

This principle focuses on applying reusuability and reducing repitition in code. This implies you should not require a change in logically unrelated components on changing a certain single element.

When you reuse components you basically are reducing code to be written. Less code results in better maintainibility!

As an engineer, Automate and Reuse whenever you can!

Most common example of these are functions! A general rule is if you are writing same logic more than thrice, it’s time to refactor the logic to a function and reuse!

Database normalization is one of the methods to reduce redundancy of data by eliminating columns. This is an example of DRY!


YAGNI is an acronym for “You aren’t gonna need it”

This principle states that you should not optimize and increase complexity thinking about future.

Do what is required now. Don’t optimize prematurely!

Also, you don’t know what new cases may arise ahead! Why waste additional time and effort on something which is not actually required! Although, you should design your systems in a way that minimal changes are required for a future predictable change.

It syncs with KISS principle on avoiding any additional complexity.

A simple example would be not not use databases when simple file system can work!


This principle in acronym of acronyms 😛

  • SRP - Single Responsibility Principle
  • OCP - Open Closed Principle
  • LSP - Liskov Substitution Principle
  • ISP - Interface Segregation Principle
  • DIP - Dependency Inversion Principle

Single Responsibility

Definition from Wikipedia is quite clear -

Every module or class should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class

Each method or class should be bounded to some functionality. It should not do anything less or more. There should be only a single reason for it to change!

Example - Login package should deal with the user login code, It should not deal with user signup.

func showPosts(listOfPost []string) {
 sort.Strings(strs) // Basically any code dealing with sorting
 for _, post := range listOfPost {

The above code violates SRP, because there are reasons to change showPosts() if our sorting logic changes. Correct way would be to call sort function and then pass sorted list to this method.

func showPosts(listOfPost []string) {
 for _, post := range listOfPost {

// In some other function
listOfPost := []string{ "post1", "post2"} // Some array list
// sort the list
// show the list

Now, the showPosts only changes when we want to show additional info about post. (Single reason to change)

Open/Closed Principle

Once you have written a piece of code and then some new features comes, now you have to go back to old code and change it again! Open/Closed principle exactly deals with this!

Write code in a way so that your classes/methods are -

Open for extension, but closed for modification

Liskov Substitution Principle

LSP advocates that the objects of your subclass should behave in the same way as the objects of your superclass.

class Vehicle
   double speed;
   double getSpeed() { ... }
   void setSpeed(double d) { ... }

   Engine engine;
   Engine getEngine() { ... }
   void setEngine(Engine e) { ... }

   void startEngine() { ... }

class Car extends Vehicle
   void startEngine() {
    // start the car engine

class Bicycle extends Vehicle
   void startEngine() {
    // throw error - Bicycle has no engine

In the above example Car and Bicycle both extend the Vehicle class. This fails LSP because the Bicycle object cannot replace Vehicle since its startEngine() will return an error!

Interface Segregation Principle

Clients should not be forced to depend upon interfaces that they do not use. - Robert C. Martin

This implies you should keep your interfaces as small as possible. Don’t pollute your interfaces with methods that are not required.

interface Animals {
    public void eat();
    public void fly();
    public void swim();

class Dogs implements Animals {
    public void fly() {
       // Throws error - dogs cannot fly
    public void swim() {
    // Throws error - dogs cannot swim
    public void eat() {
      System.out.println("Dogs eat!");

In this case, our interface is polluted with methods like swim and fly which doesn’t apply to Dog class. We can fix this by breaking our interace into multiple interfaces like AnimalsWhoSwim and AnimalsWhoFly. Animals interface can contain function eat()

Dependency Inversion Principle

DIP basically suggests that the high level modules should not depend on low level modules, rather both should depend on abstractions. It implies you should use interfaces instead of concrete implementations wherever possible.

There is a good example on this, will guide you there in case you want to understand it better.

Tell, Don’t Ask

Tell, don’t ask principle suggests to avoid asking object about their state, rather tell them what to do based on decision i.e tell the object what to do!


// isLoggedIn returns true/false
if user.isLoggedIn() {  // Asking whether user is logged in
} else {

Here, we are asking whether the user is logged in or not, and then asking for profile. We wanted to get the profile, we just tell the object to show us thr profile, the login check should be internally implemented in showProfile() itself. The correct way should be -

user.showProfile() // Tell!


Do try and follow the principles you read here because -

You cannot swim without getting wet ― Vusi JCK Maseko

Show other useful principles you follow in comments 👇

Liked the article? Consider supporting me ☕️

I hope you learned something new. Feel free to suggest improvements ✔️

I share regular updates and resources on Twitter. Let’s connect!

Keep exploring 🔎 Keep learning 🚀

Liked the content? Do support :)

Paypal - Mohit Khare
Buy me a coffee