Tuesday, March 27, 2012

Internationalization, In Spirit - Part 2: Cultural Sensitivity

In Part 1 of this series, I touched upon how software should target a wider audience by being easy to consume by people around the planet. I used the term "internationalization" in that post, but I really meant a combination of internationalization (i18n) and localization (l10n). In this post, and the rest of this series, I use these terms interchangeably. I realize technically speaking they are different but I really think both these terms should for the most part, be mentioned in the same breath.


In my opinion, the biggest missing piece in the whole global software story is cultural sensitivity. When designing, developing and distributing software, we often overlook the fact that the user of this software could be from a culture that is diametrically opposite to our own. Let me refrain from taking names; but for a moment take a look at the list of software installed on your computer or phone and you will know what I mean. How many of the concepts presented in these software are you really familiar with?

I will draw up a list of hypothetical examples here to drive home my point:

  • Imagine a software tool that has one particular “fun” feature and names it Aloha. Now an American might immediately associate Aloha with Hawaii and therefore with fun, but what difference does it make to a person on the other side of the globe?
  • Imagine a role playing game in which one particular level involves the player attending high school prom. If your game targets a global audience, chances are most of your users have never been to prom; and those who do not have Hollywood influence don’t even know what a prom is.
  • Suppose you have a game where you grade your players according to high scores. What do you think would be the consequence of grading them as “Sachin”, “Viru”, and “Dhoni”? I’m sure people from non-cricketing nations reading this post won’t even get the reference.

One can go on and on pulling out examples, but you see where this is heading, don’t you? The underline here is this: In an attempt to make a product more user-friendly, we tend to link it to things that we see and use every day. Unfortunately, we fail to realize that those very “things” might be totally unheard of in markets where our products are targeted.


I don’t believe there is an easy solution though. None of the options seem to be good in their own right.

  • It is highly improbable that one will find one concept that fits all cultures.
  • The costs associated with adapting the very concepts the product is based on, to various cultures, is sure be prohibitive.
  • Keeping things culture-neutral is likely to make the product dry and boring - a kill-joy for sure.

In the end it is a matter of finding the balance that works for you. But before arriving at that formula, it is worth considering the cultural aspect in some detail so as to be in the good books of all end-users!


In the next installment of this series, we will look at how the software development community could be more inclusive of developers around the world.

Monday, March 19, 2012

Override and Debug

What would we ever do without a debugger eh? In the Java world, it’s JPDA. Integrated with your favourite IDE, it makes debugging your source code a breeze. Just set a breakpoint someplace in your code, and then step through.

But wait. What happens when you step into code that’s outside your project? What if you step into a method that’s from a library, or from the core platform itself? You end up seeing something illegible: some bytecode, or just a “Source not found” message (if you are using Eclipse that is). Go ahead: try it out:
  • Write a bare minimum “Hello World!” application.
  • Put a breakpoint at the line where you print the message to System.out.
  • Now debug your application and step into the System.out.println method.
What do you see?

 

Solutions?

The best solution, of course, is to attach the source code, if available. Unfortunately, most of the time the source code is not available, and even if it is, “attaching” it is not the easiest thing to do. If you have worked with Android, you know what I mean.

What’s the second-best solution? Use the override-debug technique. Although this technique does have its limitations (as we will discuss later in this article), it does turn out to be useful in a large number of use-cases. The technique is as follows:
  • Choose the library method that you wish to debug. Note that you might not care about the method that you call directly from your code. Instead, you might be interested in a method, say, four levels deep in the call stack.
  • Extend the class which contains this method, and override it.
  • Simply call the super method in the overriden implementation.
  • Finally, while debugging, put a breakpoint in the brand new one-liner method that you just implemented.

Congrats! You’ve just managed to see what’s happening four levels deep in the call hierarchy; without even having the source code.

 

Show me some Code!:

Much of that did not make sense, did it? Probably because it was all text and no code? Fear not, for the code example is here!

I use an (admittedly contrived) example to demonstrate this technique. I have a Laundry class and a doLaundry() method within it which takes a bunch of clothes as arguments. This method
  • First invokes the WashingMachine object to wash and rinse the clothes.
  • Then it calls upon a Dryer to spin them.
  • Finally, it hangs out the clothes to dry on a Clothesline.
