The ‘L’ Principle
Tags: Solid Principles, Software Design, Liskov Substitution, Software Architecture

Meet Barbara

The ‘L’ Principle? Before we get into definitions and theories, let us take a sneak peak of some of our everyday rituals through the eyes of Barbara. Barbara is a working woman living in a gated community. She is passionate about technology and hence applies the same in her day-to-day chores.

Christmas is Coming!

Barbara finds her house to be super messy and plans to book a service from a household service aggregator. She opens her mobile app, CityClap, and makes a booking. While she wraps up the booking, she gets a message from her cousin! Ting… ‘Hi Barbara, Surprise! I am at town. Shall we meet sometime?!’ Barbara, looks at the time and plans for a quick visit. She books a cab in a taxi aggregator app, Ober. Driver details are assigned and she makes a visit to her cousin. She did not like the food outside, and as she returns home she feels hungry. She opens a food aggregator app, Chiggy, and orders food. She settles down and enjoys her food.

Wait! Why is the story of Barbara shared here and how is it relevant to the so called ‘L’ Principle? There is truly a connection. Let us examine each one of them.

Household service

The app’s booking engine aims at assigning a suitable person for cleaning work. The person can either be an experienced + most popular workman (or) an average credit earned workman. Barbara would not interrogate on the person’s experience . She is happy as long as the person services effectively and the home is clean.

Taxi booking system

The booking engine could either allot a driver with own taxi (or) a driver with rental taxi. Barbara is least bothered about the taxi’s ownership. She is satisfied with the service if the driver takes her to the destination hassle free.

Food delivery system

The delivery person at the food delivery system could either be working part time or full time. Barbara is delighted as long as her food is delivered at the right time.

The delivery person assignment system is independent of the type of employee. The portion of the system to the right of dotted line is thus substitutable.

Is the underlying subtle commonality evident? To be precise, the workman in the household service app, the car ownership data in taxi booking system and the delivery person employment data in food delivery system are independent of the booking made in each of the systems. These attributes are substitutable and the system remains unchanged if one of them change. We, as consumers of the services, delegate these choices to be made within the system.

Let’s dive into the principle

This is the underlying concept of a very important principle in software design, the Liskov Substitution Principle (LSP). As per Robert. C. Martin’s definition from the book Clean Architecture,

What is wanted here is something like the following substitution property: If

for each object o1 of type S there is an object o2 of type T such that for all

programs P defined in terms of T, the behavior of P is unchanged when o1 is

substituted for o2 then S is a subtype of T.

In the above examples, what are P, T and S?

Breakdown of P, T and S in Liskov Substitution Principle

For the purpose of understanding the principle better, the following words are best suited in the Object Oriented (OO) world.

Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.

In the breakdown table above, the base class is T and the derived classes are S.

What this principle is NOT!

Let us use one of the examined examples and write code in both ways - one that follows LSP and one that violates.

public interface WorkSchedule {

LocalTime getStartTime();

LocalTime getEndTime();

} public class PartTimeSchedule implements WorkSchedule {



@Override

public LocalTime getStartTime() {

return LocalTime.of(18, 0);

}



@Override

public LocalTime getEndTime() {

return getStartTime().plusHours(5);

}

} public class FullTimeSchedule implements WorkSchedule {



@Override

public LocalTime getStartTime() {

return LocalTime.of(9, 0);

}



@Override

public LocalTime getEndTime() {

return getStartTime().plusHours(10);

}

} class FoodDeliveryPerson {

private WorkSchedule workSchedule;



FoodDeliveryPerson(WorkSchedule workSchedule)

{

this.workSchedule = workSchedule;

}



void printWorkTimings() {

System.out.println("Work timing : " +

workSchedule.getStartTime().toString() + " to " +

workSchedule.getEndTime().toString());

}

A FoodDeliveryPerson can either have a full time or part time work schedule. The program works independently from the type of WorkSchedule injected in FoodDeliveryPerson . This is an example of Liskov Substitution Principle (LSP) applied.

Consider, we have a requirement to capture credits earned by each delivery person. In case of full time employee, extra credits are granted.

class FoodDeliveryPerson {

private WorkSchedule workSchedule;

private int creditsEarned;



FoodDeliveryPerson(WorkSchedule workSchedule, int creditsEarned) {

this.workSchedule = workSchedule;

this.creditsEarned = creditsEarned;

}



void printWorkTimings() {

...

}



int getCreditsEarned() {

if (workSchedule instanceof FullTimeSchedule) {

return creditsEarned + 10;

}

return creditsEarned;

}

}

getCreditsEarned method is an example of LSP violation. The WorkSchedule type injected is no longer a black box for FoodDeliveryPerson , as the method checks for the WorkSchedule type and calculates the credits.

This brings us to the final section - Introduction to this blog.

Introduction to this blog is purposely structured to be the last section. Having understood the practical applications of LSP, we could now relate to why this is important in large systems. Some of the benefits that LSP brings to the table are,

Better delegation of work

Loose coupling

Scalable and extensible system.

Just like a building architect, who is responsible for the structure and the visual appearance of a building, a software architect, owns the structure of the system. How to architect a system effectively? Are there any guidelines or protocols to be followed? Well, this is subjective. However there are quite a few principles that can be embedded in the design to bring out a cleaner architecture. One of them is the L Principle - The Liskov Substitution Principle, which is the third of the SOLID Principles.

Let’s build cleaner systems by employing the right principles at the right places!