My main() Method Is Better Than Yours

August 29th, 2008 · 7 Comments ·

By Miško Hevery

People are good at turning concrete examples into generalization. The other way around, it does not work so well. So when I write about general concepts it is hard for people to know how to translate the general concept into concrete code. To remedy this I will try to show few examples of how to build a web application from ground up. But I can’t fit all of that into a single blog post … So lets get started at the beginning…

Here is what your main method should look like (no matter how complex your application) if you are using GUICE: (src)

public static void main(String[] args)
  throws Exception {
    // Creation Phase
    Injector injector = Guice.createInjector(
             new CalculatorServerModule(args));
    Server server = injector.getInstance(Server.class);
    // Run Phase
    server.start();
}

Or if you want to do manual dependency injection: (src)

public static void main(String[] args)
  throws Exception {
    // Creation Phase
    Server server = new ServerFactory(args)
                               .createServer();
    // Run Phase
    server.start();
}

The truth is I don’t know how to test the main method. The main method is static and as a result there are no places where we can inject test-doubles. (I know we can fight static with static, but we already said that global state is bad here, here and here). The reason we can’t test this is that the moment you execute the main method the whole application runs, and that is not what we want and there is nothing we can do to prevent that.

But the method is so short that I don’t bother testing it since it has some really cool properties:

  1. Notice how the creation-phase contains the code which builds the object graph of the application. The last line runs the application. The separation is very important. We can test the ServerFactory in isolation. Passing it different arguments and than asserting that the correct object graph got built. But, in order to do that the Factory class should do nothing but object graph construction. The object constructors better do nothing but field assignments. No reading of files, starting of threads, or any other work which would cause problems in unit-test. All we do is simply instantiate some graph of objects. The graph construction is controlled by the command line arguments which we passed into the constructor. So we can test creation-phase in isolation with unit-test. (Same applies for GUICE example)
  2. The last line gets the application running. Here is where you can do all of your fun threads, file IO etc code. However, because the application is build from lots of objects collaborating together it is easy to test each object in isolation. In test I just instantiate the Server and pass in some test doubles in the constructor to mock out the not so interesting/hard to test code.

As you can see we have a clear separation of the object graph construction responsibility from the application logic code. If you were to examine the code in more detail you would find that all of the new operators have migrated from the run-phase  to creation-phase (See How to Think About the “new” Operator) And that is very important. New operator in application code is enemy of testing, but new in tests and factories is your friend. (The reason is that in tests we want to use test-doubles which are usually a subclass or an implementation of the parent class. If application code calls new than you can never replace that new with a subclass or different implementation.) The key is that the object creation responsibility and the the application code are two different responsibilities and they should not be mixed. Especially in the main method!

A good way to think about this is that you want to design your application such that you can control the application behavior by controlling the way you wire the objects together (Object collaborator graph). Whether you wire in a InMemory, File or Database repository, PopServer or IMAPServer, LDAP or file based authentication. All these different behaviors should manifest themselves as different object graphs. The knowledge of how to wire the objects together should be stored in your factory class. If you want to prevent something from running in a test, you don’t place an if statement in front of it. Instead you wire up a different graph of objects. You wire NullAthenticator in place of LDAPAuthenticator. Wiring your objects differently is how the tests determines what gets run and what gets mocked out. This is why it is important for the tests to have control of the new operators (or putting it differently the application code does not have the new operators). This is why we don’t know how to test the main method. Main method is static and hence procedural. I don’t know how to test procedural code since there is nothing to wire differently. I can’t wire the call graph different in procedural world to prevent things from executing, the call graph is determined at compile time.

In my experience that main method usually is some of the scariest code I have seen. Full of singleton initialization and threads. Completely untestable. What you want is that each object simply declares its dependencies in its constructor. (Here is the list of things I need to know about) Then when you start to write the Factory it will practically write itself. You simply try to new the object you need to return, which declares its dependencies, you in turn try to new those dependencies, etc… If there are some singletons you just have to make sure that you call the new operator only once. But more on factories in our next blog post…

Tags: Advice · Rant · Testability

7 responses so far ↓

  • Abhirama // Sep 6, 2008 at 11:37 pm

    I have a doubt regarding the separation of object graph creation and application running. Say I am writing a person class and the constructor takes weight as an argument. Now I want to make sure that the weight assigned is within some bounds, say it should not be negative or something like that. Do you advocate doing this validation in the constructor itself, before assigning to the weight instance variable?

    Btw thanks for the wonderful blog.

  • Where Have all the “new” Operators Gone | Miško Hevery // Sep 10, 2008 at 10:23 am

    [...] My main() Method Is Better Than Yours we looked into what a main() method should look like. There we introduced a clear separation [...]

  • iwamot // Jan 18, 2009 at 1:30 am

    Hi Misko, I’m a manual DIer (and am a Japanese).First, for the second example, I think the ‘args’ should be passed to the createServer() method. The constructor doesn’t seem to use it. Any reasons?Second, I think there should be a ‘Parsing Phase’ before the ‘Creation Phase’. The ‘args’ often needs to be parsed by a parser(ex. Commons CLI). What’s your opinion?

  • misko // Jan 18, 2009 at 9:39 am

    Hi Iwamot,

    The GUICE module should be one responsible for parsing the args using your favorite CLI parser. The module should than set up different bindings based on the arguments. Once GUICE builds the server and hands it back to you the server is already wired with all of the configuration information set. You just need to start it.

  • peter // Sep 6, 2009 at 5:30 pm

    Hey!
    Maybe I’m missing the point here, but why not wrap the startup task inside a command (pattern)eg. ApplicationStartupCommand that takes a Server and args as the constructor arguments ..
    eg.

    public class ApplicationStartupCommand extends Command{

    Server server;
    ApplicationStartupCommand ( Server server){
    this.server = server
    }

    public void Run(){
    server.Start(); }
    ….
    }

    }
    Then the ApplicationStartupCommand becomes testable (because we’ve seperated it from the application and we can mock the server) and the main method (applying MY simple mind to this) becomes.
    // for the Manual injection
    static void main(String[] args){
    Command startup =new StartupCommand ( new ServerFactory(args)
    .createServer() ) ;
    startup.Run();
    }

    I’m not a Java guy so forgive me for not know what the server factory etc does.

    It would be cool if you could shed some light on the above.
    Once again, Thank you

  • misko // Sep 9, 2009 at 8:53 pm

    @peter,

    Your reasoning is correct, if the main method is responsible for instantiating and wiring all of the pieces together, how does one tests the wiring without actually running the application. The solution is to move the instantiation/wiring into a separate class (which we call factory)

  • David Leppik // Feb 18, 2011 at 10:27 am

    Actually, the main method is the easiest method at all to test– so easy that you often don’t even need to test it!

    Assuming you’ve tested all the code going into main, when you run the program, it’s either going to run properly or it’s going to fail spectacularly, and often with an obvious cause. Typically there aren’t that many permutations to the command line arguments, and each one should be easy to test.

    The reason I say you often don’t need to test it is that many main methods (for the sorts of programs I write at least) do exactly one thing, and I’m going to be running it before I hand it off to anyone else. And if I’m bothering to write a main method at all, somebody’s going to be using it right away. Which means that even if I were silly enough not to run it before handing it off, the bug would be discovered and I would get my well-deserved public shame long before a customer gets the code.

Leave a Comment