Hello, Lumpy World!

Overview: how to generate 3D terrain for iOS. This assumes basic knowledge of iOS programming (how to create a project and add files to it.)

I’ve been working on an iOS app that uses cocos3d and Robert’s hill-generating algorithm, which make nice hills that remind me of early Mario levels. For example:

Nice starter world
My lovely verdant lumps.

You can download the hill generation library from Github. I’ve converted Rob’s code from C++ to Objective-C and added support rectangular terrain (instead of just square terrain).

To generate your own terrain with it, download and install cocos3d and create a new cocos3d2 project called “TerrainGenerator”. It’ll create a 3D “Hello, world!” application. Hit the “Play” button to make sure it runs:

hello, world
Absolutely gorgeous.

To add the hill generation code, download the library from Github and add HillTerrain.m and HillTerrain.h to your project.

Replace the contents of TerrainGeneratorScene.m with:

#import "TerrainGeneratorScene.h"
#import "CC3PODResourceNode.h"
#import "CC3ActionInterval.h"
#import "CC3MeshNode.h"
#import "CC3Camera.h"
#import "CC3Light.h"
#import "CC3ParametricMeshNodes.h"
#import "HillTerrain.h"


@implementation TerrainGeneratorScene

-(void) dealloc {
  [super dealloc];
}

-(void) initializeScene {
  // Lights
  CC3Light* lamp = [CC3Light nodeWithName: @"Lamp"];
  lamp.location = cc3v(-2.0, 0.0, 0.0);
  lamp.isDirectionalOnly = NO;

  // Camera
  CC3Camera* cam = [CC3Camera nodeWithName: @"Camera"];
  cam.location = cc3v(128.0, 0.0, 300.0);
  [cam rotateByAngle:15 aroundAxis:cc3v(1.0, 0.0, 0.0)];
  [cam addChild: lamp];
  [self addChild: cam];

  // Action! (Well, okay, just terrain.)
  [self createTerrain];

  // OpenGL fun.
  [self createGLBuffers];
  [self releaseRedundantContent];
  [self selectShaderPrograms];
}

-(void) createTerrain {
  HillTerrain *terrain = [[HillTerrain alloc] init];
  [terrain generate];

  CC3MeshNode *mesh = [[[CC3MeshNode alloc] init] retain];
  mesh.vertexContentTypes =
    kCC3VertexContentLocation | kCC3VertexContentColor | kCC3VertexContentNormal;
  [mesh populateAsRectangleWithSize:CGSizeMake(terrain.size.width, terrain.size.height)
                  andRelativeOrigin:CGPointZero
                    andTessellation:CC3TessellationMake(terrain.size.width-1,
                                                        terrain.size.height-1)];

  int count = 0;
  for (int j = 0; j < terrain.size.height; ++j) {
    for (int i = 0; i < terrain.size.width; ++i) {
      float height = [terrain getCell:cc3p(i,j)];
      [mesh setVertexLocation:CC3VectorMake(i, j, height * 128) at:count];
      [mesh setVertexColor4F:ccc4f(0.0, height, 1.0-height, 1.0) at:count];
      ++count;
    }
  }

  [mesh setShouldUseLighting:YES];
  [self addChild:mesh];
  [terrain release];
}

@end

Save and run, and you should see something like this:

Default terrain
Hello, lumpy world!

The createTerrain method is where all of the magic happens, so let’s take it one section at a time:

Generating the terrain

Here’s the part that actually generates the terrain:

  HillTerrain *terrain = [[HillTerrain alloc] init];
  [terrain generate];

You can change any of the parameters you want here, for example, let’s try a different seed:

  HillTerrain *terrain = [[HillTerrain alloc] init];
  [terrain setSeed:123]; // Because I'm so creative.
  [terrain generate];

This generates a nice range of mountains:

A blobby range of mountains
The majestic Blob Range

Creating something OpenGL can use

The next part is mapping this terrain onto an array of vertexes. First, we create a mesh, aka the surface we want to display. You can picture it like a fishing net you’ll be draping over the landscape.

  CC3MeshNode *mesh = [[[CC3MeshNode alloc] init] retain];

Specifying the types of storage we’ll need

Next, we have to let Cocos3d know what type of info we want to store about this mesh. For us, this includes:

  1. The location of each vertex, because that’s the point of all this.
  2. The color at each vertex, because it’ll vary based on height.
  3. The normal of each vertex, which is the direction light will bounce off of it. This is automatically populated by Cocos3d, so you don’t have to worry about it for now. However, it’s interesting to try removing this one and seeing what the terrain looks like.
  mesh.vertexContentTypes =
    kCC3VertexContentLocation | kCC3VertexContentColor | kCC3VertexContentNormal;

