How I got here

Published: October 16, 2006. Filed under: Django, Frameworks, Meta, Programming.

I’m not a formally-trained programmer. I wasn’t a computer science major in college (my degree is in philosophy), and my first job after graduation didn’t involve programming (it was phone-based customer service at a health-insurance company). But here I am, developing software for a living.

I’ve never written a compiler. I’ve never hand-tuned something by dropping in bits of assembly, or even by writing C extensions for an interpreted language. I’m too young to have ever hacked on a Lisp Machine. But here I am, developing software for a living.

My language of choice is Python. I don’t evangelize it a lot, and not just because Python in general doesn’t market itself very much, or because I feel that language cheerleading isn’t a particularly productive use of my time. I also don’t evangelize it much because I feel like I’m not the sort of person to turn to for advice on choosing a programming language; I’m just a jumped-up liberal-arts kid who never took an algorithms class in college and is still playing catch-up on that front.

But every once in a while I feel like I should explain how I got here, and why I’m writing in Python, instead of PHP or Perl or Ruby or Java or C# or any other language that’s applicable to the domain I work in. So here goes.

Entry point

I didn’t grow up hacking. I learned BASIC as a kid (in fact, I learned a few different flavors of it at various points), and when I was in the second grade I learned Logo and used it to draw amusing pictures. But outside of brief encounters, programming wasn’t a part of my formative experiences. A lot of this had to do with the economic situation I grew up in; aside from a third-hand Apple II, neither I nor anyone else in my family had owned a computer until I was in my second year of college. Now, sitting on my couch with one computer in my lap and four more strewn around my apartment, I can’t help feeling that I’m living in unbelievable luxury; I could, if I wanted to, throw one of them away and buy a new one. What affluence!

So it wasn’t until I was in college that I had a chance to really learn much about computers. I started, ignominiously, with HTML, which I learned almost on a whim. I had to produce a web page for a class I was taking, and HTML didn’t look too difficult, so I dove in.

Naturally, I didn’t stop with the web page I was supposed to produce for the class; now that I knew how to write HTML, I took advantage of the free web space my college provided to all its students, and set up my very first personal web site. I had an irregularly-updated journal which I managed by hand, and I was proud of myself.

The next step, logically, was to learn a programming language I could use to automate the management of that site.

In those days, there were two choices for an amateur who wanted to dabble in web programming: Perl/CGI and PHP. I spent a little time looking at examples of both before I made my choice, but it wasn’t a particularly difficult choice to make.

Why PHP won

Most of the “serious” web programmers I came into contact with back then with wrote Perl, and tended to look down their noses at PHP. Looking at it now I can sort of understand why, but I also understand why they all kept a working knowledge of PHP on their résumés: PHP was winning over the Web. Perl was a more mature language and certainly a more robust language, but Perl was losing. It had been the language of web programming for quite a while, but still it was losing.

The reason is simple: PHP was easy. You just wrote your code, threw in a little bit of HTML, tacked a .php on the end of the filename and uploaded it. Whereas Perl, even at its best, required you to learn a few things about CGI and web servers before it would work on most hosting accounts.

And that’s putting it nicely. In more accurate terms, PHP stomped the ever-lovin’ crap out of Perl for a first-time web programmer. Perl was originally designed as a glue language to do text processing on Unix systems, and only later grew CGI functionality and server integration. PHP was originally designed to do web programming, and integrated into Apache in a way that even a mentally-impaired chimpanzee could understand. In the hearts and minds of a generation of new web developers, one of whom was me, Perl didn’t stand a chance.

My web hobby continued to be mostly a hobby for the remainder of my college years. I learned CSS, and I learned SQL and I learned JavaScript for the first time (and hated every second of it), and my little personal site grew lots of interesting new capabilities. Most of my disposable income was being spent on ways to impair the computer inside my head, so I never bought a real domain or real web hosting; when I graduated and didn’t have free hosting from the college anymore, I set up Apache on my personal computer (I’d been converted to Linux by that point), got a dyndns.org subdomain and kept on chugging. Once or twice, people paid me to build sites for them, but they never involved any serious programming.

Broadening horizons

I did eventually learn Perl, but I never really liked it. I usually attributed that to the fact that PHP had been so much easier, but as time went by I came to understand the real reason why I didn’t like it, a reason which was also behind my eventual break with PHP.

