On the Revolutions


@brandon_rhodes
DjangoCon Europe
The Ides of May
2013
kopernik.jpg
Mikołaj Kopernik
1473–1543
Kraków
Bologna
Padua
Ferrara

De Revolutionibus Orbium Coelestium

Kopernik lifted the Earth
into the heavens

Near-Earth environment

300s BC — Aristotle — spherical Earth
200s BC — Eratosthenes — radius of Earth
100s BC — Hipparchus — distance to Moon
What about the cosmos
beyond the Moon?

the data

  1. Daily motion of the sky
  1. Planets moving more slowly
  1. Retrograde motion

the old model

100s BC
Ptolemy

Almagest

geocentric-system.png
kopernik.jpg

Pythagoras

From De Revolutionibus

“First I found in Cicero that Hicetas had
realized that the Earth moved, and
later in Plutarch that others
had held the same view.”
Aristarcus of Samos
Sun was fixed like the stars
and the center of planetary motions

Q:

Why was no one taking
these ideas seriously?

A:

Medieval and early Renaissance
scholars were too empirical!

Physical Objections

  1. Cannot feel the Earth rotate
  2. Cannot feel the Earth revolve
  3. No stellar parallax
It was this lack of physical
evidence that was decisive at
Galileo's trial 90 years later

Cardinal Bellarmine

“I say that if there were a true
demonstration that the sun was in
the center of the universe…
we would, rather, have to say that
we did not understand those Scriptures,
than to say that something was false
which had been demonstrated.”

Cardinal Bellarmine

“But I do not believe that
there is any such demonstration;
none has been shown to me.
Despite the absence of
physical evidence, the ideas
did keep getting better
1618
Kepler
Three Laws
1638
Galileo
Inertia
1687
Newton
Gravity
But physical evidence
did not appear until 180 years
after Kopernik published
1725
Bradley
Stellar aberration
1838
Bessel
Stellar parallax

Why did it take 113 years?

Stellar aberration: 0° 0′ 40′′
Stellar parallax: 0° 0′ 0.314′′
It took 1,900 years after the Greeks
learned the distance to the Moon
for us to find the distance
to the nearest stars
1851
Léon Foucault
Pendulum
pendulum-diagram.gif
pendulum-real.jpg

Evidence took 200–300 years to arrive

--1500s-- --1600s-- --1700s-- --1800s-- --1900s--
                             
                             
               Newton         
            Galileo            Foucault
          Kepler               Bessel
    Kopernik          Bradley

       Ideas               Evidence

Q:

Why did Kopernik
ignore all available
physical evidence?

A:

Beauty
Let's express Ptolemy's
system using Python code
epicycle-direction.gif

Ptolemy

# x-coordinates of the seven planets
# t = time, in Earth years
#
#        deferent  +  epicycle

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = sin(t / 1.88) + 0.658 * sin(t)
ju = sin(t / 11.9) + 0.192 * sin(t)
sa = sin(t / 29.5) + 0.108 * sin(t)

Kopernik

# Step 1: make sin(t) coefficients = 1.0

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = sin(t / 1.88) + 0.658 * sin(t)
ju = sin(t / 11.9) + 0.192 * sin(t)
sa = sin(t / 29.5) + 0.108 * sin(t)
#

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = 1.52 * sin(t / 1.88) + sin(t)
ju = 5.21 * sin(t / 11.9) + sin(t)
sa = 9.26 * sin(t / 29.5) + sin(t)
# Step 2: move sin(t) to the front

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = 1.52 * sin(t / 1.88) + sin(t)
ju = 5.21 * sin(t / 11.9) + sin(t)
sa = 9.26 * sin(t / 29.5) + sin(t)
#

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = sin(t)        + 1.52 * sin(t / 1.88)
ju = sin(t)        + 5.21 * sin(t / 11.9)
sa = sin(t)        + 9.26 * sin(t / 29.5)
# Step 3: “It's not you, it's me”

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = sin(t)        + 1.52 * sin(t / 1.88)
ju = sin(t)        + 5.21 * sin(t / 11.9)
sa = sin(t)        + 9.26 * sin(t / 29.5)

Kopernik's model

# x-coordinates of the seven planets
# t = time, in Earth years

su = 0
me = 0.375 * sin(t / 0.24)
ve = 0.719 * sin(t / 0.62)
ea = 1.00 * -sin(t)    # Earth moves
ma = 1.52 * sin(t / 1.88)
ju = 5.21 * sin(t / 11.9)
sa = 9.26 * sin(t / 29.5)

def planet_position(x):
    return x - ea
So what did
Kopernik accomplish?
The most famous code
refactoring in history

Why did he do it?

Why did he do it?

Not because of physical evidence!

Because it made
the code so pretty

From De Revolutionibus

ancient philosophers were willing
to take the sequence of the planets as
being in accordance with the size of their
revolutions … Saturn the highest … Jupiter
under it, and after that Mars”

