Blogging from Sydney | Australia
Some past thoughts

Yep, learning the hard way

Woohoo! Lesson: 
Hi <name>, 
How's your day been?

25 odd characters of awesomeness, thanks <name>.

Got to tone down these intricate 30-second thoughts, TMI, and come back to Earth.

Fascinating how the academic world of course tends to push so hard in the other direction towards theses of hundreds of pages, but that doesn't excuse me for being an $%^hole.

I suppose I'm just happy I at least got to learn something, thanks <name>.


Can you upgrade to Python 3?

Basically it comes down to whether your dependencies are up to date and if they aren't, if you want to help and contribute back to the community to move them along. The easiest is to drop your requirements.txt file into:


Both of the following are also excellent tools to get an overview of how well the community is progressing:


Python 3 in Production at Mathspace

And Python 3 only in development.

A huge thank you to everyone on the Mathspace Team who supported, reviewed and helped out with this endeavour.

One day the Mathspace Team will put up a dedicated engineering blog, but until then this can live here.

For those who haven't heard me talk about bringing step-by-step working out, handwriting recognition, teachers never needing to mark homework again, adaptive mastery-based learning, geometry, interactive graphing, calculus, The Martian content (currently under development) and so on to High School and College education:

Love it? Want to help make it happen faster for parents, students and teachers? We're hiring.


Mathspace Overview

8 or so developers, similar number of content team members, lots of sales and support staff, moving to a bigger office soon.


86 Python Dependencies 

pip freeze | wc -l


147 Django models across two databases



~160k Python LOC

find . -name "*.py" | xargs wc -l


Driving change

Above all do it incrementally, following lean startup ideas such as reduce batch size, thanks Don Reinertsen, and thanks for coming to YOW! Sydney.

Based on:

for i in $(git log --grep="py3k" --format=format:"%H" --all); 
do git diff $i $i~1 --stat | grep "changed"; 

Some quick git stats:

  • 42+ specific merges to master between 30 August 2014 and 11 January 2016. It just wasn't quite ready for Christmas/New Year 2014 so as things go we built out more math features.
  • 1629 files changed
  • 18027 insertions(+)
  • 16885 deletions(-)
  • So around 11% of our code base changed, including the final 2to3 conversion, but excluding final few bug fixes for legacy code without unit tests.

Most of the development battle felt like it was dependencies because frankly Github is awesome but there's always higher latency than tapping a colleague on the shoulder or @colleague in Slack or Trello.

Upgraded dependencies

