My life in code

If you just want to read my resume, go ahead and read my resume. This is the story behind my resume.

I took some computer science classes back in high school and early college — mainly C style languages with object oriented features thrown in, as used to be the rage in the 1990s. I must have done a year of C++, with a semester of Java thrown in. I was a pretty classic late-90s nerd, I guess — even before I knew much formally about programming, I was playing around with writing GUI applications in C for my old Mac OS system.

I started to work for a language laboratory in college, at Cornell's Language Resource Center, and I ended up learning most of what I know about software/web development in the workplace. First I got thrown headfirst into Linux server land (originally Red Hat). I got up to speed in Python, which powered our now-totally-obsolete Zope platform. Before long before we needed non-document-based data storage, so I set up a MySQL instance, made it talk to Python, and learned something about normalized database schemas.

A few years later in grad school, I went back to web programming at the University of Chicago, in Humanities Computing. At first I worked on their public-facing websites (mainly Drupal); I remember building some custom event planning module for their big development event. Next door, there was a web applications programmer who was building internal administrative software in Ruby on Rails, which sounded more exciting. He gave me a crash course in Ruby, in the MVC pattern, and in test-driven development. Then he left for a startup, and I got hired into his position.

My code quality improved from more intensive practice (I think). But the real skill I learned through Rails development was about managing the larger lifecycle of a software project in a big institution. I shipped a lot of new projects and got better at supporting web applications in production. I got good at making clean, performant GUIs for our internal apps. I built our testing infrastructure up from almost nothing (lots of unit tests, some integration tests). I built a dashboard app to monitor realtime activity from end users. I got a lot of practice triaging production exceptions (which ones are urgent? which ones can wait a little bit? do we need extra logging or debugging?). I maintained our web infrastructure (not the Linux servers themselves, but the web and database software that ran on them). And I spent quite a bit of time working with our clients, who were mainly internal administrative offices who needed custom software.

It was also kind of wild to see how fast the web software scene was evolving. In academia, things move really slowly. The tech world was much more energetic, and everything seemed to change overnight. Javascript was becoming a more serious programming language, with build tools, better syntax (ES6), and better libraries. But mentally, the big shift for me was towards the more functional and dynamic styles of programming that were popular in Javascript and Ruby. I'd seen some of these styles in Python, like the heavy use of map and lambda functions instead of loops. But suddenly I found myself doing function chaining and passing around closures everywhere, thinking about prototypal inheritance (in Javascript), or writing Ruby DSLs in a more declarative style. I'd still like to learn more about fancier functional languages, and more about asynchronous programming, of the kind you need for client-side Javascript interface design.

Meanwhile, it turned out to be really useful to be trained as an anthropologist while working in software. It teaches you to really listen to people — clients and colleagues alike. It teaches you to write, in lots of different styles. And it helps you get good at moving between very different contexts and different levels of abstraction. That's what cultural anthropologists do — translate between contexts and idioms — and in a funny way, that's what you have to do in software development too.

So anyways, that's my little journey through software development. I've toyed with the idea of going back to get an MA in computer science — I know how to get a lot of things done with software, but sometimes I wish I knew more about compilers, discrete math, and some other parts of the computer science curriculum. We'll see!

How does this website work?

This website is based on hand-written static HTML. There's never been a strong enough reason to rewrite it in a dynamic web framework, or even to use a static site generator; the site is small enough that manual content editing is not annoying.

That being said, sometimes I do get tempted to start automating the editing process. I've written a few ruby scripts to update the site nav, and to pull in content from external data sources. If things keep getting more complicated, I just might have to stop reinventing features that I would get for free in a more full-fledged web development environment. Still, it keeps me in touch with the web to maintain a static site myself, to do the layout myself (even if it's not fancy), to maintain the CSS, to keep it minimally mobile friendly, and so on. Modern web applications have so many layers of abstraction, and it starts to be nice to simplify.

To give you a couple examples of things I've automated for this site, the HTML for my former academic CV is autogenerated from structured data files. And on the page about my academic book project, the manuscript work log is based on the git log for the project.

Here's the script I wrote to transform a git log into HTML.

#!/usr/bin/env ruby

# argv0 should be the path to the git repo whose log you want to export
# invoke with `./update-writing-progress.rb "/path/to/your-git-project"`

require 'nokogiri'

OUTPUT_PATH = 'html/book.html'
OUTPUT_HTML_SELECTOR = '#writing-status'

# Find repo
abort("No repo path specified") unless ARGV[0]
repo_path = ARGV[0]
abort("Repo path not valid") unless Dir.exist? repo_path

# Load new content
raw_history = `git -C #{repo_path} log --pretty="%ad|%s" --date=short`
git_history = raw_history.split("\n").map { |line| line.split "|" }

# Render tabular content
new_content = do |date, log|

I like writing these little shell scripts in Ruby -- I especially like the heredoc string interpolation, the handy library for working with HTML (nokogiri), and the low-overhead integration with other shell tools (backtick operators). Obviously there's more you would do to improve this script if it were for general use or public distribution -- more error checking, maybe a different strategy for doing configuration. But this is just a script I use privately, so it's safe to make some assumptions about the user. By the way, I'm sure there's a way of rewriting this script in one line of Bash, but I'll take readability any day.

I've also learned to love deploying web projects from git, so this static site lives in a private git repository and has a handy one-stop deployment script. It's served from nginx on Ubuntu.

Anyway, underneath this very simple static site is a larger thought that you learn from software development: all software constantly has to make tradeoffs given its environment and available resources. So partly, this project works as my sandbox for exploring some of the tradeoffs of modern web development. I could make a much fancier website, with a custom content management system. But this one works (on the devices I've tested) and I don't have a strong reason to improve it. Enough said.