Subscribe: The Devel!
Added By: Feedage Forager Feedage Grade B rated
Language: English
ads  app  code  content  discussion  don  email  good  method  page  rails  reply  server  user  web  work  write  yatter 
Rate this Feed
Rate this feedRate this feedRate this feedRate this feedRate this feed
Rate this feed 1 starRate this feed 2 starRate this feed 3 starRate this feed 4 starRate this feed 5 star

Comments (0)

Feed Details and Statistics Feed Statistics
Preview: The Devel!

The Devel!

Updated: 2016-12-29T23:39:17+08:00


File Uploads 2015


Another day, another monolith Ruby gem to reach deep into the bowels of your app config, models, views, controllers and make you manage uploading of file, storage of files, processing of files together with the rest of your business logic, only with the promise of loads and loads of syntax-sugar and enough config option to hang yourself with.

paperclip, carrierwave, dragonfly, refile, shrine…

The libraries may have high code quality, full coverage specs, flexible, comprehensive, easy, but it is bad architecture. I’ve covered most of them in this presentation and won’t repeat them here.

While the Ruby community wasn’t looking, the rest of the world has moved on to having standalone servers to manage & process their file uploads. Latest example:

When you adopt a server-client pattern (as oppose to syntax-sugar-into-my-monolith-rails-app pattern) you’ll discover can optimize, manage, scale independently, extend and improve using standard protocols; a whole new world of possibilities.

What? This rack+imagemagick server not working out for you? Swap in your own clustered-faster-attache.go server and your Rails app chugs along oblivious to the change.

What? Don’t like reactjs in the attache client gem? Introduce your own no-framework-js-attache gem and your attache server can remain oblivious to the upgrade.

What? Need to support that spanking new open protocol for resumable upload over unreliable network? Have option for Instagram-like processing? Well then add a middleware to your image server and both your server and Rails app can remain blissfully ignorant.


You already know it. That’s why the common pattern is to use a database, redis, nginx alongside your Rails app. Instead of just having syntax-sugar inside your Rails app to wrangle with b-trees.

Or maybe this will work better: microservices!


A New Plan for Spam: Turing


Background: Spammers don’t really mind when you delete their spam mails or “mark as spam”. Same reason they want to be obviously spam: they only want to spend time communicating with the gullible. If they have to spend time communicating with people who wouldn’t end up being tricked (aka false positive), it would greatly increase their cost of business.

Thomas Bayes has served us well for a few years, now is a great time to employ Alan Turing’s help.

I propose to have an “F1” competition of sorts, for companies (or talented individuals) working on AI and NLP. Here’s the competition challenge:

Hold a conversation with a spammer for as long as possible #TuringTest

The entity that accumulates the longest durations over a period of time, e.g. 1 year, is champion for the year.

To do this, ironically, we need spam. We’ll need mail clients (e.g., Gmail, Hotmail, Outlook) to rewire “mark as spam” to deliver, round robin, spams mails to everyone participating in the #F1forAI competition.

From there, the end points will communicate with the spammer onbehalf of the end user, likely using the same SMTP server to hide scent.

And, that’s about it really.

Oh, yes we need a global ranking table, like the one Dropbox created for their Great Space Race


Robot Vacuum Cleaner


Well this floated in my facebook feed today and my facebook-bubbled world goes crazy

Dyson finally announces a robot vacuum cleaner! - theverge

IMHO, as an ex-iRobot user, and certifiable lazy human being, ahem, no.

The “problem” with robot vacuum cleaner (and the problem to solve if you’re thinking of re-inventing one) is not if your robot can see better, can move faster, suck the floor cleaner, reach further into the corners, cover every inch better, map the house better, etc performance related aspects.


What’s the advantage of a robot vacuum cleaner vs any other methods of cleaning the floor?

It is cleaner? Nope. It is faster? Nope. Covers more floor area? Nope.

Answer: it doesn’t require supervision. You schedule it once, it wakes up, it runs around on its own, cleans everywhere, returns to park and recharges itself, repeat. OMFG! It is a cron job! Write it once and I’m set! For life! I don’t even remember how many cron jobs I have, but that’s the point right?

That’s the robot vacuum cleaner advantage, in theory.

But it isn’t a cron job, and you’re not set for life. Instead, for the rest of your life, you are set to pick up that robot, after every N times that it has done its rounds, to empty its days-old dirty dust bag/container, clean its now-days-old-dirty brushes and throw those dirty away. If you fail to clean your robot punctually, your dirty robot will be going around the house, like you’d scheduled it, and dirty your house everywhere, return to park and recharges itself, repeat. HAAA! Take that, yo! Who’s scheduling who now?