Allocating the mesh

Now that we’ve told Cocos3d the types of storage we need, we tell it the shape and size to allocate: a rectangular grid the same size as our terrain.

  [mesh populateAsRectangleWithSize:CGSizeMake(terrain.size.width, terrain.size.height)
                  andRelativeOrigin:CGPointZero
                    andTessellation:CC3TessellationMake(terrain.size.width-1,
                                                        terrain.size.height-1)];

andTessellation specifies how many squares across the terrain will be, so you want that number to be one fewer than the number of vertexes you have. For example, if you had a tessellation of 1 square by 1 square, you’d need 4 vertexes (one for each corner of the square). Thus, the -1s.

Mapping the terrain onto the mesh

First, we get the height at one of the map coordinates. This will be a number between 0 and 1, so we’ll scale it up to something reasonable, given our scale (height*128 in this case).

      float height = [terrain getCell:cc3p(i,j)];
      [mesh setVertexLocation:CC3VectorMake(i, j, height * 128) at:count];

Then we set the color, making the high locations greenest and the lowest locations bluest:

      [mesh setVertexColor4F:ccc4f(0.0, height, 1.0-height, 1.0) at:count];

The at:count indicates the index of the vertex we’re setting. Cocos3d keeps all of the vertexes in a big array and this is the index into it.

Turning on the lights

Finally, we tell OpenGL to actually apply light to the mesh. (Try removing this line and see what it looks like.)

  [mesh setShouldUseLighting:YES];

And we add the mesh as a child to our scene and free the terrain memory:

  [self addChild:mesh];
  [terrain release];

That’s it! If anyone has any suggestions or improvements, please feel free to file a pull request. I’m not too happy with island generation yet: I haven’t figured out the right combination of options so my islands aren’t just lumps.

If you’re interested, Rob’s algorithm is pretty interesting and easy-to-follow. I recommend reading through his description if you plan on using it in a project.

Achievement Unlocked: Found bug in LLVM debugger (maybe)

Also, on an unrelated note, I seem to have found a bug in LLDB (the LLVM debugger) in the making of this blog post, which makes me inordinately proud.

The Basics of Signal Handling

The-Great-Gatsby-Green-Light

Signals are one of the most basic ways programs can receive messages from the outside world. I’ve found limited tutorial-type documentation on them, so this post covers how to set them up and some debugging techniques.

The easiest way to get a feel for signal handling is to play with a simple C program, like this:

#include 
#include 
#include 

void my_handler(int signum) {
  const char msg[] = "Signal handler got signaln";
  write(STDOUT_FILENO, msg, sizeof msg);
}

int main(int argc, char *argv[]) {
  printf("PID: %dn", getpid());

  // Set up signal handler
  struct sigaction action = {};
  action.sa_handler = &my_handler;
  sigaction(SIGINT, &action, NULL);

  while (1) {
    pause();
  }
  return 0;
}

Compile and run and try hitting Ctrl-C a few times:

$ gcc signals.c -o signals
$ ./signals 
PID: 11152
^CSignal handler got signal 2
^CSignal handler got signal 2
^CSignal handler got signal 2

Each signal calls the signal handler we set up.

If you attach strace (system call tracer) and then hit Ctrl-C in the terminal running ./signals again, you can see each signal coming in:

$ $ strace -p 11152 -e trace=none -e signal=all
Process 11152 attached - interrupt to quit
--- SIGINT (Interrupt) @ 0 (0) ---
--- SIGINT (Interrupt) @ 0 (0) ---
--- SIGINT (Interrupt) @ 0 (0) ---

As we can’t kill it with Ctrl-C, we can use kill to shutdown ./signals:

$ kill 11152

kill defaults to sending a SIGTERM, which we’re not handling (yet). You could add a handler for it by adding the line sigaction(SIGTERM, &action, NULL); but then we’d have to kill -9 the process to kill it (which is two extra characters of typing) so I’m leaving SIGTERM unhandled.

Ignoring Signals

There are also ways to make your program not even receive signals: ignoring and blocking them (which are subtly different). To ignore a signal, change sa_action to SIG_IGN:

#include 
#include 
#include 

void my_handler(int signum) {
  const char msg[] = "Signal handler got signaln";
  write(STDOUT_FILENO, msg, sizeof msg);
}

