Saturday, December 31, 2011

Thursday, December 29, 2011

Web Services in Python (Part 1) - You Only Need 3 Lines Of Python Code

I cringe whenever I see someone meddling with Apache or nginx config files to do something simple these days.

And worse - the usual LAMP stack is terrible at handling anything that's actually asynchronous in nature, like WebSocket or Comet. It can also be a pretty big security hole as well, see Slowloris.

And yet, you have to read lengthy manuals and fiddle with lengthy config files to get anything done with the traditional web servers - instead of getting shit done, like, right now. Seriously, this is 2011. You're doing more for less if you're sticking to the 2000 ways.

Let's try another way.

So, let's say you have a usual Ubuntu, or Debian, or the more trendy Mint machine. Try this in your home directory:
$ sudo apt-get install libevent-2.0 libevent-dev python-dev python-virtualenv
$ virtualenv webservice
$ . webservice/bin/activate
$ pip install gevent gunicorn
Well, congratulations! You've already got a self-contained web server package installed with the above four lines of shell commands! If your Linux machine has libevent and virtualenv installed already, you can even cut out the first line.

So, 3 lines of shell code to get the infrastructure ready.

The Apache guy is.. eh.. still looking through the manual pages for how to set up virtual hosts. We'll get back to him later, after the late-night news, supper, and.. watching grass grow.

Now, for the web server's content, we'll try a Hello World first. It'll be a Python script for now - we'll make it more like a real web server (i.e. serves your .html, .js, .css and runs scripts and frameworks just like your Apache, nginx, etc.) in another post.
$ cd webservice
$ cat >
#!/usr/bin/env python
def application(environ, start_response):
 start_response("200 OK", [("Content-type", "text/plain")])
 return [ "Hello World!" ]
Just in case you're not familiar with UNIX, press Ctrl-D after the last line to save the file.

So, 3 lines of Python code to make the server serve.. something.

Finally.. we start the web server:
$ gunicorn -w8 -k gevent --keep-alive 60 application:application
And.. it's alive! It's running at port 8000 by default. You can see it in http://localhost:8000/

The performance isn't shabby as well, considering the web server part of it (i.e. gevent.pywsgi, which handles the underlying HTTP protocol) is written in 100% Python:

$ ab -c 32 -n 12000 http://localhost:8000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd,
Licensed to The Apache Software Foundation,

Benchmarking localhost (be patient)
Completed 1200 requests
Completed 2400 requests
Completed 3600 requests
Completed 4800 requests
Completed 6000 requests
Completed 7200 requests
Completed 8400 requests
Completed 9600 requests
Completed 10800 requests
Completed 12000 requests
Finished 12000 requests

Server Software:        gunicorn/0.13.4
Server Hostname:        localhost
Server Port:            8000

Document Path:          /
Document Length:        12 bytes

