Book Giveaway: Dependency Injection Exclusive Chapter Download
DZone and Manning Publications have partnered to bring you an exclusive chapter from 'Dependency Injection' (by Dhanji R. Prasanna). This chapter covers organizing code in modules, watching out for tight coupling, designing with loose coupling, testing code in discrete units, and working with key rebinding.
Building Modular Applications
So far, we’ve looked at what it means for objects to be well behaved and classes to be well designed in the small. But in any real-world project, there’s also a big picture to be considered. Just as there are principles that help our design of objects in the micro, there are principles for good design in the macro sense. In the coming sections,
we’ll talk about these design principles and see how to relate them to dependency injection.
Chief among these is testing. DI facilitates testing and testable code, the latter being an extremely important and often-overlooked condition to successful development. Closely tied to this is the concept of coupling, where good classes are linked to the dependencies in ways that facilitate easy replacement and therefore testing—bad ones
are not. We’ll see how to avoid such cases, and finally we’ll look at the advanced case of modifying injector configuration in a running application.
First, let’s start at in the micro level and explore the role objects play as the construction units of applications.
4.1 Understanding the Role of an Object
We’re all very familiar with objects; you work with them every day and use them to model problems, effortlessly. But let’s say for a moment you were asked to define what an object is—what might you say?
You might say an object is:
- A logical grouping of data and related operations
- An instance of a class of things
- A component with specific responsibilities
An object is all these things, but it is also a building block for programs. And as such, the design of objects is paramount to the design of programs themselves. Classes that have a specific, well-defined purpose and stay within clearly defined boundaries are well behaved and reliable. Classes that grow organically, with functionality bolted on when and where required, lead to a world of hurt.
A class can itself be a member of a larger unit of collective responsibilities called a module. A module is an independent, contractually sound unit that is focused on a broad part of business responsibility. For example, a persistence module may be responsible for storing and retrieving data from a database.
A module may not necessarily be meant for business functionality alone. For example, a security module is responsible for guarding unwarranted access to parts of an application. Modules may also be focused on infrastructure or on application logic but typically not both. In other words, a module is:
- Whole —A module is a complete unit of responsibility. With respect to an application,
this means that modules can be picked up and dropped in as needed. - Independent —Unlike an object, a module does not have dependencies on other
modules to perform its core function. Apart from some common libraries, a
module can be developed and tested independently (that is, in an isolated environment). - Contractually sound —A module conforms to well-defined behavior and can be
relied on to behave as expected under all circumstances. - Separate —A module is not invasive of collaborators, and thus it is a discrete unit
of functionality.
These qualities of a module are largely important in relation to its collaborators. Many modules interacting with one another through established, patent boundaries form a healthy application. Since modules may be contributed by several different parties (perhaps different teams, sister projects, or even external vendors), it’s crucial that they follow these principles. Swapping in replacement modules, for example, replacing persistence in a database with a module that provides persistence in a data cluster or replacing a web presentation module with a desktop GUI, ought to be possible with a minimum of fuss. So long as the overall purpose of the application is maintained, a system of well-designed modules is tolerant to change. Much as different incarnations of an object graph provide variant implementations of a service, different assemblies of modules provide different application semantics. A module is thus an independent, atomic unit of reuse.
Objects and modules that collaborate typically have strong relationships with each other. Often the design of a dependency is influenced by its collaborators. However, each object has its area of responsibility, and well-designed objects stick to their areas without intruding on their collaborators. In other words, each object has its area of concern. Good design keeps those concerns separated.
Click here to download the entire chapter
The above introductory excerpt was taken from Dependency Injection, published in August 2009. It is being reproduced here by permission from Manning Publications. Manning early access books and ebooks are sold exclusively through Manning. Visit the book's page for more information.
| Attachment | Size |
|---|---|
| DICh4.pdf | 462.94 KB |
| bookcontest_depen-inject.jpg | 28.82 KB |
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Carl Dea replied on Fri, 2009/08/28 - 3:59pm
Lyndsey,
Sometimes books lean towards a particular product or library. Having said that, does this book focus on Google's Guice and/or Spring IOC frameworks?
Thanks,
-Carl
Dhanji Prasanna replied on Fri, 2009/08/28 - 5:26pm
Brian Hurley replied on Fri, 2009/08/28 - 5:56pm
Dependancy Injection is a basic design pattern that everyone should know if they program Java, C# or .Net. Dependancy Injection In Action give the reader a good foundation to undetstand thoes concepts. The major open source frameworks like Spring and Guice use the technology of dependancy injection to handle primary functionality. DI just makes programming much easier to seperate levels of concerns and test in isolation.
If you do not know what dependancy injection is then you need this book! If you are experienced with DI then you will probably pick up some extra tricks.
- Brian
Carl Dea replied on Fri, 2009/08/28 - 7:26pm
in response to:
Dhanji Prasanna
Dhanji,
I like it when books aren't product centric either and should be agnostic when they explain concepts. But, sometimes there is a huge learning curve when it comes to learning any framework API, let alone understand a fundamental architectural design pattern.
In the days before annotations I've used the Java Proxy API to acheive Dependency Injection. While creating a well designed interface swappable implementations can be configured for factories.
I will look forward to reading the book.
Thanks!
-Carl
Rogerio Liesenfeld replied on Fri, 2009/08/28 - 10:06pm
The code to be tested (based on listing 4.1):
The "impossible" test class:
This test uses JMockit.
Muhammad Khojaye replied on Thu, 2009/09/03 - 3:58am
The most important advantage I have found using dependency injection is that it make my testing a lot easier.
Zaheer Paracha replied on Mon, 2009/08/31 - 4:43pm
Carl Dea replied on Fri, 2009/09/04 - 12:08pm
Dhanji and Lyndsey,
With DI concepts and frameworks maturing what happens to older Java based AOP frameworks? What are the distinctions or does it make certain solutions obsolete?
Thanks,
-Carl
Sudhakar Ramasamy replied on Tue, 2009/09/15 - 12:26pm