From De Revolutionibus

“But what reason can be produced
by those who put Venus below the Sun,
and Mercury after it? … Then it must be
either that the Earth is not the center…or
else that there is no system in the order”

From De Revolutionibus

“Consequently I think we should
certainly not despise the argument which
was well known to Martianus Capella
… that Venus and Mercury revolve
around the Sun

Ptolemy

Ordering is not consistent
#        deferent  +  epicycle

me = sin(t)        + 0.375 * sin(t / 0.24)
ve = sin(t)        + 0.719 * sin(t / 0.62)
su = sin(t)
ma = sin(t / 1.88) + 0.658 * sin(t)
ju = sin(t / 11.9) + 0.192 * sin(t)
sa = sin(t / 29.5) + 0.108 * sin(t)

Kopernik

Ordered by both period
and size of orbit!
su = 0
me = 0.375 * sin(t / 0.24)
ve = 0.719 * sin(t / 0.62)
ea = 1.00 * -sin(t)    # Earth moves
ma = 1.52 * sin(t / 1.88)
ju = 5.21 * sin(t / 11.9)
sa = 9.26 * sin(t / 29.5)
Beauty

Michael Polanyi

“What is the true lesson
of the Copernican revolution? …
The only justification … lay in the
greater intellectual satisfaction he
derived from the celestial panorama as
seen from the Sun instead of the Earth.”

Michael Polanyi

Kopernik “gave preference
to … delight in abstract theory,
at the price of rejecting the
evidence of our senses”

Or, in other words—

It made the code so pretty

KopernikThe Great Refactorer

“Copernican Refactoring”

Making a system simpler
by moving something
new into the center

examples

Car Chargers

USB Type A
usb-plug
Cigarette lighter
car-plug
Palm V
car-plug usb-plug
Treo 180
car-plug usb-plug
Treo 600
car-plug usb-plug
Google G1
car-plug usb-plug
and then I saw it
usb-car-charger.jpg
blown.gif
if — the cable doesn’t fit
then — I need another cable
usb-car-charger.jpg
fix the receptacle instead!

Mercedes 300D fan bolts

craftsman.jpg
snap-on.jpg

Hank van Cleef

“it's ‘special tool time.’
That's when you take a bench grinder
to the box wrench to reduce its height.
I have several box wrenches ground
at various points, heated and bent, etc.,
for dealing with nasty fastener locations.”
blown.gif
grinding.jpg

general principle

arrows.png

dependency injection

# Ugly: injecting I/O routines everywhere

import beautifulsoup, urllib2

def tw(handle, urlopen=urllib2.urlopen):
    url = 'http://twitter.com/' + handle
    u = urlopen(url)
    return beautifulsoup.BeautifulSoup(u.read())

tw('brandon_rhodes')

#
# Tests use: tw('user', urlopen=fake_open)
#

wishbone splitting

"""Instead, I pull I/O up to a higher level."""

import beautifulsoup, urllib2

def make_url(handle):
    return 'http://twitter.com/' + handle

def parse_page(u):
    return beautifulsoup.BeautifulSoup(u.read())

url = make_url('brandon_rhodes')
u = urllib2.urlopen(url)
soup = parse_page(u)
clean-architecture.jpg

docopt

keleshev.jpg
Vladimir
Keleshev

The old

from argparse import argparse

def main():
    parser = argparse.ArgumentParser(
        description='Concatenate files.')
    parser.add_argument(
        'FILE', nargs='*',
        help='Path(s) to files')

    args = parser.parse_args()
usage: command [-h] [FILE [FILE ...]]

Concatenate files.

positional arguments:
  FILE        Path(s) to files

optional arguments:
  -h, --help  show this help message and exit

With docopt

"""Concatenate files.

Usage:
  cat [-v] [FILE ...]

Options:
  FILE            Path(s) to files
  -v, --version   Display version

"""
from docopt import docopt
def main():
    arguments = docopt(__doc__)

Django!

Without a framework

m = re.match('/user/([a-z_]+)$', path)
if m:
    username = m.group(1)
    return render('user.html', username)
m = re.match('/product/([-a-z_]+)$', path)
if m:
    productname = m.group(1)
    return render('user.html', productname)
m = re.match('/help/([-a-z_]+)$', path)
if m:
    helppage = m.group(1)
    return render('help.html', helppage)
return render('404.html', code=404)

With Django

def userview(request, username):
    return render_to_response(
        'user.html', username)

def productview(request, productname):
    return render_to_response(
        'product.html', productname)

def helpview(request, helppage):
    return render_to_response(
        'help.html', helppage)

Copernican refactorings

are my favorite refactorings!

The next time you
feel like your code is making
you work backwards—

Stop, and think of Kopernik!

kopernik-statue.jpg

Thank you very much!

@brandon_rhodes