Monday, April 27, 2015

Is this a toothbrush?

Ceci n’est pas une brosse à dents?
Today’s vigilant practitioner of oral hygiene won’t be convinced by appearances alone.

…and though the label may say ‘toothbrush’, its diminutive size and unassuming positioning may do little to assuage the doubts of the hardened toothbrush denier.

OK, it’s a toothbrush.

Thursday, November 20, 2014

What would it take for you to change habits?

I care a lot about Uber.

Their latest outrage has attracted a lot of negative press this week, and rightly so. A reassuring number of people are horrified at the company’s SVP proposing a million-dollar scheme to invade the personal lives of journalists and smear them, though, to my disappointment, I’ve seen only a few people remark on how alarmingly specific that supposedly off-the-cuff proposal was, and, surprisingly, none on how come that SVP had already dug enough dirt about a journalist to make ‘a particular and very specific claim about her personal life’.

I think it’s easy to get scandal fatigue over endless tales of corporate malfeasance, and if I were to be as engaged by every other corporate scandal as I have been on this one, I’d have no time for anything else. I’d like to explain why Uber’s myriad tales of wrongdoing is such a personal matter to me, and why I think, whether you care or not, the outcome could make a big difference to your life too.

It wasn’t just through ruthless determination that Kalanick and co. got Uber where it is today. Greasing the wheels of their steep ascent was a king’s ransom in venture capital. Today, a few very rich people stand to become very much richer from the company’s years of exponential growth, and none of them wants to upset the applecart by calling out their misdeeds. Remarkably, even the do-no-evil company has taken sides with the don’t-get-caught one and hasn’t dared to say a peep throughout this whole scandal.

(And by ‘scandal’, I’m referring not to Emil Michael’s recent moment of candor, but to the whole pattern of wrongdoing that speaks to the heart of Uber’s corporate culture. Many others have documented their ethical record better than I ever could; let me just encourage you to search for yourself).

My key point is this: if, as a society, we allow Uber’s playbook to succeed, then the big lesson that investors and startups alike will take home is that playing dirty is the new key to success. In very little time, expect a race-to-the-bottom of corporate ethics as amorality becomes the metric by which a new wave of startups will compete.

And that’s why it’s so personal to me. Being an INFP, I have a creative side that yearns to pioneer new ideas, and an idealism that clings to the belief that they can be taken at their merits. It’s upsetting to see a company portray itself as a scrappy young David, facing the Goliathan powers of incumbents and regulation; only to grow big and, as Nick Gillespie points out in Time, start a campaign to work with local governments to entrench their position and use regulation to shut out competition.

It’s that preoccupation with killing off their rivals, and the shameless dirty tricks they’ve engaged in to do it, that disturbs me so viscerally. And it shows no sign of abating. In his Business Insider article, Henry Blodget remarks that Uber’s latest round of financing, in which they’re seeking to raise (if rumors are to believed) $1-2 billion, make no sense from a product point of view. A company that stands only as a middleman between supply and demand, and whose solution is already mature and operating at scale, doesn’t need anything like that amount of additional funding. But it does make a lot of sense from the perspective of:

“When a competitor enters an Uber market, one investor in an Uber-competitor says, Uber immediately and radically cuts its prices. Uber then happily loses money on each ride, knowing that the new competitor, with inferior scale, will lose even more money on each ride. Uber bleeds the competitor until the competitor realizes that Uber will do whatever it takes to crush it. The competitor then often gives up and withdraws — and Uber raises its prices again.”

Just for the record, I don’t want to suggest that other issues aren’t important too. Misogyny, disregard for privacy, callous disregard for customerssafety, etc. are very serious issues in themselves. But in the grand scheme of things, I think that outsiders will see them less as keys to Uber’s success, and more as things that they’ve been able to get away with. Nobody’s about to create a startup that competes on disregard for privacy, whereas I genuinely fear a huge glut of money will flow into those who can prove themselves the most anticompetitive.

Some influential figures have called for a replacement of senior management. Even if it were to happen, it’s not enough. To forgive the company after a change at the top would be to reward all, including those forced out, with the spoils of victory, and the harm done to the competition (and indeed, to competition in general) would be irreparable.

It takes so little for customers to switch providers. There’s a small handful of companies offering services so identical that using an alternative demands nothing more than a change of habit.

Please, I implore you. Make the switch. You’ll lose nothing, and in the long run, have much to gain. 

Thursday, August 7, 2014

ObjectiveDDP and Meteor 0.8.2 compatibility

We shipped our version 1 iPhone app using version 0.13 of ObjectiveDDP to talk to a live Meteor server. When Meteor changed their protocols in 0.8.2, compatibility with the iPhone app died for us; ironically not because of lack of backward compatibility, but rather, a bug in ObjectiveDDP, which the new Meteor code exposed.

Upgrading ObjectiveDDP versions can solve the problem for new iOS apps, but what about the ones already out there? The nature of the bug means that ObjectiveDDP won’t even connect to the server; hence, if we bumped revisions, we’d have no way to alert the old clients that they’d need to upgrade. They’d just see endless unavailability.
  
To solve the problem, we needed to patch the server to have it accept the existing clients. The bug was that the old ObjectiveDDP was neglecting to inform Meteor of which protocols it could use, so the fix was to force Meteor to assume the old protocol (‘pre1’) if the compatibility list wasn’t specified.

Here’s what worked for me...

In ~/.meteor/releases there’s a release.json file corresponding to each Meteor version. I wanted to get 0.8.2 patched, so took a look inside 0.8.2.release.json. There, there’s a unique identifier for the version of the livedata component it’s using. In this case, with the line:

    "less": "188c110be5",
    "livedata": "f9cf0125ce",
    "localstorage": "27cc42083e",

Armed with that number, I edited
~/.meteor/packages/livedata/(that number)/os/packages/livedata.js
Somewhere inside, there’s a _handleConnect function. In the case of 0.8.2, it’s around line 1997:

   _handleConnect: function (socket, msg) {
    var self = this;

    // The connect message must specify a version and an array of supported
    // versions, and it must claim to support what it is proposing.
    if (!(typeof (msg.version) === 'string' &&
          _.isArray(msg.support) &&
          _.all(msg.support, _.isString) &&
          _.contains(msg.support, msg.version))) {
      socket.send(stringifyDDP({msg: 'failed',
                                version: SUPPORTED_DDP_VERSIONS[0]}));
      socket.close();
      return;
    }
    ...

(Note that I’m omitting to show the numbered comments on the right hand side of each line. Safest to leave them there and patch around them, I found).

That empty line after the self declaration was a perfect opportunity to sneak this in:

    var self = this;
    if (!msg.support) msg.support = ['pre1'];
    // The connect message must specify a version and an array of supported
    ...

And… world saved for now, but it’s a shame this was necessary. With more foresight I should have had the old iOS app connect to a unique hostname, one that resolves to the same IP address as the website, knowing that I can always shuffle DNS entries around to accommodate any future protocol divergences.