Java is a habit-forming programming language. After a few years, good programmers find efficient ways to code. They’ll accept the programming language’s shortcomings. And they’ll make the best of a not-so-good situation. Pair programming and code reviews have provided a means for programmers to share ideas. They learn from each other to write better and cleaner code. It’s a social experiment of sorts. The more you are exposed to other developers and their code, the more your skills improve. It’s an evolution.
Programming in any organized programming language is more than just simple programming. It’s an adventure in style. Breaking down complex code into functions, loops and control structures. This styling helps in writing logic into maintainable code. That’s if everyone evolves and follows the cultural norms. Tools like SonarQube help in some of these issues. But there is more to it than just adhering to SonarQube’s guidance.
After a few years of development, you notice certain coding patterns. Bits of code you write every day to make your code easier to read and maintain. Often you’ll write the same lines of code over and over again, but each with different variable names or circumstances. All this boilerplate code is implemented in most cases to improve performance. Increase readability. Or to prevent common errors and exceptions from occurring.
But in many cases, when a community adheres to a socially accepted way of doing things. Often the tools used by that community adapt. After all, if you want to keep the community as a whole happy, you give them what they want. Unfortunately, when it comes to the development community, the compilers and interpreters don’t often adapt to how programmers use a given the language. Sure, new features are added to make the language more complex. But never are features added to make a language less bothersome.
A programming language’s tools should be intelligent enough to recognize often used coding patterns and optimize the code to reflex their purpose. How often has a developer assigned an ugly and complex data structure to a simple variable? And then used that variable going forward simply because it was cleaner and more convenient. Yet under the hood, the compiler creates another variable in the heap. Taking up more memory, executing more instructions, when in fact simplicity was the intent. There are several similar scenarios. Like single-use code that is extracted into private methods but never inlined when compiled.
Having said all this, even though compilers and interpreters should improve to become better tools. Developers should be more open to learning new coding patterns. Below is a short list of the ones I’ve used. You’re welcome to share your own.
Coding Patterns
In the sample code below I’ve implemented four coding patterns that I use often. Recognizing those patterns help in several ways. One of which is being able to write better unit tests. All of these patterns should be self-explanatory.
Coding Pattern #1: Extract complex logic into a method
Any messy lines of code that doesn’t alter the logic of the main function I usually extract. I especially try to do this when the method I’m calling might throw an exception that would require ugly exception handling code that can be handled locally. The purpose is to make the top level of the call stack function to be as succinct and easy to understand as possible.
Coding Pattern #2: Assign long complex structure to a simple variable
Java, being an OOP language, often has these deep and complex data structures. And as always, these lend to an extremely long chain of accessors. And if the variable names are long, can result in a multi-line statement. If the terminal point of this chain needs to be accessed several times, it can be advantageous to assign that terminal object to a simple variable.
Coding Pattern #3: Extract a complex condition into a method
Sometimes business logic can be complex. Requiring multiple conditions to be verified in order to execute one line of code. It can be very daunting when the overall condition is difficult to understand. This is especially true when working with legacy code that may not contain little to no documentation. It can be a good idea to extract the full or partial condition to a method and provide a meaningful business description to the method.
Coding Pattern #4: Validate variables are not null and arrays are not empty before using them
As stated above, Java often has deep and complex data structures. This always requires the developer to check that any portions of the data structure aren’t null or that arrays aren’t empty before getting to business. This often doubles the length of a statement but is necessary to prevent obvious bugs. It’s painful and tedious coding, but always necessary.
Sample Code
public class Sample { public static void main(String... args) { List<Cart> cart = createCart(); Item item = getFirstItemInCart(cart); System.out.println(item.itemName + ": $" + item.itemRegularPrice.toPlainString()); } // Coding Pattern #1: // Extract complex logic into a method. private static Item getFirstItemInCart(List<Cart> shoppingCarts) { Item item; if (isFirstCartItemExist(shoppingCarts)) { // Coding Pattern #2: // Assign long complex structure to a simple variable. item = shoppingCarts.get(0).shoppingItems.get(0); } else { item = new Item(); item.itemName = "No product"; item.itemRegularPrice = new BigDecimal("0.00"); } return item; } // Coding Pattern #3: // Extract a complex condition into a method. private static boolean isFirstCartItemExist(List<Cart> cart) { // Coding Pattern #4: // Validate variables are not null and arrays are not empty // before using them. return cart != null && !cart.isEmpty() && cart.get(0) != null && cart.get(0).shoppingItems != null && !cart.get(0).shoppingItems.isEmpty(); } private static List<Cart> createCart() { List<Cart> cart = new ArrayList<>(); cart.add(new Cart()); cart.get(0).shoppingItems.add(new Item()); cart.get(0).shoppingItems.get(0).itemName = "Teddy Bear"; cart.get(0).shoppingItems.get(0).itemRegularPrice = new BigDecimal("12.99"); return cart; } static class Cart { List<Item> shoppingItems = new ArrayList<>(); } static class Item { String itemName; BigDecimal itemRegularPrice; } }