The Final (Constants) Story - Conditional Compilation Variable Location (Page 7 of 7 )
When implementing conditional compilation, the question of where to put these compilation variables always comes up. There are many potential solutions to the problem, but you need to watch out for a couple of pitfalls.
First of all, putting a variable in the top-level package of your product is probably not a good idea. The problem is that there may be other classes in this package as well. Since all classes will be referencing this package, you could accidentally create circular package dependencies.
Circular dependencies arise when Package A depends on Package B, which in turn depends on Package A. Circular dependencies make it very difficult to separate code into components, and circular references make code fragile by allowing bugs to migrate across the dependencies into other packages.
Your best bet is to create a new package in each of your major products. If you are an employee of a Sun, for example, each major product would be defined by the package directly undercom.sun. I like to create a package named_developmentunder the major packages of my clients’ products. The leading underscore helps me remember that this package is not part of the product base but is instead a container for things such as these variables. Inside this new package, place a class namedDevelopmentMode.
In this class, install one variable for each package in your product. Then you can simply import the class and access the appropriate variable. For the Hardcore Java example code, the class would look something like the following.
package oreilly.hcj._development;
public final class DevelopmentMode {
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_bankdata = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_collections = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_constants = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_datamodeling = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_exceptions = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_finalstory = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_immutable = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_nested = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_proxies = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_references = true;
/** Development mode constant for package oreilly.hcj.bankdata. */
public static final boolean hcj_review = true;
private DevelopmentMode() {
assert false: "DevelopmentMode is a Singleton.";
}
}
In this class, you don’t specify theoreillypackage because it would be a bit redundant, since all the code you would be writing for your company would be in that package. However, the variable naming here is a matter of taste. The important fact is that all packages can be turned from development to deployment mode in one place. Using the constant is easy:
package oreilly.hcj.finalstory;
import oreilly.hcj._development.DevelopmentMode;
public class ConditionalCompile {
public void projectVariables(){
if (DevelopmentMode.hcj_finalstory) {
// ...do conditional code.
}
}
}
You merely use the constant in the same way it was used in the last section. This allows you to take advantage of conditional compilation in a maintainable manner. However, be careful not to place any malfunctioning code into the_developmentpackage (or whatever you named your package), or you may create circular package dependencies. The_developmentpackage shouldn’t depend on anything other than third-party libraries and the JDK itself.
Using final as a Coding Standard I imagine that many of you never thought you would see an entire chapter written on a single keyword. However, this particular keyword is quite useful. I strongly advise that you spread final all over your code. You should use it so much that not seeing it becomes a rare, if not completely unknown, occurrence.
This coding standard may take a little getting used to but it will really pay off in the long term. The best way to get started is to force yourself to usefinalheavily whenever you write or edit code. Also, you should force the junior developers working for you to adopt the use offinalas a coding standard. They may grumble and balk for a bit, but the coding standard will quickly become so automatic that the developers won’t consciously think about it.
Like good Javadoc habits, this one is much easier to implement if you do it while you are coding. Having to go back through old code to implement the standard is a real pain. For this reason, I suggest you make it a coding standard starting today. If you have tools that allow you to edit the code templates, edit them to introducefinaleverywhere you can. Also, when you edit someone else’s code, introduce thefinalvariable liberally. Doing so helps to guarantee that no one can mess up your code without actually trying to do so.