Informatics 122 Winter 2013
Project #5: Recovering the Satellites

Due date and time: Monday, March 11, 11:59pm

This project is to be done in groups of three, which will be assigned


In the previous project, we explored the use of dependency injection to produce a more decoupled design. While we were explicitly focused on the problem of making our design more amenable to unit testing, the benefits of dependency injection are not limited to this scenario; the technique has gained mindshare in recent years, and for good reason. Designs that use this technique often exhibit a level of flexibility that's difficult to achieve in other ways, because the individual components can be snapped together in ways that you didn't initially expect. Completely changing the behavior of one component is often as easy as injecting a different dependent component into it.

One of the things you may have noticed while proceeding through the previous project, however, is that dependency injection led to a fair amount of manual work, as you had to construct little trees of dependent objects, passing each into the constructor of others, until you finally had all of the objects required to solve some particular problem. This problem gets progressively worse as a design becomes more complex, as objects and their dependencies gradually become more deeply nested. Whenever we find ourselves doing this kind of grunt work, our attention should rapidly shift to ways that we can automate it.

As luck would have it, this problem is already solved multiple times over in the Java community, as there are a number of dependency injection frameworks available. The basic idea underlying a dependency injection framework is this: rather than manually creating objects and passing them into constructors, configure which kinds of objects are required to solve certain kinds of problems and ask the framework to build and return the right objects to you, with all of the dependent objects wired up automatically. At first blush, this doesn't sound like much of a solution, as it seems that you would need just as much configuration as you were manually doing in the previous project; however, the reality is that you can often configure an object's type in one place and reuse it throughout a large part of your system, with the framework automatically handling such details as determining the appropriate type of object to build, deciding whether objects should be shared singletons or constructed fresh every time, and so on.

In this project, we will explore the design and use of one such framework: Google Guice 3.0. While you will need to experiment with the framework some in order to understand how to use it, your primary focus will be in reading and understanding its source code, so that you can recover and document the details of its design.

Being able to understand the design of existing code is a vitally important skill for software developers of all stripes. When you're newly hired into an organization, there will likely be existing code that you'll have to interface with, modify, or extend. When you want to use existing third-party products — especially open-source projects, where the source code is available to you — you'll often find yourself wanting to build on top of them, extend them, modify them, or do troubleshooting; the quality of the source code may even be a large factor in your willingness to adopt the product. We can't allow ourselves to fear "someone else's code," because there's too much to be gained from embracing it.

Obviously, the quality of a design is one determining factor in your ability to read the source code and understand it; in my experience, though, other major factors include patience, concentration, developing an early sense for what parts of a program are likely to be more or less important, recognizing well-known design patterns and techniques (so you can understand larger components without having to hone in on every little detail), and applying the same modularity techniques that you do when you write code (in particular, trying to understand individual parts before trying to understand the whole).

With this kind of work, having other people to share ideas with can be a big help, so I'll require you to work on this project in groups of three.

Group Work

This project will require you to work in groups of three. Each of you will be randomly assigned into a group; each of you will be receiving an email specifying who your partners are. (After sending these out, we'll send an email out to the entire class, so you'll know when you should have received one.) Just as you can't always work with your first choice of people in real-world projects, you won't get your first choice here, either, but this is something worth getting used to; everyone in this course has something to offer, and part of the trick of succeeding in group work is to identify and exploit complementary skills of different group members.

Keep some notes on your assessment of the participation level of each member of the group, as you will be assessing each other in a more formal way at the conclusion of the project, with part of your score determined by others' perceptions of your contribution to the effort. This is partly to keep everyone honest — everyone should be pulling their weight — and partly to acclimate you to the idea that you also need to honestly evaluate others' work in real-world contexts, even in the presence of social and political implications.

Pre-Group Preparation

Getting an Early Look at Guice

Before you begin working with your group, you will want to gain some background knowledge, so you can hit the ground running. Guice is accopmanied by some comprehensive, well-written documentation detailing its use, so your first order to business is to read through and begin to understand what problem it solves, how it solves that problem, and how you can integrate it into an existing program.