int main(int argc, char *argv[]) {
  printf("PID: %dn", getpid());

  // Set up signal handler
  struct sigaction action = {};
  action.sa_handler = SIG_IGN;
  sigaction(SIGINT, &action, NULL);

  while (1) {
    pause();
  }
  return 0;
}

Now recompile and run and hit Ctrl-C. You’ll get something like this:

$ ./signals
PID: 86579
^C^C^C^C^C

If you attach strace, you’ll see that ./signals isn’t even receiving the SIGINTs.

You can see the signals a program is ignoring by looking at /proc/PID/status:

$ cat /proc/86579/status
Name:   signals
State:  S (sleeping)
Tgid:   86579
Pid:    86579
PPid:   30493
TracerPid:      0
Uid:    197420  197420  197420  197420
Gid:    5000    5000    5000    5000
FDSize: 256
Groups: 4 20 24 25 44 46 104 128 499 5000 5001 5762 74990 75209 77056 78700 79910 79982 
VmPeak:     4280 kB
VmSize:     4160 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM:       352 kB
VmRSS:       352 kB
VmData:       48 kB
VmStk:       136 kB
VmExe:         4 kB
VmLib:      1884 kB
VmPTE:        28 kB
VmSwap:        0 kB
Threads:        1
SigQ:   0/192723
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000002
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: ffffffffffffffff
Cpus_allowed:   ffffffff
Cpus_allowed_list:      0-31
Mems_allowed:   00000000,00000001
Mems_allowed_list:      0
voluntary_ctxt_switches:        2
nonvoluntary_ctxt_switches:     3

SigIgn is a hexidecimal number and it has kind of a weird format: the ignored signal number’s bit is set. So, for 2, the second bit is set. For SIGTERM (signal 15), the 15th bit is set: 0100_0000_0000_0000 in binary or 0x4000 in hexadecimal. So, if you were ignoring both SIGINT and SIGTERM, SigIgn would look like: 0000000000004002.

SigCgt is for signals that are being caught by the program and SigBlk is for signals that are being blocked.

Blocking Signals

What if you want your program to handle any signals that come in, just do it later? You might have a critical section where you don’t want to be interrupted, but afterwards you want to know what came in. That’s where blocking signals comes in handy.

You can block signals using sigprocmask:

#include 
#include 
#include 

void my_handler(int signum) {
  const char msg[] = "Signal handler got signaln";
  write(STDOUT_FILENO, msg, sizeof msg);
}

int main(int argc, char *argv[]) {
  printf("PID: %dn", getpid());

  // Set up signal handler                                                                                                                                                                                
  struct sigaction action = {};
  action.sa_handler = &my_handler;
  sigaction(SIGINT, &action, NULL);

  printf("Blocking signals...n");
  sigset_t sigset;
  sigemptyset(&sigset);
  sigaddset(&sigset, SIGINT);
  sigprocmask(SIG_BLOCK, &sigset, NULL);

  // Critical section
  sleep(5);

  printf("Unblocking signals...n");
  sigprocmask(SIG_UNBLOCK, &sigset, NULL);

  while (1) {
    pause();
  }
  return 0;
}

First we create a sigset_t which can hold a set of signals. We empty out the set with a call to sigemptyset and add a signal element: SIGINT. (There are a bunch of other set ops you can use to modify sigset_t, if necessary.)

If you compile and run this and try Ctrl-C-ing while signals are blocked, one signal will be “let through” when the signals are unblocked:

$ ./signals
PID: 86791
Blocking signals...
^C^C^C^C^C^CUnblocking signals...
Signal handler got signal 2

One common use for this is blocking signals while the signal handler is running. That way you can have your signal handler modify some non-atomic state (say, a counter of how many signals have come in) in a safe way.

However, suppose we called sigprocmask in the signal handler. There will always be a race condition: another signal could come in before we’ve called sigprocmask! So sigaction takes a mask of signals it should block while the handler is executing:

#include 
#include 
#include 

void my_handler(int signum) {
  const char msg[] = "Signal handler got signaln";
  write(STDOUT_FILENO, msg, sizeof msg);
}

int main(int argc, char *argv[]) {
  printf("PID: %dn", getpid());

  // Set up signal handler                                                                                                                                                                          
  struct sigaction action = {};
  action.sa_handler = &my_handler;
  sigset_t mask;
  sigemptyset(&mask);
  sigaddset(&mask, SIGINT);
  sigaddset(&mask, SIGTERM);
  action.sa_mask = mask;
  sigaction(SIGINT, &action, NULL);

  while (1) {
    pause();
  }
  return 0;
}

