Monday, July 16, 2012

StringBuilder or not StringBuilder that is the question...

Ten years ago, I achieved competence in my first programming language, Java. Now, a decade later, I found myself back in Java-land programming apps on Android. Even though Java is verbose like a bad russian novel, I found myself enjoying it in a homecoming sort of way. I've decided to periodically share some nitty gritty of Java with the world with the hope that folks will find it useful. Today I want to talk about string concatenations.

String concatenations happens all the time in our code. Most of the time, we need to generate a short message to display to the user or send some snippet of text to the log.

The problem with strings in Java is that they're immutable. Every time we concat two strings we are creating a third string. So the above code has the same effect as:

The intermediate strings from the concat operations become garbage immediately. And since strings are objects, all the overhead of object allocation and instantiation applies, as well as garbage collection at some time in the future.

To solve this problem Java designers came up with StringBuffer, and much later, StringBuilder. These classes are supposed to give programmers a more efficient way to concat strings. The biggest difference between StringBuffer and StringBuilder is that StringBuffer is thread-safe. It turns out 99.9% of the string concatenations are not done across multiple threads so synchronization is an overkill. Since synchronization is not free, it is expected that StringBuilder will outperform StringBuffer.

The previous example, using StringBuilder, becomes:

But the $100 question is: does it actually perform better?

I created a micro benchmark (code here) using caliper to compare the three different ways of concatenating strings. The first using the + operator, another using StringBuilder, and the last using StringBuffer. Since phones have limited memory, I ran the benchmark using 3 VM configurations: 16 MB, 32 MB and 512 MB. The results are surprising:

memoryMax      benchmark  ns linear runtime

  -Xmx16M StringAddition 226 =========================

  -Xmx16M  StringBuilder 246 ===========================

  -Xmx16M   StringBuffer 269 ==============================

  -Xmx32M StringAddition 143 ===============

  -Xmx32M  StringBuilder 155 =================

  -Xmx32M   StringBuffer 166 ==================

 -Xmx512M StringAddition 135 ===============

 -Xmx512M  StringBuilder 152 ================

 -Xmx512M   StringBuffer 166 ==================

As expected StringBuilder outperforms StringBuffer, but StringBuilder is about 10% worse than the + operator.


It turns out StringBuilder (and StringBuffer) uses an intermediate structure to store the result (most likely an array of some sort). And the underlying array have to expand if more strings are appended to it than its capacity. The default constructor creates an array of size 16. It would appear that expanding the underlying array is more expensive than creating and throwing away a few strings.


To prove this, I created a second benchmark (code here) that instead of using the default constructor, gave it the initial capacity of 100 (which is more than enough to fit the test result). And voila!

memoryMax      benchmark  ns linear runtime

  -Xmx16M StringAddition 217 =============================

  -Xmx16M  StringBuilder 202 ===========================

  -Xmx16M   StringBuffer 221 ==============================

  -Xmx32M StringAddition 143 ===================

  -Xmx32M  StringBuilder 126 =================

  -Xmx32M   StringBuffer 138 ==================

 -Xmx512M StringAddition 143 ===================

 -Xmx512M  StringBuilder 125 ================

 -Xmx512M   StringBuffer 137 ==================

Without array expansion, it appears that StringBuilder is around 10% better than the + operator. 
With the evidence in hand, I come to 3 conclusions.
  1. You almost never want to use StringBuffer
  2. StringBuilder may be more efficient, but it's tricky to use properly. If you initialize it with too small a capacity, it will be slower (due to array expansion costs) and if you give it too big a capacity, you're wasting memory.
  3. I'm going to stick to using + to concat my strings. For small number of concatenations the performance boost with StringBuilder is not worth the extra typing and I don't have to think as hard.

Wednesday, June 27, 2012

Reliving the childhood game

I only played one computer game when I was a kid. It was an old DOS flight simulator called F-19 Stealth Fighter with 16-bit graphics and horrendous sound. But I remember it fondly. Firing maverick missiles and getting Distinguished Flying Crosses consumed quite a few hours of my childhood.

This past weekend I decided to relive the nostalgia and play it again. I installed a DOS emulator for my macbook pro caller Boxer and it wasn't too hard to find a copy of F-19 floating around in the abaondonware universe.

The game is still fun. Even more than before.

For one thing, I'm a lot better. I decided to glance at the manual this time around and figured out how to play the most difficult levels. When I was a kid I could never advance far enough, because to play this game properly required a lot of patience. Flying a stealth fighter, after all, is not about blowing everything up. This time around, it was quite easy to win the Congressional Medal of Honor (the highest achievement in the game), where as before it seemed impossible.

Screen Shot 2012 06 26 at 11 37 19 PM

