I have been lately discussing SOLID in my previous posts – some of the basic principles of OOD . Recently while doing my project work , we had to decide between Entity Framework or NHibernate which are popular ORM layers in .Net framework . The decision was not easy , we got stuck at Second Level caching support …and could not reach any decision right away. I started thinking that may be for now we have to write our layer in such a way that we choose one ORM , and then we can switch to a different one worst case if need be. Ideally a situation like this should not arise , but if it does happen , you need to be able to do it. Once again I felt how a very fundamental OOD principle could come in handy –
Program to an interface , not an implementation.
These words above can be very ambiguous and abstract when you just read them .
However when seen from a context , you understand how powerful this is , and how it can increase flexibility and ability to switch . Seen from my own situation where we needed the flexibility to switch data access mechanism if need be, let’s understand this by constructing a scenario. For example , a common problem could be implementing a subscription mechanism for a data service that your system may provide. Users can subscribe to the data service and get notified when a change occurs. We need to persist the subscription information to the database , where you will need to use some database access mechanism.
As usual there is a presentation layer that gathers some subscription information and passes it along to the data service which persists the information to the database . For simplicity’s sake , let’s say we have a SubscriptionService , which is our data service for persisting subscriptions . We can discuss this further in the context of an ASP.Net MVC application – where a View is our Presentation layer through which Subscription details are collected. A controller action method is typically invoked to pass along the information to the server.
We can assume for our article purposes that our application provides notifications on Food Recalls. So the member user to our website subscribes to recalls for a certain type of food issued by different organizations like FDA etc. The Subscription in simplicity could be :
Please note : all code is pseudo only , this is not a working solution that can be downloaded and built.
public class RecallsSubscriptionService { Boolean Subscribe( int userId, string food_type, string organization) { // data access code to insert subscriptions return false; } }
Most of the times the controller action method would look something like this:
public class SubscriptionController : Controller { [HttpPost] public ActionResult Subscribe(int userId, string food_type, string organization) { try { SubscriptionService myservice = new SubscriptionService(); myservice.Subscribe(userId, food_type, organization); return RedirectToAction("Index"); } catch { return View(); } } }
So , we make a decision we will use Entity Framework 6 to implement our data access to store subscription information. The above code will work fine . The code goes into production . However later we decide that due to certain project requirements we have to switch to NHibernate. This is a tough situation – our controller here , who is a client of the SubscriptionService , is heavily dependent on instantiating this specific service which accesses the database with Entity Framework 6. Although we expected the problem could arise we didn’t design our system for this flexibility. Even though we encapsulated the data access code into a Service , we did not free the client from the implementation of data access because the client program is indirectly tied to EF implementation.
We need to make some changes , so our controller is independent of the future changes that could happen to the database access mechanism. To bring transparency into how data access may happen from a client’s perspective we need to introduce interfaces. We write an interface instead for the SubscriptionService :
interface IRecallsSubscriptionService { Boolean Subcribe(int userId, string food_type, string organization); }
We could write two implementations of the above interface or we could just use the same implementation we had earlier , and replace it with NHibernate.
public class RecallsSubscriptionServiceEF { Boolean Subscribe(int userId, string food_type, string organization) { // implement using EF ; return false; } } public class RecallsSubscriptionServiceNH { Boolean Subscribe(int userId, string food_type, string organization) { //implement using NH ; return false; } } /*( not that the above approach is recommended , where you keep two implementations available for the same requirement. This is for understanding purposes only )*/
The above mechanism allows us to drive the Subscribe method call through the IRecallsSubscriptionService interface. In order to effectively use the method above , we will need to pass IRecallsSubscriptionService as a parameter to the controller constructor and use dependency injection in this scenario to have the right concrete class to be instantiated during run-time. I will not dive deeper into that because it is outside of the scope of this topic.
This is the whole basis of Dependency Inversion and Injection ( this is also the ‘D’ in SOLID ): here we program to an interface , not an implementation as we saw above. This gave us the flexibility to change our implementation completely without changing the client code. So the basic idea is programming to an interface decouples the client from the internal implementation freeing calling programs from knowing the internals leading to flexibility in changing implementation as the need arises.
Even in scenarios where there are published APIs , when you use objects go up in hierarchy to program to the interface as opposed to the concrete class. So if you are using a List object and comparing individual strings- then if this object implements IComparer , then program to IComparer –
instead of writing:
List myList = new List(); myList.Compare( myList[0] , myList[1]); //Write as : IComparer myList = new List(); myList.Compare( myList[0], myList[1] ); //This gives you the freedom to use a different flavor of Compare method if you need to , IComparer myList = new Array(); myList.Compare( myList[0], myList[1] );
The advantage of the above is ability to switch different comparison methods if they are available. And also test program can easily switch different implementations and see what works the best.
We also need to understand that “Program to an interface” should not be taken literally . Even Abstract classes can act as interfaces in this context and give us the same flexibility.
Interfaces should be used wisely and only when needed. If there is no potential for an implementation to ever change there is no need to bother with interfaces. For example , a Utility class that converts a string to a number. There is no need to write interface to this . Interfaces should also be used in projects where testability is a big concern and mocking may be required.
Thanks for an excellent demonstration of the OOD principle AND for show us another important thing: How we should proceed when we analyze a project. You evaluate carefully your options and decided, based on the NEED OF THE PROJECT, what path must be followed, even if means create additional code to make easy the change just in case you need it.
Sadly, I have seen several times how people just simply choose any of the frameworks they already know because “it just work” or “they have experience about it”, without evaluate the project first. The excuses are all the same: “all is urgent”, “we need to cut the analysis time to gain the project”, “the project looks like others we have implemented before”, etc.
This is known in the Antipatterns world as “Golden Hammer” https://en.wikipedia.org/wiki/Golden_hammer
magikfingerz , thanks. A little bit more thought put ahead of time in a project saves you a lot of time later.
Hey there! Quick question that’s entirely off topic. Do you know how to make your site mobile friendly? My weblog looks weird when browsing from my iphone 4. I’m trying to find a template or plugin that might be able
to correct this problem. If you have any recommendations, please
share. Cheers!
Loved this post. Very clear and concise. Just what newbies that are diving into .NET need. Can’t wait to read more of your insite!
Admiring the time and effort you put into your blog and
in depth information you offer. It’s great to come across a blog every once in a while that isn’t the same
unwanted rehashed material. Fantastic read! I’ve saved your site and I’m adding your RSS feeds to my
Google account.