Here, we’re masking both SIGINT and SIGTERM: if either of these signals comes in while my_handler is running, they’ll be blocked until it completes.

Inheritance

Ignored and blocked signals are inherited when you fork a program. Thus, if a program isn’t responding to signals the way that you expect, it might be the fault of whoever forked it. Also, if you want your program to handle signals in certain ways you should explicitly set that rather than depending on the default.

If you want to use a signal’s default behavior (which is usually “terminate the program”), you can use SIG_DFL as the sa_handler.

What you can do in a signal handler

You might notice that I’m using write in the signal handlers above, instead of the somewhat more friendly printf. This is because there are only a small set of “async safe” functions you can call in a signal handler and printf isn’t one of them. There is a list of functions you can call on the signal(7) man page. A few examples that often come up: you cannot heap-allocate memory, buffer output, or mess with locks.

If you call any unsafe functions in a signal handler, the behavior is undefined (meaning it might work fine, or it might make your car blow up).

Edit: thanks to Vincent Bernat, who mentioned this in the comments.

References:

Labeling Git Branches

I came across git branch descriptions today and it is so freakin useful that I wanted to share.

My branches usually look like this:

$ git branch
  add-feature
  feature-add
* implement-foo
  implement-foo2
  temp
  temp2

It is… not the clearest. Luckily, you can add descriptions to branches:

$ git checkout implement-foo2
$ git branch --edit-description

---Pops up an editor---

These are the tests for my implement-foo change, they can be cherry-picked onto implement-foo when they are done.

---Save & exit---

The only problem is that these descriptions don’t show up when you do git branch. To display them, use jsageryd‘s script (and vote up the comment, it should really be nearer the top):

#!/bin/bash

branches=$(git for-each-ref --format='%(refname)' refs/heads/ | sed 's|refs/heads/||')
for branch in $branches; do
  desc=$(git config branch.$branch.description)
    if [ $branch == $(git rev-parse --abbrev-ref HEAD) ]; then
       branch="* 33[0;32m$branch33[0m"
    else
       branch="  $branch"
    fi
  echo -e "$branch 33[0;36m$desc33[0m"
done

Save it as something (I called it “branch”), make it executable, add it to your path, and then you can do:

$ branch
  add-feature
  feature-add
  implement-foo
* implement-foo2 These are the tests for my implement-foo change, they can be cherry-picked onto implement-foo when they are done.
  temp
  temp2

It’s even got nice colors for the selected branch and descriptions.

Music Gremlins is Approved!

Derpy gremlin

My iPad app is approved and going live on July 1st!

Music Gremlins is an ear-training game where you beat gremlins by matching the notes that they play. Different types of gremlins demand different strategies. As a musician, I found it very difficult to practice relative pitch and this makes it easier and more fun.

I wanted to have Music Gremlins be more game-like, but it turned out kind of like Mavis Beacon Teaches Typing for ear training. Oh well, I hope that at least musicians still find it useful. And it’s only my first attempt.

Details: it’s also only for iPad at the moment but it is totally free.

The App Store Process

Last weekend, Music Gremlins was almost ready to go so I put in a focused effort to finish it up. I spent all weekend doing a thousand little “last things” and submitted it for review on Sunday.

It took me hours to actually submit the damn thing. If you ever come across Apple’s “Download Application Loader”, run away. The Application Loader is a pit of hell from which there is no escape. You can upload your app directly through XCode, which involves a mere hour or so of swearing.

Once XCode has uploaded your app for you, you get an automated email that your app is “Waiting for Review.” The review process for my app was painless, but Music Gremlins didn’t exactly stretch the bounds of iOS. I uploaded it on Sunday, June 9th and they got back to me today (June 17th), which was a lot faster than I expected. I got several emails today, that my app was “In review,” “Processing,” and finally:

App Store Approval

Screenshot from the final game:

iOS Simulator Screen shot Jun 9, 2013 9.41.59 AM

Unfortunately, I forgot to remove the debugging framerate, so you can see the frame rate in the lower left corner. This is a screen shot from the simulator and is running at 20fps, but on my iPad it runs at 60fps (yay!). I’m going to try to remove that by July 1st…

It’s turtles all the way down

Turtles all the way down” is a concept that Java handles very nicely:

public class Turtle {
    Turtle prevTurtle;

    public Turtle(Turtle prevTurtle) {
        if (prevTurtle == null) {
            throw new RuntimeException("It's turtles all the way down.");
        }
	this.prevTurtle = prevTurtle;
    }
}

