SOLID : Liskov Substitution Principle (Part 1)

The “L” in SOLID stands for Liskov Substitution Principle, named after Barbara Liskov, who initially introduced in 1987 keynote address. LSP provides guidelines for creating inheritence heirachy where a client can use any class or subclass without breaking the expected behavior.

We will begin by looking at the official definition first.

If S is a subtype of T, then objects of type T may be replaced with objects of type S,without breaking the program.

It would be unwise to explain this theoratically, hence like always, let hit the Visual Studio and write some code. I would like borrow an example given by Tim Correy in his famous video.

Assume we have an Employee class defined as follows.

public class Employee
{
public string Name{get;set;}
public Employee AssignedManager{get;protected set;}
public virtual double GetPay()
{
var currentSalary = 500;
Console.WriteLine($"Current Pay {currentSalary}");
return currentSalary;
}

public virtual void AssignManager(Employee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}
}

Now let’s assume we have a Manager class, which inherits from Employee

public class Manager:Employee
{
public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine($"Current Pay {currentSalary}");
return currentSalary;
}

public override void AssignManager(Employee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}
}

Let’s write some client code now which consumes these classes.

var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Employee();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

Output

Current Pay 750
Current Pay 500
Manager Assigned

As you can observe, the output is perfectly fine. Let us try making some changes to the Client Code now. Let us replace the Employee class (programmer instance) with Manager.

var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Manager();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

Output

Current Pay 750
Current Pay 750
Manager Assigned

This has turned out fine as well. Yes the output is different, which is expected considering the Pay for Manager and Employee are different, but the client hasn’t behaved unexpectedly. Let’s write one more class, inheriting from Employee and call it CEO.

public class CEO:Employee
{
public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine($"Current Pay {currentSalary}");
return currentSalary;
}

public override void AssignManager(Employee manager)
{
throw new Exception("Am the CEO, no Manager for me !!");
}
}

The difference this time is of course the CEO doesn’t have a Manager and it raises an exception in the AssignManager method. Let’s head back to out Client code and replace Employee with CEO in our original code.

var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new CEO();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

Output

Exception:Am the CEO, no Manager for me !!

Aha, we have an exception here. When replaced the Employee (Base type) with a subtype (CEO), the expected behavior of program has been broken. This is a violation of LSP.

Let’s examine the violation further. It is often said that Inheritence is the IS-A relation. However, if you truely examine CEO and Employee, do they follow a IS-A relation in every sense ? Not really, not according the current definition of Employee. Yes, that is right. The problem doesn’t quite lie in CEO, but it originate from the definition of Employee class. While designing the Employee class, we “assumed” that all Employees would have a manager.

So what is the best solution for this scenario ? What if we were to ensure the Employee class had only those functionalities which are common to every employee ? Obviously, the Manager is not applicable for everyone, so let’s remove it and create an interface which contains only the basic employee functionalities.

public interface IBaseEmployee
{
string Name{get;set;}
double GetPay();
}

public abstract class BaseEmployee:IBaseEmployee
{
public string Name{get;set;}
public virtual double GetPay(){ return 0;}
}

Remember, we still have to consider the Manager assignment. What we would do here is define another interface IHasManager, which would wrap the functionalities required for Employees who has Manager.

public interface IHasManager
{
IBaseEmployee AssignedManager{get;set;}
void AssignManager(IBaseEmployee manager);
}

Let’s now define our Employee and Manager classes.

public class Employee:BaseEmployee,IHasManager
{
public IBaseEmployee AssignedManager{get; set;}
public override double GetPay()
{
var currentSalary = 500;
Console.WriteLine($"Current Pay {currentSalary}");
return currentSalary;
}

public virtual void AssignManager(IBaseEmployee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}

}

public class Manager:BaseEmployee,IHasManager
{
public IBaseEmployee AssignedManager{get; set;}
public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine($"Current Pay {currentSalary}");
return currentSalary;
}

public void AssignManager(IBaseEmployee manager)
{
Console.WriteLine("Manager Assigned");
AssignedManager = manager;
}
}

As you can see, the Manager and Employee inherits from BaseEmployee and implements the IHasManager interface. The next step is to define our CEO Class, and this time, we know that he doesn’t need a Manager.

public class CEO:BaseEmployee
{

public override double GetPay()
{
var currentSalary = 750;
Console.WriteLine($"Current Pay {currentSalary}");
return currentSalary;
}

}

That’s it. Let’s rewrite our Client code now.

var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Employee();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