Concurrency Level:      32
Time taken for tests:   1.182 seconds
Complete requests:      12000
Failed requests:        0
Write errors:           0
Total transferred:      1644000 bytes
HTML transferred:       144000 bytes
Requests per second:    10148.61 [#/sec] (mean)
Time per request:       3.153 [ms] (mean)
Time per request:       0.099 [ms] (mean, across all concurrent requests)
Transfer rate:          1357.77 [Kbytes/sec] received

Connection Times (ms)
        min  mean[+/-sd] median   max
Connect:        0    0   0.2      0       4
Processing:     0    3   1.9      2      22
Waiting:        0    3   1.9      2      22
Total:          1    3   2.0      3      23

Percentage of the requests served within a certain time (ms)
50%      3
66%      3
75%      4
80%      4
90%      5
95%      6
98%      8
99%     11
100%     23 (longest request)
For comparison, Apache 2.2 running on the same machine, serving a static file does 12k requests per second. And you can pretty much forget about playing with Comets in it without a lot of configurations and modifications.

Monday, December 26, 2011

I bought a domain at Namecheap today, because GoDaddy supported SOPA

Godaddy Supports SOPA, so...

It's - nothing special, just a domain for my own computers.

I haven't even set up a web server on it yet.. but it's a static IP and it's linked to a small Linux machine at my home.

If you think having a Great Firewall in the US via SOPA is a bad idea, I highly encourage you to do the same or something similar. It's only $12 with the SSL certificate. You can also pass this little message around if you want your friends to do the same.

If you want something other than Namecheap for some reason, Lifehacker has a list of alternatives to GoDaddy. There's also a list of GoDaddy-owned registrars that you should avoid at nwlinux.

Monday, November 28, 2011

The Easy Way Out

It's not easy these days to find people who can talk in a way that I feel truly interesting, but the ski trip I had this weekend did lead me to such people.

X: "I feel America is on the way to decline, we're here to witness it... This will be like what happened to the British Empire in the last century. This century is going to be the China century."
Me: "I don't think so, China's legal system is a mess. We (as in the Chinese people) still has some very big obstacles in front of us."

It's funny when you have one US native and one Chinese native both thinking their respective countries are a mess.

But I neglected to tell him the details.

The Easy Way Out

A few months ago, I was sitting in Cheesecake Factory in Palo Alto, talking to an entrepreneur from Stanford. It's interesting how the same topic often happens with Americans.

Me: "The mindset of the typical mainland Chinese is very different from the people here (Silicon Valley), and it will be for a long time, I think. It's hard to see what really matters when you see corruption all around you. You'd simply lose your purpose and direction."
Y: "I know what you're talking about. I lived in Mexico. People think they can get ahead by playing little power games here and there. Nothing real gets done in an environment like that."
Me: "Yup, taking the easy way out, instead of innovating.. that's what I meant."

The conversation ended in a pretty sobering conclusion - if the future belongs to one of the existing countries of the world, it'll be neither the China nor America that we see today. Either they change a great deal, or another country will take up the position.

I hope it's a China 2.0... But, good way to spot sinking ships there.

Salesmen and Bean Counters

On the return from the ski trip, I read this.

“The company does a great job, innovates and becomes a monopoly or close to it in some field, and then the quality of the product becomes less important. The company starts valuing the great salesman, because they’re the ones who can move the needle on revenues.” - this one is actually from Steve Jobs. But can be found in the article.

It (the article, not SJ) continues, "... It’s not just the salesmen. It’s also the accountants and the money men who search the firm high and low to find new and ingenious ways to cut costs ... The activities of these people further dispirit the creators ... crimp the firm’s ability to add value to its customers. But because the accountants appear to be adding to the firm’s short-term profitability, as a class they are also celebrated and well-rewarded, even as their activities systematically kill the firm’s future."

"In this mode, the firm is basically playing defense. Because it’s easier to milk the cash cow than to add new value, the firm not only stops playing offense: it even forgets how to play offense. The firm starts to die."

With all due respect, I respect salesmen and accountants when they actually pay attention to the details - not the numbers after the decimal point, but how things went from point A to point B and how it can go to point C or D. Warren Buffet greatly values accounting skills when properly used to assess a company's underlying value, for example.

But then, I think we all know what happens to companies who simply focus on their financial reports, or their "VC relations" for startups - rather than their customers. So while I don't believe everything the article says, it has something to keep in mind.


This is my favorite.. I love playing this with some people and see how they react. Made plenty of people hate me. But if your brain is hardwired like that, you're not gonna be my (or any hardcore entrepreneur's, or hacker's) friend anyway.

Z: "I have this assignment which is about what kinds of medicines would be the most useful to a third world country, but are not yet available to them."
Me (after reading a bit into the report): "I don't see the logic in your conclusions."
Me (after a lot of discussion): "Ok, we're not going anywhere with all these different concerns about the kinds of sickness in a third world country, the affordability of the medicines to the people, the people's life expectancy, age structure, etc. How about this... If the new medicines are actually used, people (or their government) would need to buy them. We can then use market demand, and thus, money, as a proxy measure. So, what kind of medicines do you think could be the most profitable if made available to the poor country?"
Z: "All that you think about, is money. (To some other guy) I'm trying to save lives here, do you think it's correct to think about money?"

It's useless to explain anything to Z after this point - if you don't want to accept an opinion, labeling the source as "evil" is the easiest way out. To a computer scientist, it would be totally intuitive - to sort a list (most useful medicines to a poor country), you need to have a single metric. You can get people to hate you for telling them this. You can also get people to love you for totally revolting concepts with other trigger words. Looking for cracks in people's minds - salesmanship. Find a friend to practice near you.

Saturday, June 11, 2011

Present State of HTML5 in Mobile App Development

“We’re doing our next mobile product in HTML5.”
“Yeah. A lot of people do that these days. I’ve been playing with Appcelerator as well.”
“Uh.. but that’s not what I meant by HTML5.”

I’ve been having a lot of this kind of conversations lately - partly because I’m doing an HTML5 app myself. But like “AJAX” back in 2005, the term “HTML5” is never clearly defined and is quite easy to throw around without considering the actual technical benefits, the trade offs, and the implications in the operations side. If you’re working in a company managed by buzzwords of the day, then Dilbert may very well be sitting by the next cubicle - if you’re lucky.

Two Divergent Roads

When people talk about HTML5 on mobile devices, there are actually two very different things that they may be talking about.

The more intuitive, and technically simpler path is to use the web browser - either embedded to your app (e.g. PhoneGap) or, the app is supposed to be opened from a bookmark icon on your mobile phone (e.g. Financial Times for iPhone and iPad). The usual benefits of this path include being able to reuse existing web design and development talents, products are highly and trivially portable, are easy to debug and fix (e.g. via weinre), and thus, fast iteration. Trade offs are performance and features - features is less of a hassle if you use an embedding architecture like PhoneGap. Performance is the #1 problem for this path.

The not-so-intuitive way is to use the JavaScript engine to control native features directly, ignoring the web browser component on mobile devices. Performance problems in HTML5 apps are mostly caused by HTML/CSS rendering, not JavaScript execution - so this approach can and do give you massively increased performance - if used correctly. Examples of this approach include Appcelerator Titanium, Mobage/ngcore from ngmoco, Game Closure, and whatever PhobosLabs is doing.

Node.js for Client Side

Take PhobosLabs’s project as an example - what they’ve done is take WebKit’s JavaScriptCore component, interface that to OpenGL on the device’s side, and expose an HTML5 canvas API on the developer’s side. What this means is, the developer can be developing and testing his game on a desktop browser with good canvas support, and put that to his mobile device and have his game run with similarly good (and perhaps better-than-desktop) performance. This is very similar to the approach taken by Node.js - take the JavaScript engine and add your own stuff to it for your specific use case.

Appcelerator Titanium expands on that concept and exposes a whole abstraction layer of UI widgets - such that it can be applied to general applications in addition to (instead of?) games. What this means is, an app developer can create buttons from Appcelerator’s UI library in JavaScript, and Appcelerator’s internal logic will translate that to e.g. a native UIButton on iOS. The UIButton on screen will then be completely controllable within JavaScript - the developer, theoretically, won’t need to write any Objective-C.

The trade off to this kind of approach is, while you’re still coding in JavaScript, you’re saying goodbye to the layout logic and declarative style definitions given by HTML and CSS. You’re also saying goodbye to the excellent debugging tools available to normal HTML5 developers. This is a smaller problem, and thus a sensible trade off, for HTML5 gaming APIs like Mobage because canvas exposes a relatively small set of interfaces - so there are less things to go wrong in the first place. But once the interfacing layer gets big, like in Appcelerator’s case - if anything goes wrong, you’d have to go back to Objective-C (or Android API)’s level, and also take the additional complexities added by the interfacing layer into account - while debugging. A lot of the negative reviews for Appcelerator out there can be understood if you take this in mind.

Back to the Browser

The first problem of doing a full-stack HTML5 mobile app is that it’s slow. The second problem is that the tool chains (e.g. broken persistent nav bars in jQuery Mobile, iOS’s innerHTML bug I discussed earlier) out there are still very buggy - which either means you need to reduce your features to avoid the bugs or you spend some time to work around the bugs. Features is only really the third problem - you can get around that with a plugin architecture like PhoneGap.

If you did some experiments yourself with one or two UIWebViews in an iOS app, plus a bit of your own JavaScript - no non-essential libraries added - you’ll find that it’s quite feasible to make a fast, full-stack HTML5 app... With no features. The PhoneGap iOS project template takes only 1 to 2 seconds to launch on an iPhone 3GS - a relatively old phone. What that tells you is, as a baseline, full-stack HTML5 apps can be very fast. So, if you find out your HTML5 app is hanging 10-15 seconds for some operations, or the app is taking 15 seconds to launch - then it’s almost always some JavaScript or UI library’s fault.

Two UI Libraries

What a mobile full-stack HTML5 app developer needs is usually two things: one, a bridging layer between the native platform and the web view; two, a mobile UI library. PhoneGap is pretty much the default choice as the bridging layer these days - it allows you to do things like calling out the camera, accessing the address book, reading and writing files, from JavaScript. The two most popular UI libraries are jQuery Mobile and Sencha Touch.

jQuery Mobile is a project founded late last year so it’s relatively new. It is quite obviously immature to anyone having actually tested it - persistent navigation bars are broken, page switching is noticeably slower than native, no way to incrementally add to lists without refreshing the whole page, high CPU usage when tested on desktop platforms (as of alpha 4), etc. I chose it for my project for its relative simplicity (i.e. hackability), the MIT license, and because it’s based on jQuery - every respectable web developer knows jQuery so it’s easy to train someone in jQuery Mobile.

Sencha Touch is, purportedly, much more mature and is faster. I have an instinctive abhorrence towards things that comes with a higher complexity, because I always have a feeling that there are gonna be a lot of features that I wouldn’t use and end up as dead weights pulling down the overall performance. I may be wrong though - the top featured mobile app on PhoneGap’s apps page is IGN Dominate - it’s extremely fast and it’s based on Sencha Touch - although I’m sure they’ve put in a lot of their own optimizations to do that.

Debugging and Making Changes

But the upside of doing full-stack mobile HTML5 - which a lot of people misses - is that it’s easy to debug and make changes. Any developer who’s worked on any non-trivial project would tell you, debugging and maintaining the project can easily take up 80% of the time, if not more. What this means is, when you see a certain tool chain claiming you can build, e.g. a chat app, in 15 minutes - it’s really telling you it has compressed 20% of your trouble into 15 minutes - the remaining 80% may have been made 3x worse.

This was a tough problem for mobile HTML5 apps because console.log() in a UIWebView normally logs to nowhere. So if anything goes wrong in JavaScript, you would need alert() or you wouldn’t be able to see that. PhoneGap improved this a bit by patching in a console.log() that logs to XCode’s console. But that’s still not enough.

The best solution right now is weinre. It is buggy and slow but it works - with that you can literally debug your mobile app’s UI from Web Inspector on your computer. It is based off WebKit’s Web Inspector with its debugger back end taken out and replaced with a remote back end. I’ve done some investigations into Web Inspector’s code myself two or three weekends ago and found that it’s not really that hard to turn it into a remote debugger. weinre’s development may speed up in the coming months or someone may make a better project replacing it - we’ll see.

This will be the actual big thing in mobile app development for the coming years, because it solves tons of problems in the 80% part of the app developer’s workload. Want to change your UI design in Objective-C? Edit, recompile, run - repeat until you get satisfactory results. This can easily take a whole day if the recompile step is long. Doing that same thing with HTML5? Edit a few CSS attributes in weinre and experiment away - you don’t even need to shut down the app. Yes you can debug an HTML5 mobile app, to some extent, by running it in a desktop browser. But believe me - your app will have a bunch of bugs that happens only on the mobile device, so weinre is absolutely needed.

Unfortunately, people usually tout their toolkits and their features and seldom glorify useful debuggers, so I guess it won’t get talked a lot even though it’ll actually be the thing that mobile HTML5 developers use the most.

The Present State

I hate writing conclusions, but this is a really long blog post, which even myself will need a few points to remind myself - when I read my own posts later.
  1. Two ways to do HTML5 apps on mobile, full-stack or only using the JavaScript engine.
  2. The JS engine approach makes sense for making games. I have reservations for implementing a full UI toolkit on that due to the complexities involved in the interfacing layer - but, we’ll see.
  3. Full-stack HTML5 mobile app is slow and buggy, but can be mitigated with custom optimizations. Not many people have managed to do that but it's possible.
  4. The real benefit of doing HTML5 mobile apps is the possibility of debugging and changing it online. Native app developers will have a hard time matching that kind of development speed advantage - once the team has problem #3 resolved.
  5. Oh yes, porting is easy as well. But I assume everyone gets that automatically.

Thursday, June 2, 2011

How to make the Push Notification prompt reappear during iOS app development

If you're developing an iOS application and your application is using push notifications, chance is, you'd like to be able to test the push notification registration step during debugging.

Problem: the push notification dialog only appears once for your debug application. It doesn't matter that you remove the app and reinstalled it - it won't appear again. This kind of behavior is dangerous for developers because it means it's impossible for you to test the push notification registration step reliably - it might have worked last week but stopped working this week, and you just wouldn't know.

Apple has a technical note dealing with this behavior. What an app developer can do in this case is to uninstall the app and adjust his development phone's clock to 1 day later. If he reinstalls the app after this, the push notification dialog will be allowed to appear again.

But... there's always a better way. It requires jailbreaking your iPhone but who doesn't? :)

