Monday, July 30, 2007

A "new" way of hardcoding

We are all familiar with hardcoding values when programming; mostly out of laziness or we are just not aware of potential solutions based on industries best practices and experience. There are infinite ways to hardcode values. Some are temporarily acceptable based on the cost it would take to change it. However, the majority of hardcoded values should be avoided as it makes your class less reusable, brittle, and the other 500 obvious bad reasons.

A few common examples to make my point:

URI uri = new URI("http://jlorenzen.blogspot.com");
File file = new File("/home/jlorenzen/glassfish.log");

or my personal favorite pet-peeve:

<a href="http://rss-bc.dev.java.net/downloads/download.htm">Downloads</a>


The problem with my first two examples, is that when defined in another class as say instance variables, everyone who uses that class is now forced to those specific values. Some typical solutions include putting values in a database, properties file, var args (main), or System Properties (-D). For my HTML <a> example, always use relative paths: <a href="../downloads/download.htm">Downloads</a>l. Keep in mind that when you use a String and it's not a constant, more than likely you are hardcoding some value.

Now for all you experienced Java programmers, you may not be aware that you are hardcoding values everytime you use the Java keyword "new". When instantiating a new class, you are basically forcing users of your class (most importantly your unit tests) to use that implementation. This is what makes the Factory Pattern so useful and common. But we don't need a factory everytime we need to create a new object. An alternative is practicing Dependency Injection (Inversion of Control). DI is a way to inject an object into a class, passing the control of creating a class to someone else. An easy way to explain DI is its similar to Java's terms IS-A and HAS-A, but instead I refer to it as GETS-A. For me the most important advantage of DI is it easily allows you to write unit tests using mocks objects. Some popular DI containers are Spring, Google Guice, and PicoContainer.

Here is a naive example of code you might write today:

public class MovieManager {
MovieFinder finder = new MovieFinder();

public Movie findMovie(String zip) {
return finder.get(zip);
}
}
Now anyone wanting to use MovieManager is forced to use the MovieFinder class. This makes unit testing this class difficult without using reflection (no thanks). The alternatives are using constructor or setter injection, or passing it as a variable into the findMovie method.

In summary, anytime you instantiate a new object, think about whether or not you want to limit users of your class to that implementation. DI has revolutionized my programming and if you practice it enough your code consequently gets cleaner and more usable.

0 comments: