“Coding to the interface,” “coding against the interface,” “interface-based programming” and more… are just a few names given to a, in my opinion, incredibly useful and scalable technique for writing systems that are highly dependent on changes. It came to my mind to talk about this when a few days ago a colleague with whom I’m working on a project told me that he was having a tough time understanding the code I wrote; the big question arose “why so many interfaces?” I felt somewhat identified because even for me (that wrote all that code) was difficult at times find something between all those files. But the reason for it? Simple: “Coding to interfaces, not implementation.”
Coding to interfaces is a technique to write classes based on an interface; interface that defines what the behavior of the object should be. It involves creating an interface first, defining its methods and then creating the actual class with the implementation. At first, it looks like over coding, but, there are two main reasons that why I decided to go for it: Test Driven Development and Flexibility.
On the testing side, is absolutely needed. TDD is about creating the tests for the functionality to achieve, to later develop the code required to pass the tests. As there is no implementation of the code yet, using Interfaces to Mock objects is necessary to accomplish the test cases; when the actual implementation is ready, is just a matter of substituting the mocks and injecting the real object. If the object complies with the interface, your tests will behave the same way as the mocks. It also works when creating tests that depend on code done by another person or team and you do not have the real object yet.
On the other hand, there is flexibility and maintainability. To explain why, I’ll first tell a story about our project. A few days ago (curiously the same day that my friend asked about interfaces), due to a change of requirements, we had to change the two API’s that we were using on our project; These APIs were, nevertheless, part of our core functionality. When looking at the new APIs, we realized that refactoring the code was going to be a lot more work than just refactoring the code. Why? Because we had coded against interfaces, therefore, as soon as we finish the new code, all other objects dependent on the implementations did not even notice that something changed. And guess what? All our tests passed on the first run, like if nothing had changed.
I like to imagine it like this: think about your car’s wheels; you have the stock, regular looking wheels that came with it when you got it. But after going to the dealer, you fell in love with a new, limited edition set of wheels that they are offering for an incredible price. Now imagine for a second that your car and your wheels were uniquely made to work together. Either you modify the wheels to work with your car (what?), or you adjust your car to work with the wheels, crazy right? Thankfully, carmakers have made cars in a way that you just buy your new wheels, install them, and go driving. In this scenario, your wheels are an interface and the default wheels and the limited edition wheels are just different types of wheels, but both of them just “roll.” It does not matter the actual properties, if your car knows how to use a wheel, your car will ride.
In this code example, you can test how this works. And how the car “knows” how to use a wheel.
I hope this example illustrates enough the point of coding to interfaces. is fair to say that this is not a technique to use in every project. As I always say, one doesn’t fit all. If there are few possible scenarios in which your implementation may change and these changes are not difficult to track and refactor, you might not need to use this. Otherwise is a good practice to do this. If you are interested in seeing the real application of this from my project, just leave a comment, and I’ll upload it or send you a link.