- Multi-language Coding in Modern Business
- Reworking an Example in C Using Metrics
- Reworking an Example in Java Using Metrics
- Five Steps to Better Multi-language Coding
- Summary: Metrics-Driven Coding Improves Quality
Reworking an Example in Java Using Metrics
In Five Steps to Better Multi-language Programming Using Metrics: Simplicity in Multi-language Coding: C/C++, Java, Bash, and Python, I review the block of Java code shown in Listing 5.
Listing 5 JBoss Java code example.
public class ExecutionProfiler { @AroundInvoke public Object profile(InvocationContext invocation) throws Exception { long startTimeSnapshot=System.currentTimeMillis(); System.out.println("Now at the beginning of the interceptor method " + invocation.getMethod() + " startTimeSnapshot " + startTimeSnapshot); try { return invocation.proceed(); } finally { long endTimeSnapshot=System.currentTimeMillis(); long executionTime=System.currentTimeMillis()-startTimeSnapshot; System.out.println("Now at the end of the interceptor method " + invocation.getMethod() + " endTimeSnapshot " + endTimeSnapshot); System.out.println("Method " + invocation.getMethod() + " time taken: " + executionTime + " milliseconds"); } } }
The code in Listing 5 isn’t too bad. This is another key skill to develop; that is, the ability to read code written by other people. The principal method in Listing 5 is called profile(), which gives a good solid hint about its purpose. An educated guess would suggest that this code serves to provide some timing details for execution profiling. It turns out this guess is correct; the choice of a meaningful name by the original programmer has helped the downstream user (that’s us).
In terms of legibility, the code spacing is a little bit off in lines like these:
long startTimeSnapshot=System.currentTimeMillis()
But we can fix those lines with ease, if we like. Now let’s review the metrics.
Metric |
Result in Modified Code (Listing 5) |
Variable names that are too short and provide no usage context |
No change needed. |
Code that provides no context or obvious purpose |
No change needed. |
Inconsistent spacing |
Better. Notice the use of spaces in Listing 5, improving readability. |
Inconsistent parameter-type definition |
No change needed. |
Incomprehensible code |
No change needed. |
Code that’s too long |
No change needed. |
No exception handling |
Needs attention. |
No automatic resource management |
No change needed. |
External calls that are not contained in separate methods |
No change needed. |
Inadequate abstraction (need for higher-level code) |
Needs attention. |
Code that’s difficult or impossible to change |
No change needed. |
Now that we have a metrics-driven blueprint for refactoring, let’s update the Java code and then review the modified version.
Listing 6 illustrates the Java code after examination with our 11 metrics.
Listing 6 Reworked post-metrics JBoss Java code.
public class ExecutionProfiler { @AroundInvoke public Object profile(InvocationContext invocation) throws Exception { boolean exceptionOccurred = false; long startTimeSnapshot = System.currentTimeMillis(); System.out.println("Now at the beginning of the interceptor method " + invocation.getMethod() + " startTimeSnapshot " + startTimeSnapshot); try { return invocation.proceed(); } catch (Exception exc) { exceptionOccurred = true; System.err.println("Exception: " + exc.getMessage()); // Do something with the exception, cleanup, close files, etc. } finally { if(!exceptionOccurred) { long endTimeSnapshot = System.currentTimeMillis(); long executionTime = System.currentTimeMillis() - startTimeSnapshot; System.out.println("Now at the end of the interceptor method " + invocation.getMethod() + " endTimeSnapshot " + endTimeSnapshot); System.out.println("Method " + invocation.getMethod() + " time taken: " + executionTime + " milliseconds"); } } } }
The code in Listing 6 is now less brittle than that in Listing 5. This is because the Listing 6 code takes into account any exceptions that might occur. You might also notice that the exception-management approach used in Listing 5 is very common—using a try-finally statement without a catch clause. This technique is often convenient to code, but in my opinion is quite a dangerous omission. Why so?
Well, in any exception scenario, the finally clause will always execute in any case, even if a catch clause runs. If no catch clause is included (as is the case in Listing 5), then the code running in the finally clause may have suffered some serious exception condition. This exception can then leak back into the main code flow. This is such a serious issue that it even has a name: exception leakage. Leaking an exception back into your main application code is not a recipe for success. This is why the exception handler in Listing 6 is superior to that of Listing 5.