When Not to Apply the Dependency Inversion Principle

dependency-injectiondesignsolid

I am currently trying to figure out SOLID. So the Dependency Inversion Principle means that any two classes should communicate via interfaces, not directly. Example: If class A has a method, that expects a pointer to an object of type class B, then this method should actually expect an object of type abstract base class of B. This is helps for Open/Close as well.

Provided that I understood that correctly, my question would be is it a good practice to apply this to all class interactions or should I try to think in terms of layers?

The reason I am skeptical is because we are paying some price for following this principle. Say, I need to implement feature Z. After analysis, I conclude that feature Z consists of functionality A, B and C. I create a facade class Z, that, through interfaces, uses classes A, B and C. I begin coding the implementation and at some point I realize that task Z actually consists of functionality A, B and D. Now I need to scrap the C interface, the C class prototype and write separate D interface and class. Without interfaces, only the class would've needed to be replaced.

In other words, to change something, I need to change 1. the caller 2. the interface 3. the declaration 4. the implementation. In a python directly coupled implementation, I would need to change only the implementation.

Best Answer

In many cartoons or other media, the forces of good and evil are often illustrated by an angel and a demon sitting on the character's shoulders. In our story here, instead of good and evil, we have SOLID on one shoulder, and YAGNI (You ain't gonna need it!) sitting on the other.

SOLID principles taken to the max are best suited for huge, complex, ultra-configurable enterprisey systems. For smaller, or more specific systems, it is not appropriate to make everything ridiculously flexible, as the time you spend abstracting things will not prove to be a benefit.

Passing interfaces instead of concrete classes sometimes means for example that you can easily swap reading from a file for a a network stream. However, for a great amount of software projects, that kind of flexibility is just not ever going to be needed, and you might as well just pass concrete file classes and call it a day and spare your brain cells.

Part of the art of software development is having a good sense of what is likely to change as time goes on, and what isn't. For the stuff that is likely to change, use the interfaces and other SOLID concepts. For the stuff that won't, use YAGNI and just pass concrete types, forget the factory classes, forget all the runtime hooking up and configuration, etc, and forget a lot of the SOLID abstractions. In my experience, the YAGNI approach has proven to be correct far more often than it is not.

Related Topic