Right around the time I graduated, I started learning Python. Given that my first foray into JavaScript had been fairly shallow and I’d been using PHP 4 for web stuff, this was my first experience with real object-oriented programming. OOP was easy for me to pick up; it was an abstraction, and a useful, sensible abstraction to boot. Just for kicks I did learn some Java on the side, to get a feel for a “pure” object-oriented language, but I didn’t really enjoy that and don’t like to admit to it now.

Python was also my first experience with a language that allowed you to do functional programming, and my first exposure to the concept of functional programming in general. So I read up on it. I learned about Alonzo Church and the lambda calculus; I learned about Haskell Curry and the various things named after him; and I worked through a few basic Lisp tutorials.

The more I learned, the more I wanted to learn. I read as much as I could understand of the fundamentals of computer science (my degree in philosophy ended up doing a lot of good there; a philosophy major doesn’t have very many direct applications to the real world, but a solid grounding in logic and formal systems really paid off in this particular case), and particularly in the philosophies behind different programming languages. The guiding principles behind the various languages I’d learned started to stand out more clearly, and even though I started recognizing the flaws in Python I kept right on liking it.

And I kept wishing I could use it for the web stuff I was doing (by this point I’d quit my customer-service job and was freelancing full-time). Some guys in the local LUG were making good money building stuff with Zope, but it didn’t feel right to me, and I didn’t have the time or the energy to invest in learning it; Zope was such a mind-bogglingly huge thing that the only way to get a handle on it was to start memorizing pieces and hope they’d eventually come together and make sense.

Finally, something clicked.

Memorize this

One day a little light went off in my head, and I understood why I didn’t like Perl or PHP, and part of why I liked Python and a few of the other languages I’d dabbled with. Much later I was reading Steve Yegge’s rant about Perl and got to this bit, which explained it far better than I could ever hope to:

Every operator in Perl (not just the Range operator) has six different behaviors depending on the invisible context in which its surrounding expression is being evaluated. When you evaluate a hash in a string context, for instance, you get back a string that’s a fraction, such as “7/10”, the numerator of which represents the current number of keys in the hash, and the denominator of which represents of total number of buckets allocated. And so on, and so forth. There are no rules, no heuristics, no patterns. It’s pure memorization.

He’s right that a huge amount of learning Perl is memorization: committing all the operators and contexts and special global dollar-sign-plus-Chinese-character variables to memory and learning how to make them work together. And even though I’m fairly good at it, I hate learning things by memorization. I like to understand things, to know what makes them work and how their parts fit together; I don’t like hearing “oh, just assign this value to the the magic global $make_it_work variable, and remember that for next time”.

This also explained a large part of why I didn’t like PHP, because PHP is almost as bad. A lot of its problems on the memorization front could be solved by either A) implementing namespaces or B) choosing a consistent naming scheme for built-in functions or C) preferably both, but that’s probably never going to happen because the existing system has way too much inertia.

All of this is part of why I use Python.

Why Python, part 1

Python asks for very little in the way of memorization. The core language is small and the built-ins have sensible, consistent names. The standard library is large, but everything is in module namespaces, and you can be an advanced and very productive Python programmer without having to memorize every symbol exported from every standard module — knowing a few important modules well, and having a good general understanding of what the rest of them do, is enough to take you a long, long way.

Yearning to be free

I’d been hearing rumblings for a little while about something called “Ruby on Rails”, and how it basically kicked the crap out of everything else in the web-development world the way PHP used to, and I was intrigued. So I started learning Ruby and picking up Rails.

This was a pretty interesting experience, because it organized and cemented a lot of things I hadn’t really understood previously, like metaprogramming. Rails really isn’t “Ruby” so much as it’s a domain-specific language for web programming which happens to be implemented in Ruby. And Ruby as a language is exceptionally well-suited to writing domain-specific languages. It was the first time I’d seen that sort of “bottom-up” approach in the real world, and it was an eye-opener.

Unfortunately, from a professional perspective I was still stuck firmly with PHP and Perl, and getting more and more stuck every day. I’d built a reputation on being handy with a couple of niche CMS products, and business generated from that reputation was paying my bills and putting food on my table, so I couldn’t just dive headlong into something else. And, of course, the Rails hype machine and the associated bevy of companies willing to throw money at people with any sort of Rails knowledge hadn’t yet kicked into full gear; if the timing had been different, I would now be writing Ruby by day and snorting coke off the bellies of hookers by night.

And even though Ruby and Rails were unarguably cool, I still really liked Python.

And all that jazz

