Net neutrality in Jamaica

I'm not sure if you've been keeping up on the net-neutrality debates happening in the US, but I wanted to take a moment to propose a less severe version of this for Jamaica based on an article I read about Digicel blocking certain services they deem to be competitive.

First, some background.

The net-neutrality debates in the US are focused on whether or not ISPs should be allowed to expose "internet fast lanes" for a surcharge. The debate centers around the issue of smaller companies (ie, startups) not being able to afford those faster speeds, and therefore being at a competitive disadvantage.

For example...

If Big Company had a video sharing website that was terrible but they paid the extra $100m USD per year to keep it fast, even a better video sharing website (think YouTube when it was starting) wouldn't be able to compete because it would be considered too slow compared to Big Company's site.

So where is the debate?

The debate I think we should be having in Jamaica is slightly less extreme than the one happening in the US.

I think we should consider drafting legislation similar to the Netherlands’ Telecommunications Act that says that ISPs cannot deliberately throttle traffic based on the content or purpose of that traffic (barring a few exceptions including throttling for congestion, integrity and security of the network, spam, or legal reasons).

If Digicel, LIME, or Flow decide to add a "faster lane" of traffic, we should debate the legality of charging for that later. For now, I'm saying no one should be slowed down.

Why does this even matter?

If Jamaica is serious about relying on innovation and investment in technology to level the playing field when competing on a global market, we cannot be at the whim of an Irish Telecom's top line revenue or quarterly targets.

It would be terrible to see a Digicel executive decide, in an attempt to meet revenue targets for the quarter, say "Let’s block WhatsApp so that people have to spend a bit more on text messages this month", or "Let’s charge WhatsApp a fee to allow their app to be used on our network".

Investment is already risky enough, and without any protections that Jamaican software companies won't be arbitrarily cut-off (or worse: held hostage) by an ISP, it isn't reasonable to continue investing in technology in the country.

Put simply: I won't be able to reasonably invest in tech companies targeting Jamaica.

  • As an investor in 10 Pound Pledge, I have to face the very real possibility of losing Caribbean customers based on an ISP not willing to deliver high-quality video content.

  • As an investor in EduFocal, I have to face the very real possibility that educational videos won't be delivered to customers without a hefty "transfer fee" (to be decided at the whim of the ISP).

  • As an investor in Blaze, I have to face the very real possibility that Digicel will build their own mobile money solution, and Blaze (being now found competitive to Digicel) will find themselves blocked from Digicel subscribers.

So what now?

I hope that Jamaican regulators and policymakers understand the implications of what they are allowing their telecom providers to do -- and the unintended and potentially disastrous consequences.

As an investor, I can certainly say that this move will make Jamaican-focused tech companies less competitive and less attractive for investment. It seems quite hypocritical for this to happen at a time when the government and the IMF are telling the Jamaican people that their main focus is on growing the economy.

Similarly, I hope that Jamaicans take a stand and tell their representatives that they won't tolerate discrimination of their data; that blocking traffic an ISP feels is "competitive" is unacceptable; that without treating all data the same, true innovation will be stifled just when we're starting to see great progress in Jamaica.

Safe deployment on App Engine

In a previous article I wrote about the need to update your Datastore indexes on App Engine before deploying code that relies on them. To simplify the deployment process, I put together a script that waits for your indexes to be built before deploying new code.

#!/usr/bin/env python

# Need to import and fix the sys path before importing other things.
import remote_api_shell  
remote_api_shell.fix_sys_path()

import time

from google.appengine.api import datastore_admin  
from google.appengine.ext.remote_api import remote_api_stub  
from google.appengine.tools import appengine_rpc


APP_ID = 'your-app-id'


def configure_remote_api():  
  def auth_func():
    return ('your.email@gmail.com', 'your.application.specific.password')

  remote_api_stub.ConfigureRemoteApi(
      APP_ID, '/_ah/remote_api', auth_func,
      servername='%s.appspot.com' % APP_ID,
      save_cookies=True, secure=False,
      rpc_server_factory=appengine_rpc.HttpRpcServer)
  remote_api_stub.MaybeInvokeAuthentication()


def main():  
  print 'Checking indexes...'

  configure_remote_api()

  interval = 10  # seconds.
  building = True

  while building:
    # Start with a fresh run: maybe we're done building?
    building = False

    for index in datastore_admin.GetIndices('s~%s' % APP_ID):
      # If any single index is building, we're not done.
      # Sleep for a bit and then this cycle should repeat.
      if not index.has_state() or index.state() != index.READ_WRITE:
        building = True
        print 'Indexes are still building... Waiting %s seconds.' % interval
        time.sleep(interval)
        break

  print 'All indexes are up to date.'


if __name__ == '__main__':  
  main()

Since this script will “block” until all indexes are built and ready, you can add this line to your deployment script, which should look something like...

$ appcfg.py update_indexes .
$ ./wait_for_indexes.py  # (The script above...)
$ appcfg.py update .

Protecting your idea

TL;DR: Requiring someone to sign an NDA just to hear your idea is unreasonable.

Every so often, I get an e-mail asking me for feedback on an idea, with a generic NDA attached that I'm asked to sign before I can hear what the idea is... I won't do that. And I'll let others much more experienced than I am explain why:

(The short version of each these is basically: "I can't and won't sign an NDA to hear your pitch or see your business plan.")

I’m happy to give feedback (who knows if it’ll even be useful to you), however the points in Carol Roth's article summarize the theme very well:

  1. Your idea already exists (or being new can be a problem)
  2. The value is not in the idea
  3. Sharing ideas makes them better

If you’re going to share anything generally considered “secret sauce” (like access to your code repository or the special formula for the Red Bull competitor you’re starting), asking for an NDA is a reasonable request -- you have to protect your property (however, a first e-mail typically wouldn’t be the place to discuss sharing that level of detail though).

If you're just sharing the high level idea, see it for what it is: something that hasn’t materialized yet and will likely change a lot as you work more on it.

Python dictionary comprehensions

I’m a little embarrassed to say that I haven’t yet used these in my own code -- they seem so obvious now that I look back on it.

>>> d = {'a': 1, 'b': 2', 'c': 3}
>>> keys = ['a', 'c']
>>> { k: d[k] for k in keys }
{'a': 1, 'c': 3}

Getting started with tmux

As a long-time user of GNU screen, I knew it would be difficult to switch, but I’ve made the move and am so far pretty happy. tmux does all the same things that screen does and was a lot easier to customize. I figured I would share my tmux configuration file and some of the things that made the switch relatively painless.

Keyboard bindings

I changed the default keyboard bindings to be more like screen:

  • Ctrl-b is the default for tmux; I prefer Ctrl-a.
  • Ctrl-(left/right) arrow to move between windows. No screen equivalent (that I know of).
  • Ctrl-a twice to go “back”.
  • Setting Ctrl-a, r to reload the config file made it very easy to debug.
  • Status bar at the bottom

I set my status bar to use the session name and my machine name on the far left, open tab names centered in the middle, and the system time and date on the far right.

Project-specific configurations (and attach tool)

There's a cool project called tat that does some neat things to make project-specific configurations really easy to set up, and attach to them later on. It also includes tab-completion for existing sessions and your project directory names.

With tat you can create a .tmux file in your project directory, which will be run with the session name as first argument. You can use this to configure your project work space easily and consistently. Here’s one of my example .tmux project files:

# The session name should have been passed in, but if not
# default to 'default-session-name'
session=${1-"default-session-name"}

# Create and name some windows.
tmux rename-window -t $session:1 bash  
tmux new-window -t $session:2 -n webserver  
tmux new-window -t $session:3 -n python  
tmux new-window -t $session:4 -n templates  
tmux new-window -t $session:5 -n js  
tmux new-window -t $session:6 -n less

# Configure the various windows.
tmux send-keys -t $session:2 "make serve" C-m  
tmux send-keys -t $session:4 "cd templates && clear" C-m  
tmux send-keys -t $session:5 "cd media/ && clear" C-m  
tmux send-keys -t $session:6 "cd media/less/ && clear" C-m

# Attach to the first window.
tmux select-window -t $session:1  

Tab-completion

Enabling tab-completion for tmux was easy. On Ubuntu I did the following:

$ sudo curl https://raw.github.com/mithro/rcfiles/master/bash/completion/tmux > /usr/share/bash-completion/completions/tmux

Task Queue support in App Engine's ext.Testbed

A while back I wrote some (now deprecated) code that allowed you to easily test your Python App Engine applications and their interaction with the App Engine APIs. When we got acquired by Google, I started working with some of the awesome App Engine engineers on making that code part of the official App Engine codebase.

We launched that, but one of the APIs that was noticeably lacking helper-methods was the Task Queue. I added one of the old methods (get_filtered_tasks()) but a bit later I noticed a pretty serious bug where timezones weren’t handled properly.

So that code hid quietly in the App Engine code base, undocumented and technically broken. Sorry :(

I wrote some extra code to fix it, but that didn’t get merged into the main repository for quite a while.

But now it’s here.

If you’re curious about the change, feel free to check out the diff (scroll to the bottom). The method is still called get_filtered_tasks() and takes several arguments as “filters” for various properties of tasks — and it should properly handle timezones when you set the eta or countdown properties when creating tasks.

Sorry for the delay. And enjoy.

PS: Since this isn’t documented on the official App Engine page, the API may change. I don’t intend to change it, but I can’t promise it won’t. Apologies in advance if you use this helper method and have it break out from under you.

Also, check out the official code.

Some example code:

import unittest  
from google.appengine.api import taskqueue  
from google.appengine.ext import testbed


class TaskQueueTestCase(unittest.TestCase):

  def setUp(self):
    self.testbed = testbed.Testbed()
    self.testbed.activate()
    self.testbed.init_taskqueue_stub()
    self.task_queue_stub = self.testbed.get_stub(testbed.TASKQUEUE_SERVICE_NAME)

  def tearDown(self):
    self.testbed.deactivate()

  def testTaskAdded(self):
    taskqueue.add(url='/path/to/task')

    tasks = self.taskqueue_stub.get_filtered_tasks(url='/path/to/task')
    self.assertEqual(1, len(tasks))
    self.assertEqual('/path/to/task', tasks[0].url)

unittest.main()