"Why is everything an interface?"
"Because we may need to swap out its implementation in the future. It's Clean Code."
"Then refactor it out into an interface when you need it! What's an IDE for?"
"Why is everything an interface?"
"Because we may need to swap out its implementation in the future. It's Clean Code."
"Then refactor it out into an interface when you need it! What's an IDE for?"
For example, you have a repository for some entity as a dependency of a service and you would like to test some behavior of the service when the repository fails. In this case, the service can depend on an interface of the repository instead and the test can create a stub that implements that interface, whereby you can simulate the error. If the service depended on the actual repository, this becomes very difficult to do.
Can you explain why this is? or maybe more specifically what you mean by this.
Depending on interfaces means you (by definition) can't depend on the implementation. It's a decoupling thing more than anything else. You get some benefits for mocking during testing and so on but it's mostly just to get something like a C++-style class declaration/definition (or .h/.cpp)-split.
It's admittedly taken a bit too far in some codebases and often done without much thought to why, but it's also a bit of an artifact of pre Jigsaw-era Java where it was very hard to enforce boundaries between modules. In that light it makes at least some sense.
An interface isn't just a type construct, it communicates the intent of the systems design.
For example, in Delphi classes in the same unit (file) can access each others protected members. This is usually a code smell, which interfaces prevent.
A more concrete example of an A and B that need to interact with each other might be a user account service and a (financial) transactions service. (Why not let them live in the same module? That can also be a solution, but as the scope of each grows and especially if separate teams end up owning each it can make sense to split them and enforce some boundaries via the interfaces.) Another example could be a notifications service and several of its clients, like whatever is handling user posts kicks off a notification event and asynchronously the notification service processes it and may need to reach around to call back into other services that could be part of the sender's module. (Passing simple lambdas may be an adequate alternate solution too.)
This is what Fowler describes as “Separated Interface”. [1] Specifically he calls out the specific need for this special case:
> “[Y]ou might need to invoke methods that contradict the general [module] dependency structure. If so, use Separated Interface to define an interface in one package but implement it in another.”
It’s a special case because until you need to “contradict the general dependency structure”, you don’t need to do it. In particular, this is not the first tool one should reach for if you have a circular dependency between two modules.
[1] https://www.martinfowler.com/eaaCatalog/separatedInterface.h...
It's not easy to uniformly change in a way that doesn't add regressions. It's also not usually easily changed except by a large team. That large team likely adds more regressions because communication is lossy.
"Simple code" that avoids abstractions leans more on people, code that embraces abstractions (good or bad) attempts to lean more on the machine.