In the summer of 2005, a new Python web framework popped up, and immediately people started comparing it to Rails. I set it up on my testing machine (by this point I was rich enough to afford two computers!) and started fiddling with it, and I was almost immediately hooked. There were some un-Pythonic things about it, and there was a fair amount of “magic” in it (both have been dealt with since), but I realized I’d finally found what I was looking for. I could finally use Python on the Web.

The rest, of course, is history. I got involved in the Django community, one thing led to another, and now here I am, working at the Journal-World, writing Python full-time, maintaining a couple branches of Django and loving every minute of it.

But playing with Django was the final little nudge that made me understand the other thing I’d always liked about Python, even though I’d never been completely conscious of it before. It tends to get glossed over a lot, but it’s probably the single most important feature of Python.

It makes sense

When I worked in PHP and Perl, I was mostly working with a couple of off-the-shelf open-source CMS products, which I learned to adapt to various tasks. In PHP I was using Textpattern, and in Perl I was using Scoop.

Of the two, Scoop is by far the more massive, and I was extremely fortunate in mostly being a subcontractor for a couple of the people who develop it; when a client needed Scoop to be hacked up, I didn’t have to do the heavy lifting. And that’s good because, even though Scoop’s Perl is pretty clear and straightforward, it’s still a massive system written in Perl, and massive systems written in Perl are not things that you can just dive into the source of and start understanding.

Textpattern is smaller and simpler, and is written in PHP. PHP can be written in an obscure and confusing manner, but Textpattern isn’t, or wasn’t the last time I looked at it; most of it is clean, well-written code. But figuring out what was going on inside Textpattern still took me a little while, and wasn’t as easy as I’d have liked it to be.

When I was learning Rails, I took a few peeks under the hood; the face it presented to an end user was so tightly organized that I figured its internals would be pretty easy to work out once I got over a few speed bumps related to my inexperience to Ruby. I figured wrong. As it turns out, even some of Rails’ biggest evangelists and core people will tell you that its source is not for the faint of heart. There’s so much metaprogramming and, worse, monkeypatching of monkeypatching, that just figuring out where you are in the code can take a good long while.

A little while back I wrote an entry which walks through all the steps Django takes in processing a request; I wrote that mostly because someone asked for it, and until I started writing I had only a rough, general idea of what went on inside Django (if that sounds bad, keep in mind that Django was, at the time, nearing the end of a major rewrite, and huge swathes of code had changed).

That entry took about four hours to write. That’s including the time I spent writing, and the time I spent poking around in the code to see what was going on at every step. Given all the stuff it does, Django’s internals are amazingly simple and clear, and you can easily carry the whole thing around in your head.

Why Python, part 2

Get ten programmers in a room and ask them to rank the things they value most in a programming language, and you’ll get ten different sets of rankings. Some value conciseness above everything else. Others value expressiveness (which isn’t the same thing) more. Others look for strong standard libraries. Still others will go on about the merits of different philosophies of type handling, or availability of multiple implementations or all sorts of other things.

If you’ve got a Python programmer in that hypothetical room, odds are that at or near the top of her list will be “readability”.

Pretty much from the beginning, Guido has stressed that Python should be a language that’s easy to read (and, by extension, easy to understand), and several features of the language itself work to enforce that. On top of that, the official style guide seems to be fairly widely used, and there is a general sense in the community that, outside of things like “obfuscated Python” contests, code that’s clever at the expense of readability is bad.

And with the sole exception of Zope, pretty much every significant piece of Python code I’ve ever looked at has been clear, consistent, and relatively easy to follow along with. When I’ve had to stop and take a while to think something through, the language has rarely been the cause; it’s almost always been the fact that whatever I was looking at was dealing with some genuinely hard and complex problems, and so understanding the code required a corresponding understanding of those problems.

It’s an interesting variation on one of the Perl slogans: in Python the easy things are easy to read, and the language doesn’t make the hard things unreadable. To someone who’s constantly trying to learn and understand newer and harder things, that’s enough to forgive almost any other sin of language design (and Python does commit several of those, but on the whole it’s surprising how little there is about it that needs forgiveness, compared to other languages I’ve tried).

It may not be right for everyone, and I won’t ever try to argue that it is, but that’s why Python is right for me. That’s why I’m writing Python instead of PHP or Perl or Ruby or Java or C# or any other language that’s applicable to the domain I work in. It took a long time, and it took some radical changes in how people think about web development, but I’ve finally gotten to where I can do this, and it makes me happy.