Saturday, May 28, 2011

Now for something completely different...

Another midnight/early morning note to my blog so that I don't forget what went in my mind earlier.
  1. The current approach of embedding scripts for all browser support in libraries like jQuery, and embedding all available widgets in libraries like jQuery UI and jQuery Mobile - is completely wrong. The extra parsing and code complexity may not matter for Core i7 desktops, but it really hurts performance in mobile devices.
  2. If the uncompressed size of the .js file of the UI framework for your upcoming mobile app is 1.5MB+ ... you're doing something very wrong.
  3. Narrative JS. Can be used to solve a lot of problems if it works well. I should find some time to investigate this thing.
  4. The current approach PhoneGap is using for communications between JavaScript and Objective-C is very hacky and slow - even though it works. Adding a micro Comet server on Objective-C's side and use Comet for communications will work much better. It sounds crazy, but it's more doable than most people think.
  5. I need to do more screencasts like AFeature's, for those "micro" open source projects (like bson and bson-objc) that I do in weekends - just to brush up my presentation skills.
  6. The current way people do Comet and WebSockets haven't accounted for unreliability at the physical layer on mobile devices (aka. AT&T).
  7. Comet on mobile devices is also not a very good practical idea because (from our experiments), mobile browsers tend to minimize active TCP connections - s.t. even though you can sort of keep the receiving connection "persistent", the send will not. Which means, the send part of your Comet session will have high latency.

