After my pilot article in this series here comes the second part. Enjou your reading!
1. Write small methods and remember about cyclomatic complexity!
What is cyclomatic complexity? It’s a software software metric which tells us the number of independent paths, flows through the source code. We can measure it for a whole application, class, module and function (method). In this case I’d like to focus on function.
Let’s say we have a method:
public String getCapitalCityName(String country) { if (country == null || country.length() == 0) { return "Country name cannot be empty."; } switch (country) { case "Poland": return "Warsaw"; case "UK": return "London"; case "India": return "New Delhi"; case "Russia": return "Moscow"; case "USA": return "Washington"; default: throw new IllegalArgumentException("There's no such country!"); } }
How many return statements do we have here? Too much! The cyclomatix complexity of this method is too high and we need to reduce it. I can for instance introduce enum class with values of country names and its capitals or a map that stores key-value pairs (country-capital in this case). I will go for the first one in this example.
enum Country { POLAND( "Warsaw"), UK("London"), INDIA("New Delhi"), RUSSIA("Moscow"), USA("Washington"); Country(String capital) { this.capital = capital; } String capital; } public String getCapitalCityName(Country country){ if(country == null){ return "Country name cannot be empty."; } return country.capital; }
Now the complexity has been decreased and the code is easier to maintain and add new feateures. Also we will not be able to provide a country that does not exist in the enum as it wouldn’t even compile in this case.
2. Use fields instead of magic numbers
This is very simple but sometimes forgotten rule. Some methods or constructors require us to provide some numbers as their parameters. We are often tempted to pass a bare number of loop iterations or some delay value. It is called the magic number. We should really prevent ourselves from using it. Let’s imagine that you are new to the codebase and see such a magic number. Without any additional information you wouldn’t figure out what’s it all about. Code should to be easy to read and the person that takes over it shouldn’t hate you from the very beggining.
NO:
for (int i = 0; i < 10; i++) { System.out.println("This is going to be printed: " + 10 + " times."); }
YES:
int timesPrinted= 10; for (int i = 0; i < timesPrinted; i++) { System.out.println("This is going to be printed: " + timesPrinted + " times."); } }
3. Not too many method arguments!
Let’s say we have a method like this:
public static void showSentence(String firstName, String lastName, Integer age, String city, String country, String occupation) { System.out.println("User's name is: " + firstName + " " + lastName + " and age of: " + age + ". User is from " + country + " and lives in the city of " + city + " User's occupation is: " + occupation); }
Ok so this is absurdly bad design but it shows the idea. So we have a method that has 6 parameters which is like 4 too much at least. The ideal method is the one that takes no parameters or 1. This is usually impossible to achieve but we need to do our best.
How to improve that?
First of all we need to create a class out of those parameters. We can clearly see that they describe a user.
class User { String firstName; String lastName; Integer age; String city; String country; String occupation; @Override public String toString() { return "User's name is: " + firstName + " " + lastName + " and age of: " + age + ". User is from " + country + " and lives in the city of " + city + " User's occupation is: " + occupation; } } // setters // all args constructor public static void showSentence(User user) { System.out.println(user); }
What happens here? I have created a separate class User that holds all the data and overrides a toString method which is called under the hood when calling println. Now our method takes only one parameter and that’s cool.
The User class has to have an all args constructor or we can use a builder pattern. Or we can set the object’s properties “manually” using setters. It’s still much better that passing all the bare parameters to the method. Speaking of constructors and builders, you need to get familiar with Project Lombok. It takes a lot of boiler plate code away by simply using annotations! I really encourage you to check this out.
Thatβs it when it comes to part II of my series. See you round!.
Should you have any questions, donβt hesitate to reach me via linkedin, facebook, email or via comments.