Author: Mark Seemann
Aimed at: Experienced programmers and software architects
Pros: Well written, contains everything you need to know
Cons: Have to commit to it
Reviewed by: Nikos Vaggalis
What is Dependency Injection and how do you use it? If you want answers to these questions, is this the right book for you?
This is a very interesting book on DI from a .NET perspective, although it can be also followed by readers familiar with other statically typed languages like C++ or Java since the code snippets (in C#) are brief and most of the discussion is devoted to concepts and design patterns.
It mostly applies to experienced programmers with an outlook on software architecture, but someone with a strong OOP background would not have a big issue following the terminology and talk on design patterns, as understanding the code samples helps in getting the overall picture, albeit not a complete one. For example, most people use the .NET event model without realizing that they are actually utilizing the Observer pattern or the foreach construct which utilizes the Iterator pattern. On the whole, however, it is software architects that will benefit the most from this book.
The author, as well as being a great architect is also an accomplished cook, and hence uses a lot of cooking analogies, matching them to the process of creating software. I must admit that I had more trouble following the gourmet terminology used than anything else, which does not come as a surprise since my reputation as a lousy cook precedes me!
So what is Dependency Injection (DI) and why is it so highly regarded? This is the question addressed in the first chapter which explains that DI is a set of design patterns and principles that work in harmony for the purpose of building loosely coupled applications.
At its foundations lies Programming against the Interface, a technique that is well known even by programmers who are not familiar with DI , but DI looks at it mainly, but not only , from the perspective of who is burdened with the task and responsibility of composing objects, attempting to free the consumer code from instantiating classes using the new keyword which introduces tight coupling wherever used. It then looks at the merits of loosely coupled architecture:
late binding, extensibility, parallel development, maintainability, testability.
Chapter 2 goes practical by analyzing a popular example of building a 3-tier app, the “traditional” way and then the DI way by leveraging Construction Injection and the Composition Root. The comparison is particularly eye-opening and clearly highlights the benefits of DI and loose coupling.
It is also emphasizes the point that although RAD tools like Visual Studio make setting up an application easy, they do not necessarily enforce good programming practices as they tempt the developer into introducing tight coupling.
Chapter 3 looks into DI containers which are software libraries that take the complexity out of utilizing DI, although they will not offer much help if the application is not designed from the ground up with DI in mind, as well as examines the Composition Root and Construction Injection in more detail.
Chapter 4 looks at the specific patterns comprising DI and explains in which cases they should be used, while the next chapter looks at anti-pattern that hinder DI’s appliance and how to spot them in code.
After getting rid of anti-patterns, areas that can be refactored and improved by applying DI are explored. Example 6.1 is especially revealing and in my opinion is representative of DI’s essence and benefits. It is an example of how easy is to plug components or services in and out without having to modify client code to adapt to the change. It uses the Abstract Factory pattern to demonstrate how client code can, based on runtime decisions, work against a new algorithm without the need to change, or even know, the algorithm’s internals; a feature that allows us to swap or introduce new algorithms at will without interrupting the established ecosystem.
After being spoiled by the ease of use and practicality of the DI containers, you wonder why Chapters 7, 8 and 9 go on to show how to do the Poor Man’s DI – that is, implement DI yourself without a container. Essentially it explores how containers work behind the scene and how they create the three dimensions of DI:
Object composition, Lifetime management and Interception.
The reason is that getting acquainted with the internals of the APIs enables developers to pick up a container from a vast pool of availability and use it without much trouble, as the logic that pertains all of them stays the same.
Chapter 7 is especially practical since it goes through a variety of .NET frameworks such as ASP.NET, WPF, WCF and others, DI friendly or not, and shows how to compose objects in them. Next Chapter 8 tackles lifetime object management. The problem here is that objects are managed by the container and thus the consumer has no control over the object’s lifetime, something that gets even more complicated with a framework like .NET which implements automatic Garbage Collection.
Chapter 9, in my opinion, is the most interesting of the book, as it goes through many subjects such as SOLID, Aspect Oriented Programming, Cross Cutting Concerns, the Single Responsibility Principle and Separation of Concerns. Mainly it discuses Interception; intercepting a call from a consumer to a service and executing some code before or after the service is invoked (or in my terms placing a ‘hook’) and, without interrupting the caller or service, provides improved features or features not designed for, such as security, auditing and authentication.
Finally the last part takes a detailed look into well-known DI container frameworks with xchapters devoted to each of: Castle Windsor; StructureMap; Spring,NET; Autofac; Unity; and MEF.
Summing up, this is not a one-off read but a book you will return to for guidance, correction as well as inspiration. It contains everything you need to know about DI, but at the same time can be difficult to follow if you are not already familiar with the design pattern concepts and terminology, which continuously overlap, although they get incrementally explained as the reading progresses, and can be also looked up in the glossary section. It contains a lot footnotes and references to many other design books (like Martin Fowler’s). A multimedia format full of hyperlinks, popups, pictures and diagrams would be really suitable for this kind of book
In short, it requires commitment, reads and re-reads - just like a recipe book until you get the dish right.
Following the author’s pattern of thought, DI is a meal difficult to prepare, requires a lot of ingredients, patience and sticking to the recipe book, while the times that you have to go back to the drawing board or peek at the recipe book will be countless. But after you master it, you will not only have a good holistic view of DI, but of design patterns in general.
Who said that the way to becoming a master chef is paved with ease?