views:

43

answers:

2

I plan to create 3 editions of a piece of software in java from existing code base. what's the best practice? should I create 3 different projects one for each edition? Also any tools for managing editions?

+1  A: 

My first thought would be to keep a single codebase if at all possible and use some kind of flag for switching.

If not possible, I'd try to keep as much as possible the same and have the larger project use the smaller project as a sub-project, If possible automatically enabling some features--for instance, each of the projects could have it's own main, the different builds may just call the different mains which set flags to enable features.

If your flags are final, it should even avoid pulling unnecessary code into your project at all.

Finally, worst case, 3 branches in Subversion.

Edit:

You made me think a bit more on this and I think I found a better solution.

I think I'd separate this into four projects, combining all the "common" stuff into a base project and the stuff that is different, I'd spread out to the other three projects--so let's say you have base, demo, pay and business projects..

Where the three might differ, you would have an object from one of the demo/pay/business classes provide the functionality. For instance, if the pay version has new menu items, you might have a getMenuItems in one of your objects. It would return a menu tree that you could place in your menu bar. The demo version would have less items.

In this way your "Base" never knows which version it's running, it just uses objects.

To get the objects, I'd have a factory. The factory would look something like this:

private String[] availablePackages={"business", "pay", "demo"};

public getMenuClass() {
    Class c;
    for(String package : availablePackages) {
        try {
            c=Class.forName("com.meh.myapp."+package+".MenuClass");
        } catch... {
            // No package by that name
        }
        if(c != null) {
            return c.newInstance();
        }
    }
    // Something went wrong, no instance found.

The updraft is that you should try to instantiate com.meh.myapp.business.MenuClass first, then try ...pay.MenuClass finally ...demo.MenuClass.

This should allow you change your configuration by simply shipping different jars--If you decide to only ship the demo and main jars, you'll get a demo app. By shipping the pay jar you'll get the pay app.

Note that it's pretty likely that you'll want business to delegate much of it's work to "pay", and "pay" to delegate a bunch of it's work to "demo", but demo knows NOTHING of business or pay, and "main" only knows of the other three reflectively.

This would be a nice solution because there is no configuration required--in fact, you'd only have to ship the pay jar to upgrade from demo to pay, the main and demo jars are reused and stay right where they are.

Bill K
do you have any links to the final flag for java compilation? a quick search didn't yield me much info. how does it throw away unused code?
What I meant was not a compile flag, I meant if you have a variable that is final, such as "private final boolean INCLUDE_CODE=false" anything protected by it, for instance: "if (INCLUDE_CODE) myVar=new SpecialClass();" SHOULD never even compile into the code. It should recognize that it can never be true and optimize it out. If this is the ONLY place that SpecialClass is referenced, then SpecialClass shouldn't be pulled into your project at all--but I may have come up with a better solution anyway, re-read my answer.
Bill K
A: 

The ideal way would be dividing your app into "core", "additional stuff", "more additional stuff" and combine these dependencies. This would probably be a lot of work depending on the code base you have, though.

If you use SVN for source code management, you can create 3 branches for each edition from the existing code base. Generally people try to avoid that because e.g. if you need to fix a common bug across these branches, you will need to fix that one in one of the branches and then merge that to the remaining branches. Maybe other source repositories handle that kind of situations better, but for SVN, I guess this is the only way.

As for managing versions, we use maven. If you take the "core", "additional stuff", "more additional stuff" approach, maven can help because it can track the version of each component pretty cleanly (using pom).

EDIT:Bill's suggestion is probably the most practical. If you use a final flag, yes the compiler should throw the unreachable code away.

Enno Shioji