The above code compiles and executes as expected. Let’s replace the Employee with a Manager first.

var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new Manager();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

That works fine as well. Let’s try again, and this time replace with CEO.

var manager = new Manager();
manager.Name = "John Doe";
manager.GetPay();

var programmer = new CEO();
programmer.Name = "Roel Doel";
programmer.GetPay();
programmer.AssignManager(manager);

Not surprisingly, that doesn’t compile at all. CEO doesn’t have the AssignManager method as it doesn’t implement the IHasManager interface. Your client no longer have unexpected behavior as such errors are caught during compilation.

That was pretty easy, isn’t it ? But we are not done yet. There is more to the definition of LSP. In the next part of this series, we will examine the Contact and Variance rules which must be followed for LSP compliance.

GOF: Composite Pattern

Composite Pattern, in a way, literally takes of from where Decorator Pattern ends. One might be inclined to think of it as a specialized case of Decorator Pattern which composes one or more instances of similiar objects and manipulate them uniformly. This allows the client to work on a single entity or composition of entity uniformily, or in other words, it eliminates the need of programmers to discriminate between leaf and branch, and thereby avoid writing specific logic to handle both scenarios.

The key components of Composite Pattern can be defined as follows

Component
Components defines the interface that specifies the behavior that needs to be uniformly executed by primitive object or composite object.

Leaf
The non-decomposible leaf object, which defines the behavior for the primitive object

Composite
Holds the collection of Child components, and implements the behavior of components that have children.

That would be enough of theory, let’s write some code now. For the sake of example, we will write a little program that would print the size of given File/Directory. Let’s begin by defining the Component interface.

public interface IMetaInfo
{
double GetSize();
}

The next step would be define the behavior of the primitive object, which in this case would be the File.

public class FileObject : IMetaInfo
{
private string _fileName;
public FileObject(string fileName)
{
_fileName = fileName;
}
public double GetSize()
{
Console.WriteLine($"Calculating size of {_fileName}");
return 0;
}
}

As one can understand, the actual behavior is different for File and Directory. The size of Directory needs to be cumiliative size of all the individual Files in it. Let’s define the behavior for Directory Class now.

public class DirectoryObject : IMetaInfo
{
private string _directoryName;
private List<IMetaInfo> _fileCollection;
public DirectoryObject(string directoryName)
{
_directoryName = directoryName;
_fileCollection = new List<IMetaInfo>();
}

public void Add(IMetaInfo file)
{
_fileCollection.Add(file);
}

public void Remove(IMetaInfo file)
{
_fileCollection.Remove(file);
}
public double GetSize()
{
var directorySize = 0d;
foreach (var file in _fileCollection)
{
directorySize += file.GetSize();
}
return directorySize;
}
}

As one could see in the example code, the Directory Structure uses the bahavior of the individual File Structure to calculate the cumiliative Size. Let’s write the code for Client now and see how client can work without having the knowledge of what exactly it is dealing with.

class Client
{
static void Main(string[] args)
{
Console.WriteLine("When using Composite Object");
var directoryInstance = new DirectoryObject("BaseDirectyory");
for(var i = 0; i < 10; i++)
{
directoryInstance.Add(new FileObject($"{i.ToString()}_File"));
}

GetSize(directoryInstance);

Console.WriteLine("When using Component Object");
var fileInstance = new FileObject("Another File Instance");
GetSize(fileInstance);
Console.ReadLine();
}

private static void GetSize(IMetaInfo instance)
{
instance.GetSize();
}
}

The Client.GetSize() method accepts an instance of IMetaInfo as the parameter. It doesn’t really know whether it is actually dealing with a Composite object or a Primitive one.

The Composite pattern is a highly useful pattern when one needs to deal with a irregular structure of objects and composite of objects, enabling the client to deal with them uniformly.

The entire source code shown in this example are available in my GitHub.

Law Of Demeter

If you ask any Software Developer, he would vouch that separation of concerns is the fundamental principles for maintaining any complex system and one of the vital links for achieving Separation of Concerns is decoupling.

Law of Demeter (LoD), also known as Principle of least knowledge, intends to reduce coupling between objects as proposed by Ian Holland.

Definition

The original version is outlined as follows.

Each unit should have only limited knowledge about other units: only units “closely” related to the current unit. Or: Each unit should only talk to its friends; Don’t talk to strangers.

The gist of the definition lies in the simple fact that the class should speak only to objects that it directly knows, or in other words, do not talk to strangers.

