Book review of "Dependency Injection Principles, Practices, and Patterns" and lessons I learned from reading it.
Introduction
My first job as a software developer was writing C# for a software development agency that worked very closely with Microsoft. As a junior engineer, I had a basic notion of object-oriented programming and SOLID principles, but I was puzzled every time I opened a project that used .NET dependency injector container. Why are we writing an interface for everything? Why aren’t we instantiating instances inside of classes? Why are we passing all instances through the constructor? It all seemed very bureaucratic. I didn’t understand why we were following these strict ru…
Book review of "Dependency Injection Principles, Practices, and Patterns" and lessons I learned from reading it.
Introduction
My first job as a software developer was writing C# for a software development agency that worked very closely with Microsoft. As a junior engineer, I had a basic notion of object-oriented programming and SOLID principles, but I was puzzled every time I opened a project that used .NET dependency injector container. Why are we writing an interface for everything? Why aren’t we instantiating instances inside of classes? Why are we passing all instances through the constructor? It all seemed very bureaucratic. I didn’t understand why we were following these strict rules that added so much code, when we could keep the code lean and simple by getting rid of those boiler-plate interfaces, and instantiating the instances of a class inside where they were going to be used.
Fast-forward a couple of years, while working for another company, I decided to pick up "Dependency Injection Principles, Practices, and Patterns". I remember the book showing up in the background of a Youtuber’s video. At the time, I thought that reading it could help me introduce some more structure and order to our projects. Part of me was curious to know if the book could answer the questions that plague me all the way back to my C# days. After reading the book, I can say it did answer all of my questions and more. It has helped me have a much better understanding of object-oriented programming and software design as a whole.
The book authors, Steven van Deursen and Mark Seeman, do a great job of explaining central concepts to dependency injection such as "decoupling", "cohesion", and how they relate to the SOLID principles. They provide examples of dependency injection pattern,s common "anti-patterns", and "code smells", all of which help illustrate their main advantages of dependency injection to the reader. The book is very well written, and I highly recommend it to anyone working with object oriented programming.
Having introduced the book, I would like to share with you 3 ideas from this book that have had the biggest impact on how I approach software development. Beware, I am not aiming to boil down the book, or dependency injection to 3 ideas. If you look to understand dependency injection, and all of its benefits, I would encourage you to read the book.
Low Coupling
The book introduces the concept of coupling with an analogy to a hotel’s hair dryer. Many hotels’ hair dryer’s are wired directly into the socket. Like code that is highly coupled together, it is a pain to fix or change. When the hair dryer breaks, an electrician has to come, switch off the electricity in the room, and de-solder the cabling before they can start replacing the hair dryer. With highly coupled code, the process can be very similar; having to change other modules before you can replace the module that needs fixing or refactoring.
In contrast to the direct-wired hair dryer, a hair dryer with a plug is easier to replace; all you have to do is unplug it from the wall socket. Loosely coupled software behaves the same; it is easier to replace, remove, and maintain.
Maintainability is a very important aspect of software development. A software solution that is not maintainable means that it has a very high cost to change, and for business that means software features being released less often. Loosely coupled code improves a project’s maintainability which enables the development of new features at a faster pace.
High Cohesion
The authors touch upon the SOLID principles, and the principle that gets mentioned the most is the "Single Responsibility Principle", which they define it in the following way:
The Single Responsibility Principle (SRP) states that each class should have only one reason to change.
In relation to the Single Responsibility Principle (SRP), the authors define cohesion and how cohesion allow us to determine if a module violates SRP.
Cohesion is defined as the functional relatedness of the elements of a class or module. The lower the amount of relatedness, the lower the cohesion; and the lower the cohesion, the greater the possibility a class violates the SRP.
When aiming to write loosely coupled code, the Single Responsibility Principle becomes an invaluable guideline that helps us achieve that. The loose coupling has to take place with modules that have a high level of cohesion. Otherwise you have a difficult to understand software solution, and that impacts the maintainability negatively.
Volatile and Stable Dependencies
Although loosely coupled code contributes to a more maintainable code base, it also has a cost. That cost is having more "seams" in your code.
Everywhere you decide to program against an Abstraction instead of a concrete type, you introduce a Seam into the application. A Seam is a place where an application is assembled from its constituent parts, similar to the way a piece of clothing is sewn together at its seams.
Because of this cost, it is important to introduce seams only where they are necessary, like for volatile dependencies. A volatile dependency, as opposed to a stable one, is a dependency that meets one of the following criteria:
- The dependency runs in a different environment, like in a different machine or different process within a machine. An example would be a database.
- The dependency does not exist or is under development.
- The dependency contains nondeterministic behavior.
- New versions may contain breaking changes.
Conclusion
There are so many other concepts I’ve learned from reading this book that I haven’t added here. It is an easy read thanks to its structure, explanations, and analogies. I would recommend everyone to buy it, read it at least once, and find a space in your bookshelf to have it at hand for whenever a question pops up.