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.

No.

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

What happens when your user replies to that email, using email? You could stonewall with a non-existant donotreply@example.com… 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:

  1. 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
  2. Configure postfix to handle that email with an smtp-to-http shell script
  3. 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: discussion-42@webapp.com; an email notification for Discussion id=99 would use a different Reply-To: discussion-99@webapp.com address.

When a user replies via email, the webhook handler parses To: discussion-42@webapp.com 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: <discussion42messageid> and References: <discussion42messageid> 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: standard@webapp.com is for Dicussion.find(42)? We look inside the values array of In-Reply-To + References instead.

For example, an outgoing email from your webapp just need to craft the correct, unique-per-conversation Message-Id: <discussion-42@webapp.com>. A email reply to that will automatically contain these headers

1
2
In-Reply-To: <discussion-42@webapp.com>
References: <discussion-42@webapp.com>

And our webhook handler can still locate Discussion 42 based on values array of In-Reply-To + References. Thus, managing Message-Id alone will suffice.

Warning: earlier we mentioned using email.from to identify the User, but that’s not reliable since email From: header can be easily faked. A better mechanism would be to embed the author identity in References

Summary

A quick summary of this scheme is

  1. User#1 create new Discussion#42 with User#2 as participant
  2. App delivers ‘new discussion’ email to User#2 with Message-Id: <D42> and References: <D42-U2SECRET>
  3. User#2 replies to email, email automatically carries In-Reply-To: <D42> and References: <D42> <D42-U2SECRET>
  4. Webhook handler picks up D42 to retrieve Discussion#42, and picks up U2SECRET to locate User#2 and proceed to create a comment
  5. App delivers ‘new comment’ email to User#1 with References: <D42> <D42-U1SECRET> (notice Message-Id doesn’t matter from here onwards)

Diymailin

That could be the end of the story for most people, but for various reasons I couldn’t afford to have an unreasonably low cap on the number of incoming emails, and have attachments stripped.

So for my own setup, I pay $5/month for a Digital Ocean box to run a diymailin instance. With that I can support the numerous apps that I have using diymailin’s built in web interface, without mucking around with arcane postfix config.

Mail2Webhook

But if you’re too lazy to setup your own diymailin instance, you can hop on to mail2webhook.com and use my setup instead.

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 (Google.com, Amazon.com), 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 customer, and they’d have to explicitly install apps from an app store. The result is, developers can easily charge money for the app in a way that agrees with how people pay for things. Thanks Apple AppStore, for training the mass consumers!

A side effect is, since you’re now selling your app, you no longer need to sell your users: Hey, your product has no ads.

Epilogue

There once was a social network idea pitched to me: an anti-Facebook.

With superb privacy configs, access controls so anal that the infrastructure requires each user to store content in their own harddisk (Ha!). No big brother. No subpoena. I told my peers they’re crazy.

Perhaps they’d just needed a better go to market strategy.

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 => user.email
  click_button "Reset Password"
end