(Probably there should be a special FiniteTurtleException, but I wanted to keep the code compact.)

Similarly for other circular references:

class Chicken {
    Egg cameFrom;

    public Chicken(Egg hatchedFrom) {
        cameFrom = hatchedFrom;
    }
}

class Egg {
    Chicken cameFrom;

    public Egg(Chicken mother) {
        cameFrom = mother;
    }
}

You can do it in C-like languages, but you need to be a little clever in your header files, which takes some of the fun out of it.

Yertle the Turtle

Adding an Assertion Macro in Objective-C

TL;DR:

#define CHECK(val) NSAssert((val), @#val)

// Then use:
CHECK(/* something (hopefully) true */);

Long version:

iOS made the the somewhat bizarre choice that dereferencing a null pointer is not an error. The program just ignores that line and keeps going. Now this causes fewer crashes (yay-ish), but when I developing I’d really like the program to fail fast instead of just skipping huge swaths of code.

As far as I can tell, there’s no way to make dereferencing a null pointer an error. Thus, I’ve started adding asserts everywhere that I expect values to not be null:

NSAssert(my_var != nil, @"my_var isn't supposed to be nil");

I wrote that all of once and decided I needed a macro:

#define CHECK(val) NSAssert((val), @#val)

Now, I can just say:

CHECK(my_var != nil);

