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.