DEV Community

Aaron McIntyre
Aaron McIntyre

Posted on

Consistent success on easy problems in really boring.

Consistent success on easy problems is really boring - getCode()

What is the worst bug you have ever had in an application?

getCode() was a 2+ year long bug that would not go away. I have nightmares about getCode(). Here is the deal…

Our app was written by a contractor and they did not use the best mobile coding practices. My description of the app at that time would be “It is a Java app running on an Android Device” It was fighting default android the entire way.

When I joined it was already an issue. My predecessor could not find the issue and that was clear to me because in the core login logic there was an if statement that went something like this…

Copy code
String code = _loginInfo.getDefaultCurrencyCode();
if (code == null || code.length() == 0 || code.trim().length() == 0
        || code.trim().toLowerCase().equals("null")) {
    _loginInfo.setDefaultCurrencyCode("USD");
}

Enter fullscreen mode Exit fullscreen mode

So in a global application if we could not find a currency we would default to USD. That it did not help at all and causes real problems with reports and currency conversions. After a few deep dives on the problem and a lot of logging I found out what was really happening and dubbed the problem the getCode() problem.

A currency has a currency code and a user has a default currency. Problem occurs when default currency is null. The currency is fetched from the database by currency code instead of id mostly so we can call getCode()… (facepalm)

Copy code
public static Currency defaultCurrency() {
    Currency defaultCurrency =
        DataModel.findSingleRecordWithFieldValue(Currency.class, "code",
        LoginInfo.getInstance().getDefaultCurrencyCode());
    return defaultCurrency;
}

Enter fullscreen mode Exit fullscreen mode

So the database is empty when this is executed and it returns null. why? (Tried to add null check here but we still do not have a currency) User is not allowed into the app until they have a default currency from login. And we do not delete currencies from the database… except. we do.

getCode crashes were happening more often around app upgrades. When user upgrades the app we erase the database when we have made changes to it and rely on a full sync to restore everything. UserDefaults are stored in shared preferences including currency code. So on upgrade user is allowed into the app.

I started digging. Found that when we upgrade we set a static variable called shouldSyncOnLogin that triggers a full sync and works with the database upgrade to ensure everything works. I was sure this was the problem. I tested it out over and over and could not make it crash. For 2 years I made multiple attempts to find other issues that might cause missing database entries and attempted a few fixes that always just pushed the error to another place. We started adding analytics around this specific crash trying to wrap our heads around it.

Then one day I had this thought about that static variable… What if the app was not around after the upgrade? - If android kills the app, <– it can do this. - then the static variable telling app to sync gets reset to false, - and the app never syncs on relogin. - If it never syncs then it never has any currencies to look up in the database.

My theory was simple

. The average mobile user does not upgrade the app and then watch the upgrade happen like we were doing in test. They click upgrade and then put the phone in their pocket. I confirmed this issue when a co-worker walked up to me a day later and described my exact use case. I was able to track it to a specific getCode() crash within our crash logs.

My fix was simple. Persist the static variable to shared preferences and reset it accordingly.

Because this affected EVERYTHING we did a soft test of this by implementing my fix in a release but only to compare to current variable. Results were only logged if the variables were different. We got results and after 2 years I actually jumped out of my chair because we finally found the problem and fixed it.

It was such a relief to finally fix this issue. It was a hard problem to solve and it took a lot of time and effort, but it was worth it in the end. It's not always easy to find and fix bugs, but it's always worth it when you do.

I look back and wonder how I did not find this sooner I have to remember that this is the one bug that nobody could solve. I have a love hate relationship with issues like this. Most do not last this long and they give me drive me in this profession. But it is issues like this that remind me that success is not as meaningful when there are no failures behind it. Solving difficult problems can be frustrating and time-consuming, but it's also a great opportunity to learn and grow as a developer. The next time you're faced with a difficult problem, remember that it's a challenge worth facing.

So, don't be afraid to take on a difficult problem. Embrace it, and enjoy the journey of solving it. Happy coding!

Top comments (0)