Your first step is to head over to the Guice Wiki. A good place to start is the Motivation page in the User's Guide, which does a very nice job of laying out not only Guice's approach to dependency injection, but also more background on why dependency injection is so important in the first place. From there, continue through the User's Guide. Don't worry if you don't understand every detail; the goal in your first reading is exposure and a broad understanding.

Prerequisite Java Knowledge

Depending on what courses you took before this one, you may or may not have seen two features in Java that will be important if you want to complete this project. Before joining your group, be sure you're reasonably familiar with these concepts from Java:

If you ever wondered how JUnit is able to find and execute your unit tests automatically, these two features are the answer: annotations allow you to mark a method as a test, while reflection allows JUnit to find these methods for you and call them automatically. Guice uses similar techniques for a different purpose: to automatically identify places where dependent objects need to be injected, then to facilitate that injection automatically at run-time.

A quick code example from another of my courses would be worth reviewing if you'd like to get an overview or a refresher about these topics:

Downloading and Integrating Guice in an Eclipse Project

There are two distributions of Guice 3.0 that you'll want to download in order to complete this project: the pre-packaged JAR files and the source code. From the download page, download these two files:

To use Guice in a program, you can begin by extracting, within which you'll find a collection of JAR files, which contain compiled versions of the entire Guice framework. Guice is a complex framework, but you won't need to use all of it. We'll stick with the "core" portion of the framework, the compiled portion of which is contained within three of the JAR files in

If you want to write a simple program using Guice, you'll need to include these three JARs on the build path of your project. A simple approach to do that follows:

At this point, you're ready to write a short program to exercise Guice a bit. Do that before you proceed. In particular, be sure you know how to implement a simple AbstractModule, a constructor that includes the @Inject annotation, create an Injector, and ask it for an instance of an object that includes injected dependents.

Recovering the Design of Guice

Once you've experimented with Guice and acquired a feel for the functionality it provides and how to use it, it's time to begin delving into the source code.

Extracting the Source Code and Focusing on the Right Parts

If you haven't already, extract the archive you downloaded earlier. Inside, you'll find a folder called guice-3.0-src that contains a number of things of note:


Your group is responsible for producing the following deliverables:

Each of these documents should be in either Microsoft Word (.doc or .docx) or PDF (.pdf) format.

Making the Most of Your Group

It's best to begin by taking your own individual look at the source code, before meeting with others and talking about it. This will ensure that everyone is entering meetings with information to provide and a readiness to benefit from what others have to say; without everyone being prepared, meetings can be an unpleasant, frustrating experience.

When there is investigative and documentation work to be done, it's fine to divvy it up amongst the group to make the task more manageable. However, do be sure that you meet regularly and resync everyone's knowledge; successful groups will be ones that bring everyone along for the ride and ensure that everyone has an understanding of what's been discovered and documented, so that any given task could theoretically be assigned to anyone who has the available time to complete it.

A Word of Warning

Your exploration of Guice is deeper than any that I've previously done, so I'm sure that you will reach details that are as new for me as they are for you. The underlying techniques are certainly not new for me, but I haven't yet read and digested the entire design of Guice. I'm committed to helping you work through issues, understand the patterns you're seeing, and so on, but you may have to indulge me sometimes when you ask me about a part of it that I haven't seen before. As always, starting the project early and asking questions early enough in the process that you can afford to wait for an answer is paramount.

Submitting Your Deliverables

Submit all of the deliverables to Checkmate, as usual. To ensure that the right version is graded, only one member of each group is permitted to submit, so be sure you know who in the group has that responsibility.

Follow this link for a discussion of how to submit files via Checkmate. Be aware that we'll be holding you to all of the rules specified in that document, including the one that says that you're responsible for submitting the version of your files that you want graded. We won't regrade a project simply because you submitted the wrong version by accident.

Assessing the Work of Your Partners

After you've completed and submitted the project, please download and fill out the following form that allows you to comment on the work done by your partners, along with anything else you'd like to include.

Instructions are specified in the form. Please email this form back to me after you've completed it.