Let’s examine a real life scenario. You are out to stroll with your favourite pet. You do not order your pet’s legs to walk. Instead, you order your pet, which inturns commands its legs to move.

If we were to examine the rule from the perspective of an Object Oriented Programming Language,

A Method M, of an Object of Type C, may only call methods of
a) Class C
b) Parameters of method M
c) Instance variables of C
d) Objects created by M
e) Global Variables

Let’s write some code to replicate the Pet Scenario we discussed earlier.

public class Owner:IHuman,IHasPet
{
public string Name{get;set;}
public Pet Pet{get;set;}
public void MovePet()
{
Pet.GetLegs().Move();
}
}

public class Pet
{
private Legs _legs;
public Legs GetLegs ( )=>_legs;
}

public class Legs
{
public void Move()
{

}
}

As observed, the Owner Class uses instance of Pet to retrieve instance of Legs, and then request them to move.But, there is no reason the owner needs to be have access or knowledge of the legs or how the Pet commands the legs to move. This is the responsibility of the Pet class and should not be exposed the owner class.

In the above scenario, the Owner class has knowledge of something, which it doesn’t instantiate or should knowledge of and is a clear violation of Law of Demeter.

We can rewrite the classes to overcome the problem.

public class Owner:IHuman,IHasPets
{
public string Name{get;set;}
public Pet Pet{get;set;}
public void MovePet()
{
Pets.Move();
}
}

public class Pet
{
private Legs _legs;
public void Move()
{
_legs.Move();
}
}

In fact, if you look back at Gang Of Four patterns, many of the patterns discretely follows the Law Of Demeter.

A Word of Caution.

While the benefits of following the rule is evident, one also needs to be beware of focusing way too much on adherence to the rule, rather than fulfilling the purpose of the rule, which is to reduce coupling.

Code Smells : Dispensable

Continuing on our discussion on Code Smells and Refactoring techniques, we will discuss Dispensable in this post.

Dispensables are avoidable components whose absence would make the code much more cleaner, readable and efficient.

Comments

A joke is not a good one if needed to be explained. A similar philosophy holds for code as well. If you feel that the code requires comments to understand, then it is better to refactor  it such a way that it eliminates the need of comments.

You could start with refactoring techniques like Rename Method, Rename Variable, along Extract Variable and Extract Method. Quite often using asserts (introduce assertions) can also aid in increasing the readability of the code.

Duplicate Code

When you have a larger team, there is a distinct possibility that two developers working different parts of the project might end up developing similar/same method. The similarity could could be subtle as well, where similarity is visible to only in certain parts of code, while performing the same job.

Extract Method, Extract superclass and Extract class are some of the refactoring methods that can be applied. If two methods do same job but using different algorithms, refactoring techniques like Substitute algorithm (Strategy Pattern) can be applied. Similarly, if the duplicated code is only visibly similar, but isn’t quite identical, Form Template Method technique (Template Method Pattern) can be applied.

Lazy Class

There could exist classes in your code which has become obsolete or the functionalities are near-useless, you could employee techniques like Inline Class to remove it.

Maintaining code is expensive and any unused code should be carefully eliminated.

Data Class

Classes are identified by two factors – Properties and Behaviours.  If you stumble upon a class that has only properties, then it is a good candidate for Data Class code smell.

 The first step you need to take is to review the client code that uses the class, and review if the functionality could exist in the Data Class itself. You could also review if the conventional collection such as Arrays could be used to store the Data in the class, thus eliminating the need for class.

Dead Code

Dead Code is often resultant of changing requirements/specifications, and a development team that was unsure/lazy to clean up the code. A good IDE such as the Visual Studio can aid in detecting such code and can be eliminated.

Remember, it doesn’t need to be a method, the dead code could also be a unused parameter, which can be eliminated using the Remove Parameter refactoring technique.

Speculative Generality

How often have we been guilty of creating functionality in anticipation of future requirements, but ended up never having to use them ? It is a common trait in teams, which is highly infectious and needs to be avoided. XP Principles like YAGNI, KISS can be highly useful in this regard in educating the team to avoid such pitfalls.

Refactoring techniques such as Collapse Hierarchy an Inline class can be used for eliminating such code.

Design Pattern : Memento Pattern

Memento Design Pattern allows to capture internal state of an object in an external object and restore it to the desired checkpoint when required, all the while being in compliance with encapsulation.