At compile time, the assert’s message will automatically be set to the string @"my_var != nil" (that’s what the preprocessor instruction # does: it means “wrap in quotes”).

Most libraries have a macro like this for asserting, but I’ve never programmed it myself. Nifty stuff!

P.S. If you need to debug the macro, you can run Objective-C files through GCC normally to see the preprocessor output:

$ gcc -E Gremlins.m > Gremlins.E

MongoDB: The Definitive Guide 2nd Edition is Out!

MongoDB: The Definitive Guide

The second edition of MongoDB: The Definitive Guide is now available from O’Reilly! It covers both developing with and administering MongoDB. The book is language-agnostic: almost all of the examples are in JavaScript.

Upgrading from a previous edition?

If you have read the first edition, the new edition covers a lot of new material (it is twice as long!). Everything has been updated and lots of sections on new features have been added.

Translations

I hear O’Reilly is working with their translators to get this edition translated into other languages, but I tend to be the last to hear about that so I don’t know what the schedule is.

So…

Pick up a copy and let me know what you think!

First Two Weeks at Google

I’ve been at Google two weeks now and I’m loving it so far. My team is great and the work’s very interesting, but I can’t talk about what I’m doing, so:

There’s a ton of orientation stuff new employees have to do, which hasn’t been much fun. There was a scavenger hunt (which is the kind of thing I usually loathe) but we did find some cool stuff. One of the places on the list was “the music room.” When we went in it was a soundproofed room with a half-dozen guitars along one wall, an electric drumset, synth, a mic, soundboard, amps… it was amazing.

Other things I’ve discovered so far are:

  • The library, which has big comfy armchairs and couches, shelves of physical books, and a sci-fi touch interface for checking out ebooks.
  • The juice bar: free smoothies anytime.
  • The workshop with metal/wood crafting supplies and a 3D printer.

I also got this, er, unique hat:

Google beanie

If anyone wants a propellor beanie, let me know.

Stock Option Basics

Here’s what I wish I’d known when I started working at 10gen. Disclaimer: don’t take this as financial advice, consult someone who actually knows what they’re talking about before making any financial decisions, this is for entertainment purposes only, etc. Also, the numbers used below do not match any startup that I know of, they’re just hypothetical.

Intro to Stock Options

Stock options are the option to buy X shares of stock in a company at a guaranteed price of $Y per stock. Generally, they have some time constraints: they are doled out to you slowly over 3-5 years (the vesting schedule) and expire after a certain number of years if you don’t buy them.

$Y is the strike price, the price of the stock when you’re given your stock grant. Basically, it is determined by taking the value of the company (say, $2,000,000) and dividing it by the number of shares that have been issued (say, 5,000,000). This would give you a strike price of $0.40.

If the company is successful, the stock price should be higher when you sell the shares. For example, say that the startup above is successful and their stock price rises to $5.00. Now you can buy your shares for $0.40 and sell them for $5.00, making a nice $4.60 profit on each share.

Except you can’t, because of taxes. If you are the kind of person who doesn’t know what a stock option is, you probably have common, or non-qualified stock options (companies prefer this type because you’ll be footing the tax bill instead of them). For non-qualified stock, you get taxed twice: when you buy (or exercise) your options and a second time when you sell the stock (these are called taxable events).

Let’s say you’re in the situation above: you have 10,000 shares with a strike price of $0.40 and you want to exercise your options. The current price is $5. You exercise your options for $4,000 ($0.40 * 10,000). However, according to the government, you just “made” $46,000 ($5*10,000 – $4,000), which you’ll now be taxed on. I have no idea how this tax rate is computed, but for me it was ridiculous. If my options matched this example (they don’t), I would have had to pay ~$30,000 in taxes (about 60% tax rate). Also, you have to hand the company a check for these taxes when you exercise the options, you can’t put it off until April.

So be careful: if you own a lot of options and the price rises a lot, you can “golden handcuff” yourself to a place because you cannot pay the taxes to actually buy your options.

The second taxable event is when you sell the stock. If you sell the stock within a year, you’re hammered again with short-term capital gains taxes. If you wait for more than a year to sell, you “only” get hit with long-term capital gains taxes.

Negotiating Options

When you get a job at a startup, often part of the offer will be stock options. If the startup is early stage, I’d recommend pretending that your options will be totally worthless forever. Is the salary acceptable on those conditions? (Almost every other startup I know of has failed in the time 10gen’s been around).

In retrospect, I wish I had negotiated more stock options instead of more salary when I started at 10gen, but if I was joining an early-stage startup again, I would do the same thing: not sacrifice salary for options.

The exception is if you’re joining a startup at a later stage and you’re pretty sure they’ll be successful. In that case, you might want to negotiate for more options.

Option Expiration

Typically, options have an expiration date. Make sure you buy them before they expire (if you want them). Also, options are typically designed as an incentive to stay, so they don’t follow you after you leave the company. If you quit or are fired, you’ll have to buy any vested ones before or shortly after leaving.

Buying Unvested Options

You can buy unvested options, but I can’t see why you would unless you’re pretty sure the company’s going to succeed, you’ll be there until the options vest, and you’re trying to avoid the tax hit. If all those hold true, Max Schireson wrote a good blog post on what you need to know about that. In fact, go read his post regardless, because it’s a really good and more technical coverage of a lot of these points.

Dilution

In the example above, you have 10,000 shares out of 5,000,000, meaning you own (or could own) 0.2% of the company, you tech mogul. However, whenever there’s a round of funding typically more shares are issued. Thus, instead of there being 5,000,000 shares, there are now 10,000,000 and you only own 0.1% of the company. Your company should tell you how many stocks are outstanding (the number issued in total) if you ask. I think this number is typically confidential, but I’ve heard people advise that you should ask during salary negotiations, so YMMV.

The other significant event is board meetings, where the board decides how much the company is worth. This changes what the current stock price is. Funding rounds also often have an effect on price.

Stockholder Privileges

Even if you’re at an early-stage startup, it might be worth buying a few shares to get stockholders rights. Find out how many shares you need to buy to get these, if you want a look at the books and so on.

Keeping Your Documents

Particularly at an early-stage startup, there may not be anyone keeping track of this stuff. When 10gen got an Finance/HR person, I asked them about the options grants they had on record and they were missing my original hiring grant. Luckily, I still had the paperwork. Keep everything safe somewhere, just in case.

Exercise Quickly

If you’re leaving a company, get on exercising your options as quickly as possible. You generally have a limited time period before your options disappear and your company might have arbitrary restrictions on when you can exercise (like “not within a month of a board meeting”). Also, it’s not exactly a speedy process: it took 10gen three weeks from when I signed the paperwork and gave them the checks to actually send the stock certificates. You don’t want to have to be dealing with HR at your last company while you’re dealing with new hire HR at your new job.

Recruiting in all the wrong places

A recruiter had an email exchange at me the other day. It started with the standard recruiter email:

Hi Kristina,

How are you enjoying 10Gen? Any interest in going to something earlier stage? I’m working with a client in <field I’m not interested in>. Obviously the specificities of that are fascinating. Let me know if you’d be interested in hearing more.

I ignored it. A few minutes later, I got a follow-up email from him:

Subject: Whoop, how humiliating

Just saw on LinkedIn you left 10gen last month. Do you have plans for what’s next?

Closer, but not quite. A few minutes later:

Ach! Forgive me. Congratulations on the Google job.

Should you ever need the services of an incompetent sourcer, please, don’t hesitate to reach out!

And I kind of wished that I needed a recruiter because that was pretty funny.