So, no. Save the frenzy for when you see a robot vacuum cleaner that’ll finally clean itself too.

For now, I’m filing this under #SolvingTheWrongProblem #HeyOurVersionOfCronRunsYourJobFasterButYouNeedToSuperviseIt


Better incoming email handling for your webapp


A standard feature in a webapp is to send emails to an end user. This can be done by using the locally installed mail transfer agent (MTA) like postfix (not available on heroku) paying a bit of money and using SendGrid sending directly to the recipient smtp server (doesn’t work well if you are on ec2) What happens when your user replies to that email, using email? You could stonewall with a non-existant… but how about when you do want to handle a reply? Add a link in the email saying click here to reply using our web interface? I find that UX onerous and usually terribly slow e.g. working through my inbox during commute. A better UX would be to allow an actual email reply. Incoming email Handling incoming emails might seem like dark waters for web developers. Many solutions offered on stackoverflow & mailing lists usually involves gmail, imap and polling. Polling. Ugh. Event driven incoming email A better way is to pipe incoming email directly to your application for processing. And for web developers, “pipe” preferably means a HTTP POST into your favourite web framework. aka a Webhook. A quick overview of such setup is: Point MX dns entry for your domain to the server that can receive email (e.g. ubuntu with postfix installed); this server can be a different server from your webapp Configure postfix to handle that email with an smtp-to-http shell script Now every incoming email is just a regular HTTP form post to your webapp. Throw the blob of email content into a parser like mail or mailparser and you’d have a handy email object to manipulate. Configuring your own Postfix server and installing that script to work with Postfix might be difficult to some, walk in the park for others, but definitely a hairy piece of infrastructure to keep around. You can make things less hairy by paying a SaaS provider to take care of #1 and #2, but there are caveats. Reply-To as Identifier Most webapps I see uses a custom Reply-To email address (e.g. Basecamp & Github) In this design, an email notification sent from Discussion id=42 would use Reply-To:; an email notification for Discussion id=99 would use a different Reply-To: address. When a user replies via email, the webhook handler parses To: header, retrieves Dicussion.find(42) and create a new discussion comment on behalf of User.where(email: email.from), using the email html/text body as comment.body. Unfortunately, unless you pay an arm and a leg, you’ll only get 1x email address to use as your Reply-To. Also, any attachment in the email would be lost. So having unique-per-conversation Reply-To address is inefficient & restrictive your infrastructure options. Discussion Thread One more thing. Unless you want your webapp’s email messages to reach your user’s inbox as individual, annoyingly unrelated messages, your job is actually not done yet. A conversation in your webapp should ideally be threaded in the same manner in your user’s inbox (e.g. see Basecamp discussions & Github Issues). So when userX comments on Discussion 42, the outgoing email notification sent to other participants of the discussion should properly set In-Reply-To: and References: in order for them to thread properly in Gmail, Apple Mail and presumably anything else. Having a matching mail subject is essential too, but that’s the easy part. By now we’d have a module to manage mapping of Discussion records to-and-fro Reply-To values. And another module to manage a consistent value of Message-Id, In-Reply-To and References for Discussion records. Seems unnecessarily complicated. Message-Id as Identifier (duh) We can simplify the design by giving up unique-per-conversation Reply-To. Uh? Then how do you know if an email replied To: is for Dicussion.[...]

Connecting Dots


I was listening to a post from High Scalability today, and it reminded me of this old talk the spread of an epidemic can provide a model for the spread of information throughout a network and … techniques based on that model can be used to create ultra-scalable software infrastructures that exhibit unparalleled robustness and scalability properties. — Werner Vogels, E-Commerce at Interplanetary Scale Taken to its logical conclusion, instead of our familiar client-server architectures, “everybody” will have to be hosting a piece of the system in order for us to reach where Werner Vogels describe: scale is no longer a problem to tackle but like a virus, the more nodes there are, the more robust the system. Even if we solve the technical issues, the first big hurdle is actually: how do we convince everyone to run a piece of infrastructure 24x7? Go To Market At AllThingsD, when asked to comment on a TV product, Steve Jobs implied that the problem is not purely technical; he rightfully pointed out that there was no good go-to-market-strategy. To appreciate how a go-to-market-strategy can make or break a product, let’s consider the original iPhone: a beautiful jewel in your hands, but a rather lame cell phone (poor battery life, no 3g, no keyboard) Who knows if the entire vision was already there, but the initial focus was solely on the beautiful device & beautiful interface. While flying lame and humble under the radar of incumbent players, get this pretty device into enough affluent people’s hands, and while they’re smitten, require an unlimited data plan (imho, a critical but understated move in 2007). Later, a reveal: hey Mac developers, a few million rich people is using our phone, running your familiar OS X, has 24x7 internet connection, plays video, mp3, has GPS, has Google Map, real web browser, multi-touch, accelerometer, camera, compass… Wanna sell them some apps? (you have to time-travel back to 2007 to appreciate how impossibly desirable that was) The proverbial chicken and egg hurdle was deftly leapt over with a feint. Interplanetary Scale Space Monkey says they are taking the cloud out of the datacentre, then they talk about the 1TB of storage… your photos, videos, documents, and music. You’d think they’re building a Dropbox, iCloud or Amazon S3. Perhaps they do really mean just that. But let’s assume they don’t :-) Feint While Dropbox is a darling right now and “Cloud” is buzzword, Space Monkey is quite a desirable consumer device. So use that story and get the device into the hands of a big enough group of geeky people (Kickstarter hurray!) Later, a reveal: hey developers, we have a big group of rich geeky people hosting our computer servers across the globe, powered up and connected to the internet 24x7, with a TB of storage each… Wanna sell them some apps? Botnet App Store What if an app running on this “data center” cost nothing extra to scale up? Instead of paying for computing resources in East Coast of USA to serve users in Australia, how about if every user “pay for their fair share” instead? Let’s say users install your app from Space Monkey “app store”, onto their own device. Your app runs off that device at home, stores their own content there too. Users can still access your app from Starbucks like a regular SaaS app (Space Monkey “data centre” platform takes care of that, no worries) Nay sayers may immediately say “that’s a lame data centre! you can’t possibly launch a search engine this way!”. Some types of app won’t work well (,, but others could potentially thrive (Shopify, Gmail, Dropbox). And being lame to incumbent products is not always a bad thing. “If you’re not paying for the product, you are the product” Like an iPhone, the device belongs to the[...]

Learn hacking, not ABCs


While looking for a place to start learning programming, my friend Phil brought this to my attention: Codecademy Closes $10 Million Round. He asked me what I think of it [as a place for him to start].

While I applaud their existence, and congratulate their funding, I doubt I would’ve gotten into programming if I were introduced via something like Codecademy.

I’m lazy, impatient and have lots of things I’d rather be doing than whatever I’m doing right now. And I definitely don’t want to sit through grammar school, regardless of whether it was English language or the lovely Ruby programming language. I find programming interesting only because gets me results.

Story was, our home PC’s 40mb hard disk crashed and we were left with whatever that was on floppies. My brother borrowed a book from the library with computer games inside. I would boot up the computer, ran “gwbasic”, choose a game from the book, and type all the gibberish code into the computer, character by character. Some games were a few lines long, some spanned a few pages. After everything was typed in, I’d run and play my game.

I remember especially liking a cowboy fast draw turn-based game that had dice roll based on your character’s stats (speed, accuracy), distance, dealt damages based on the gun you used and where you hit. It was fun.

Before long I realize I didn’t have to transcribe every character in the book. If I changed some numbers, the computer wouldn’t know it came from me, and the game would play out differently. I made the games better (or worse, depending on whether you think god-mode is a good thing or not).

Before long I realize I didn’t have to transcribe anything from the book. If I’d just written anything I wanted, the computer wouldn’t know none of it came from the book. The computer would follow my instructions and run my game like it would run the games from the book.

Wow. I am as authoritative to the computer as The Book.

(The next big milestone would come several years later, when I produced my first “.exe” file. aka, shit just got real.)

That’s why I’m biased to think that programming should only ever be introduced as a means to get something real done or done faster. Hacking on something you already understand. Then there is a purpose and motivation to learn. Then programming is meaningful. It is sad [to me] to know that some people’s first contact with programming would be a dry grammar class (or some patronizing guided tour to nowhere, ”yippie, you can count!”) that they just have to sit through to learn, no biggie, like everything else they’d done in school.

[Update 27 Sept 2012]

This essay was an immune response, triggered by hearing too many times that Inventing on Principle was “about live coding”, and seeing too many attempts to “teach programming” by adorning a JavaScript editor with badges and mascots.

– “Learnable Programming”, Bret Victor


TDD for Those Who Don't Need It


A public service announcement: There’s still a lot of pretty good programmers who don’t write tests… and programmers who write tests are not necessarily any good. It is easy to forget that. BDD/TDD propaganda can be a thick fog. A year ago the only “BDD” I’d done was “Bug Driven”, i.e. “Bug in production? Add a test & fix it”. There were no test culture from where I began writing code and we write code by simply writing the code. New, file, tap tap tap, run; That’s how we do it, that’s how we’ve been doing it, work gets done, everyone is happy. Nowadays, there’ll be TDD folks sweeping in to shame you into writing tests. “Oh, you DON’T write tests? Then how can you possibly be sure your code is correct?!11 Fwahahahaha.” “I did test it myself. It’s in production and it works.” Still, you might eventually succumb to such peer pressure and decide to “write some tests” in your next project… only to find it tedious, distracting, cumbersome & standing between you and your deadline. No more tests in the next project. My issue is, every sell for TDD has to do with some future benefit: Tests give you confidence to refactor [next time]. Writing tests makes your design better [you’ll be thankful next time]. Tests serves as documentation [for the next developer, or yourself next time]. Untested code is legacy code [when you have to touch it again, next time]. Well, YAGNI is a good principle too, and it can apply here. Perfectly capable programmers, who don’t currently write tests, are not actually against having confidence to refactor, against better api design, against having documentation, or against maintainable code. It is pointless trying to convince them the benefits of that. In fact, chances are (believe it or not) they strive for that harder than you might imagine - they probably know their patterns of refactoring, may have solid habits of writing javadoc/rdoc/etc doc, and are likely to leave great commit messages too. They have different [arguably inferior] means at their disposal, that’s all. On the other hand, something that’s not YAGNI, and a very real issue of writing software, is the amount of information you have to hold in your head at the same time. Writing a feature of many moving parts is almost magic, this piece here, that piece there, fits perfectly somehow and everything works. On a good day, the programmer is in The Zone, pieces fit effortlessly. On a bad day, maybe nothing gets done. That’s why the headphones. That’s why the night shift, morning shift. And if you’re not a programmer, that’s why your programmers bite when you approach their desks - you missed the sound of a thousand and one intricately placed detail crashing down like a house of cards, when you slap their back, “Hey, how’s it goin?” What eventually got me into writing tests, was a point about TDD that is often buried, not clarified & maybe mentioned in passing. (On hindsight, I realise most TDD materials are meant to convert TDD folks of a different sect, and not really meant to get outsiders into TDD) An example is in this RailsCast, at the 4m37s mark, Ryan Bates made a throw away comment, “I really like this approach of testing, it just walks you through: what’s the next step I have to do to get this working.”. Though this may seriously not be the most important benefit for most TDD advocates, but as a reason to start adopting TDD… That. Was. It. Writing your test first is like putting a golf flag at the hole. 1 2 3 4 5 6 7 it "emails user when requesting password reset" do user = Factory(:user) visit login_path click_link "password" fill_in "Email", :with => click_button "Reset Password" end Now that the flag[...]

Nokia Lumia 800


Finally gotten my hands on the Nokia Lumia 800. It looks gorgeous. Touch The Metro UI is sleek, and very responsive to touch. In fact, the touch could be described as too sensitive - it often mistaken my “mousedown” (if I may call it that) for a “tap” (as if I’d let go). This isn’t as big a problem in the normal menu navigation; when in the browser I’ll accidentally trigger zoom in/out surprisingly often. Perhaps it is a MSIE thing. In any case, it is not laggy. [6 days in] The gesture misreads is getting rather irritating. Reading and scrolling a webpage very often trigger the zooms or even unintended click on links YMMV, but I don’t even think about the worrying about such accidents on iOS; Perhaps they err on the side of less destructive gesture or something smart. Regardless, my experience is that even the original iPhone interprets gestures generations ahead of Lumia 800. [Update] This informative video of Microsoft explaining how touch hardware needs to “meet specifications” actually speaks volumes of the great amount of attention Apple has put in since the first iPhone. The touch experience on the 2007 iPhone is still unsurpassed in 2012, think about that. (Can’t shake off the feeling that the video is an irresponsible (we did our part) & pre-emptive disclaimer of “their hardware is at fault, don’t blame us”) There is also inconsistent treatment of “mousedown” style on links. e.g. In Google Mail tile, the links are helpfully highlighted when “mousedown” - like on iOS. Whereas in People tile, reading a tweet and clicking on a url is tricky - the whole tweet gets a “3d mousedown” treatment (like tapping a wooden plank floating on water) and only when you release then do you find out if you’ve tapped the link or done nothing useful. Readability [6 days in] Metro, a typography-based design, renders itself (home, menu, native apps) very well. I’ve initially commented to my wife that the fonts look sharp & I didn’t even miss the “retina display” (unlike when I look at older iPhones). Sadly, the same cannot be said for webpages in the browser - where fonts tend to be smaller. Text look ugly there. [1 month in] The Metro layout allocates a lot of space on boasting its own sense of style (which looks gorgeous to demo, e.g. the big screenshot above content only shows after ~40% of the screen, and the right 10% is “spent” on revealing the next screen). This might be fine for a desktop or tablet, but starts getting pointless on the small screen after extended usage. A survey of some apps in their app store (e.g. Facebook app), seems like when following Metro look and feel, it is very easy to fall into the trap of only using half the screen for content. Web Browsing [6 days in] On Mobile Safari, if the web page doesn’t render well I’ll [double-tap] zoom & scroll as I read, or I’ll tap “Safari Reader”, if that still doesn’t work I’ll tap my Instapaper bookmarklet & read it later on my Instapaper app. On the Lumia, due to touch gesture issues, the “zoom & scroll” route has 50% chance of taking me through an article. If that doesn’t work, then there’s no redress: No readability feature, no Instapaper app (unless I pay monthly subscription). The net effect is, I’ve caught myself dreading to visit a link, go search for something on the web or generally using the browser. This is quite unlike the general sentiment of web browsing on the iOS. Transitions Stark changes to rectangular areas on the screen is often confusing. When tastefully used, subtle animation can help explain to a user where something came from or went (e.g. [dis]appearance of dialog boxes). In Metro, pages of[...]

Ruby for Rails Beginners


I've been doing this exercise for a few Rails beginners (or non-rubyists who glanced at Rails a bit before) and the general feedback is that they learn Rails but not Ruby, and this is new to them. So I suppose I should just write it down to save future effort. If you already know Ruby you'd want to stop reading here. "Computer, book me on the cheapest flight to Mexico for tomorrow!" The unfortunate thing is, most folks' first contact with Rails will be some short code snippets like class Comment < ActiveRecord::Base belongs_to :user end class User < ActiveRecord::Base has_many :comments validates_uniqueness_of :username, :case_sensitive => false end Very succinct. Looks like english and could even appear friendly to non-programmers. It doesn't look "real" and has "toy" written all over it. The jaded programmer will see "config file", "no real syntax", "fragile", "abitrary subset", "haml" (zing!) or "not powerful" as if a guy in grey suit just demoed how he told his computer what to do verbally - "How sustainable can such fake syntax be?". And perhaps beginners might go, "Rails lets me write english-ish code! Wow wee!" Let's start somewhere else In mainstream OO languages like Java, you can't really write Java code anywhere you like. "Huh?" Yes, you just don't usually think about it this way. For example you can't simply insert Java code anywhere, say… System.out.println("here?"); public class Hello { public static void main(String [] argv) { System.out.println("world!"); } System.out.println("or here!"); } It's not allowed and you'd get errors $ javac class, interface, or enum expected System.out.println("here?"); ^ expected System.out.println("or here!"); ^ illegal start of type System.out.println("or here!"); ^ 3 errors In Ruby, however, you can write Ruby in weird places: puts("here?") class Hello def self.main(argv) puts("world!") end puts("or here!") end Hello.main(ARGV) Which runs like this instead $ ruby hello.rb here? or here! world! So? Big deal Taking another step back, let's look at this Ruby class class Hello def an_instance_method() puts("This is inside an_instance_method") end def self.a_class_method() puts("This is inside a_class_method") end end If you're a programmer you'd have ascertained def defines a method (or function). Now, the difference between def an_instance_method() and def self.a_class_method() is that a_class_method is a class method (or Java programmers like to say "static method") and is used like this Hello.a_class_method() which prints This is inside a_class_method whereas an_instance_method is an instance method that you can call on instances of the Hello class, x = x.an_instance_method() So? Big deal Say we define our Ruby class like this, with a puts statement at the bottom class Hello def an_instance_method() puts("This is inside an_instance_method") end def self.a_class_method() puts("This is inside a_class_method") end puts(self) end Running it would produce $ ruby hello.rb Hello Notice puts(self) has printed the name of our class Hello. This means we are referring to the Class which we're still in process of defining! And since we can refer to it, we can also use it (as much of it as we've defined so far) cla[...]

Giving Feedback On A Design You Are Paying For


Disclaimer: I’m not knowledgeable in this area, but am interested to know what’s up. Please feel free to correct my misconceptions.

“Make this blue”, “Too big”, “Bigger”, “Darker”, “Too narrow”, “Put the logo here”

I find it hard to comprehend why anyone paying good money for design, would review in this manner. Over and over, round after round. Sounds more like a person trying to work Photoshop with voice control. Shouldn’t we let the skilled worry about their craft? If your designer doesn’t know design better than you, why there is a business relationship?

On the back of such encounters (as an onlooker), I had concluded [mistakenly] that having multiple rounds of design reviews was just masturbatory and that a customer should only focus to communicate the whys clearly and leave designers to do their job.

Yesterday, 37signals posted another “Behind the scenes” article on their blog. As I was reading their recap of multiple iterations and feedback, it occurred to me that my conclusion was misdirected. There’s nothing wrong with the fact that there were multiple rounds of review. My issue was with the nature of the critiques.

The feedback for each round were about story, intent, clarity. Not pixel pushing. Seems to me, that is how a money paying customer should be reviewing to get his money’s worth.




I had the need to show some folks example screens of webapps I’m working on recently. Using those screenshots, the other party could have a better feel of things, we could have a clearer discussion. But the irritation [for me] is always the setup

  1. The app I’m working on is still in flux, i.e. design & data attributes will likely change, often
  2. The content I have is often imported from real data sources, and hence is somewhat private & sensitive
  3. I’m too lazy to think up fake names, fake scenarios, fake photos to fill my database, just so I could have a fragile, demo screenshot (I’d need to redo / update later)

What I’d really like is

  1. To be able to use my current webapp, as-is
  2. To be able to use my current data, as-is
  3. To protect private & sensitive data

Smells like a bookmarklet? So here it is Loremipsumizer. After installing it, I can anonymize any webpage instantly (then take a screenshot, annotate or print & discuss with somebody else, without worrying about the sensitivity of content)

Click here to try it on this webpage!

The Loremipsumizer will anonymize all text, scramble all numbers, replace images, flash embeds (& video tags?) with wireframe-ish cross-boxes (via data uri). Unfortunately I didn’t have an elegant solution to anonymize background images (css sprinting, image size, etc) so I’ll need suggestions there.

In any case, here are a few screenshots of webpages I’ve anonymized. No prizes for guessing which websites:

(object) (embed)

Note: Loremipsumizer does not require any JS library, and have not been tested on irritating browsers. Patches are welcome.


FOAF Rewards


The Joneses is an interesting idea: if you push product placements all the way to 11, you'd have it done in real life. But how do you attribute a [growth in] sale of product P, to the "Joneses" team member? Target market of product P + geography of the sale? And what if the network effects is far reaching and has no geographical boundary (i.e. internet)? So, no two "Joneses" teams should pimp the same product? No good.

What if we try something more pre-emptive, using something more direct - FOAF. So when customer Charlie buys Product P, your CRM picks up that amongst other customers who bought P, customer Betty is in Charlie's FOAF network (Facebook, Twitter, email, blog, flickr, etc).

With this knowledge, you could directly credit Betty a referral reward and hope to gain an army of MLM team. But this risks displacing Betty's original reason of buying your product with a weaker, extrinsic motivation.

Alternatively, you could credit Betty with a discount on her next purchase. This approach is good and already exist informally. But it is also unsurprisingly inefficient in its current state: the connection happens if you manage to make the sales assistant remember you and they bother to inquire about referrals when serving a new customer.

Wouldn't it be great if a hypothetical "iCashRegister (now with FOAF)" exist to make this more efficient?

To cap the potential hemorrhage of "discount credits" on heavily connected customers, if there are several customers connected to this new customer, they'd only each get a slice of the credits. Also, for some business, it might make sense to attribute a referral based on the transaction of the same product. For other businesses, it might make sense to attribute a referral based on purchase recency.

So now any customer connected to a subsequent customer gets discount credits. And all this can happen regardless of whether (you) the business owner is servicing the customer, or if it was just your part-time sales assistant in the shop.

To hell with wimpy loyalty cards. Why isn't your business using "iCashRegister (now with FOAF)"?

Update: Do check out Anafore if you're interested in this topic!


Yet another $5 iPad stand - this one is for the Brits


Finally, our bulky British Standard power socket design is useful for something.

(object) (embed)

Only $5.50 - but you'll probably already have one in your house. No warranty. RssPaper app sold separately.


You're Doing It Wrong - ACM Queue


What good is an O(log2(n)) algorithm if those operations cause page faults and slow disk operations? For most relevant datasets an O(n) or even an O(n^2) algorithm, which avoids page faults, will run circles around it.
the results coming out of the CS department would be so much more interesting and useful if they applied to real computers and not just toys
- Web annotation on You’re Doing It Wrong - ACM Queue

Since @replies can come from anybody


Someone, let's say Yahoo, could roll out their own twitter-like service (let's call it yatter). And all yahoo mail users "become" yatter users automatically, like how they became Openid accounts.

  1. when a yatter user "joe" yatts, "@twitter/charlie what are you doing?"
  2. yatter's twitter bot called "yatter" relays the tweet, "yatter/joe: @charlie what are you doing?"
  3. twitter user "charlie" sees the message in his @replies stream, and can respond, "@yatter/joe hitting my refresh button again and again"
  4. a bot called "twitter" relays the message, "twitter/charlie: @joe hitting my refresh button again and again"
  5. yatter user "joe" sees that in his @replies stream in (repeat from the top)

I'd guess it makes sense for yatter apis to be fully compatible with, in the vs kind of way. So twitter clients just need to add a new config, "hostname", and we're done.

I think could technically allow @yatter/joe to follow @twitter/charlie. The question is, would allow their @charlie user to follow @yatter/joe?

Yatter could use the age-old hotmail trick and append the latest status message of the mail sender to the email footer. That should pique interests of recipients. Besides, "a signature" is an existing, understood concept that users can easily see why they'd would want to update their "yatter status"..


An iPhone optimized web page


[UPDATE: Proof of concept no more, RssPaper is now in the store!]

The defacto way of making a web page "optimized for iPhone" is to slap on iUI (or variants) to simulate the look & feel of a native app (i.e. the UITableView). You can click on an item in the list, and the page slides sideways to reveal another list, or more details… etc.

However, the starting point of trying to mimic meant we're aiming for the web site's experience is to be worse-or-almost-as-good compared to if it was a native app. e.g. Can aim to be different instead?

In trying to mimic a native app, the iUI approach locks down the browser's width & scaling capability. I actually liked that part of browsing on the iPhone – its automatic zoom! To zoom-in, you simply double-tap on an area of the page. To zoom out, double-tap again. (There's pinching, but it is manual & I don't like tedious things)

Unfortunately, most layouts don't make it easy for iPhone to automatically zoom-in. The kicker is, a good & fluid CSS layout actually hinders! e.g. the text is still small after double-tapping on

Turns out, the automatic zoom is controlled [only] by the width of the page segment.. meaning, the page's font size can be infinitesimally small – it doesn't matter. As long as the containing width is also small (e.g. contains 5 words across 1 row), the user can still comfortably zoom in and get big text with sharp font of 5 words across the entire screen width!

Taking this to an extreme, we could have all our site's content render in tiny little font inside narrow columns on 1 single page and the iPhone visitor can still effortlessly zoom in and read everything! No click, ajax, network lag, read content, back, click another, .. etc.. i.e. instead of content hierarchy behind deep navigation, we could have it based on font sizes.

Sounds like a newspaper huh?

To try this out, I'd hacked up this proof-of-concept a few days ago, and have been using it to read my RSS feeds on my bus rides the past few days. While the app itself is not there yet, the zoom interface experiment has really been working out very well!


Have an iPhone/iPod touch? Try it and lemme know?

PS: A more extreme sell for a zoom-based UI is Microsoft's famous Seadragon demo.
PS: this whole experiment was sparked off when I tried to read the beautiful on my iPhone.


9.99 Reasons to Love IE6


A friend showed me this website today: "Bring down!" Such angry words. There's so much negativity on the Internet regarding a browser.

Instead of 1) getting good folks to put feeble badges on websites, or 2) resigning to fate & cursing whenever you have to fire-up IE6 and check, or 3) getting bigger, better tools to do stupid things faster… Maybe we can be more constructive.