Now that the flag is planted, the actual work of “writing the code” becomes an almost mindless stroll of hitting the ball towards the flag - fixing the next error thrown from the test: “error: no link with title, id or text ‘password’ found” ok, let’s add that ‘password’ field; “error: `new_password_reset_path’ undefined” ok, let’s add that ‘new_password_reset_path’ route; etc until there’s no more errors. Then you’ve reached the flag. The feature is done. And chances are, you haven’t even needed to launch that browser to “check”.

(If your test code can’t produce “reads like english” code like the above sample, then just write your steps in prose first. You can add test code next to the [then commented out] prose later. The end result is the same, and fwiw I actually do prefer test code to read like code than english-y dsl)

This approach addresses the “house of cards” issue by helping you persist details quickly, and often, into writing. Interruptions are still annoying of cos, but you can survive them better now: the next error is always clearly in sight, just solve it to move on to the next error. Next boss to kill, in a mindless arcade. In fact, you can leave it “half done” and come back tomorrow without missing a beat, or requiring “boot up time” (recalling & loading details back into your brain) before you get started.

Certainly this isn’t a silver bullet for all scenarios, but it’s been effective enough for me. I’d found myself ploughing through features steadily despite being drowsy from flu medication or being interrupted by loud wails across the room (I’m also a stay-home dad to my 4-month old baby).

So, if you’re a good programmer but not writing tests yet, hopefully this can strike a chord with you and get you started. A word of caution: there is just TOO MUCH testing libs out there, learning about most them is simply a waste of time. Just use the bare minimum & get going.

PS: This is known as the “red/green/refactor” mantra, which like a company mission statement, fail to appeal to me in any way. Wikipedia, ”TDD constantly repeats the steps of adding test cases that fail, passing them, and refactoring. Receiving the expected test results at each stage reinforces the programmer’s mental model of the code, boosts confidence and increases productivity.” zzzzz zones out… um, watever.

[Update 27 Sept 2012]

Working in the head doesn’t scale. The head is a hardware platform that hasn’t been updated in millions of years. To enable the programmer to achieve increasingly complex feats of creativity, the environment must get the programmer out of her head, by providing an external imagination where the programmer can always be reacting to a work-in-progress.

– “Learnable Programming: Create by reacting”, Bret Victor

Nokia Lumia 800

Finally gotten my hands on the Nokia Lumia 800. It looks gorgeous.

Nokia Lumia 800 Black

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 often peek at you from beyond the screen edge, elements at the top/bottom bounces around, and things in the middle often swirl & flip themselves silly, tapping on buttons sometimes give you that a slight vibrating buzz (a poor attempt at tactile feedback).

(Regarding the part where pages peek: unfortunately Metro chose to wrap you around as you swipe toward the page on the right, instead of ending on the “last page”. Thus making it lose all the spatial benefit of having a view port in a big space metaphor)

Though much better than Vista days, I continue to get the feeling that Microsoft interfaces enjoy telling the user, ”Hey, look at ME!” more than removing distractions from the task at hand or leaving limelight for the user’s content.

A case in point is the hardware “search” button. When you want to search for something on the web, e.g. “metro ui”, tap and it will bring up Bing.

The beautiful background photo is sprinkled with tiny animated boxes - if you tap on them, will show you a trivia of some sort. This eye candy obviously speaks well of whoever had put it together, “Look at our new search page, mum!”. However, the task at hand is to search - not marvel at the search page. A better flow would be to bring up the keyboard for the user to immediately type whatever he’d want to search for before he’d forgotten it (which is “metro ui” in the previous paragraph).

Bing Bing, after tapping on search bar

To make it worse, the search button is located below the bottom of the screen, whereas the obvious next step is to tap something at the top of the screen.

What’s nice though, is their sidestep of Apple’s rubber band (bounce scrolling) patent. This might have changed, but I recall Android to have a lame, abrupt halt when a scrolling window reaches the end. Metro, however, implements an equally effective [to Apple’s rubber band] effect by squeezing the height of elements into the edge of the scroll window, like passengers pressing onto each other (and bouncing back) when the train screeches to a sudden stop.

Sleep/Wake

How do you pick up your phone from your desk? Go ahead and try it. Not something I’m conscious of before this, but I pick it up by the sides. Unfortunately this means I’ll often accidentally hit the sleep/wake button on the Lumia 800 - that button is smack in the middle on the right side. A reference for iPhone 4 users, the equivalent would be having that button just above your sim card slot. Yea, go figure. What’s wrong with having the sleep wake button on the top edge? Was that patented as well?

Hardware Back Button

[6 days in] The issue with a hardware back button is the lack of a hardware forward button (when combined with the fact that websites just love redirecting you to their mobile version).

For example,

Tap on People tile > Read news feed > Tap on tweet > Tap on url in tweet > Loading link > Redirected to mobile version > Page loads

After reading, you tap back to Tweet screen to reply that tweet, but you see Loading link > Redirected to mobile version > Damn, you tap twice but the redirect was faster than you, you’re still at mobile tweet page, then you tap faster, tap.. You’ve tapped too many times and you’re back at news feed screen (or worse: home screen).

Without an equivalent forward button, it is onerous to get back to the correct place to reply that tweet (how far did you scroll?). Especially since re-entering some of these screens will refresh and thus change positions of items in lists. At this time, it begins to feel like a chore.

[3 weeks in] To make things worse, the “Home button” on WP7 does not bring you back to the Home screen. Instead, it launches the Home screen app on top of your current app. This is a subtle, but important difference to where you thought the “Back” button will bring you.

On more than one occasion, tapping the “Back” button had unexpectedly brought me past the Home screen and [back] into a screen that I’d forgotten about, lost for a moment, and not sure what I’m supposed to do since the screen is totally irrelevant now.

Flipboard

I like the “People” tile. If you’re willing to let Microsoft in to your world of Facebook, Twitter & Google, you’ll basically get a Flipboard phone. Their [addressbook] integration extends into the “Calendar” and “Pictures” tile. Tweeted pictures, Facebook photos shared to you will all show up promptly neatly organized into albums.

I don’t actually have the urge to download a Twitter or Facebook client for this phone. Yet.

It would’ve been even better if the randomly chosen background photo (in Pictures app) could get some just-in-time blur / contrast treatment applied (like Path). Currently, the slim, white text can be a tad difficult to read.

[6 days in] I’m finding the People tile integration / presentation of Facebook newsfeed (which impressed me earlier) to be shallow - messages spammed by friends playing games appears unfiltered, listing purely by recency isn’t as interesting as how Facebook interleave activity, uselessly small thumbnails are also tiring to look through. As a result, I’ve been looking at far less shared videos… which could be a good thing.

Camera

Scenes: auto, backlight, beach, candlelight… White Balance: auto, incandescent, cloudy… Exposure Value: -0.5, 0, 0.5, 1.0… ISO: auto, 100, 200… Metering Mode: Centre Weighted, Frame Average, Centre Spot… Effects: Normal, Black & White, Sepia…

Settings that reads like an actual point & shoot camera. I hate it.

Also, having Press the screen to take pictures = On as default is sure to trip up migrants from iPhone. But maybe they are only trying to poach adopters from the market size leader.

Computer

The phone told me there was software update available, instructing me to “connect to a computer”. Obviously, that simplistic instruction wouldn’t work on my mac. After a bit of googling, I concluded that I need to install “zune” on my mac - which brings me to this page.

The download is a .txt file. Inside the file, is the instruction to go to another URL (itunes.apple.com) to download the app. WTF? Instructions inside a text file? Did they steal that awesome user experience from some random bittorrent site? Where’s my ascii art?

FWIW, Paypal is worse for doing such 302 Redirect with a PDF file.

Copy Paste

[3 weeks in] You tap on a word and the copy-paste icon immediate jumps up. Tapping on the icon will prepend the icon into the list of auto-complete words. Now, whenever the keyboard shows up, the [paste] icon is there, ready for you to tap and paste into the text field. I find this reuse of the existing auto-complete mechanism very elegant.

Select Copy

After pasting once, the icon goes into partial hiding into the left of the screen. Tapping on it will reveal it in full, and tapping it again will paste the content into the text field (and the icon goes into partial hiding again). I find this dance slightly unnecessary, since it doesn’t save a lot of pixels. Moreover, you can “throw” the icon left and it will completely disappear from the autocomplete list and save even more space (only to re-appear when focusing on a new text field)

Also unfortunate, is if you turn off the screen (easily by accident, as mentioned earlier), the clipboard is completely deleted. This is either due to security concerns, or (more likely) due to the need to have a way of free-ing up the autocomplete screen space.

End

The OS appeals to me and I attribute all hiccups encountered to the relative youth of the platform. I’m hoping to use it, at least for the next few weeks, as my full-time phone.

But I sure miss Instagram already.

[6 days in] Though I paid for my iOS Instapaper app, I’m not a paid subscriber for Instapaper, thus no Instapaper app for me; I’m very much missing the relatively new (and relatively minor) feature on iOS: Safari Reader.

[1 month in] I’ve sold it.

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 Hello.java 
Hello.java:1: class, interface, or enum expected
System.out.println("here?");
^
Hello.java:6: <identifier> expected
  System.out.println("or here!");
                    ^
Hello.java:6: 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 = Hello.new()
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)

class Hello
  x = self.new()
  puts(x)

  def an_instance_method()
    puts("This is inside an_instance_method")
  end
  x.an_instance_method()

  def self.a_class_method()
    puts("This is inside a_class_method")
  end
  self.a_class_method()
end

Running it would produce

$ ruby hello.rb 
#<Hello:0x0000010084f778>
This is inside an_instance_method
This is inside a_class_method

Notice how instance x obtains an instance method after the fact! Let's clean up our class: rename it as User, and rename the class method to validates_uniqueness_of, and add some arguments to the class method…

class User
  def self.validates_uniqueness_of(what, options)
    puts("This is inside validates_uniqueness_of #{what} and #{options}")
  end
  self.validates_uniqueness_of('username', Hash['case_sensitive',false])
end

The #{blah} syntax is string interpolation, allowing Ruby code to run within a string, like "Five plus One is equal to #{5 + 1}". So, running this file would produce

$ ruby hello.rb
This is inside validates_uniqueness_of username and {"case_sensitive"=>false}

In Ruby, Hash objects (or associative arrays) can be defined literally as {'case_sensitive'=>false}; (brackets) and {curly braces} are largely optional; self is implied; You can also use :symbols to denote things you'd usually use enums or constants for

class User
  def self.validates_uniqueness_of(what, options)
    puts "This is inside validates_uniqueness_of #{what} and #{options}"
  end
  validates_uniqueness_of :username, :case_sensitive => false
end

We can use the < syntax to denote inheritance and define the class method elsewhere

class Base
  def self.validates_uniqueness_of(what, options)
    puts "This is inside validates_uniqueness_of #{what} and #{options}"
  end
end

class User < Base
  validates_uniqueness_of :username, :case_sensitive => false
end

We could stash more methods into our Base class

class Base
  def self.has_many(what)
    # some code
  end
  def self.validates_uniqueness_of(what, options)
    # some code
  end
end

Or we could use Mixins to organize them neatly into standalone modules and compose them together

module Relation
  def has_many(what)
    # some code
  end
end

module Validation
  def validates_uniqueness_of(what, options)
    # some code
  end
end

class Base
  extend Relation
  extend Validation
end

Either way, we can now have something that looks familiar

class User < Base
  has_many :comments
  validates_uniqueness_of :username, :case_sensitive => false
end

So you see, the toy looking code is not Rails-specific, nor is it some limited-capacity syntax for PPT & luring beginners.

Came for Rails? Stay for Ruby

And that's it. If this has piqued your interest, you might want to investigate how Ruby lets Rails get away with the syntax of config/routes.rb and how Ruby makes has_many and validates_uniqueness_of possible to implement.

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.

Loremipsumizer

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.js. 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:

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!