The Memento Design Pattern comprises of 3 actor classes.

  • Originator : The class which needs to have the ability to store its internal state and restore itself to checkpoint when required.
  • Memento : Contains the internal state of Originator.
  • Caretaker : The shepherd class who is in charge of storing and restoring Originator from Memento.

Let’s go ahead and implement the actor classes

Classic Approach

public class Memento
    {
        public string FName { get; set; }
        public string LName { get; set; }

    }

 public class Caretaker<TSource>
    {

        private IList<Memento> _stateMemory;

        public Caretaker()
        {
            _stateMemory = new List<Memento>();
        }

        public Memento GoBack(int level) =>  _stateMemory.Reverse().Skip(level-1).First();

}

 public class Originator: IOriginator
    {
        public string FName { get; set; }
        public string LName { get; set; }

        public void RestoreState(Memento memento)
        {
            this.FName = memento.FName;
            this.LName = memento.LName;
        }

        public Memento Save()
        {
            return new Memento() {
                LName = this.LName,
                FName = this.FName
            };
        }

    }

The above code showcases the implementation of Memento in its simplest form. You could step up things by making the Memento generic so that it can be reused with other classes as well.

Generic Memento with Serialization.

Instead of defining each properties of the Originator class, we could create a completely generic version by utilizing the powers of serialization.

In the following example implementation of Memento class, I have used ProtoBuf for serializing the class.

public class Memento<TSource>
    {
        private byte[] _state;

        public Memento(TSource data)
        {
            using(var stream = new MemoryStream())
            {
                ProtoBuf.Serializer.Serialize<TSource>(stream, data);
                _state = stream.ToArray();
            }
        }

        public TSource Value
        {
            get
            {
                using(var stream = new MemoryStream(_state))
                {
                    return ProtoBuf.Serializer.Deserialize<TSource>(stream);
                }
            }
        }
    }

The entire source code shown in this example are available in my GitHub.

Stairway Pattern

How do you feel when you invite your friend for a private family function and he brings along a dozen strangers (his friends) ?

 

Entourage Anti-Pattern

This is similar to the scenario when you want to add a library as reference and in turn ends up referring a different set of libraries which you are not directly dependent. This scenario is perfectly defined by the Entourage Anti-Pattern. The Entourage pattern also describes the (avoidable) practice of packaging the abstraction and implementation in the same assembly.

The Stairway Pattern

The stairway pattern describes a better alternative by organizing your abstractions and implementations in separate assemblies, which in turn allows both to evolve and vary independently.

It also means the references now doesn’t bring an entire entourage of assemblies along. One of the thumb rules you can adhere too is to ensure the abstraction assembly doesn’t depend on any external references.

Looking back at DRY

Continuing with our series to bring together the common design patterns and principles, we will, in this particular post, look into arguably the most famous design principle known to programmers – DRY. Don’t Repeat Yourselves – or DRY, is possibly the easiest to practice, at the same time, one that could go wrong in the ‘rush hours’ of project deadlines.  The principle, as you would be aware of, aims in reducing/eliminating duplicate software patterns in the system.  The Pragmatic Programmer describes DRY principle as follows

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system – Andrew Hunt, Dave Thomas

The evils of a non-DRY system is obvious.If you have same functionality defined in two places, and you forget to change in one of the place when the functionality changes, you are left with a system that is self-contradicting. The principle doesn’t exclusively apply to code, but rather it applies to documentation, comments in code as well. Consider a scenario when the developer changes the code, but forgets to change the comments associated with the code, the result could be a future developer banging his head to understand what is now an obsolete comment.

The duplication could be broadly categorized into four categories (again thanks to Pragmatic Programmer).

Imposed Duplication
There could be scenario’s when the Project Specifications or the technology limitations imposes duplication on the development team. Such scenarios are hard to tackle and the near perfect solution would be localize the impact of violation.

Inadvertent Duplication
This kind of duplication involves scenario when the developer doesn’t realize they are guilty of duplication. This could be resultant of a rather imperfect design.

Impatient Duplication
This is the most avoidable of the four categories of duplication and describes the scenarios when the developers are lazy or pressurized with deadlines, and end up finding shortcuts via duplicating. However, the develop team as a whole needs to remember that this tiny shortcut could lead to catastrophic impacts in latter stages of project

Interdeveloper Duplication
Most commonly seen in large disconnected teams and possibly the hardest to detect. The developer in one sub team could duplicate a functionality which was already developed.

DRY, as seen from above, is possibly the most easiest of Design Principles to master, if you are always on your toes. The key lies in keeping an eye on the bigger picture of project, refactor your code regularly.