Pages

Friday, April 28, 2017

My Python Rumspringa, or There and Back Again

tl;dr In 2014 I started an unexpected journey into a foreign land fraught with peril. Now I'm back and have a thing or two to share about both Go and Python. The JourneyBuilding A Home: My Python History

A New Adventure: GoComing Home

The Spoils (What I Brought Back)The Good

The Bad

The Ugly

SummaryWhat Python Can Learn from Go Appendix: Raw Go Observations

(Note: I started writing this post nearly a year ago, not long after I left Juju.)

The Journey

Building A Home: My Python History

In 2006 I started my first programming job, working on a system that migrated accounts between web hosting platforms. It was written in Python (for which I have Van Lindberg to thank). Over time, my curious nature led me to delve deep into the language. Within a couple years I started following the Python mailing lists and bug tracker. In 2008 I went to my first PyCon, but only attended the talks.Everything accelerated in 2011. I was more confident about participating and had even contributed both ideas and feedback. At PyCon that year I somehow managed to get a seat at the language summit and most nights hung out with the core devs who I knew from the lists but had never met in person. In a few short days my Python world was shifting. Most importantly, I stayed for the sprints.On the first day of the sprints I actively participated in the in-person discussions with Guido et al. that resolved the fate of namespace packages. There were two competing PEPs. In the months prior I had been involved in email threads about those PEPs on the import-sig list. In the discussion at the sprints I was able to have a concrete impact on the decisions being made. It was amazing! That marked my serious commitment to the project and the language.

A New Adventure: Go

In 2014, right after PyCon, I started looking for a new job. Until then I had been lucky enough to have worked in Python full-time. However, deep down I knew that I needed to expose myself to new things and different perspectives. In order to keep growing I needed to broaden my view. In the midst of the decision on which opportunity to pursue, I chose a job at Canonical working on a project called Juju. Among other new things (to me), I'd be working exclusively in the Go language.Typically it is best to know what you are getting yourself into. Consequently I took some time while preparing for interviews to get a feel for Go. Within a few hours I had a pretty good sense of the language. To be honest, in 2+ years my initial impression has stayed relatively true: Go is a fine language with a few things that bug me. I knew it would be good for me and I could tell it wasn't what I'd want in the long term. I even promised myself that I'd stay with Juju for at least two years, just in case I started having doubts before I'd truly benefited from the experience.For two years I enjoyed my work. Juju is a great project with a unique and effective approach to the hard problem of managing many interoperating services in the cloud. The folks I worked with were solid. The work was both challenging and rewarding. Above all, I got what I was after. After two years my perspective on writing software had broadened significantly, particularly thanks to Go. At the same time I was longing for my metaphorical home.

Coming Home

I came to realize something at that point; I was in a figurative long-distance relationship with Python. At first I would visit often. I'd write. I'd call. However, without even realizing it at first, I'd begun to be less involved. In fact, after the first year of working in Go I finally noticed that I was contributing less to CPython. I was on the mailing lists less. I wasn't on the issue tracker as much. I'd started to build up a backlog of things I needed to fix. As hard as it was for me to believe, I was becoming less excited about working on Python!As with nearly all long-distance relationships, I had to make a decision: to move back or to end the relationship. It wasn't hard for me. In fact, I has already been looking into an opportunity with some Python friends (which ultimately didn't pan out). My two years was almost up. An unexpected opportunity appeared (which ultimately *did* pan out). PyCon came around in 2016 and I started putting out feelers.In the end I chose to get back to Python. I'm now working on the Landscape team at Canonical. I'm still in that awkward phase where Python and I are adjusting to being around one another again, but I can feel it all returning. Was it worth it? Absolutely! The experience taught me a lot and I'm glad I did it.

The Spoils (What I Brought Back)

Here are some observations rooted in my experience working full-time in Go for two years. Keep in mind that my work on Juju specifically has heavily influenced my point of view here. Some observations are about Go, some about Python, and some about software in general. Note that I'm not going to talk much about things that aren't more than a different flavor (e.g. curly braces, defer). At the bottom of this post I've included an appendix that outlines my observations a bit more in depth but without elaboration.I'll take some time in later blog posts to elaborate on some of the points. I'll also update this post if I think of any other points or with more detail.

The Good

These are things that I appreciated about Go.

Go's Concurrency Story

based in CSP

dedicated syntax (go, select, <- [channel send, receive])

built-in primitives (goroutines, channels)

Parts of Go's Type System

interfaces (i.e. declarative duck typing)

composition instead of inheritance

embedding

explicit collision resolution

reverse template pattern

structs

fixed set of fields

methods

slices

(sort of) first-class functions

function param structs (in lieu of keyword arguments)

"Anonymous" Type Support

in-line types and functions (i.e. literals)

multi-line function literals

anonymous blocks (scoping)

Some of Go's Syntax

type-after-name variable declarations

switch, type switch

struct field tags

multiple return values (vs. C)

"ok" returns from maps, etc.

Tooling

go * (esp. fmt)

The Bad

These are things that I wished were different/better, but could live with. Mostly these actually either aren't that bad or aren't a big deal in practice. Some of these may improve in time.

Parts of Go's Type System

type incompatibility

converting []interface{} to []Spam

compatible signatures

the need for compatibility shims

pointers

builtin types vs. user-defined types

types are not first-class

packages are not first-class

no generics (yet?)

no enums

no "magic" methods

inference (weak for a "modern" language)

nil, interface{}

nil vs. underlying nil

namespaces

exported vs. unexported (incl. internal packages)

function comparison

no keyword arguments

no function argument (or struct field) defaults

no anonymous tuples

Parts of Go's Memory Model

nil

immutability

value ownership

Some of Go's Syntax

methods harder to visually associate with struct

Tooling

go * (esp. fmt)

dependency versioning

Standard Library

stdlib hard to customize

Philosophy

minimalist (reminds me a little of Lua)

few stdlib helpers in most areas

designed to address Google's problems, not necessarily everyone else's

trying hard to be a systems programming language (feels like the 70s)

The Ugly

These are things that constantly either bothered me or significantly impacted my productivity.

Multi-file Packages

makes it a pain to figure out which source file a package member is in

too easy to split up a struct's methods across multiple files

Error Returns (vs. Exceptions)

a lot has been said about this already elsewhere on the internet -- I'm on the side of exceptions (the Python kind anyway)

a step up from C, but that's about it

introduce a ton of superfluous boilerplate (if you're using them properly)

Boilerplate

no generics

error returns

type/signature compatibility shims

Testing

full-stack

white-box testing

immature

Summary

My experience on Juju was a valuable one. I'm glad I did it. Go is a fine language, but not one I'd want to use full-time, long-term. At one point I built a spreadsheet comparing Python, Go, and Rust. Perhaps I'll write up a post about that comparison some day.

What Python Can Learn from Go

Everything above surely betrays my bias toward Python. That said, I think there are quite a few lessons Python can take from Go. That includes both how Python can improve and how Python gets many things right. Most notably, Go's concurrency story is a step up from Python's, which I'm working to improve. Here are a few other things I'd like to see in Python: