As a developer, there's often a point when you're tasked to build something that's a key part of the architecture of your software. Maybe it's not a key component to all of the application, but it's pretty foundational at least for a part of the application. Often we put our thinking caps on, plan a bit of what we're about to code, and then dive right into it. If you do TDD, you might go start coding your tests but regardless of your approach, you're likely going to start coding some classes pretty soon.
Start With Interfaces
In my opinion, if you're writing code that's part of your application's foundation, you should start with interfaces. If you're already rolling your eyes and whining to yourself that now you're going to have to code some class and then have some interface that just redefines the methods and bloats your code, then take a deep breath. Here's my reasoning:
- The interface defines what goes in and out of your class. If you're only looking at this, you'll see how other developers have to interact with your class.
- If others can extend your work, you offer a lot more flexibility by providing an interface than forcing them to implement a concrete class.
- There's this fancy programming topic called Inversion of Control that you can make happen a lot easier just by starting with interfaces first, and you might need something like it down the road.
- Interfaces are excellent for your layered architectures.
It's not a big list so maybe you actually go through that on your one deep breath I told you to take. Maybe the tremendous code bloat of adding a few method signatures in a file has you so upset already that you can't even focus on what I just said. That's okay, you can always come back and try again once you've calmed down.
How Others Interact
The interface defines the exposed parts of what your class will implement. If you already have trouble making classes and trying to guess at what to make
private, this might help you out. Whatever you put in your interface must be visible to others outside of your class because interface implementations have
public members. All your other functions you wanted to implement? You start to think "Well... maybe this would be useful outside of this class...". But now the question is, how useful? If it's that useful, then is it foundational enough to be part of the interface? If not, it should probably be scoped to the class and not outside of the class.
If you read my post on what makes a good API, I touch on a lot of the great points for interfaces. You're probably correct if you don't think this warrants the several line code bloat. Hang in there.
Extending Your Work
So you have your whole API set up like a bauss now. You think it's all fine and dandy because it gets the job done and passes all the tests. Awesome. But it's only awesome today. Tomorrow someone needs to extend your work. Someone wants to provide their own object into your code as a parameter now, let's say. Here's the signature that you wrote:
void CoolestFunctionEver(MyConcreteClass input);
You weren't wrong by being excited that everything works. You should be proud about that--congrats. But now if I want to provide my own input to your function, I have to go extend your class like this:
public NicksConcreteClass : MyConcreteClass
Which may not seem that bad... but if I had another class that existed and already had most (if not all) of the information and functionality, I essentially have to duplicate it or create some sort of copy constructor to make it work. If you had done this with your original method signature and been thinking of interfaces:
void CoolestFunctionEver(IMyInterface input);
Then the world would be a better place. I could use my existing class, implement your interface, and just pop my reference right in there as a parameter. No need to add any duct tape or glue to make it work. It just works nicely.
If you don't see the value to this already, I would argue that you may not have written enough code in large projects. That's not meant to sound like a jerk or anything, but this is not an unusual scenario and unfortunately leads to more code bloat than defining an interface would have.
Invert That Control
If you haven't heard of this, it will seriously open your eyes to some better code design. Inversion of Control (IoC) lets others "inject" their own classes and dependencies into your existing code. The only way to get this working nicely is if you have interfaces.
If your functions are operating on concrete classes, that means they depend on those concrete classes. Dependencies lead to coupling and code that isn't very extensible. You may not have seen scenarios where this can come up, but let me try to provide an example.
Let's pretend we have a layered application with a presentation layer, application layer, and a data layer. Suppose we have our entire application working and we have a MySQL based model in our data layer. Everything is great. One day, someone comes along and says "MySQL has been working great for our customers, but in order to penetrate this other market segment, our users need to be able to use SQLite". (Okay, maybe this is a little contrived but still...) You think to yourself "No problem! We aren't using anything fancy from MySQL so implementing SQLite is going to be 5 minutes of work!". But then you realize it... Everywhere that accesses your data layer uses the MySQL model class that was created. Everywhere does it. You need to be able to use either though, so you can't even just replace it with all with the SQLite model you're about to create. Uh oh.
If interfaces were used from the beginning, this would have been a walk in the park. Literally if you have one near the office, because it would have been a 5 minute fix leaving you tons of time for a stroll. If all of the code referencing models instead referenced a nice clean model interface, say,
IModel then you could "inject" your new model. In the few areas where you actually go to initialize your concrete model class, you could add the logic to do MySQL or SQLite and then everywhere else just sees it as an
IModel. They actually have no idea what the underlying implementation does, and they don't care!
This point alone, in my opinion, is worth the "code bloat" of your interface definition. It could save you hours and the cost of a bottle of Advil.
Layers on Layers on Layers
This point kind of ties in with the IoC points and my points on extending your work. If you have a layered architecture, then you need to split up your code into pieces that are functionally different. Your presentation layer is responsible for rending things and making them pretty for user interaction. Your application layer does the heavy lifting, and your data layer does all that low level stuff nobody wants to think about. :)
Interfaces help to provide a nice layer of abstraction. If you declare your class that implements your interface in some other project or want to move its definition between layers, this won't really have any affect on the code relying on the interface so long as the interface definition doesn't move.
Why is this good? Well, to exaggerate my point, let's pretend someone is an absolute beauty and decides to implement your amazing data model in... your presentation layer. Great. Okay so despite it being in the wrong location, it works, and it works real well. If your data model interface resides in the correct spot and everyone is using the interface, then it's minimal work to move your data model class to the right spot. Cut it out, move it to the correct project/layer, and change the one/couple spot(s) that initializes the reference. All of that code that references the interface can go absolutely untouched. Talk about bauss mode refactoring. You just moved the bulk of your data layer between projects and across layers and didn't have to worry about breaking much code.
If you still aren't convinced, then I suppose I did a poor job explaining all of this. Leveraging interfaces in your code helps to ensure a flexible and decoupled architecture... And you can't really ask for much more than that. If you're concerned with adding a file here and there to contain some signatures because you think it's going to bloat your code base, you're probably the guy/girl trying to compress all your code into one line. In which case, you should have started here.