SOLID Principles – In conclusion

This series certainly was a challenge to write however it was a lot of fun. But before we say good by to it, i would like to leave you with some thoughts.

In my first 5 years of software development I worked at a company with a few colleagues from the university where I studied. We didn’t had anybody around who could teach us what to do and what not to do. When I changed the company I worked for I considered myself to be in a great disadvantage but it turned out to be very beneficial for me. I made all the mistakes a developer can make, I saw how my own code can turn against me, and become my own nightmare after a year or two.

Because of this, when i first read these principles it was easy to reflect on what situation I could have avoided if I knew better, so I started to adopt them instantly. In a weird way, i feel lucky about my initial years. What i also learned that the success of a project doesn’t hang as much on immaculate code as i thought initially.

I know these days, these principles are thought at the university and even on internships. Since they are hard to understand and even harder to put in practice, they can cause a lot of frustration for people early in their careers. I advise you to have patience with yourself.

Don’t expect that you will understand them just by reading about them. You cannot understand boxing advice from a book. They will make more sense once you spend a few rounds in the ring, especially after you get punched in the face a few times.

I also advise you to study more from different sources, eventually you will find some explanations that will make sense to you. Also don’t run directly to your technical lead when you face a dilemma. Try out your ideas, see where they lead, draw some conclusions and undo all if necessary.

So hang in there and try to respect these principles as much as you can. See you soon!

SOLID Principles – Dependency Inversion Principle


one should “depend upon abstractions, [not] concretions.”

Dependencies are practically anything that your class controls trough another class. For example if you need to manipulate a file, you will do this through a class which is exposed by the framework you are using. Here are a few common dependencies: Database, Network, File System, System information, Time, Printing, Mailing, Timers, External Hardware, External Services, etc.

Building upon the examples we discussed so far in this series, let’s add the following requirement. Our client wants to vary the percentage of discount given based on the quantity. Since he wants to modify this later for each warehouse he requested us to read this data from a CSV file.

In other words, our class needs to process some information. That information is currently stored in a file called “C:\abc.csv”. My first instinct is to open a files stream, read the information and then process it. Remembering what we learned so far we correctly identify that, fetching the data is a different responsibility then processing it, and we learned we should have only one. It is clear we need to separate these two, so we come up with something that looks like this.

Continue reading

SOLID Principles – Interface Segregation Principle

many client-specific interfaces are better than one general-purpose interface.

During interviews when we talk about these principles, candidates try to glide over this one very quickly. People usually understand this principle, and as a result it is considered to be easier to digest even by junior developers. Imagine the surprise on their face, when I ask them “why?”, “convince me that I should respect this principle”. I’m interested in their reasoning to discover their level of understanding. Like the other principles, you will understand it better if you try to not respect it.

In out last example the GeoPaymentModifier was selecting the closest warehouse. Because the closest might not have the ordered good, this can become a more complex task. The responsibility of the GeoPaymentModifier should be to know what amount to charge not to know how to select the best candidate warehouse.

To raise a bit the difficulty, let’s also consider that the warehouse info and their stock is stored in the database. The database abstraction will look something like this:

interface IDataStorageService
{
	IQueryable<UserInfo> Users { get; }
	IQueryable<ClientInformation> Clients { get; }
	IQueryable<Order> Orders { get; }
	IQueryable<WarehouseInfo> Warehouses { get; }

	void CreateOrder(Order order);
}
Continue reading

SOLID Principles – Liskov Substitution Principle

objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.

I noticed that this principle is a mystery even for experienced software developers. The reason for this is that you run into it very rarely, but once you do you’ll understand all the issues that arise from it.

Let’s try to implement the GeoPaymentModifier based on what we decided in the previous posts in the SOLID series. To recap, we receive the requirement to add a shipping cost to the total amount, if the shipping location is further away than 20 km. Since our client has multiple warehouses we need the closest warehouse location. Our class will look something like this:

class GeoPaymentModifier : IPaymentCalcModifier
{
	public WarehouseInfo ClosestWarehouse { get; set; }

	public double Calculate(Order order, double currentPrice)
	{
		return GetDistance(order) > 20
			? currentPrice + 100
			: currentPrice;
	}

	private int GetDistance(Order order)
	{
		int warehouseLoc = ClosestWarehouse.Location;
		int shippingLoc = order.ShippingInfo.Location;
		return Math.Abs(warehouseLoc - shippingLoc);
	}
}
Continue reading

SOLID Principles – Open/Closed Principle

Software entities should be open for extension, but closed for modification.

First time I’ve read this principle my initial react was “WHAT”, are these people high or something? I failed to realize how big difference is between introducing code trough extensions and through modifications. I knew about object oriented programming, abstractions, interfaces but looking back at the way I was coding then, I didn’t make use of the power behind these constructs at their full potential.

Let’s use the PaymentCalcuator example from out Single Responsibility post, there we concluded that how the calculation is done for each is a responsibility on its own. We can think of the following requirement for the payment calculation.

  • 10% discount for VIP customers
  • 10% discount in October
  • 5% for items from which they ordered at least 50

This I pretty simple you might say, so the code will look something like:

class PaymentCalculator
{
	double Calculate(Order order)
	{
		double total = 0;
		foreach(var item in order.Items)
		{
			var price = item.Quantity * item.IndividualPrice;
			if (item.Quantity >= 50)
				price *= 0.95;
			total += price;
		}
		if (order.ClientInfo.IsVIP)
			total *= 0.9;
		if (DateTime.Now.Month == 10)
			total *= 0.9;

		return total;
	}
}
Continue reading