Ahhh, interfaces! Also known as APIs / protocols / behaviours / your-favorite-languages-jargon-term-here. The source of plenty of pain, much rejoicing, and far too much discussion. I plan on contributing, here and now, to that third category.
Why do we use interfaces? People will usually give you the standard reasons: it's easier to test, it enforces boundaries and seperation of concers, it decouples components. All of these are great, but none of those are my favorite reason to use interfaces.
I love interfaces because they protect me from your shitty code.
Did you use 13 spinlocks, all beautifully choreographed to keep 7 seperate maps in sync? Did you start multiple background threads, which all poll some resource far too frequently in a desparate attempt to stay up to date? Is your codes control flow best viewed in the fourth dimension? Maybe you really went out there and started using the lava design pattern?. Guess what, I don't care!
Let me tell you a story. Junior Dev Dave joins a new software team, learns the basics of the code base, and instead of just fixing &&/|| improving other parts, it's now time for him to create his first component from scratch. Does he immediately dive into it and start experimenting with various implementations? NO! Senior Dev Sarah tells him to first specify the contract that this new component will have with the rest of the codebase. She then spends quality time with him to make sure it's a good one, and then promplty fucks off and repeats this entire allegory with someone else. Senior Dev Sarah does this with confidence, because the only part of her application that really matters, the interface, is done! Junior Dev Dave is free to play in his little sandbox in the corner and do whatever he likes!
There's an implicit assumption here that whatever interface Junior Dev Dave comes up with will actually work. I think that's a safe assumption; anyone who's a decent enough programmer knows that making things work is not the hard part. The hard part is ensuring, as the software grows, that with added new features, complexity grows as close as possible to a factor of
O(N) instead of
O(N^2). How do you do that? You guessed it, interfaces.
A smart person once said "Good abstraction is as little abstraction as possible". Notice they didn't say no abstraction. Interfaces are the dividing walls, the geopolitical barriers, and the defensive design pattern you've been wanting ever since you took a look at your teammates idea of "good" implementation and thought to yourself "wtf". So use them; hell, abuse them. As long as it's all hidden behind a good interface, it's all the same to me.
"Well then, get your shit together. Get it all together. And put it in a backpack. All your shit. So it’s together. And if you gotta take it somewhere, take it somewhere, you know, take it to the shit store and sell it… Or put it in a shit museum, I don’t care what you do, you just gotta get it together. And then put it behind an interface" -Morty, adapted