Uncategorized

I am allergic to Strings

I hate raw text strings in source code. In my mind, there is never any good argument for them. Extracting strings into properties files makes sense for externally facing, UI related strings, and I doubt anyone would even disagree with that. However, even strings that are only ever used internally should be extracted. One way to do this is to define Enums.

Consider this slightly contrived example. In mCent we want to track the active country when the mCent application is installed. Here are two methods that are involved in that process:

private void trackCountrySource(String countrySource) {
	self.track(BuildConfig.APPLICATION_ID, BuildConfig.VERSION_CODE, countrySource);
}

private String getCountrySource() {
	String country = getNetworkCountry();
	if(!Strings.isNullOrEmpty(country)) {
		return "network";
	}
	country = getSimCountry();
	if(!Strings.isNullOrEmpty(country)) {
		return "sim";
	}
	country = getDeviceCountry();
	if(!Strings.isNullOrEmpty(country)) {
		return "device";
	}
	return "unknown";
}

At some point during the install, we would make the following call:

trackCountrySource(getCountrySource());

This is fine, its an internal private method and it’s completely under our control. If we want to add a new country source, we can just update the getCountrySource() method. We know what those strings are and what that method can return.

However, what happens when its six months down the road, and a new team is working on a new feature. The PM says, ‘When we get and install from the Great Wall Attribution Co. in China, make sure we track the country source as “gwac”‘.
The developer looks in the source code and finds:

private void trackCountrySource(String countrySource) { ... }

‘Great! that’s what I need’, they think and add the following call:

trackCountrySource("gwac");

So now the possible country source strings are defined in multiple places, the getCountrySource() and wherever that new line of code is added. It makes it that much harder to answer the question ‘What are the possible country install source values that are tracked from the app?’

Now consider this change:

public enum CountrySource {
	NETWORK,
	SIM,
	DEVICE,
	UNKNOWN
}

private void trackCountrySource(CountrySource countrySource) {
	self.track(BuildConfig.APPLICATION_ID, BuildConfig.VERSION_CODE, countrySource.toString());
}

private CountrySource getCountrySource() {
	String country = getNetworkCountry();
	if(!Strings.isNullOrEmpty(country)) {
		return CountrySource.NETWORK;
	}
	country = getSimCountry();
	if(!Strings.isNullOrEmpty(country)) {
		return CountrySource.SIM;
	}
	country = getDeviceCountry();
	if(!Strings.isNullOrEmpty(country)) {
		return CountrySource.DEVICE;
	}
	return CountrySource.UNKNOWN;
}

Usage in the install process looks the same:

trackCountrySource(getCountrySource());

But now, calls like this are not possible:

trackCountrySource("gwac");

New developers to the code can clearly see that trackCountrySource(CountrySource countrySource) expects a CountrySource argument. From there they can see what the CountrySource enum represents and how it works. And more importantly we now have complete control over what it means to be a valid CountrySource.

In a perfect world, there would even be javadoc what each value in the enum represents and what it means. And all you have to do to answer the question ‘What are the possible country install source values that are tracked from the app?’ is simply look at the enum declaration.

So as I said, this is a contrived example, but it gets to the point I am trying to make. You can and should extract your raw strings into enums wherever possible. At least make sure to do so in the PRs you submit for me to review. Or at least be ready to explain why you didn’t.

And in case you’d like to submit PRs for me, we’re hiring!

Discussion

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s