SQLAlchemy ORM: Joins Question

One of the readers of Essential SQLAlchemy sent me an email with more questions about how .join() works.  In the example below, he wanted to know why join was only required for User, LineItem, and Cookie objects. Why isn’t Order required?

query = session.query(Order.order_id, User.username, User.phone,
                      Cookie.cookie_name, LineItem.quantity,
query = query.join(User).join(LineItem).join(Cookie)
results = query.filter(User.username == 'cookiemon').all()

To answer that question, lets take a look at the SQL generated by the ORM for our query.

query = session.query(Order.order_id, User.username, User.phone,
                      Cookie.cookie_name, LineItem.quantity,
SELECT orders.order_id AS orders_order_id, 
       users.username AS users_username, 
       users.phone AS users_phone, 
       cookies.cookie_name AS cookies_cookie_name, 
       line_items.quantity AS line_items_quantity, 
       line_items.extended_cost AS line_items_extended_cost 
FROM orders, users, cookies, line_items

We can see that the FROM clause contains the Orders, Users, Cookies, and LineItems ORM objects __tablename__s for each object in the query. Also, notice the order is based on where they appeared in the SELECT clause. Just like in SQL, we need to define how the tables are related with JOIN clauses. These JOIN clauses need to follow the order of the relationships between the tables. This means we need to make sure that the table to the left of the JOIN clause has a relationship with the table in the .join() statement. This can be a bit confusing when we have chained .join() statements as shown in the first example. The table in the prior .join() statement to the left must have a relationship with the table in the current .join() statement that was being evaluated. Lets look at the SQL generated after all the .join() statements.

query = query.join(User).join(LineItem).join(Cookie)

SELECT orders.order_id AS orders_order_id, 
       users.username AS users_username, 
       users.phone AS users_phone, 
       cookies.cookie_name AS cookies_cookie_name, 
       line_items.quantity AS line_items_quantity, 
       line_items.extended_cost AS line_items_extended_cost
FROM orders JOIN users ON users.user_id = orders.user_id 
     JOIN line_items ON orders.order_id = line_items.order_id 
     JOIN cookies ON cookies.cookie_id = line_items.cookie_id

We can see now that the FROM clause contains the JOIN clauses in the order we chained them into the query. So Order is the target of the first JOIN with User, which is why we didn’t have to have a .join() for it. You can see and play with this more with an ipython notebook available at https://github.com/jasonamyers/blog-12-31-15-join-question/blob/master/blog-join-example.ipynb.


Setting up my Ubuntu Dev Environments

1. Install Ubuntu (Whatever flavor you like)
2. sudo apt-get upgrade && sudo apt-get upgrade
3. Copy over SSH keys
4. chmod 600 .ssh/*
5. sudo apt-get install -y emacs git vim make gnome-tweak-tool curl build-essential libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev wget llvm libncurses5-dev
6. Run Tweak Tool -> Click Typing -> set Caps Lock key behavior to “Make Caps Lock an additional Ctrl” -> set Alt/Win key behavior to “Alt and Meta are on Alt keys”
7. Setup Firefox Sync
8. Copy down dotfiles: git clone git@github.com:jasonamyers/dots
9. cd dots
10. ./setup.sh
11. Download the lastest version of Go from https://golang.org/dl/
12. Install Go: sudo tar -C /usr/local -xzf go1.5.2.linux-amd64.tar.gz
13. ./stage2-setup.sh
14 Open emacs, it will compile for a while and end in an error about go auto loads
15. Run M-x update-file-autoloads, Use “~/Misc/emacs/go-mode.el/go-mode.el” as the first answer, and “~/Misc/emacs/go-mode.el/go-mode-load.el” as the autoloads files
16. Exit and Save emacs
17. Test it with: racer complete std::io::B


  • Install Slack https://slack.com/downloads
  • Install Virtualbox https://www.virtualbox.org/wiki/Linux_Downloads
  • Install Vagrant https://www.virtualbox.org/wiki/Linux_Downloads

How Docker 1.9.1 Tags an Image/Container

I’ve been exploring how docker 1.9.1 handles tagging, pulling, and pushing.  Here is my walkthrough of how docker tags an image/container.


Configuring Emacs for Rust Development

When I code, I typically want the following from my editor:

  • Syntax highlight and indentation
  • Auto completion
  • Error checking
  • Jump to definition
  • Inline documentation

When coding in rust, I want these same features.  Thankfully there are a several great packages to help us achieve those desires.

Before we do any futher I wanna make sure to give credit and a huge thanks to Bassam and his blog post. This is just to update based on what changes I found I needed.

Installing Packages

You’ll need to start by updating your package list contents by:

  • M-x package-refresh-contents

Next, we will install the follow packages in Emacs by M-x package-install <RET> <PackageName><RET>:

  • company - An autocompletion framework - Website
  • company-racer - A backend that enables company autocompletion with racer - Website
  • racer - A rust autocompletion engine - Website
  • flycheck - on the fly syntax checking - Website
  • flycheck-rust - A rust backend for flycheck - Website
  • rust-mode - An Emacs mode for editing rust files - Website

Configuring Emacs

Now we need to configure these packages inside of our emacs configuration.  Here is a snippet of my .emacs.d/init.el:

;; Reduce the time after which the company auto completion popup opens
(setq company-idle-delay 0.2)

;; Reduce the number of characters before company kicks in
(setq company-minimum-prefix-length 1)

;; Set path to racer binary
(setq racer-cmd "/usr/local/bin/racer")

;; Set path to rust src directory
(setq racer-rust-src-path "/Users/jasomyer/.rust/src/")

;; Load rust-mode when you open `.rs` files
(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-mode))

;; Setting up configurations when you load rust-mode
(add-hook 'racer-mode-hook #'company-mode)
(add-hook 'rust-mode-hook #'racer-mode)
(add-hook 'racer-mode-hook #'eldoc-mode)
(add-hook 'racer-mode-hook #'company-mode)
(global-set-key (kbd "TAB") #'company-indent-or-complete-common) ;
(setq company-tooltip-align-annotations t)

Installing Rust

In case you don’t have Rust installed on your system you can install it either by:

  • Downloading the installation binary from Rust’s website.
  • or using Homebrew: brew install rust.

Building and Installing Racer

To generate the Racer binary that company-racer uses for it’s magical powers, you will need to clone the racer repository from Github to your home directory and run cargo build --release.

  • git clone https://github.com/phildawes/racer.git /tmp/racer
  • cd /tmp/racer
  • cargo build --release
  • mv /tmp/racer/target/release/racer /usr/local/bin
  • rm -rf /tmp/racer

After running these commands and restarting your terminal you should be able to run the racer command which should complain about a missing $RUST_SRC_PATH.


If you go back to the elisp function you added to our init.el earlier you will be able to see that you defined racer-rust-src-path which points to .rust/src in your home directory. You will need to add the Rust source code there so Racer can use that to load methods for completion.

  • git clone https://github.com/rust-lang/rust.git ~/.rust
  • Add export RUST_SRC_PATH=/Users/YOURUSERNAME/.rust/src to your .bashrc or shell init file.
  • Restart your shell and emacs then open a Rust file.

You should now have all the features we desired earlier.  You can test this by:

  1. Open a rust file and try typing use std::io::B and press <tab>. You should see some completion options.
  2. Place your cursor over a symbol and hit M-. to jump to the definition.

If that does not work, make sure that racer works from the command line by doing the following:

  • racer complete std::io::B

You should see some autocompletion options show up.

Building a Keyboard: Part II – Into The Matrix

So last week, I talked about Plates, Switches, and Keycaps which means we are ready to talk about how keyboards detect keypresses. I am hand wiring keyboard so we don’t have a fancy PCB or breadboard in which to solder the pins of our keys. We have to build this key press detection system ourselves. It turns out that we need to build something called a key matrix.

Building the Matrix

On the bottom of every key switch are two pins, as shown below, that are connected when the switch is depressed.


To begin making our matrix, we pick a pin and make a connected row across the bottom of our top line of switches. It is important to use the same side pin on each key switch to make it possible to spot and fix mistakes.  If you are wicked smart feel free to mix and match. Now we are gonna make our rows out of little diodes. (I’ll explain why in a few.) Diodes allow current to flow in a single direction, so we have to make sure to put them on “facing” the right way. Since current will be coming from the column side, we face the cathode towards the row. The cathode is indicated by a black ring on our diodes. (We are using 1N4148 diodes.) Here is an example. BTW feel free to laugh at my work I had never done
any of this before.


We repeat this for all four rows of the board.


With the rows done, I began working on the columns. For the columns, we run a cable vertically to the second pin. However, we have to make sure that the wires are shielded from the rows. If we don’t, we will have a short in our matrix. Well, if there is a short it no longer is a proper matrix, but anyway back to the important stuff. I used an Exacto blade, and made a circular cut around a stretch of wire at the position of the row 2 switch’s pin. Then using my fingernails, I made a small gap in the insulation of the wire. I repeated this process for the row 3 switch in that same column, and followed with row 1 then row 4.  The result is a wire with uninsulated sections at each pin and insulated in between. There is probably an easier way…


So you repeat that process for every column. There are special cases for wider switches. For example, this board has a two column wide space bar. In that case you wire the space to the which ever column is closet. **It is super important to remember which one!**  Here is an example.


I ran my columns under my rows because their is so little space in the case.

We now have the matrix done!

How the Matrix Works

The matrix works by cycling power through the columns one at a time, and listening to the rows to see what point in the matrix is connected via a key press.  So in this image from PCBHeaven.com, we power up the B column while the bottom at the intersection of column B and row 3 is pressed. This sends current to row 3, and we would be able to tell that key B3
was pushed.


This works fine even for multiple keys at once until we have three keys pressed down at once where two of the three are in the same row and two of the three are in the same column.  For example if we look at the last image, what if B3, B2, and C2 were all pressed?  When column C is powered, we will see C2 as pressed; however, B2 won’t be seen. Also because B2 is pressed the B column has power. This power is connected to row 3 by B3 being pressed, but since we originally powered C, the current on row 3 is interpreted as C3! This problem is known as ghosting. There is another related problem called masking. This occurs when we can not read a change because of ghosting.

To fix these problems, we use a diode on each key. In the scenario above, the B column would not get power from B2 because the diode would prevent it from flowing in that direction. So B3 would not have power, and not be seen while the C column is powered and being read.

Check out pcbheaven for more on this with great animations.

Reading the Matrix

We are going to use a teensy microcontroller as our keyboards brain. We need to connect each row and column to it. I start by connecting some bridge wires to each of them. The teensy will need it’s USB port between columns 2 and 3. so keep that in mind when cabling. I again ran my cables under the row and column cabling.


In that picture, there is a bundle of four cables connected to the rows.  I connect those to the teensy first like:

Teensy PIN Matrix
F0 row 0
F1 row 1
F4 row 2
F5 row 3

Any pin works except for Vcc, GND, RST. Just make note of what went where. I used the upper right corner as row 0, column 0.


Now for the columns. I started on the other side of the teensy as follows:

teensy-colsIn the next part we’ll talk about how to program our microcontroller, the teensy, with C. Part 3 will be all keyboard layouts and then it’s about that C, and how we build the firmware for our device.

Teensy PIN Matrix
D5 col 0
C7 col 1
C6 col 2
D3 col 3
D2 col 4
D1 col 5
D0 col 6
B7 col 7
B3 col 8
B2 col 9
B1 col 10
B0 col 11

Building a Keyboard: Part I – Plates, Switches, and Keycaps

I’ve been into keyboards for quite a while, and into mechanical keyboards for
the past few years. I’ve owned many so called “awesome gaming” keyboards from
Razer, Microsoft, and Corsair; however, a few years ago I got my first
mechanical keyboard. I wasn’t sure what the hype was all about. The gaming
keyboards I had been using where in the $100 “high end” keyboard market, and I
was sure nothing could be better. Then I learned about the difference between
rubber dome keyboards and those with actual mechanically activated switches. I
bought a CODE keyboard with Cherry MX Green switches, and it blew me away. It
honestly felt good to type, and type I did for hours on that board at home, and
then at work. (Sorry it was so loud former coworkers.)

Then I got the urge to get a second board, and to try some other switches. In
the end I tried every kinda of Cherry Mx, Matias, and Topre switch. I also
sampled Kailh and Gateron switches. The switches are the foundation components
of a keyboard. They define how hard it is to press the keys (force), what it
feels like to press them down (linear, tactile, or click), and how far the
switches need to be pressed down (actuation point and bottom out). The rest of
the article is gonna focus on Cherry Mx switches as they are the mostly commonly
used switches, and my personal favorites the Matias quiet clicks. The Kailh and
Gateron are Cherry Mx clones. Topre switches are a completely different type of
switch that uses electro-capacitive technology under an inverted rubber cup.

**Now… Now I wanna build a keyboard from scratch**

No prebuilt fancyness except a teensy microcontroller, keyswitches, wires,
solder and C… plain old C.

Details of Cherry Mx and Matias Switches

The first thing to know about switches, is that there is no single best switch.
Different switches are preferred for different usages and vary by each
individual. You can see a good breakdown of the stats about Cherry Mx switches
on [wikipedia](http://en.wikipedia.org/wiki/ZF_Electronics#Cherry_switches). As
a synopsis of that information basically switches are divided by their feel and
weight. Keyswitches have two important points in the keystroke, the actuation
point and the bottom out point. The actuation point is when the keystroke is
registered, and bottoming out is when it hits the bottom of the switch. On a
rubber dome keyboard these are often one in the same. So the keystroke is
registered when the the PCB underneath the rubber dome is touched. This hurts my
hands just thinking back to those days. If you take a look at an animation of
the Cherry Mx Clear switch. (my personal favorite)


You can see the way the tactile bump tells the user the switch
has been actuated early in the keystroke. Once you learn to feel for that bump,
you can swiftly and lightly press the switches to just that point and avoid the
abrupt stop of bottoming out. The tactile bump is one type of Cherry MX switch
feeling, some switches also make an audible clicking sound; however, some people
prefer the smoothness of a linear switch. With a linear switch there is still
quite a bit of separation between the actuation point and bottoming out, and you
can learn to touch type on them as well. The weight of a switch refers to how
hard you have to press to reach the actuation and then bottom out point.
Typically a light switch is around 45g of force to actuate with mediums around
55g and heavy switches anything higher than 60g. Bottoming out force is often
either the same or slightly lower than the actuation force.

Here is a simple chart with the most common types of Cherry Mx Switches:

Switch Type Weight Type
Black Heavy Linear
Red Light Linear
Brown Light Tactile
Clear Medium Tactile
Blue Medium Click
Green Heavy Click

The Matias Quiet Click switch is roughly the same specs as a Cherry MX Clear but
with a higher actuation point and a stronger bump. It also gives in completely
after actuation with just a 35g bottoming out force compared to the 45g of the
Clear. This makes it easier to feel the switch give and start to pull the finger
back up. Due to some old hand injury, it’s this bottoming out that causes pain
in my fingers after a few hours of typing on a rubber dome or laptop keyboard.

The switches snap into metal plates or mount directly onto PCBs depending on the
desired feel and type of keyboard. Since we’re building from scratch I won’t
have a premade fancy PCB I’m going to be doing some old fashion hand wiring. The
plate I’m using is from [Ortholinear Keyboards](http://www.ortholinearkeyboards.com)
and is called an Atomic keyboard. It’s a grid like board with a small 2 unit
space key. Here is an example of the plate and some switches installed on it and
one waiting to go in.


You might notice the the stems of these switch are a plus sign and kind of a
translucent white colors. The plus sign is the standard for all Cherry Mx
Switches, and the color tells me this is a Clear switch. (trust me on that one)
On the switch to the left, it’s two units wide, so we have the keyswitch
surrounded by a stabilizer. A stabilizer is used to make sure that a key presses
down evenly no matter where on the key you press it. We’ve all had that weird
space bar that kinda pushed down awkwardly. (I’m looking at you Microsoft
Ergo 4000!) There are several different types of stabilizers; however, the ones
pictures are a plate mounted Cherry Mx stabilizer.

Disassembled Cherry Stabilizer

A stabilizer is made of two plate mounted slides, two sliders and a small bar
that ensures that both sides of the stabilizer move up and down together.
Just like the key switches, they snap into the plate. Here is a view of those
same switches from the bottom

Bottoms Up


Keycaps are a subject one could get lost in but from a basic stand point they
are typically made from ABS or PBT plastic. PBT keycaps normally have a nicer
texture, and are thicker and better made than ABS keycaps. Nonetheless, the
simplicity and variety with which ABS keycaps are made make them extremely
popular in the show off crowd. I want a board that feels good, but some extreme
keyboard modders just wanna look good. There are entire parts of the internet
devoted to just this part of keyboarding alone. (sigh so many wasted electrons).
Anyway for my build I’m using some high quality simple PBT keycaps from
[Signature Plastics](http://www.pimpmykeyboard.com) Here’s a good pic of them
from below.

Keycap stabs

You can see there are stabs built inside the keycap to accept those plus sign
posts on the switches, and the longer switches with the stabilizers have
multiple stabs. The position of these stabs depends on the layout of your
keyboard and how the switches are positioned on your plate or PCB. Since, I’m
crazy nothing about this board is standard, but it is very geometric :). So
here is our board after putting on the keycaps.

Keyboard Part 1

In the next part we’ll talk about how keyboards work and how we’re going to wire
this beast up to our microcontroller. Part 3 will be all keyboard layouts and
then it’s about that C, and how we build the firmware for our device.

I’ll leave you with some of my previous keyboards during my misspent designer

View post on imgur.com

Testing Bluebird promises with Mocha

So I have a node.js application that contains the getAccountInfoFromToken
function below, and I want to test it with Mocha. This function has been gutted
and the account details are embedded now instead of called in to make the
example clearer.

Promise = require('bluebird'),
getAccountInfoFromToken: function(token) {
return new Promise(function(resolve, reject){
// Get Account details
var sample_return = {
"accounts": [
"account_id": 1725389
var accounts = sample_return["accounts"];
if (accounts.length > 0) {
} else {
reject('No Accounts');

So initially I took a very naive approach to the test because I wasn’t clear on
how javascript compared arrays. So I had the test you see below.

"use strict";

describe("token_vending_machine", function () {
var tvm = require("../src/server"),
sinon = require("sinon"),
assert = require("assert"),
expected_token_return = [
{"account_id": 1725389}

describe("#getAccountInfoFromToken()", function () {
it("should return the right details when called with a token", function () {
tvm.getAccountInfoFromToken("test").then(function (data) {
assert.equal(data, expected_token_return);

However Mocha would report that as a pass but then I got an error from Bluebird
about a possibly unhandled AssertionError… like you see in the output below.

✓ should return the right details when called with a token
Possibly unhandled AssertionError: [{"account_id":1725389}] == [{"account_id":1725389}]
at /Users/jmyers/dev/token_vending_machine/test/tvm.js:40:24
at tryCatch1 (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/util.js:43:21)
at Promise$_callHandler [as _callHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:627:13)
at Promise$_settlePromiseFromHandler [as _settlePromiseFromHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:641:18)
at Promise$_settlePromiseAt [as _settlePromiseAt] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:804:14)
at Promise$_settlePromises [as _settlePromises] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:938:14)
at Async$_consumeFunctionBuffer [as _consumeFunctionBuffer] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:75:12)
at Async$consumeFunctionBuffer (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:38:14)
at process._tickDomainCallback (node.js:463:13)

1 passing (8ms)

That possible assertion error is a real thing because I thought my test was
passing when it wasn’t because Mocha wasn’t getting the information it needed.
Next I tried to catch the error and throw it. So I edited the test like so…

describe("#getAccountInfoFromToken()", function () {
it("should return the right details when called with a token", function () {
tvm.getAccountInfoFromToken("test").then(function (data) {
assert.equal(data, expected_token_return);
}).catch(function (err) {

That lead to a timeout error, which actually made Mocha show the test as
failing. It also logged what the actual error was. That output is below

{ [AssertionError: [{"account_id":1725389}] == [{"account_id":1725389}]]
name: 'AssertionError',
actual: [ { account_id: 1725389 } ],
expected: [ { account_id: 1725389 } ],
operator: '==',
message: '[{"account_id":1725389}] == [{"account_id":1725389}]' }
1) should return the right details when called with a token

0 passing (2s)
1 failing

1) token_vending_machine #getAccountInfoFromToken() should return the right details when called with a token:
Error: timeout of 2000ms exceeded
at null. (/Users/jmyers/dev/token_vending_machine/node_modules/mocha/lib/runnable.js:157:19)
at Timer.listOnTimeout [as ontimeout] (timers.js:112:15)

Now I knew I needed to use a deepEqual to get the test to pass; however, I still
didn’t wanna have to wait 2 seconds per test for my test to get marked as
a failure. Enter Mocha’s done function which tells Mocha that the test is
complete. It needs to be called after the assertion, and in the error handler
in order to work properly. Here is the updated test.

describe("#getAccountInfoFromToken()", function () {
it("should return the right details when called with a token", function (done) {
tvm.getAccountInfoFromToken("test").then(function (data) {
assert.equal(data, expected_token_return);
}).catch(function (err) {

the clearer Mocha output:

1) should return the right details when called with a token

0 passing (6ms)
1 failing

1) token_vending_machine #getAccountInfoFromToken() should return the right details when called with a token:
AssertionError: [{"account_id":1725389}] == [{"account_id":1725389}]
at /Users/jmyers/dev/token_vending_machine/test/tvm.js:35:24
at tryCatch1 (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/util.js:43:21)
at Promise$_callHandler [as _callHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:627:13)
at Promise$_settlePromiseFromHandler [as _settlePromiseFromHandler] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:641:18)
at Promise$_settlePromiseAt [as _settlePromiseAt] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/promise.js:804:14)
at Async$_consumeFunctionBuffer [as _consumeFunctionBuffer] (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:75:12)
at Async$consumeFunctionBuffer (/Users/jmyers/dev/token_vending_machine/node_modules/bluebird/js/main/async.js:38:14)
at process._tickDomainCallback (node.js:463:13)

Now to actually make the two arrays compare properly and getting a passing test.
All that we need to do is to do a deepEqual instead of an equal.

describe("#getAccountInfoFromToken()", function () {
it("should return the right details when called with a token", function (done) {
tvm.getAccountInfoFromToken("test").then(function (data) {
assert.deepEqual(data, expected_token_return);
}).catch(function (err) {

And our happy Mocha output:

✓ should return the right details when called with a token

1 passing (6ms)

So you wanna start a conference…: Early Birds and Sponsors

This post is part of a series:

So you wanna conference
Proposals / CFP

The Importance of Early (Organizers)

One of the most important time periods for a conference is the early bird periods.  So you know you want to have an event, and the CFP is taking off. But, how on earth do you make it reality.  This is where early birds and launch sponsors are a HUGE help.  One of the most expensive parts of a conference is that up front section where you are need to secure vendors and make deposits.  You’re not sure how big of a success your conference is going to be and you’re nervous about being on the hook for all these expenses.

Reaching out and engaging your potential attendees early is critical. It builds excitement for the event not on in them, but also in you.  It’s this early excitement that you need to secure the initial funds required for a great event.  In the early bird periods, you’d like to get roughly 40% of your tickets sold.  The fervor will increase as the event gets closer, but deposits are a very, very real thing that is due up front.  Consider offering hugely discounted tickets or other perks such as unique swag or recognition for your early bird and launch sponsors.

Don’t get discouraged, it’s a war and it will take time. You won’t sell out of tickets before the scheduled is even announced. So don’t fret it if you make your deposits, but don’t see every ticket.  Keep contacting and reaching out to people.

The Importance of Early (Attendees)

If you are interested in an event, not only can being an early bird often save you money, but it ensures the viability of the event.  It also keeps the organizers from going insane.  It’s a HUGE undertaking to run an event, and the high they get with each ticket sale will propel the organizers to do even more than they often envisioned. Plus in community conferences, it’s people who have a shared interested in the same thing you do, and want to make a better community.  This is a super simple way to push that forward.

The Importance of Early (Sponsors)

Being an early sponsor is great for your company.  It makes sure you are the first name people see when they hit the website, and often those websites are hit most during the call for proposals, ticket sales launch, and the month leading up to the event.  If you get in early, you’ll be there for all three of those time periods.  Often times you can negotiate reduced rates or additional perks like special shout outs and mentions above your sponsored level.  You also demonstrate to everyone visiting that page, that you care about the community in which they work.  They will remember that the next time they need a service or are looking for a new job.  Community focused customers and employees will push you to new heights. Also, many times you are a member of that same community and will want your own employees to attend.  Your early sponsorship helps ensure the success of the conference.

So you wanna start a conference…: Proposals / CFP

This post is part of a series:

So you wanna conference


Selecting proposals from the CFP process is very difficult, and you need a very diverse group of talk selection committee members. It is also one of the first parts where PR can get out of hand and negativity brews around the event. We received over 100 proposals, and we had a total of 36 slots… UGH.

PyCon has a great selection process in my opinion.  It shifts through HUNDERDS of talks.  You can see the details here.  We adapted that slightly to fit the smaller scale of PyTennessee.


* By Nov 3rd: Initial review took place on the website. The committee reviewed each proposal, left feedback for the author, and voted on the proposal using an “identify the champion” system. We also meet occasionally on IRC to discuss talks and coordinate feedback to presenters.
* Nov 3rd: IRC review begins. The first round, nicknamed “kittendome”, reviewed each talk in isolation, determining if the proposal would be a “good talk” for PyTN. Some talks were rejected at this point; the rest will passed on to…
* Nov 3rd: The second round, nicknamed “Thunderdome”. The remaining talks (typically about half of the proposals) were grouped by topic into groups of 3-5. During Thunderdome, we’ll discussed one group at a time, and select the best talk(s) from each group.
* Nov 4th: Notify Speakers
* Nov 15th: Publish Talk listing

Initial Review

The committee had two goals here:
* Give feedback to authors and help them improve their proposals (authors could edit proposals up until the CfP closes).
* Get an initial set of votes from as many committee members as possible. This will inform the later meetings.

We made sure that each talk got reviewed by at least 3 committee members (and ideally more).


The process we used to assess proposals was based on the Identify the Champion process. The idea is to to assess each talk and identify “champions” and/or “anti-champions” — people who will argue strongly for or strongly against a talk in initial review.

The document linked above uses an “A/B/C/D” scale for reviewing; we use the same idea, but use “+1/+0/-0/-1” labels (after the Apache voting system). These votes mean:

+1 — I will champion the talk at the program committee meeting. The topic sounds good and the proposal is solid. This vote means you’re willing to put your reputation on the line in favor of the proposal and its author, and that you believe PyTN would be worse off for not having the talk.

+0 — This topic is good and the proposal is solid. The speaker is capable of correcting any deficiencies, and I think a significant number of PyTN attendees would want it available. I don’t feel strongly enough about it to serve as its champion at the program committee meeting.

-0 — I am not in favor of this talk as proposed. The talk, the topic, or the proposal has problems that concern me. I’d rather see it not accepted.

-1 — This talk or its proposal has significant problems. I believe that PyTN would be worse off for having it, so I will argue strongly to reject this talk.

If you don’t know enough about a topic to judge a proposal’s coverage of it, or it’s a topic you tend to actively avoid, you should not recuse yourself from voting on that basis alone. You can still judge the structure of the proposal, the likelihood that the speaker can cover the material proposed in the time allotted, whether the topic is likely to appeal to others, etc.

“Obvious” accepted/rejected talks

After the initial review, there will be a small set of talks that are “obviously good” or “obviously bad”. We’ll set a threshold, by committee consensus, for talks that are automatically rejected or get to automatically skip ahead to Thunderdome. This is usually something like “reject all talks with 3 or more -1s and no +0s or better” or “accept all talks with at least 4 +1s and no -1s”. Let me know your thoughts

These accepted talks aren’t a free pass to PyTN – it just means that the talk goes directly to Thunderdome. A reject is final, however; it weeds out the few obviously bad proposals that nobody on the PC wants to support. After the initial review we had nine 45 minute talks, and six 30 minute talks that all had roughly equal ratings, or a program committee member who really wanted to raise a talk up the rankings.

IRC Meetings

Next, we held meetings in IRC to discuss the talks. We allowed a champion to speak for the talk being discussed, and allowed the rest of the program committee to respond.  We then took another vote.  This process continued until all of those talks were refined down to the list you see on the schedule, and a set of backup talks.
There we three attempts to add a 5th track to the conference to accommodate more of the talks. We wanted to accept many more talks than we did; however, we have a big enough event on our hands now for a first one.
Then we wrapped up with a vote on the conference as a whole.  The question was, “Did anyone feel that any one talk would detract from PyTennessee being a great conference?” After that passed, we have the list you see today


In the first round of meetings, we went through each proposal individually. The goal here was simple to determine if a given talk — reviewed in isolation — is potentially good enough for PyTN. That is, in the first round we reviewed talks strictly on their merits and avoid holding them up against similar talks (we do that next, in Thunderdome).

We reviewed talks, one at a time. We gave a couple minutes for the champions (identified by the website votes) to make an argument for the talk. Then, a few minutes of general debate. Finally, we voted yay/nay on each talk. Majority rules – a majority of “yay” votes will indicated that the talk was accepted — it moves onto Thunderdome. A majority of “nay” votes indicated that the talk was rejected — it’s out. The chair will break ties.


After round one has ended, we’re left with a set of talks that are all “good enough” for PyTN, and so we pit similar talks head-to-head and try to select the best.

In each “round” of Thunderdome we reviewed 3-5 talks, roughly grouped by theme/content/topic/etc. Out of each group we’ll got one or more winners, possibly some damaged talks, and some talks that are out. We did this by discussing, and then the committee voted for the talks they liked. Members voted for any number of talks (including none or all of them).

The winners were the talks from the group that absolutely should be at PyTN. It advanced and was safe from future cuts. It’s on the program! The winners were talks that had a 75% supermajority.

Damaged talks were ones that had been voted down by Thunderdome but aren’t quite out of the running yet. There may not be any damaged talks in a given group, or all talks may end up damaged. Damaged talks are any talks that didn’t win, but did receive votes from at least 50% of the committee.  Talks that were selected by fewer than 50% of the committee in attendance are out – they will not appear at PyTN.

We then allowed a champion to speak for each damaged talk, and allowed the rest of the program committee to respond.  We then took another vote.  This process continued until all of those talks were refined down to the list you see on the schedule, and a set of backup talks.

There we three attempts to add a 5th track to the conference to accommodate more of the talks. We wanted to accept many more talks than we did; however, we have a big enough event on our hands now for a first one.

Then we wrapped up with a vote on the conference as a whole.  The question was, “Did anyone feel that any one talk would detract from PyTennessee being a great conference?” After that passed, we had the list that appeared at the conference.


We attempted to do a fair and honest review of the talks, did we do a perfect job… No.  Program Committee members were not allowed to submit talks, share talk reviews, or beseech outside opinions.  During Kittendome and Thunderdome people abstained from voting for coworkers, bosses, close friends, etc. In my case, that meant I cast less than 5 votes the entire dome process for individual talks. :(  I’m certain people could find flaws in our process, or point out some sort of bias.

I can be bought with Cookies, and that’s really no secret.  

So what kind of drama did we have?

Well first, we were clear from the onset that we wanted to be a different conference. We picked a diverse group of talks, and didn’t limit ourselves to just python or even code.  In fact, two of the highest vote getting talks were on Systematic Bias and Mental Health. Those were contentious in the organizers group, but the amount of “not python” was a shock to people.  I got emails calling me stupid, saying I destroy the conference, and that I was doing Python a disservice.

Secondly, we choose to allow presenters to have multiple talks.  During the domes, we didn’t pay attention to how many times a speaker names appeared in our selected talks other than to decide if we could vote or not due to some potential bias.  After the committee members were done selecting talks, they noticed that a few speakers had multiple talks chosen.  A discussion then occurred, and the decision was made to say these were the talks chosen, they are the talks that should be presented.  Unfortunately, many of these people were friends or close to a few of the organizers. This also caused several emails accusing us of playing favorite or placating big name presenters, etc.

Finally, A few people we turned down sent nasty emails about how well known they were, or how great a presenter they are and how stupid I was for turning them down. In a few cases the submitted proposal was one line about the content and several lines about past presentations. As you can imagine the committee voted that talk down over one with a nice full proposal. I still got told I had no business running a conference, I obviously knew nothing about development, and that “my talk would have been selected at” conference X.

These three days lead to a massive cry!!! Thanks to strong support from the committee and a few members of our local community I made it through. I knew we had a great set of talks selected, and I knew that it was done as fair as possible. And a week later the drama had died down and people began to get excited about the talk selection and were tweeting about it.

And now looking back after the conference. It was totally worth all the drama.  We had an overwhelmingly positive response at the event. I and the rest of the committee were ecstatic with the results.

So you wanna start a conference…: Location, Location, Location

This post is part of a series:

So you wanna conference


Selecting a venue can be a long and frustrating process; however, it sets the stage for most every other aspect of the conference.  It will be the stage for your speakers, dictate your food options, network choices, tracks, and schedule.  During the venue selection process of PyTennessee we looked into about 10 different venues, and ultimately bumped up our selection a few times as our number of attendees increased.  We initially expected 100 to 150 people, and it ended up a 281 registered and 247 attending.

Venue selection is a battle of compromises, so start by making a list of what you need from an event center.  Our criteria for the venue were (in order): space for our conference tracks and young coders, security, price, A/V, WiFi, food availability, and hotel availability.


When thinking about space for your conference, keep in mind how many tracks your gonna have, what kind of room layout you need, and how you will distribute any food or snacks.  Also keep in mind how long you have access to the event space both for the conference days and setup/teardown. At PyTN, we only had access to the event space from 7AM-6PM Saturday and Sunday, and one classroom from 3PM-6PM Friday for setup time.  This meant that we had only 3 hours to prepare for young coders, and our sponsors had to setup their tables Saturday morning. It also meant that we had to have any events after 6PM at another facility.  Thank goodness [Emma](http://myemma.com) stepped up to help.  This meant attendees had to find their own transportation from NSL to Emma to attend our party and sprints.

Our venue didn’t have a great way to setup for food. (it takes people way longer than you think to get food.) If you have more than 150 people, try to find a way to setup two lines.  We had a good setup for many things, but I completely screwed up the food distribution process. We also had an issue with food for sprints the first night, as a vendor cancelled our order, another refused to help us, and we finally found a place but it caused our sprinters to get their food late. :(


Wait, why is security so high on your list?  Everyone has differing opinions about how to ensure the safety of their attendees.  Some people like to use on campus/hotel security or use the local police force to handle any incidents.  At PyTN, creating a safe place was a major part of our goals, and we wanted a visible security presence at all official events. Security is rarely included in the venue, but often they have pre-established relationships with security providers and occasionally pre-negotiated rates. For example, we used on campus security at the Nashville School of Law, and used Emma’s preferred security vendor for the events held there. We gave them simple instructions to mostly stay out of the way, but to make sure they made rounds and were noticed.  Speaking of security, we treated them and all our vendors like they were our guests as well.  We made sure to offer them food, shirts, stickers, bags, snacks, water, and anything else we thought they might want.


The price for space is all over the place, and often the prices include bundled things or put restrictions on the vendors and services you can use.  Often hotels and convention centers require you to use their kitchens, their A/V system or vendor, etc.  This can make the overall cost of the conference more than you expect.  So make a total cost sheet for every venue you look at so you can compare them accurately. You can see our cost of the venue and security during the day in the Space Rental fee, and Emma donated the use of their amazing space for sprints and the after party, but you can see our security costs for their space in the security line of our money post listed above.


A/V is the number one headache for speakers once they arrive at your site, and can affect video if you elect to do it at your conference.  Make sure you have plenty of different input support, adapters, and patience.  You will have speakers with every combination of OS, Window Manager, and output you can imagine. Don’t be afraid to ask the audience, often other people have a similar setup to the presenter, and will have the cable or adapter you need.


Whatever you get it’s never enough… At the conference strive to have 1 ap/20 attendees (consumer access point) or 1 ap/60 attendees (commerical access point). Also, try to have at least 25Mbps download / 150 attendees.  No that’s not a ton of bandwidth, but it will enable email, irc, etc.  At sprints make sure to have 25Mbps / 30 attendees.  These are my thoughts on the idea.  Our wifi wasn’t perfect, but it was good enough for the event, and I heard zero complaints about it at sprints.


Food is the greatest variable in a conference. It can cost next to nothing, or it can be your largest expense.  Try to determine your source of food up front for both the conference days, and the other events such as sprints. This doesn’t mean you have to provide food, but it means you need to know how everyone is going to eat! It has to fit into your schedule as well. If people have to go out at lunch, you’ll need a longer break to accommodate that. Plan on providing snacks and drinks even if people are going to be going out for lunch. If your venue requires you to purchase food from them, be aware of the minimums and the cost per person. Food is also a chance for you to share a bit of the flair of your city.  If your city is known for a type of food or a special restaurant try to serve or point people to that.

At PyTN, we had to supply food because the food options close to the venue weren’t very close or good.  We attempted to have food for many of the different diets people follow.  This is very difficult, and isn’t fully achievable.  We did a decent job of having vegetarian options, but we failed to provide enough gluten-free options.  To show off our city a bit, we served food from Edleys, Five Points Pizza, and Hattie B’s. The lack of acceptable food close by, and our food choices set our ticket prices for us. Food and space are the number one reasons PyTN wasn’t a free conference.


Try to find hotels near your conference venue to reduce your attendees transportation requirements; however, attendee safety and comfort tops all! Nashville is a driving city, and we offered hotels that were 10 minutes away from our event venue to ensure they were in safe parts of town, and had quick access to food and grocery.