All of this is within a library for which you don't have the source.The objective is to debug what is happening when the control reaches the Clothesline.hang() method.

public class LaundryRunner {
  private static Laundry laundry = new Laundry();

  public static void main(String[] args) {

    /*
     * Initialize the clothes for laundry
     */
    List clothes = new ArrayList(3);
    clothes.add(new ClothingItem("shirt", "white", "stained"));
    clothes.add(new ClothingItem("jeans", "blue", "dirty"));
    clothes.add(new ClothingItem("t-shirt", "red", "dirty"));

    /*
     * Objective: To try to debug whats going on inside.
     * For example, what happens by the time the clothes reach the clothesline?
     */
    laundry.doLaundry(clothes);
   }
}

You could put a breakpoint at the doLaundry() invocation, but since you don't have the source attached, you draw a blank.

The solution is to extend the Clothesline class as follows:

public class CustomClothesline extends Clothesline {

   @Override
   public void hang(List clothes) {
    System.out.println("Debugging in Custom Clothesline");
    System.out.println("Status of clothes given to me:");
    for(ClothingItem item: clothes){
     System.out.println(item.getStatus());
    }
    super.hang(clothes);
  }
}

And then, instruct the Laundry class to use your custom Clothesline instead of the default one.

laundry.setLine(new CustomClothesline());
laundry.doLaundry(clothes);

This entire project and source code is available here. I have included the dependent project as a JAR library, but it is also available as a separate project in case you want to look at it.

Ok that was just an example code. To see the override-debug technique in the real world, see this project on Google Project Hosting (pay special attention to CustomDrawable.java ). Here, I would ordinarily have used a BitmapDrawable object, but I wanted to know what happens when the onBoundsChanged() method is called. I achieved this by extending BitmapDrawable and overriding the method I was interested in.

 

Limitations:

The override debug technique has the following constraints:
  • The class that you want to debug must be extensible. This means it must be declared public and not final.
  • The method which you want to override must be, well, overridable. This means it must have a visibility of at least protected, and of course it should not be declared final.

 

An aside:

You’re probably thinking that the above two limitations render this technique more or less useless. After all, as a best practice, developers of libraries and frameworks are unlikely to allow overriding of their classes and methods unless they are explicitly designed to do so (for example life-cycle methods).

It turns out in practice this is not much of a constraint. Frameworks like Android allow you to extend and override almost anything. The following is a stackoverflow discussion on this topic.

Saturday, March 10, 2012

Internationalization, In Spirit - Part 1



You’re watching an amazing program on Discovery. It is about some mind-boggling natural wonder - say, the Grand Canyon, or the Amazon .. or something of the sort. You watch (and hear) in awe, as the narrator unfolds the statistics of the phenomenon. And then, in a bid to impress upon you how big the structure really is, he says “It is [insert-some-number] feet long, that’s [insert-some-other-number] New York city blocks put together”.

And you go, “How in the world am I supposed to know how big a block is?”. You feel anger and disappointment rising up in equal amounts. You start trying to figure out that calculation. You miss the next five minutes of the program. Before you know it, you’ve lost track, and interest.

****************

Rewind to networking class in your college days. You are studying the token ring algorithm. Your book explains the workings of the algorithm in detail, but every so often makes a reference to “token system in public service office counters”. Basically the book assumes that you are already amply familiar with this token-something-something system, whatever it is. Forget the book, the algorithm itself makes this assumption.

Bad assumption, you say. You come from a country where there is hardly a concept of a queue, let alone tokens. You have a hard time grasping the concept. Worse, you begin hating that algorithm!

****************

Okay. I admit that was exaggerated. But the fact remains.

Internationalization has gone from being a best practice to becoming an absolute requirement in most software applications. How widely a software is adopted is directly tied to how usable it is by people all over the planet.

These days it is pretty standard for any application development framework (language/platform/stack) to provide techniques for developers to easily internationalize their applications. Display messages, units, currencies are all externalized from the code itself. Heck, developers don’t even write the display messages - that task is outsourced to translators.

But, is this sufficient? Would people the world over be happy if their web app displayed messages in their language, Rupees instead of Dollars, and kilometres in place of miles? I think not. In this series of posts, I will present my argument on why I think the software world is still a far cry from being truly global.


Stay tuned for Part 2 of this series, which will talk about cultural sensitivity.