Switched out dependencies

  • Fabric => Fabric3 (at least until @bitprophet decides to give us Fabric2's alpha)
  • python-cloudfiles => apache-libcloud
  • suds (SOAP/WSDL) => Stripe billing gateway (might also use PySimpleSoap which claims Python 3 support, but it failed our unit tests before the Stripe switch and its master was broken with a print statement for months which is unfortunately not very confidence inspiring)

Removed dependencies

One pleasant point was upgrading Django because we have pretty good unit test coverage:

# -Wonce works too, just
# -Wall is funner to read out loud
python -Wall test

Tells you what's RemovedInDjango18, RemovedInDjango19, RemovedInDjango110, which you'll need to fix sooner or later.


Making the switch

Basically the things that broke were things with no unit tests. We fixed all of them over a weekend with a few quick deploys, thanks to David Cramer and the Sentry team.

How did we build the final branch?

0. Move anything that works under Python 2+3 off into a separate branch, reviewed and merged regularly.

1. pyenv (or homebrew) to install Python 3

brew update
# Mavericks and El Capitan come with versions of SQLite3 that
# segfault when running "./ test", so update it
brew install sqlite3
brew link --force sqlite3
brew install pyenv
# Tell pyenv to use updated SQLite3
# Takes around 2 minutes
time PYTHON_CONFIGURE_OPTS="LD_RUN_PATH=/usr/local/opt/sqlite/lib LDFLAGS=-L/usr/local/opt/sqlite/lib CPPFLAGS=-I/usr/local/include" pyenv install 3.4.4
# Test it
$ python
>>> import sqlite3
>>> sqlite3.sqlite_version
# Remember to use it when making virtualenvs:
mkvirtualenv mathspace_py3 --python=$HOME/.pyenv/versions/3.4.4/bin/python

2. Look for outdated dependencies, update them, split off upgrades of dependencies with 2+3 versions when possible.

3. Update / migrate our code base internally. As an end project, 2to3 was a better choice than six.

  1. 2to3 . --output-dir=. -n -w
  2. Fix imports 2to3 did not get right so unit tests run. DiscoverRoadRunner was invaluable saving me 4 minutes per test-driven-development cycle, I know I should spend more time on it though Django 1.9's builtin test runner does "--parallel" 🍻
  3. Fix other things 2to3 tool did not get right, e.g. Django's smart_unicode => smart_text
  4. Update or fix unit tests under Python 3 accordingly, things like tests that failed with different PYTHONHASHSEED values that were bugs under Python 2 but only detected under Python 3.
  5. Check things like the following don't throw errors, add unit tests if they did:
    ./ runserver
    ./ celery worker

4. Add new Python 3 servers - thanks Rackspace devops for getting poise-python working so supervisor can stay under Python 2.

5. Test on staging environments for any issues.

6. Deploy to production.

7. Fixed a few things fast. Thanks to Sentry we could pounce quickly. Maybe 20-30 users affected by Sentry events total, so 99.94% or more of our >50k users in that particular low-traffic week would never have noticed, anecdotally better than our last Django upgrade.

Was it overengineered? Perhaps, but to channel Django, Mathspacers can be perfectionists with deadlines, and we do think it is very important to provide the best experience we possibly can for parents, students and teachers.



  • Better unit testing
    with self.subTest()
  • Cleaner superclass calls:
    # Instead of monstrosities like
    super(MyClassName, self)
    super(MyClassName, cls)
  • Cleaner types and unicode support:
    long->int, str => bytes, unicode => str
  • Can't easily go the wrong way when using:
    .decode() or .encode()
  • No re.UNICODE flag required in regular expressions.
  • Don't need to remember
    # -*- coding: utf-8 -*-
    from __future__ import unicode_literals
  • No cryptic backtick syntax:
    repr(a) == `a`
  • Don't lose original error if another error triggered in an except block
  • Hundreds of other bugs fixes and feature improvements:

Nick Coghlan can tell the full story far better than I:


Why I used my house deposit to pay off my HECS-HELP loan

“Compound interest is the eighth wonder of the world. He who understands it, earns it ... he who doesn't ... pays it.” - Albert Einstein

So I tweeted this, and followed through today with the largest B-Pay I've ever made. Should be confirmed debt-free by the end of the week, at the cost of my house deposit.


The short version

A little more supporting reasoning

  • $40,000 is a relative drop in the bucket on a >$720,000 Sydney median house price. (And I'd be hard-pressed to save $30,000 a year just to pay 5% interest-only on $600,000 - a doubling of rates to 10% would wipe me out entirely and 17% from the Hawke/Keating era... I can only dream of earning that on a savings account if I could hold a job in such likely recessionary times).
  • CBA Goalsaver today = 3.81% total interest requiring $200 put in every month, with rates probably continuing to fall while CBA makes more record profits (built on a bubble, not touching our big four's shares with a 10 foot pole except in my super fund so I can argue that itch is scratched).
  • I'd pay a marginal tax rate of at least 38.5% (inc Medicare Levy) for FY2013-14 (39% in 2014-15, thankfully dodged the $80,000 additional deficit levy but such a shame they didn't try reforming superannuation which would have hit me, CGT discount which would have tripped me into speculating more, or negative gearing which would have been the best thing I think they could have done, I stand by my previous thoughts that it's the defining ridiculous misallocation of resources... paying people to lose money... utterly insane), leaving me with 2.34% effective interest on the CBA Goalsaver at most, about 0.5% under inflation.
  • Interest rates on all savings accounts I've looked at over the past year or so have continued to meet expectations and fall from well over 4% to the current levels.
  • Commonwealth Government decided to raise rates to the 10 year T-Bond rate, today funnily enough is about 3.81% (an instant rise of 0.9% relative to last year's indexation of 2.9%).
  • In sum, I would be paying between 1.5% to 3.5% for the optionality of holding my house deposit that is going to struggle to reach a reasonable 20% or $150,000 over the next 6 years anyway (with no price growth or rather a price crash), well up from 0.5% (though that may be long enough for some windfall rebalancing gains to come through if I get lucky with my other investments). But since it's never going to be enough anyway, I might as well seek the Australian Dream, er Farce in a country that has less red tape stopping developers building houses.
  • Retain some ethical / moral high ground, not one of these.
  • USA is looking more interesting all the time... (it's also nice when a highly-productive web/Python/Django/Machine Learning first class honours CS degree holder gets offers to be poached by certain technology companies) why should I support a broken system? (though they are at 90% debt to GDP so it looks like the boomers have raided everyone's cupboards...) 2015's budget will be very important to actually ending the age of entitlement, but I'm not holding my breath, just continuing to move bits and pieces offshore (with full reporting to the ATO of course).

Speculation: Negative gearing is on the chopping block

I'll believe it when I see it, but if they have the guts to do the right thing and remove this artificial negative gearing distortion saving many billions of $$$ (of course it's a scam, why should I and the members of the millenials in effect personally be paying thousands of dollars in taxes or interest on ballooning government debt to prop up existing house prices), they'll get my vote at the next election even though they've completely stalled what little progress was being made on the NBN (Turnbull, we brought you in to get things moving, not stall it completely). Thanks MB and SBS for the speculation.

Of course, I can only personally say such a thing because if I choose to stay in Australia, which is looking like a very BIG IF over the next 5 years, this is a necessary (but sadly unlikely to be sufficient) condition to deflating house prices into a somewhat affordable range.

Take a reasonable long-term historical perspective, such as average loan size just 10 years ago, c.2003 was A$120,000. Then flip it and just consider today, for instance that Boston median house prices are around US$400,000 (vs more like A$700,000 in Sydney). Or that I could buy (today with no debt, like WOW that was an eye-opener!) a dogbox studio apartment in Boston for just US$65,000 (thanks Flipping Boston S2, Ep8 via Foxtel, the worldwide perspective alone has just paid for itself many times over) whereas the bottom in Sydney starts around A$200,000. This is a lot of ranting, but it's supposed to be theraputic to get the problems off one's chest.

It's worth it if some of our politicians do get the message that outside of the 24 hour news cycle, people still need to make ends meet, still need to figure out how to plan to have a family, and want a reasonable (I'd say fair, but it became unfair when the pension age didn't start rising 20 years ago) deal from the society they are a part of. Ross Gittins has some excellent articles on economic rent-seeking, or basically taking a larger piece of the eco-cake than you should reasonably be entitled to. People will stand some oppression (for instance I fully support any efforts to reduce income inequality though I believe in bottom up economics where the poor will generally spend the money they get, boosting the economy, and even though that will disproportionately hurt me as a relatively high income earner), but too much will break the proverbial camel's back. I'm also aware that the grass always appears greener on the other side which is why I'm OK with getting a somewhat unfair appearing deal. Mostly because I think that I'm a reasonable enough person that once I've found a way to pay for one of these houses or 3+ bedroom apartments, I'll be pretty close to having "enough", then at that point I don't care if the rest goes to charity or porkbarrelling or whatever else, it's all cherries on top =)

It would be nice if the government also reduced demand in other ways, e.g. by not boosting immigration to the moon (407,000 new people or 1.8% per capita, yes it's not Libya's 20% per capita but it's still a lot, though I believe asylum seekers should be classed as immigrants), but I'm a realist so I don't support reducing that intake. An argument could be made that we actually should take these people so we have a greater societal capacity in the longer term to handle the inevitable climate refugees without having huge societal shocks, since little real progress seems to be being made on climate change.

The solutions remain as they have always been - primarily about supply, e.g.

  • Cutting red tape stopping developers getting out there and building houses and apartments (some positive signs on apartments at least).
  • Considering a broad-based land tax replacing stamp duty, to reduce the effectiveness of land banking speculation.
  • Releasing more government land for purchase by private citizens, for instance the NSW goverment appears to be planning to release land for about 800,000 people over the next 17 years (8 regions identified, around 100k per region). If one third of the 400k p.a. immigrants come to Sydney and surrounding regions, that's easily 2.2 million people (at a constant immigration quota) or a shortfall in housing for up to 1.4 million people (yes there are regional centers outside Sydney, don't know how many people can move there without an NBN) which will need to be made up by building upwards or increasing dwelling sizes just as the baby boomers kids are leaving and probably needing dwellings of their own. <Insert generation rent joke>...

To our good politicians (from all sides, primarily state and federal), I sincerely hope the electorate rewards you if you make the tough choices and pop the bubble.

I guess I understand from the expected mining capex cliff why the Reserve Bank of Australia decided it was safer to go all in on the bubble by dropping rates over the past year or so. Hope they finally get rewarded with some serious inflation that makes us all poorer. In a perverse way, the higher they rise the further they fall... so if the serious (like 30% or so as happened in Ireland) crash comes somewhere between 2017-2024 as the baby boomers look to fund their retirement and get whacked by falling "investment property" prices, I would be quite pleased. But this shouldn't be about intergenerational warfare, it should be about building (pun intended) a sustainable society, not a speculative society.

Page 1 ... 6 7 8 9 10 ... 14 Next 5 Entries »