Another added fun factor is that I've actually visited some of the places in the maps. This game was made during the end of the Cold War. So one of the maps was Eastern Europe and I had to fly missions into Czechoslovakia and Poland. It was quite amusing to fly across cities like Prague, Brno, and Krakow and see the low res renderings of them that looks nothing like the real thing. Even more fun to attack targets in those cities and imaging what those parts of the world was like frozen in time.

In the end, this was just a well made game. No wonder, because Sid Meier made this before he became famous for making strategy games. It is amazing after more than 20 years, this game is not only still playable, but still amazingly fun. Sid said of F-19:
Everything I thought was cool about a flight simulator had gone into that game.
So there you have it… a bit of my childhood that is still accessible. No matter how much two decades have changed me and the world, some things remain preserved forever.

Thursday, May 24, 2012

How to Bet Your Life

I'm standing on an abandoned bridge one hundred feet above a stream in the lush rainforest of Costa Rica. Suddenly, I had doubts. It was a great idea when we plan it in the serenity of the hostel. But up there, with the bungee cord tied up around my ankles, the view is a bit wobbly. The theoretical has just become the very real.

That exact feeling is what most people encounter when they're contemplating quitting their corporate job to join an early stage startup.

Startups are hot and everyone wants a piece. A 13-person startup can be sold for a billion dollars. Even hollywood is getting in on the action. Bono is a VC and Ashton is an angel. That's enough to make dreamers out of everyone. But what if suddenly you're offered a chance to join an early stage startup? Are you willing to give up your position in a nice, stable, established corporation for one in a hectic, never-enough-sleep, constantly-dying startup? 

Corporate jobs, especially in high-tech, is nice and cushy. If you're good, you're likely making six-figures in your mid-20s. Not a lot of responsibilities as long as you get your shit done. There will be a smattering of trips, lots of weekend parties, and plenty of time to socialize, get a hobby, or start a family. Now imagine throwing away (or I call it, de-prioritizing) all that for least for a few years. Work-life balance is a nice concept and I try to achieve it when I can, but often reality gets in the way. If you think that sounds bad, then you're not ready.

You're not ready because you're not ready to bet your life. That's what it's like living inside a startup. That's right. You don't work at a startup. You live in it. In poker, you won't double up unless you go all-in; bet all your chips on one hand. This is same in a startup. You go all-in, but you bet with your life. Everything else in your life will take second priority. And just like poker, you shouldn't go all-in unless you're sure that you have the best cards. You should only join a startup if you truly believe in its potential. And as in poker, even with pocket aces, you can still lose. That's why it's called a bet.

A line from the hip-hop preacher that I love:

To achieve success, you have to be ready, at any time, to sacrifice who you are for who you want to be.

There are only two ways to make this kind of bet. The ballsy way and the poor way.

Jeff Bezos did it the ballsy way. He asked himself what he would regret more, doing it or not doing it. And it helps that he's a crazy bastard, intensely driven and cooly logical. I did it the poor way. I bet everything when I had very little to bet with (I was poor). I had no lifestyle to lose, no debt to pay back and no savings to miss. With nothing to lose, I had everything to gain.

I jumped from that bridge in Costa Rica. That was months after I had already gone all-in with my life and sold my first company. After that, bungee jumping seemed too trivial for any second thoughts.

Sunday, April 8, 2012

The way we do product development

Our app, Skyvi, released a few months ago, has over 1.5 million downloads and our user base is growing strongly with every update. Skyvi is far from the first product we built. In fact, in the past 4+ years, my partner and I built over 20 products, and most were flops and some are too embarrassing to even list by name. But through those experiences, we developed a methodology to do product development that we believe is correct. And today, I'm sharing it.

The first step, also the hardest to get right, is knowing what to build. This one took us forever to learn because we are engineers. In the beginning, we just built stuff, all kinds of stuff, and it was easy for us. We didn't know if it was going to work, but since it only takes a week for us to build it, it didn't seem like it was going to hurt to try. But it does hurt. Experimentation is sometimes necessary, but it's never an excuse for not thinking. In the beginning we were building very simple products and it can take a week or so. But as things got more complicated, it started to take longer. Our last flop, cost us almost six months! Six months! How many six months do you have in your life? Tell me that's not expensive! So, everything we build now, we think hard about what we're going to build first. An engineer's habit of just going out and build things is very difficult to break. But I believe breaking that habit is absolutely necessary.

