Always choose a compile-time error over a runtime error where practical.
This is because compiler errors allow developers to spot problems before the application runs. Runtime errors may only surface when the application is tested, or worse; when certain rare conditions are met in production.
So non-compilable code (runtime executed code) can burn a lot of time on a project. The list of culprits includes:
Javascript
CSS
SQL
JSPs
Shell Scripts and Batch Files
Code in XML (e.g. Mule, Ant)
The problem with all these interpreted languages and formats is that syntax errors cannot be detected until the program is executed. Java code will display a compile error during the build (prior to execution) if it is not correct syntax.
If there is a choice between one of the above approaches and Java, always choose Java provided the following are true:
Your Java solution solves the problem by changing a runtime error into a compile-time error.
Your Java code is still written in the common way that all software of its class is written. For example, most Java web projects use JSPs, therefore you should probably JSPs instead of rendering HTML in Java code.
If any runtime interpreted code must remain in the project, try to precompile it as part of the build process.
Runtime Language |
How to validate |
Javascript |
There are some neat javascript unit test tools (e.g. jsunit) and linters (e.g. jslint) that can improve your certainty. |
SQL |
Some databases provide ant tasks that will validate SQL. Object Relational Mappers (ORMs) such as Hibernate thankfully remove many of opportunities for developers to write SQL. |
JSPs |
JSPs can be precompiled using a jspc ant task. Note that it is generally not recommended to deliver precompiled JSP class files in a WAR file as this can lock the WAR to one particular application server, but precompilation can at least verify a JSP will work when it is later accessed and re-compiled at runtime. Currently the very long time taken to precompile JSPs outweighs the benefits of doing it all the time but it could be done as part of a nightly automated build rather than on every developer PC. |
Shell scripts and batch files |
Few validators exist, so use this technology sparingly. Scripts execute differently depending on the Operating System the software is on, unlike Java. |
XML |
Many validators available, provided you have an XSD. If you do not have an XSD, write one. |
As an example, the following method needlessly used a runtime value to perform its task.
private static Canvas GetNokiaCanvas()
{
private static final String CLASS_NAME
= "com.bicoz.j2me.nokia.CanvasNokia";
try
{
Class canvasClass = Class.forName(CLASS_NAME);
return (Canvas)canvasClass.newInstance();
}
catch (Exception ex)
{
:
}
return null;
}
This function worked well until the library which contained the CanvasNokia class changed package names in an update. Nobody understood why the project still compiled but all of the Nokia devices failed.
The bug was missed because the String “com.bicoz.j2me.nokia.CanvasNokia” was not checked at compile time.
A simple change from a String to a compile-time reference would have solved the problem by creating an obvious build error:
import com.bicoz.j2me.nokia.CanvasNokia;
:
private static Canvas GetNokiaCanvas()
{
return new CanvasNokia();
}
Summary: reduce the amount of runtime code execution that occurs to improve software quality.
Exception: Sometimes runtime values are allowed because they are related to the execution environment of the program. For example database connections make sense to evaluate at runtime because the database server can be up or down at any time, and may depend if the application is running in Test or Production mode. Moving database connection configuration into a Java class would make no difference – the connection would still be made at runtime.