5 simple coding tricks to make your application more stable
pazvanti
Posted on September 10, 2021
Article originally posted on my personal website under 5 coding tricks to make your application more stable
The stability of your application or web service is important for both you and the user. Making things resilient is not easy, but there are a few coding tricks that you can use in order to increase stability and help you solve problems easier and faster. Here are 5 simple coding tricks that will make your application more stable, will reduce errors and will make you a better coder.
Comparing with a static String
In many applications you will need at some point to compare a string you hold in your variable to a pre-defined value. This is a common scenario and it is really easy to get it wrong, especially for beginners, and it can generate errors that, if not handled properly, can crash your application. How can you get such a simple thing wrong? Let’s look at the following example:
public void doSomething(String parameter) {
if (parameter.equals("new")) {
// do something only in this case
}
// do some more stuff
}
Looks correct, right? Well, this approach hides a NullPointerException that can happen quite often. If, for some reason, the “parameter” is uninitialized and remains null, this will trigger a NPE. The fix is quite easy.
First, let’s extract the value we want to check against. Next, when doing our comparison, instead of using the parameter first, we use our extracted value, since we know that this one is ALWAYS initialized. The new, and much better, code looks like this:
private static final String NEW_PARAMETER = "new";
public void doSomething(String parameter) {
if (NEW_PARAMETER.equals(parameter)) {
// do something only in this case
}
// do some more stuff
}
Use Optional when null can be returned
One of the features that was introduced in Java 8 was the Optional class. Even though it may not seem as much, this wrapper class can be extremely useful in making the code easier to understand, but also in code stability. This is because Optional can represent two distinct reasons.
When as part of a method you have an Optional parameter, it indicates that that method can properly work even if you don’t know or don’t have a value for that parameter. You can just use Optional.empty() and the method will, at least in theory, work well by assigning a default value or ignoring that parameter.
However, if a method returns an Optional it indicates that the method can’t return an answer in some scenarios. Prior to Java 8 this was done by returning a null which can lead to NullPointerExceptions. With optional, it is clearly indicated that an answer is not always provided. Furthermore, it tells anyone that is using that API/method, that the result should be checked with isPresent() and only in this case you should use the result.
Yes, bad programmers can still just call .get() without the check, but this should be easily discovered during code review or by static analysis tools. It does not completely solve the problem, but it should at least make anyone think twice when an optional is returned. The simple fact that you need an extra call to get the value helps with accidentally having null exceptions.
Avoid Exception Swallowing
This is a problem I encountered many times, especially in legacy systems. It is something easy to overlook and, even though it does not cause any problems with the actual processing flow, it makes things extremely difficult to investigate and fix. For those that don’t know, exception swallowing is the act of hiding the occurrence of an exception by not logging it. It is best explained using the example below:
public boolean processData() {
try {
...
myService.process(); // this will thrown an exception sometime
...
} catch(Exception e) {
return false;
}
return true;
}
In this example, the service can thrown an exception. When this happens, we catch it, so no problem with the processing flow, but we don’t log anything. For someone that is later investigating to see why the processing did not happen, he won’t have any information available. This is even worse if the same result (in this case false) can be returned in the try{} block.
Some try to fix this by just logging an error message, as in the example on the right. This, however, does not really make things better. Yes, you know that there was an error processing the data, but not much else. What did actually happen? what caused the error? How can I reproduce it? Below is how to properly fix this and avoid exception swallowing. That is why all logger methods have a Throwable as a parameter. That way you actually have the stack trace printed in the logs and can know where the problem happened and with a bit of luck, the exact cause.
public boolean processData() {
try {
...
myService.process();
...
} catch(Exception e) {
LOGGER.error("Error processing data");
return false;
}
return true;
}
public boolean processData() {
try {
...
myService.process(); // this will thrown an exception sometime
...
} catch(Exception e) {
LOGGER.error("Error processing data", e);
return false;
}
return true;
}
Have a final catch-all statement
Sometime it may be really hard to see in advance all error and exceptions that can occur. Maybe the API has changed in a library you are using after an update to a newer version, or maybe another team member was lazy and forgot to add a catch somewhere. That is why it is important to have a catch statement that encapsulates all your app or service.
There, you can log the exception that occurred and return a proper response to the client. All major frameworks have a feature where you can define what happens in case of an exception, so make sure you use it. For Play, I wrote a tutorial on how to handle exceptions not too long ago that you can read. If your application is called by a client, you will have the possibility to respond properly and not keep them waiting. If it is an application, it at least won’t crash suddenly and can continue to process requests.
Nevertheless, try to have a catch-all statement where everything that went bad is properly logged and the program finishes in a graceful way.
Don’t reinvent the wheel
Regardless of the programming language that you are using, there is a big chance that you will find libraries for many common tasks and features that you have to build. When possible, use them. Don’t try to reinvent the wheel and write everything yourself. In most cases, the code present in such libraries are more robust, handle errors well and have more functionality than you initially think you need.
Make sure that the library is well maintained and, if you are building a commercial project, check the license. Need to parse JSON text? There is a library for it. Want to test your code? There are frameworks for this as well. As a developer, you do not have to write everything from scratch, but know what resources to use and when in order to build your vision and software.
Article originally posted on my personal website under 5 coding tricks to make your application more stable
Posted on September 10, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.