How to Love Your Code

1. Introduction

In this article, I am going to present my strong personal opinions on various aspects of the code, legacy applications, and why that existing ugly looking method does not use generics? Feel free to agree, disagree, and provide any constructive feedback.

2. The Problem With Legacy Code

The main problem with the legacy code is that it isn’t the problem at all. That ugly looking method that heavily relies on HashMap was written in Java 1.4, when no had heard about the fancy word Generics. Before cursing the existing code for not being readable and not doing what we want, try to understand the circumstances under which it was written.The code might not do what we want, but hey, this the exact code that is running on production and earning $$ for the company. It is doing exactly what it’s supposed to do. It is the code that the customers are using day in day out. This is the code that generating the revenue and even our salaries.

The code might not do what we want, but hey, this the exact code that is running on production and earning $$ for the company. It is doing exactly what it’s supposed to do. It is the code that the customers are using day in day out. This is the code that generating the revenue and even our salaries.

Now, don’t think I am promoting spaghetti and unstructured code in any way. My point is, if we have a problem, then we should carefully look at it, observe it, and then try to think of ways to resolve it. We can’t just curse it and sit with hand on our hand.

Many times it happens that when I look at the code that I wrote six months back, I immediately think, did I write this crap? I am sure there will be many who agrees to this. If we can’t appreciate our own code that was written a few months back, how can we blame the code that was written 2, 5, or even 10 years back.¬†Believe me, that code was “as per the current industry standards” while it was written.

3. Stop Complaining, Start Acting

So, what should be done in this case? Improve the code. But how?

Utmost care should be taken while refactoring the legacy code. And, by the way, there is a reason it’s called “legacy code”, because it has written a legacy (I think this one is from ¬†Joel Spolsky).

Completely rewriting the entire code base is almost never a good idea. However, refactoring it bit-by-bit is the approach that we should embrace.

In our team, first, all of the team members agreed that we need to improve the existing code. Then, we identified some of the ways that we can achieve this, some automated, some manual. We took several pledges to reach our goal.

Pledge 1: Clean the Surroundings

First, we decided to start cleaning the surrounding area of code where are working. Remove the dead code and commented code, add generics to that ugly looking method, extract common code in separate methods to make it DRY, and many other small things. This started building the confidence in our team. Such things are very easy to master if you can make good use of your IDE.

Pledge 2: Strict Code Reviews

We decided that we will commit the code without peer reviews. This helped us to stay on track and avoid the temptation of “cheating”. This also made sure that everyone on the team is committed towards our common goal. This went for a while until everyone developed confidence in everyone else.

Pledge 3: More and More Junits

This is the best thing that we decided to do. Writing Junits, mocking, spying, stubbing, these quickly became the buzz words. Writing automated test cases gave us tremendous confidence to refactor the existing code with even more speed. I personally decided to never compromise on automated tests after this experience.

Pledge 4: No Sonar Criticals/Blockers

We integrated SonarQube with our project. The results of the first scan were really disappointing, but we didn’t lose hope. We worked hard to resolve the Blockers and Criticals until there were zero occurrences. Later, we started our nightly builds and integrated SonarQube with it. Every morning, we use to verify if the code committed yesterday is having any high priority issues. Gradually, we started focusing the Major issues.

This helped us reduce code smells and code complexity.

4. Well Done Is Better Than Well Said

I admit that it’s not as easy as it might sound. It took us almost a year before everyone started appreciating the code. Our clients thanked us, our managers appreciated us, and everyone was more confident than ever. But this has not yet stopped. This has to continue. There are still several areas of improvements. This is a “legacy”.

Replacing Conditional Getters With Functional Programming in Java

1. Introduction

In this small article, we will have a look at how to efficiently write a code that runs a getter (or any other method) based on some input using functional programming.

2. Problem

Instead of explaining it in words, let me show you the code directly:

private int normalMethod(MyPojo pojo, Actions action) {
    if (action == Actions.ACTION1) {
        return pojo.getActionOne();
    } else if (action == Actions.ACTION2) {
        return pojo.getActionTwo();
    } else if (action == Actions.ACTION3) {
        return pojo.getActionThree();
    } else {
        return pojo.getActionFour();
    }
}

As we can see, we are calling the appropriate getter based on the Action that we get in the input. This seems to be pretty decent at the moment, but as and when there are new actions/getters, we need to modify the code and the chain can grow longer.

3. Solution

One good solution to this is to make use of functional programming in Java. For this, we need to create a mapping of the Actions to method references:

public static final Map<Actions, Function<MyPojo, Integer>> GETTERS_MAP = new HashMap<>();
GETTERS_MAP.put(Actions.ACTION1, MyPojo::getActionOne);
GETTERS_MAP.put(Actions.ACTION2, MyPojo::getActionTwo);
GETTERS_MAP.put(Actions.ACTION3, MyPojo::getActionThree);
GETTERS_MAP.put(Actions.ACTION4, MyPojo::getActionFour);

As we can see, we have mapped every Action to the corresponding getters. Once this is done, our long if-else chain now reduces to only a couple of lines:

private Integer functionalMethod(MyPojo pojo, Actions action) {
    Function<MyPojo, Integer> getter = MyPojo.GETTERS_MAP.get(action);
    return getter.apply(pojo);
}

And that’s it. Even if we need to add another Actions/getters, we just need to add an entry in the Map. The method above doesn’t need to be modified.

4. Conclusion

We have observed that functional programming opens new doors of creativity. Please find the full source code of this article on GitHub.