Here's an idea:

Dear Developers & Designers,

Save your sanity: At $0.00 cost to you, we make your website work in IE6!

Step 1. Register your website with us
Step 2. Just copy-paste this into your website's section:
Step 3. *chuckle* There's no Step 3!

How this'll work is that, all your IE6 site visitors will be gently redirected to our payment page, explaining nicely:

We're sorry but Website XYZ no longer works with your old, antique Internet Explorer browser. BUT for just US$9.99/month (1 movie ticket!) the hardworking engineers at will fixup the website for YOU, and make this problem go away for you! It'll just take 30 seconds! We accept all major credit cards & Paypal (maybe even 淘宝! Alipay (correction by @xtinegoh) )

But you choose not to :-( you may install any of these free, modern browsers and use Website XYZ through them: [firefox logo] [safari logo] [google chrome logo] Team

If the IE6 compatibility work has not been complete yet, the above pay-wall will not be shown. Instead, we'd display a cool 1990s construction worker icon that these folks will be extremely familiar with!


All paid users can of course transparently continue to use the web site (and all other websites that uses this service).

PS: Designers & developers that would like to do Internet Explorer compatibility work (yes, all 3 of you out there, 尤其是中国的同胞朋友, Hội lập trình viên Việt Nam, and сотрудник российских программистов !!!!) Please contact me


Why pick a different domain name for asset_host - and not just subdomains


Some sites, e.g., uses subdomain for images & assets


Whereas others, e.g., uses a different domain name.


Because cookie bandwidth does add up.

PS: I spot George Oat's picture on Flickr frontpage still. I wonders if it is a form of respect or neglect.


How to really Post Load Google Ads (while keeping document.write happy & page rendering snappy)


So you have a web page and it is getting some hits. One day, you decide you might as well earn some pennies off that traffic and began copy-pasting some Google Ads into it.

But you know, Google Ads suck. They use document.write. Yep, the things we were warned against. But that's not all. Their document.write actually pulls in more javascript, which in turn say "weeeeell, while we're at it!" and start to do even more document.write! (In this aspect, Microsoft ads seem more thoughtful, or it seems from Digg's homepage).

Anyways, this chokes the browser & makes them stutter. Your web page now renders to your audience in stops and starts:

some content appear > ads appear (stall) > more content appear > ads appear (stall) > rest of content appear

A necessary evil? There are a few things that will fix to a certain extent: 1) use "script defer" or 2) hacking document.write. Not ideal in terms of fragility, and subsequent maintenance of ads embed codes.