Sunday, May 22, 2011

Some predictions and wishlist for the coming year

It's a bit late to do it in May but I'm beginning to find myself constantly forgetting big picture things.

  1. Mobile applications will increasingly be done in HTML5 and wrapped inside something like PhoneGap.
  2. Co-routine I/O libraries like gevent and eventlet, and the whole approach in general irrespective of languages, will take off. Someone will implement an Actor model on top of them to make them work nicely across processes. (note: Pykka doesn't work across processes, yet)
  3. will get more buzz.
  4. CoffeeScript will get a lot more users, especially for those people on Node.js. Writing sophisticated server-side logic in plain JavaScript is crazy.
  5. NowJS will be a flop.
  6. ChromeOS will be a flop - for now. But Google has the money and patience to iterate.
  7. WebSockets and WebGL will remain experimental.
  8. The general direction for software that'll take off are things that are lean and mean - in terms of performance, code size, ease of development, etc.
  9. Everybody that matters will will say UX instead of UI - which means just a good UX will no longer confer significant competitive advantage in general.
  10. The HK government will keep pushing meaningless things like "the wine industry" where a single tech company will easily trump the whole industry in terms of revenue - but they'll keep talking the talk on tech.
  11. HK university graduates still don't know their mainland counterparts from similarly high-ranked universities are already getting a higher salary and maybe 2x to 3x their real purchasing power.
  12. The world will not end tonight, doomsday preachers are nuts.

Saturday, May 21, 2011

An alternative workaround for Mobile Safari's innerHTML problem

One major frustration for mobile HTML5 app developers is that innerHTML in Mobile Safari stops working randomly - often at the most inconvenient times. I met the problem as the PhoneGap project scaled up in complexity in the recent months and random rendering bugs appear more and more often in my app.

There's a clear problem description in this 4-year-old blog page:

The code has been in use for several months without issue and has been working fine all this time in all the browsers I’ve tried it in. For some reason in this one particular scenario though, Safari was completely ignoring the attempts to set the innerHTML of the node. Setting the innerHTML and then on the following line attempting to read it was also giving an empty response. For example:

text = "foo";
node.innerHTML = text;
alert( "html="+node.innerHTML ); // Pops up message saying "html="

I tried numerous methods to fix this problem, including setting the property before and/or after adding the DOM node to the document. I also googled it which flagged up a number of related posts but these generally referred to pages that were served as XHTML (ie. pages with an .xhtml extension and MIME type application/xhtml+xml) and were not offering any solution.

The general consensus towards working around this problem is to set a timer to retry setting the innerHTML value again. (e.g. as mentioned in this page) Such a solution is highly inconvenient and is generally inapplicable, however, because it screws up your programming model - you essentially need to turn the simple operation of setting innerHTML into a callback-like asynchronous operation.

A Probable General Solution

I found an alternative solution yesterday when I noticed that, at the moment innerHTML stops working in Mobile Safari, DOM manipulation operations, like..
element.appendChild(document.createTextNode("Baby you're a firework!"));
.. would still work. What this means is, if you're able to translate the set innerHTML operation into purely DOM manipulation operations, you'd be able to circumvent the problem entirely - in theory.

To do this, I'd need to be able to parse the HTML in JavaScript. That's actually easier than most people think - I've worked with such a parser during my CKEditor days, and it was mostly just a bunch of regular expressions. Even better, there's a standalone JavaScript library for doing HTML parsing written by John Resig.

With that in mind, I wrote a simple JavaScript function that turns an HTML string into a DOM fragment - which in mathematical terms, is simply a forest.

Then, as I'm using jQuery Mobile, I can patch it into jQuery's html function:


Wednesday, May 18, 2011

AFeature - Interactive JavaScript console for mobile HTML5 applications

I created this because I really needed something interactive to debug my PhoneGap iOS project. There is a similar project out there called ibug but it is no longer working.

You can get the code here, and below is a quick screencast.

Edit: Turns out it was unnecessary. I kept searching for Mobile Firebug before I came to the conclusion that I need to write one myself. But someone from the PhoneGap user group told me there's actually a Mobile Web Inspector out there. It's good enough for me for now, although I have to say I don't really like the Java server code in there... looks overly complicated to me.

Monday, May 9, 2011

How to solve "assembler for architecture ppc not installed" errors after installing XCode4

I was upgrading and building a few Python modules on my Mac this afternoon, and I got this error:

Martin-Kous-MacBook-Pro:~ martinkou$ sudo easy_install -U Cython
Searching for Cython
Best match: Cython 0.14.1
Running Cython-0.14.1/ -q bdist_egg --dist-dir /tmp/easy_install-5NQPRk/Cython-0.14.1/egg-dist-tmp-gOLK4r
warning: manifest_maker:, line 19: 'recursive-include' expects <dir> %lt;pattern1%gt; %lt;pattern2%gt; ...
/usr/libexec/gcc/powerpc-apple-darwin10/4.2.1/as: assembler (/usr/bin/../libexec/gcc/darwin/ppc/as or /usr/bin/../local/libexec/gcc/darwin/ppc/as) for architecture ppc not installed
Installed assemblers are:
/usr/bin/../libexec/gcc/darwin/x86_64/as for architecture x86_64
/usr/bin/../libexec/gcc/darwin/i386/as for architecture i386
/tmp/easy_install-5NQPRk/Cython-0.14.1/Cython/Plex/Scanners.c:6694: fatal error: error writing to -: Broken pipe
compilation terminated.
lipo: can't open input file: /var/tmp//ccAtkL0J.out (No such file or directory)
error: Setup script exited with error: command 'gcc-4.2' failed with exit status 1

This error pops up for a lot of build scripts besides Python distutil's - Perl modules like ImageMagik are also failing to build on OSX after Xcode4 is installed. The reason for this is Apple has removed the PPC assembler for OSX platforms in Xcode4, yet a lot of existing build scripts for OSX are building universal binaries.

There're quite a few solutions on the Internet, but the cleanest solution I've found so far, is the second solution (as of today) in this Stack Overflow page.

So it turns out Apple has still left a PPC assembler in the iOS platform files for Xcode 4. All you need to do is to make 2 sym links at the appropriate place and it'll work.

$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/usr/libexec/gcc/darwin/ppc /Developer/usr/libexec/gcc/darwin
$ sudo ln -s /Developer/Platforms/iPhoneOS.platform/Developer/usr/libexec/gcc/darwin/ppc /usr/libexec/gcc/darwin


互聯網站 AirBnB在 SXSW後雖然確立了宣傳手法和自我特色,但仍然是小型搞作,每次只是供應幾十間住房,談不上賺錢。而談不上賺錢,對於創業者是大問題,因為幾個創辦人在三藩市的日常開支,絕不便宜。


AirBnB三人靈機一觸,由早餐想到穀物片,由穀物片想到穀物片背後的品牌和廣告,再由穀物片品牌想到總統大選。於是美國的電視上就出現了:「 Obama O’s: Hope in every bowl!」及「 Cap’n McCain’s: Put a maverick in your morning!」

利用網上宣傳的便利,美國人對總統大選的瘋狂,和前兩次搞 AirBnB網站所認識的傳統媒體, AirBnB推出了以奧巴馬和麥凱恩為主題的早餐穀物片。每款限量推出 500盒,每盒售價 40美元。 1000盒穀物片送 200盒給記者。其餘 800盒讓 AirBnB的名字除在美國迅速走紅之外,還幫 AirBnB賺了三萬美元。

「我對你們的計劃信心不大。」 08年尾, AirBnB三人去了考 Y-Combinator。考 Y-Combinator的原因並不是因為 AirBnB成功,而是因為他們沒錢。賣穀物片的 3萬元只是還了部份信用卡欠款。在全國電視一輪風光過後, AirBnB網站依然沒人流,沒收入,很快便被人忘記。折騰了一年,結果碌爆信用卡,晚餐只好吃麥凱恩和奧巴馬。考 Y-Combinator,就是想問 Paul Graham拿兩萬元給自己吃飯。

「但我欣賞你們那種大無畏的精神。不怕死,能在最壞的情況下看出並抓緊機會,比任何計劃書更好。」 Paul Graham由 AirBnB網站的統計數字觀察到,除大型會議以外, AirBnB的主要客源來自紐約。於是, Paul Graham給 AirBnB的頭號建議是,不要老是坐在矽谷,去紐約見你們的客戶。打電話給他們,敲他們的門,和他們一起拍照、開派對,用盡所有方法,令客戶記得你。

「不要想,只管做」,紐約一行終令 AirBnB人流增長。

(刊於 2011-02-26 香港蘋果日報)

Thursday, February 17, 2011


AirBnB的故事在 07年 10月開始,那是 IDSA( Industrial Designers Society of America)在三藩市的大型展覽會前夕。創辦人之一的 Brian Chesky辭掉原有的工作,搬到三藩市和朋友 Joe Gebbia一起居住。目的是到矽谷附近的三藩市,嚐嚐創業的滋味。

當時三藩市的酒店都因為展覽會全部爆滿。 Joe和 Brian覺得,這個時候出租家裏多餘的空間給短期住客,應該有市場。二人建一個簡單的網站,讓附近的人可以出租家裏的空間給參加展覽會的短期旅客,當中包括 Joe和 Brian家裏的三張氣墊床。網站一做好,兩人就以電郵主動聯絡一批與工業設計有關的博客。

不消幾天,一些和展覽會主題有關的大網站,就出現了有關 AirBnB的報道。 Joe和 Brian也如此幫自己找到 3個短期租客,賺了約 1000美元的租金。更重要是兩人體驗到短期租務市場的潛力,確立了日後透過社交媒體宣傳方向。

展覽會結束, Nathan Blecharczyk加入 AirBnB。他們用同樣的方法,攻打 08年 SXSW藝術節。宣傳同樣由博客網站入手,先找小博客,報道過就找多點人看的博客,報道一輪就聯絡更多人看的網站。如是者, AirBnB早期的宣傳方法便成形。

吃自己狗糧 了解客戶感受

那時的 AirBnB還有一個問題,要找住房,其實早就有 Craigslist和 Couch Surfing。 AirBnB當時的報道雖多,但只得幾十間住房,要擴張就得找個令自己與別不同的地方。

Joe和 Brian在這個時候,用自己的網站租了一間房來住,目的是了解客戶用 AirBnB租房整個過程的感受。矽谷稱這種做法做吃自己的狗糧。


這樣吃一吃狗糧, AirBnB團隊學到要避免在租住過程中談到租金, AirBnB就得要求租客先行付款。如此房東可以更放心放租,租客亦不會再受租金困擾, AirBnB亦可以從中收取佣金。比別人優勝的用戶體驗,成為 AirBnB的特色。

(刊於 2011-01-29 香港蘋果日報)

Tuesday, February 15, 2011

Some performance tests on gevent and libevent latencies

I set out to test the bare minimum reaction times for gevent and its underlying libevent library this morning. The exact versions used are gevent 0.13.1 and libevent 1.4.2 - not the most updated but fairly common.

The testing method I used was to run a TCP client and a server in the same process and let them ping-pong each other, and measure the rate of ping-pong requests. What this means is basically the absolute best reaction times for gevent and libevent in terms of TCP socket events. As a control experiment I also did a gevent queue ping-pong between two greenlets.

The source code of the two simple tests can be found below:

libevent test case:
gevent test case:

And here are the results -

Macbook Pro 2007 (2.2GHz Core 2 Duo/4GB RAM/OSX 10.6.6)
Martin-Kous-MacBook-Pro:testgswitch martinkou$ ./benchmark
25441.49 roundtrips per second
Martin-Kous-MacBook-Pro:testgswitch martinkou$ ./
test_tcp_socket: 8722.40 roundtrips per second
test_queue: 265788.63 roundtrips per second

Xeon Server (Xeon X3450/8GB RAM/Ubuntu Server 10.04)
martinkou@hydrogen:~/Development/levent-test$ ./benchmark
105852.88 roundtrips per second
martinkou@hydrogen:~/Development/levent-test$ ./
test_tcp_socket: 14124.71 roundtrips per second
test_queue: 430830.17 roundtrips per second

So, despite gevent's awesome performance among all Python concurrent I/O libraries - it still has plenty of space for improvement. This is actually a pretty good news for the developers of gevent and similar concurrent I/O libraries in Python. Because it means the more awesome things are still to come.

Tuesday, January 18, 2011


facebook新年市值衝上 500億美元,一間 80後開的公司市值高過港股火車頭,這是現在不少人對科技的理解:錢。但之前講過,在矽谷創業及投資的人非常多。在朱克伯格以外,還有很多故事。
「我們要做一個網站,讓家裏有多餘空間的人,租給短期旅客,令那些 backpackers之類的人有便宜的食宿選擇。」
問以上問題的是 Y-Combinator創辦人 Paul Graham。他說你的腦筋有問題,很明顯你要見心理醫生。


作為創業者,願景荒謬是常見的事。甚麼 Google或 Apple,現在馬後炮說他們聰明很容易,但在他們開始的時候,其實都很荒唐。七、八十年代走去史丹福 Homebrew Computer Club的人,不少是長髮長鬍子,滿身臭味的嬉皮士,有些甚至會吸大麻。那時候的微型電腦,只是一個盒,沒螢幕沒鍵盤,只有一排排的開關和燈。即使是那班 嬉皮士,也不知道有甚麼用。
話說回頭,想做那個網站的人,很明顯是儍的。剛巧, Paul Graham都是儍的,所以, AirBnB這個團隊考進了 Y-Combinator。


AirBnB並不是考入 Y-Combinator才開始。 08年的,是 AirBnB團隊第三次搞同類型的網站,前兩次都是失敗的。正常人的反應是放棄,一般人根本不會試三次,或失敗一次就放棄。
三個人為了試第三次,碌爆信用卡。但今時今日, AirBnB在美國的影響力足以令傳統酒店業震驚。單是紐約, AirBnB可找到的單人住房已超過 4000間,而且不限於低檔住房。 AirBnB的住房現已遍佈 168個國家, 8000多個城市。 2010年 11月, AirBnB向 Sequoia Capital和 Greylock Partners籌了 720萬美元的 Series A投資資金。
這類故事在矽谷多次發生。第一、二次人們會覺得神奇。幾十年來屢屢發生,是因為人們會隨着時間學習,發展出系統。在每一個 AirBnB疑似儍呆子變老闆神話的背後,其實都有一個實在而合理的故事。下回再講 AirBnB的故事。

(刊於 2011-01-15 香港蘋果日報)

Saturday, January 1, 2011

A Review of 2010

So, here's my story so far, in short...
  1. Joined a high-ranking open source project, FCKeditor as Core Developer (2007)
  2. Made it to computer mags (2008)
  3. Made it to newspapers (2009)
  4. Made it to TV (2009)
  5. Went to Beijing and caught a glimpse of the central government's ambition with the high tech industry in China (2009)
  6. Traveled to Silicon Valley and lived for six months (2010)
  7. Made it into two Silicon Valley incubators almost simultaneously and accepted one of the offers - SSE Labs (2010)
  8. Produced two prototype demos within the six months in SV, one of them was made public (SayCheeze), demo-ed to VCs. (2010)
  9. The other idea is more promising... so I'm working on that ;)
  10. Hooked up to an editor from Apple Daily HK which allows me to write column articles in weekends. (2010)
So I've seen plenty of action in 2010. The people I've seen were almost a blur - the top VC partners and angels (i.e. principals from funds like August Capital, Sequoia, KPMG, etc. and then people like Paul Graham - yes, I've talked to Paul Graham, in person), the Sandbox network, met a number of SV entrepreneurs from having IPO'd to having got significant funding to having sold their stake for good like RockYou's Jia, Webshots' and Stumbled Upons' founders... I've even talked to someone affiliated with the White House for a good 45 minutes.

It's quite surprising what a determined enough person can do in 3 years. But still, I'm very far from Mark Zuckerberg...

... and that kinda puts in perspective, how big this world is. Mark is only 1 year older than me. A Forbes ranking is not too significant in my eyes - plenty of people can get insanely rich by being lucky - but a hand that guides the path of technology and thus, civilization, is significant. And I mean all these in a concrete, pragmatic sense, in case you think I'm just another dreamer.

Having seen all these powerful people, the body of knowledge and business practices they've built, reminds me of a quote from H2G2:
Space is big. You just won't believe how vastly, hugely, mind- bogglingly big it is. I mean, you may think it's a long way down the road to the chemist's, but that's just peanuts to space. - Douglas Adams




譬 如一間拿過天使投資,開始做出產品雛形,有合理盈利模式,但之前團隊沒有甚麼往績的新公司,剛開始找風險投資時,通常會拿到一個 Seed Round或者 Series A。這時公司的估值通常是數百萬至一千萬美元, Seed Round投入的資金,通常是幾十萬至一百萬美元,而 Series A則由一百至幾百萬美元。


Seed Round和 Series A的作用是,給公司一至兩年生存時間,在產品開發上和市場上建立相當實力。 Series A之後的科技公司會有很多不同去路,需要再擴張,可繼續籌 Series B、 C等,這些時候投入的資本,通常會過千萬甚至逾億美元。



另一個可能性是,被較大的企業如 Google、 Apple、 Facebook或 Amazon等收購,價錢視乎情況。近年大型企業收購小型科技公司例子越來越多,金額通常在數百萬至數千萬美元。


大公司收購小型科技公司的理由,除了是擴展市場(如近月美國 Groupon Inc.收購香港 uBuyiBuy),另一理由是招攬人才。用幾百萬美元來招聘人才,聽來荒謬,但是一個具執行能力、能夠兼顧市場、營運及技術的團隊得來不易,和普通人員招聘不可相提並論。

又一個可能性是,公司已可獨立營運,以自己的收入擴張。最後一個可能性是上市,但上市需時較長,例如 Facebook,現在的市值已超過四百億美元,但還未公開上市。

(刊於 2010-12-25 香港蘋果日報)


一般人很多時會以為科技公司就是簡簡單單搞一個網站,寫一個 iPhone app,多人用就可以賺錢。但是縱觀整個科技工業,由八十年代的 Apple、 Microsoft,到九十年代的 Yahoo!、 Amazon,甚至二千年的 Google、 Facebook或 Salesforce等等,無論是企業家還是投資者,其實都已經累積了好幾十年的人才、人脈和經驗。現在的矽谷,無論是創業還是融資,都已經趨向標準化和 系統化。



譬 如 3個剛畢業的大學生自行創業,獲得 Y-Combinator之類的「孵化器」垂青,他們可以預料 Y-Combinator會給他們數萬美元的資本,換大約 6%至 7%的股份,也即是數十萬美元的估值。其他的孵化器可能會用多一點錢,換多一點股份,又或者相反。但是不同的孵化器,對團隊的要求、給予的幫助及對新公司 的估值,都有不少類似的地方。

剛開始創業的人除了找孵化器之外,還可以找天使投資者。這些人通常是之前創業成功或者是大型的企業,如 Salesforce或 Cisco創始團隊中的成員。

天使投資者和孵化器相似之處,是他們都比較重視團隊的質素,概念和商業模式反而不是太重要。天使投資者通常會給數萬至十數萬美元的資本,換 2%至 10%的股份,也就是說 100百萬至幾百萬美元的估值。相對孵化器來說,找天使投資者的難度和要求會比較高。


(刊於 2010-12-18 香港蘋果日報)