Lyndsey has posted 139 posts at DZone. View Full User Profile

Book Giveaway: Dependency Injection Exclusive Chapter Download

08.28.2009
| 9601 views |
  • submit to reddit

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.

 

AttachmentSize
DICh4.pdf462.94 KB
bookcontest_depen-inject.jpg28.82 KB
Published at DZone with permission of its author, Lyndsey Clevesy.

(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

Hi Carl, This book is primarily a software design patterns and engineering book. I try to present concepts first in a framework agnostic fashion, then choose Guice or Spring to explain solutions in examples. They are both used about equally, distributed as appropriate, throughout the book. Thanks! Dhanji.

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

Page 103 says, referring to EmailerTest: "This test case is impossible to write on Emailer as it exists in listing 4.1". Well, this isn't true.

The code to be tested (based on listing 4.1):

public class Emailer {
   private final SpellChecker spellChecker;

   public Emailer()  { spellChecker = new EnglishSpellChecker(); }
   
   public void send(String message) {
      if (spellChecker.check(message)) {
         // send message...
      }
   }
}

The "impossible" test class:

public class EmailerTest {
   @Test
   public void ensureSpellingWasChecked() {
      final String message = "Hello!";

      new Expectations() {
         @Capturing SpellChecker mock;

         {
            mock.check(message); returns(true);
         }
      };

      new Emailer().send(message);
   }
}

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

I was introduced to Dependency Injection when we started a new enterprise software using Spring framework. I must say that when I read about DI, I thought this is such a simple and brilliant concept why no one thought about this earlier. As mentioned in this article there are several benefits of using DI. From my own experience I can attest that testing complex programs and scenarios is much easier with DI (especially if you compare it to testing an EJB). A very big benefit is loosely coupled classes. DI allows you to change the implementation of an object without affecting the object that is using it. It gives you more flexibility. This book will be a good read to find more about the DI.

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

Having used Dependency Injection in what have been primarily CRUD applications, and having consequently reaped the benefits of modular testable code, I'm keen to move on to the next level in my understanding of DI. Will this book help? Glad to see such books come out in the market because it encourages the adoption of DI which is now pretty much a de facto standard in application development and should be in every developer's toolbox.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.