Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / programming / architecture

SOLIDify your software design concepts through SOLID

4.86/5 (66 votes)
8 Mar 2012CPOL14 min read 132.7K  
When you design your software, you always should think in object oriented way. To improve this thinking process with accuracy you always should observe how objects are created and managed in the real world. Along with this if you have knowledge about design principles, you will rock.

Starting With Real World

If you want to create a dolls house you may easily do that by your own. It does not necessarily need any upfront design. You just gather some materials (say papers) and start building from your imagination.

330821/image002.jpg

Give the doll’s house to your daughter. She will play with this and after some time she will not like it anymore. Then you throw it away and build another one.

330821/image004.jpg

Now your wife is asking you to build a house on the land you have just purchased. Is it possible for you to build the house by your own? I know this is an invalid question. Well, is it possible for you to start building the house if you are provided 100 people with you? The answer is no. If I ask why? You will instantly give the obvious answer – “Building a house involves lot of concerns and you need experts to handle those concerns before starting the real construction work.”

330821/image006.jpg

Some concerns could be

1. Your wife’s dream about the house.

2. The maximum area of land availability.

3. Your budget.

4. Core architectural design.

5. Floor planning.

6. Utility planning.

7. Car parking.

8. And many more.

So, the first point you need to start the work is to talk with your wife generously so that you know what exactly she wants at her house. Then go to the construction company who will work as a contractor to build your house. Tell them your expectation, area and budget. You will then be sent to the civil engineer and the architect. They will know your requirements in detail and will do thorough analysis on that. Later the civil engineer and the architect will come out with a design and plan of construction. They will consider all the concerns and are expected to handle those with maximum efficiency. The best they do it, the best your house will become. On the other hand if the architect and civil engineer do poor work, your house will suffer in the long run.

So, it is not you and the workers who are responsible for a great house to construct but it is the architect and civil engineer who can make it happen of-course backed by skilled workers who are capable of working according to plan. If your design and architecture is great, the hardest part is done.

I am sure as you are reading this article, you are a software engineer. Can you relate this house construction paradigm with the software development world?

Let us construct your house hypothetically as if it is a software and try to relate the design strategies of this house construction with some software design principles so that we can realize the necessity of following standard principles while design our software.

First of all who is the client of this house? It is primarily your wife who provided you the specification of her expectations from the house. Then you are also the client who will be the point of contract from client side. The construction company is the software house who is going to work to build your house. So, an agile environment is setup that can ensure the best production as both parties will be in close touch all the time. Now what?

Now, the architect and civil engineer will start analyzing your specification to come up with a good design. In reality building a house is a very big task. So, we will not touch too many points to make it simple. The goal will be, the designer should design your building in the best way and we will see it through some example building construction concerns.

Base foundation of the building:

The civil engineer will design the base foundation of the house. He perhaps will consider the following while doing the design:

1. Maximum area of land.

2. Maximum number of floors can be accommodated.

3. How many floors you will want to construct initially.

4. Your plan of extension in future.

Then perhaps,

5. How deep the foundation will be.

6. How many piers will be needed and how they will be distributed.

7. Etc.

During designing the base foundation plan, the civil engineer will need to work closely with the architect so that the distribution of piers does not impact the interior of the building.

330821/image008.jpg

Now, once the foundation is done, it is closed. The piers will be extendable and on top of that your house will be extended floor by floor. Let’s say you will construct your house initially with 2 floors. After some years the world under go in recession and you lost your job. So, you want to construct 2 more floors on top of your house using your saved money so that you can give that in rent and earn some continuous money. Let’s say, the engineer had not considered that you may want to construct more floors on your house. So, he designed the foundation just for 2 floors and at the top the piers are sealed. So what will you do now? Unfortunately you have no option but demolishing your house, re-do the foundation and construct it again. So, the engineer could have killed you. Is not it?

On the other hand, if the engineer is good, he will do the foundation so that you can build more floors on top of it and the piers on the top floors are extendable. So, your base foundation is closed for any modification but still open for extension. Here we have learned a very important principle that is also applicable in software paradigm. That is, you must build your base classes of the software with enough knowledge of the module you are developing and then expose the extension points from the base class so that it can be extended by the child classes.