The next step we do is to try and estimate feature effectiveness. I think this is quite unique to the way we do things. Suppose a feature is going to say, increase revenues, we explicitly state the amount that the revenue is going to increase by this feature. This may sound impossible to anyone who hasn't tried it, but I assure you, it's very possible. This step forces us to break down the feature from the user's perspective. If we don't know something, we reduce it to something we do know. For example, if we have no idea how many people are going to pay to remove ads, we can break it down into steps based on the feature. How many people are going to see the "remove ads" button? How many are going to click on it? How many are going to click through to the in-app purchase link? How many are going to have a google checkout account? How many are going to finish purchase? We try to find comparable data from our current product, other similar products, and our best guesses at each of these questions. Plug it all in and multiply, out comes your estimate. The more we do this, the better we are at answering these types of questions.

Building the product is what we do best, but it is still not easy. Sometimes a feature is actually several smaller features. They need to be thought through, individually and in aggregate. In a team environment we have used scrum to manage the actual development, but when it's just my partner and I on the project, we use a much lighter weight solution. We cut aggressively. If there's a feature that we think only marginally help with our business objective, and it takes disproportionate time, it won't make it. Proper prioritization is key and everyone agrees on and sticks to the prioritized list. Hitting deadline is absolutely essential, and we don't miss. There's nothing worse than having a great idea, and get usurped in the market because you blew your dev schedule. This is also the step that is the most parallelizable with a team.

After the product or feature is built, it's not quite ready to go out yet. It needs to be tweaked. Product tweaking is a black art and is a specialty of my partner's. He has a very keen nose to sniff out which part of the product needs minor touch ups. Maybe the error messages should to be re-worded, or the activated version of the mic button needs a textured background. I hate this step, because I have no patience for it and the engineering is neither interesting nor particularly challenging. But it's absolutely necessary to take the product from good to great. It's awesome if there's someone on the product team that's especially good at this. All you have to do is give them a few days to do it and don't get in their way. But if you don't have a tweaker on board, time box this step and do as much tweaking as you can.

Lastly, after the product launches, we must measure feature effectiveness. You are collecting data, aren't you? If you don't know if your bullet struck the target, why the hell do you even bother to aim? So, in step two we made estimates, and now we check how close reality is to our estimates. From this, we can see either the feature did exactly what we set it out to do, or a faulty assumption exists somewhere in the chain. And we would know exactly which link of the chain to blame and do better next time. For the last few months, we've found ourselves being able to confirm our prior estimates. To us, it implies that we're getting better.

Not every product you build is going to work in reality. The challenge in product development is to make sure that when a product doesn't work, the fault should be in an assumption that lead up to the product, and not in the product itself. In other words, the product does exactly what it is supposed to do, well made, minimally viable, and released on time. The product failed because people just didn't care for the problem it solved for them. That my friends, is a separate problem all to itself...

Sunday, February 12, 2012

What Jeremy Lin should teach Asian-Americans

We can safely assume the feel-good story of the year is the meteoric rise of Jeremy Lin from bench warming D-leaguer to the NBA record books in the span of a week. His story is indeed inspirational. A talent that is so long ignored, suddenly blossoms in the prototypical american dream fashion, and captivates a nation and the world in the process. What's there not to love?

But deeper down there's a much more interesting issue, one that is not so comfortably talked about in a sports bar. Jeremy's rise is all the more surprising because he is Asian. He had to deal with stereotypes and discriminations both overt and otherwise during his entire career. It probably contributed a large part to him being ignored for so long.

Today, I read an article about how Asian-Americans are all cheering for him because they finally found a star that they could relate. The final sentence struck me as profoundly telling:

There was a pause in the conversation. Daniel Chao spoke up. "I mean," he said, in a slightly stunned voice, "an Asian-American dunked."

Why is Daniel Chao surprised? Of course, I don't mean to single out Mr. Chao, but the question remains. In other words, why are Asian-Americans surprised that one of us can dunk?

Stereotypes such as Asian-Americans are bad at sports, or that we are all nerdy or that we can't sing are already fait accompli. We cannot do anything about the fact that stereotypes exist. What we can do is choose to break these stereotypes. It always takes a few pioneers to show us the way. Jeremy Lin certainly never doubted that he could dunk, otherwise he couldn't have gotten so good at basketball. Sure there's natural talent in him, but talent is nothing if not molded by endless hours of practice.

Stereotypes are dangerous, but doubly more so when we, the people stereotyped, start to believe in it ourselves. Should we be surprised if tomorrow a Korean-American R&B songtress wins a grammy, or a Japanese-American quarterback leads his team to the NCAA championships? They would be the firsts, the pioneers, the change makers, just like Jeremy Lin became this week. But whatever we do, we should not believe it is not possible just because it has not happened yet.

It is only a matter of time before Asian-Americans break out in sports, music, movies and business. Let's not be surprised anymore. We are individuals with individual talents. We just need to believe in ourselves more and pursue our dreams with guts and heart. The operating mentality should be: if it hasn't been done before, then I'll be the first. It's working out pretty well for Jeremy.