Let's look at the problem again: 1) Google wants you to paste the script where the ad appears, 2) Wherever the script is pasted, the browser will stutter & stall the content that comes after it.

For #2, maybe the "solution" is to paste the script AFTER all content? But wait – doesn't that mean #1 the ads get rendered there & not where I want them? Yes, but only initially.

Why not reposition these ads to where they're supposed to be after they are constructed:

all content appear > ads appear (below the fold, stall) > ads appear in position

Let's say that works, unfortunately it sound convoluted & a hassle, the site has too many existing ads to migrate & our guy managing the ads doesn't code, he just copies whatever Google provides & blah blah blah…

That's what the postload_google_ads Rails plugin is for :-) site-wide benefit for minimum fuss (upfront & subsequently)

To see it in action, see this demo. Click on "Before" and "After". They 2 pages are essentially the same, but only one of them applies an "after_filter":

The postload_google_ads plugin is an "after_filter" in Rails. This means that after your webapp has done its thing & generated the dynamic HTML, the after_filter transplant the ads' script tag to the bottom of the DOM tree, leaving behind some placeholders. This modified html is then sent back & rendered on the user's browser. After all your content renders, the ads will construct themselves (document.write all they want). After the ads are done, a little javascript repositions the rendered ads based on the absolute position of their corresponding placeholders.

Until ads nework catch up to use unobtrusive javascript, I guess I'll have to settle for this.


git svn rebase - could not detach HEAD (howto fix)


Sounds gross but that is the curt message:

$ git svn rebase

First, rewinding head to replay your work on top of it…
could not detach HEAD
rebase refs/remotes/trunk: command returned error: 1

Not very helpful, no clue, can't even buy a vowel. But if you try something else, the error message begin to make the problem more obvious:

$ git co refs/remotes/trunk
error: Untracked working tree file 'public/images/plugout_button.gif' would be overwritten by merge.

Well… then git-svn should've said so!

$ rm public/images/plugout_button.gif
$ git svn rebase
First, rewinding head to replay your work on top of it…
Applying ….

So there. This post is so that I commit it to my long term memory, aka Google.