In one sentence we can tell “Your base classes will be closed for any modification and still open for extension.” This principle is formally known as Open-Close Principle in software world.

More example of Open-Close Principle:

See the example codes below. If you understand the Open Close Principle you will easily see how the 1st example violating the Open Close Principle and how the second example honoring it.

330821/image010.jpg

Image – Violation of Open Close Principle

330821/image012.jpg

Image – Honoring Open Close Principle

Interior Architecture – Where to fit Air Conditioners:

As I have already said, there are so many concerns we will have to handle to construct a house. Among all those concerns very small concern like where to install your air conditioner in your bed room is no less important. Say, your architect designed the room so that you have a space for fitting air conditioner inside the window. During his design he thought of a window air conditioner and kept a place for that in the window. Now, the time changes, and you may like to install a bigger air conditioner or you may like to install a split ac replacing your old window one. What will you need to do?

330821/image014.jpg

One option is you change your window so that it allows you a bigger space for the ac. But you see if you do this, the size of the window may decrease which eventually may not be good for day light transition and air flow of your room.

So, ideal solution could be if the space for the air conditioner were not inside your window, rather into the wall, you could alter the space for your new ac in the wall engaging perhaps with very low skilled labor.

330821/image016.jpg


See the benefits here:

1. You do not need to change your window.

2. Your room will not be at risk of low ventilation and lighting.

Do you see the problem in the design where ac is to fit into the window? We all know that purpose of a window is to provide proper light and ventilation to your room. So, window should have been changed only if you need to adjust the lighting and ventilation. It was not good if you had to change your window because you needed to install a new ac.

This flaw in your build design has similarity with a very important software design principle. The principle says your objects should change for one and only one reason. In other words, your objects should always serve one and only one responsibility. Formally this principle is known as Single Responsibility Principle in software world.

More example of Single Responsibility Principle:

See the simple example below. Here 2 task is done by ApplicationSecurityContext class. One is authentication and the other is Login. You know in modern software world there could be many ways of authenticating users and also many ways to make the user logged to your application. Authentication can be done through database, windows authentication, single sign-on etc and login can be done through forms authentication, windows authentication, LDAP based authentication etc. So, it is natural that your application’s login and authentication mechanism can change. But if you implement both in the same class this class gets 2 very big concern of your application to manage. Here authentication is more of central concern of the system and login is closely related to the client interface of the application (Desktop app, Smart client app, Web app etc). In this situation we must not implement this 2 concern in same class and if we do it will clearly violate the single responsibility principle. And if we continue to mix up these type of concerns in a single class, it will become a BBOM gradually.

330821/image018.jpg

Image: Violating Single Responsibility Principle

What is the solution then?

330821/image020.jpg

Image: Honoring Single Responsibility Principle

We can create a separate class for authentication. The best approach will be to have an interface like IAuthenticationProvider and implement your desired authentication implementing the interface. The FormsAuthenticationProvider class implements the forms authentication for your application. Later you can easily implement other mechanism of authentication if required. So, it is honoring both Single Responsibility Principle and Open Close Principle.

Designing the car parking area:

In Modern buildings car parking is one of the very important areas of concern. Your engineer and architect needs to design the piers of your building so that your basement or ground floor can accommodate as many cars as possible. While doing the design, they should consider the type of cars they should support. Normally in residential houses the zips could be the largest vehicle to support. So, your engineer should design the car parking so that each space supports light weight vehicles. Now, if your architect and engineers are not ver careful they may design the space only for sedan cars. The consequence of this, when you will need to accommodate your new prado in your car parking you cannot do that.

330821/image021.jpg


So, the design principle should be, each parking space should support one light weight vehicle. In that way it should also support any type of light weight vehicle whether it is a small car or a big prado jip.

This car parking concern also can describe another very important software design principle. The principle says, in a system of an object X is used and if object Y is subtype of object X then, in that system object X should be replaceable by object Y. More formally this principle is called Liskov's substitution principle in software world.

More Example of Liskov's Substitution Principle:

Liskov substitution principle basically says the inheritances that you create in your application must be correct. Here is the classic example for which the Liskov's Substitution Principle is violated. In the example 2 classes are used: Rectangle and Square. Let's assume that the Rectangle object is used somewhere in the application. We extend the application and add the Square class. The Square class is returned by a factory pattern, based on some conditions and we don't know the exact what type of object will be returned. But we know it's a rectangle. We get the

Rectangle
object, set the width to 5 and height to 10 and get the area. For a rectangle with width 5 and height 10 the area should be 50. Instead the result will be 100. (This example is taken from http://www.oodesign.com/liskov-s-substitution-principle.html )

330821/image023.jpg

330821/image025.jpg

Image – Violating Liskov Substitution Principle

Electricity Distribution Lines:

Among many of the utilities that you must have in your building electricity is perhaps one of the most important one. Your engineer and architect will perhaps need to work with an electrical engineer to design the electricity distribution line of your building. One approach for this could be, the whole supply of current in your building will come from a single root. But you see this will make the whole supply chain too complicated. It will make it very difficult to manage, extend and trouble shoot. So, what should be the solution?

330821/image026.jpg

In fact the electricity line should be interfaced in multiple segments. First of all each floor may have a separate root and then perhaps the best way would be to have each room having separate root. If you follow this design principle, it will be very easy for you to manage and trouble shoot your electric supply lines.

Again, this has similarity with yet another important software design principle. This principle says once an interface has become too 'fat' it needs to be split into smaller and more specific interfaces so that any clients of the interface will only know about the methods that pertain to them. This principle is known as Interface Segregation Principle in software world.

More example of Interface Segregation Principle:
Interface segregation principle is closely related with single responsibility principle I explained earlier in this write-up. Here creating a different interface for IAuthenticationProvider segregating the authentication concern from the login mechanism. In the same way whenever we see a single interface is becoming too heavy and entertaining more than one concern we should segregate the interface and create interfaces for each individual task to perform. Please see the Single Responsibility Principle code block for this example.

Overall building development process:

So far, we have talked about few of the concerns of your building construction. Now let us talk about the process of the building construct. You have engaged the civil engineer and the architect and they have completed the design. Now, the actual construction will start. How will the massive construction work will go through? Definitely there be a team leader. The team leader will eventually have different teams. For example construction workers, electricians, purchase team and so on. Now, to each team the responsibility will be distributed and each team will have a team leader itself. So, the team leader of the whole construction work will just know the individual team leaders of each team. He does not need to know who the team members are working in each team. In this way, the dependencies among different teams are abstracted to individual team leaders. So, any change in the requirement and design will not need to be transmitted to all of the workers working in the project. The job of the works is just to implement what their team leaders ask to do.

330821/image028.jpg

So, the principle team leader does not depend on different teams through the team members rather he depends on different teams through the individual team leaders. And individual workers depend on their team leader to know what they need to implement.

This process of building construction can demonstrate another greatly important software design principle. The principle says:

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.

--Wikipedia

The principle is known as Dependency Inversion Principle.

More example of Dependency inversion principle:

We actually already have seen code example of Dependency Inversion Principle. Again you if look at the code block for single responsibility principle you will see a parameter of type IAutheticationProvider is passed to the method LogIn. Here the client of this LogIn method does not need to know the actual implementation of IAutheticationProvider directly rather it gets the authentication through the abstract layer of IAutheticationProvider interface.

330821/image030.jpg

Image - Dependency Inversion Principle

In modern software world there are quite a few dependency injection container that facilitates us to program honoring dependency inversion principle. Some of those are Unity, NInject, Windsor, <a href="http://structuremap.net/structuremap/index.html">StructureMap</a> etc. I have plan to have a separate write up on this later. So, keep following.

So far in this write-up I have tried to explain 5 very important design principles that we should always honor while designing and programming our softwares. Collectively these principles are called SOLID.

330821/image032.jpg

Image - SOLID copied from wikipedia

Beside these there are some other principles that we should have knowledge about. But again I have plan to write on those later. So, keep watching .

Thanks for your patience to read this write-up. Your comments and feedback's will encourage me for better work in future.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)