Category Archives: programming

New York City Office Skyline

Remote Work: 2 Years In

I’ve been working for Stripe for over two years now. The company is based in San Francisco, and I’ve been working remotely from New York City the entire time. When I was deciding whether to accept my offer, I spoke with a number of people to get a feel for the company, the work I’d be doing, and the experience of working remotely.

One of the people I talked to was Julia Evans, who had conveniently written two great blog posts about her experiences working remotely, both three months in and eight months in. With remote work becoming more popular at companies, I’d like to share my experiences of remote work after two years.

I’ve experienced a wide range of remote working configurations: For the first year, I was working at a coworking space with a few other people from the same company. For logistical reasons, we ended up moving out of the space that we worked in together, so since then, I’ve been in a different coworking space by myself. During all of that, I’ve also spent some days here and there working from other places: my apartment, working from a house where I’m visiting friends or family, and working out of our international offices.

Based on that, and talking to friends who work remotely at other companies, here are some things I’ve learned for myself about working remotely. Your mileage may vary, but it’s what works well for me. Remote works has both pros and cons, and it might not be for everyone, but at this point, I’ve found I now actually prefer it to working in a traditional office.

Don’t work from home

Working remotely doesn’t mean you have to work from your couch or your bedroom. Especially if, like me, you live in a major city and have a small apartment, I’d strongly discourage it. Going to a coworking space every day, even if I’m the only one from my company working there, provides a mental transition in my day. When I’m there, I’m in work mode, and it’s easy to focus with no distractions. I’m not averse to working from home on occasion if I need to, but if I had to do it more than a day or two in a row, it’d be really stifling. (If you’re in New York or the tri-state area and are looking for coworking space recommendations, drop me a line – I’ve worked at a number of different ones over the years, and I can give you a good run-down of the pros/cons of each).

If you do decide to work from home, I would recommend a few things. First, set up a dedicated home office. Ideally, this is a separate room that you use only for work. At the very least, put up a curtain or folding partition to give some physical separation. Don’t use this space for anything else – if you’re a PC gamer, for example, put your gaming rig in a different room. If you live with others (roommates, significant others, kids, or pets), having a physical space that says “when I’m here, treat me like I’m at the office and I’m not at home” makes things easier.

Secondly, make sure you leave the house! Cabin fever is real. Give yourself reasons to leave the house at the beginning and end of your day. Going to the gym, getting coffee, walking the dog – make these part of your routine. One person I know would leave the house every morning, walk clockwise around the block, and call that his “commute” to the office. In the evenings, he’d repeat the process, but counter-clockwise. While it might seem a little artificial, it makes a difference!

Oh, and, if you’re ever being interviewed on live TV, make sure that the door locks.

The team matters

You don’t have to be on an all-remote team to have a good experience working remotely, but the rest of your team has to be on board with supporting remote-friendly workflows. That means making sure all meetings include video conference links, so you can participate. Or using asynchronous communication (email, JIRA, etc.) to document state which otherwise would only be exchanged verbally. In a pinch, even Twitter can work – whatever you do, just make sure that the rest of the team either already has remote-friendly habits or is willing to develop them. (Remote-friendly workflows are also beneficial even on teams that are 100% co-located, so it’s to their benefit to be doing this anyway, but that’s the topic of another post!).

This applies to the company as well. If your company isn’t committed to remote-friendly workflows, or to remote work in general, you’ll have a much harder time. You don’t need the company to be 100% distributed – or even majority distributed. If you’re considering working remotely for a company, ask about how many other people work remotely, and how the company ensures that those people are integrated into their workflow. If there aren’t any, that’s fine – someone has to be first! – in which case you’ll want to ask why they’re looking to hire people remotely, and what parts of their company workflow, policies, and structure they anticipate having to modify to transition into a remote-friendly company. (There’s no specific “right” answer here; you’re looking to see what their planning process is like).

Timezones require some effort, but aren’t too hard

On my team, I’m the only person on Eastern time. One is on Central time, and the rest are on Pacific. Most engineers on other teams are also on Pacific time. At first glance, that sounds like it’d be hard – I’m 3 hours offset from most of the people I work with – but in practice, it’s not been too difficult after some adjustment. In practice, this divides my day in two: most of my meetings are after lunch, which leaves my mornings free to focus with uninterrupted time.

I still have approximately the same number of meetings per week as my teammates, so the downside is that this means my meetings are compressed into the afternoon hours. This can be tiring on a meeting-heavy day, but I’ve gotten accustomed to it.

The timezone difference is probably the biggest change between my first few months working remotely and my current experience. In the first couple of months at any job, you’re more likely to get stuck on something unfamiliar, or need to request access, or somehow involve another person in your work process. If you bump into one of these early in the day, it means you’ll need to wait until after lunch to get unblocked. The workaround is to make sure you have a few different projects in parallel that you can work on, so that getting blocked on one doesn’t kill your morning. Fortunately, this stage doesn’t last too long. Within a month or two, I found this happening less often – at least, no more often than I might get blocked on someone who worked in the same physical office.

Normally I work out of New York, but I spent a bit of time working from London and Singapore when I was traveling there for conferences. Working from London and Singapore was definitely harder, because there’s almost no overlap between normal working hours in California and London or Singapore. In both cases, it was short-term (less than a week), which meant that we could manage it with some careful planning (choosing projects that are encapsulated for that week). It would be harder to manage that longer-term without having at least some other engineers on my team working from an overlapping timezone.

Use a headset for video conferencing

For a long time, I used the built-in microphone for my laptop (along with headphones and an external webcam). Getting an all-in-one headset made a huge difference, both for me and my teammates. Between the latency and the (lack of) noise correction, using the built-in microphone meant a lot of slightly awkward pauses, or accidentally interrupting because the other person had started speaking, but I couldn’t hear it yet. With an all-in-one headset, the microphone is much closer to the source (your voice) and it doesn’t pick up the sound from your headset speakers the way your laptop microphone does when you use it without headphones. This makes the noise correction works much better, giving the illusion of lower latency, and so it feels a lot more like having a natural conversation. (I have the Jabra UC Voice), but I think any dedicated computer headset will work better than the built-in laptop microphone and speakers).

The microphone on the other end matters as well. At our office, the microphones in the conference room have noise detection that’s eerily powerful. When I first started, it took some getting used to – I kept thinking that the audio on the other end had dropped, when in reality, nobody was speaking, and the background noise was getting filtered out! It’s not perfect, but it’s better than using Hangouts or Skype between two laptops.

Visit other coworkers often

Between Slack/IM and video conferencing, it’s easy to forget that I’m 3,000 miles away from my teammates. I’m good friends with all of them, and we chat a lot throughout the day. Seeing your coworkers regularly in-person is important.

The exact cadence depends on your personal situation and also your team layout – for a team that’s mostly distributed, you can probably get away with less frequent visits. For me, going to our headquarters every three months at a minimum helps me feel connected, not just to my teammates, but to coworkers on other teams that I work with less frequently.

At first, visiting the HQ office as a remote worker is a weird experience. I end up spending a lot of my time meeting with people, mostly in unstructured meetings (“coffee walks”, etc.).Compared to when I’m working the rest of the time, I spend a lot less time writing code. The best way I’ve found to approach it is to remember that: when I’m working remotely, I don’t have as much face time with my coworkers as they do with each other, and my visits to the office are my time to pay down that “debt”.

I think that one of the reasons working remotely works well for me is that my personal interest rate on this debt is low. I’m able to get most of what I need from email, slack, or video conferencing, and for the rest, I’m able to catch up quickly enough from in-person visits. On the flip side, context-switching is expensive enough that I’d rather group my “catch-up” time into a fixed period than interleave it throughout my normal daily routine.

This might sound tiring if you’re introverted – I’ll get to this later – but it doesn’t need to be. Don’t overdo it. Just do what feels natural, and don’t worry if it feels like you’re less productive when you’re visiting. Remember: productivity isn’t just measured by lines of code, and the time you spend building relationships with your coworkers is part of your work.

Also, note that I said “other coworkers”, not “other offices”! The tech lead for our team also works remotely, and we’ve met up in other cities as well – he happened to be speaking at a conference in New York (where I live), and we both went to a conference in Portland together. As I write this, I realize that he and I have actually never spent any appreciable amount of time together in the San Francisco office, but I’ve still never felt a lack of relatedness, because I still see and interact with him enough.

At the end of the day, you’re optimizing for relatedness – the feeling of being connected to other people and caring about them – not the number or frequency of your in-person interactions. Relatedness is “the universal want to interact, be connected to, and experience caring for others” – some people need this to happen in-person to satisfy their need for human interaction, but others may not. If you’re able to satisfy this for yourself through virtual interactions, you can probably get away with meeting in-person less frequently (or even at all – I know a couple of people who are totally fine never meeting their coworkers in-person, but I think that’s rare).

Schedule recurring pair-programming meetings

I’d strongly recommend this for anyone, whether or not they’re working remotely, but it’s particularly useful for remote engineers. I have standing weekly pairing sessions with four people on my team. Ideally I could schedule a weekly pairing session with everyone, but there are only so many hours in the day!

There are a lot of benefits to regular, scheduled pairing (as opposed to ad-hoc pairing, or no pairing at all), but for now, I’ll just talk about the part that’s relevant to working remotely. When working remotely at a company that is not 100% remote, you have to make an active effort to make sure that your non-remote coworkers are aware of you, the work you’re doing, and your areas of expertise. Regular pairing sessions are a good forcing function for that: on any given week, whether you’re working on a project of yours or a project of theirs, you’re getting “face time” with your coworkers, and sharing knowledge about each others’ projects.

Introversion or extroversion

I’ve heard a lot of people argue very strongly that remote work is best for introverted people, because you spend most of your days alone. I’ve heard others argue that it’s best for extroverted people, because you have to spend more effort getting to know people across the company when you’re not physically present.

I don’t think it matters. I know people who work remotely with success who are introverted, extroverted, or ambiverted. People will adjust their work and life to match their personal styles wherever they are working, remotely or not. If you discover you need more social interaction, you’ll find ways to increase your interpersonal interaction with your coworkers, or to do that outside work. If you discover you need less, you’ll find ways to reduce it, by relying less on synchronous communication or adjusting your work schedule. Being remote isn’t only for introverts (or extroverts), the same way working in an office isn’t only for extroverts (or introverts).

If you’re working remotely (or considering working remotely), I’d love to talk more about this with you and exchange tips. Ask me on Twitter or drop me an email. Oh, and I just found out that we have a conference now too!

Thanks to Julia Evans and Karla Burnett for reading drafts of this post!

Objects & Procedures: A Python and Java Comparison

Earlier today, I had a discussion with another hackNY fellow about whether Java was more strictly object-oriented than Python. While neither language is truly object-oriented in the pure sense, it’s clear to me that Python is hands-down more consistently object-oriented, whereas Java is a mixture of object-oriented and procedural programming.

Put another way:

Java forces you to write class-based code using both objects and non-objects, requiring you to juggle both objects and non-objects simultaneously.

Python forces you to write object-based code, so you only need to handle objects, ever.

Like a good citizen of the OO world, Python makes objects so transparent and seamless that you don’t even realize that basic calls like addition involve objects.

a = 5
a += 2

As we shall see, Python lets you break out of OO strictness, but only if you really, really want to (which means you also really know what you’re doing.). Python also lets you take advantage of this object-oriented abstraction, by redefining integer addition on odd numbers to perform division instead (for example) – but again, only if you know what you’re doing!

(Python’s type system is a bit complex, so I will have to gloss over some of the details here. If you’re interested in more, I would recommend reading this StackOverflow question about metaclasses in Python and the book Python Types and Objects (available for free online). If anybody know similarly good resources for Java, I will be happy to add them here.)

Object-Oriented programming is just functional programming in disguise

Yes, you heard me! And just so you don’t take my word for it, here’s a 2003 email from Alan Kay (the ‘inventor’ of object-orientation). He closes with the essence:

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things. It can be done in Smalltalk and in LISP. There are possibly other systems in which this is possible, but I’m not aware of them.

(Note that he does not mention inheritance, classes, or polymorphism – having these does not imply object-orientation!

Also note that this email is from 2003, around the height of Java’s popularity.)

Understanding Messages

This is the most important one. You can spend a lot of time studying messaging, but I’m going to cut to the chase and tell you that (spoiler alert!) messages is basically just currying.

In the Smalltalk sense, you have an object, and you can pass messages to it. The result will be another value, which may be another object that you want to pass messages to.

This is no different from functional programming; a method is a higher-order message which takes other parameters (messages) and returns values. Calling a method and providing a parameter to a method are both just messages.

Understanding local retention, protection, and hiding

This could be a blog post in itself, but it’s essentially a comment on implementing encapsulation using scope and closure. An oversimplification: closures are a way to ‘export’ access to local variables while still maintaining control over them (ie, how they can be access/modified, and by whom).

Understanding late binding

This is the sticking point. Python is dynamically typed and uses duck typing. In other words, the following call:


does not need to know the type of ‘foo’ – all it does is look up the list of attributes that ‘foo’ has and looks for something called ‘bar’. You can do this manually with the getattr() function or the __dict__ attribute. If that attribute is a callable (a function), you can also do




This is more or less the same as passing foo the message ‘bar’, then passing the message ’(’ telling it to access the hidden ’__call__’ attribute, then passing it the message ‘5’ and the message ’)’ telling it to end the call.

What happens if ‘bar’ is not found? This is where things get interesting:

If an attribute is not found in the object, it then looks up the attribute in the class. But classes are objects in Python, so it’s looking up the attribute in another object. This is because Python classes are really just syntactic sugar for prototypical inheritance.
If getattr() doesn’t see the attribute listed in the dictionary of attributes, it then looks up the .__class__ attribute and then looks in the __dict__ associated with that. (The docs provide more precise information).

Don’t be fooled by the name .__class__ – this doesn’t actually have to be a class (at least, not the way you’re probably thinking of a ‘class’!).

This means you can do wacky things like this:

(I’d encourage you to experiment with this yourself! Try modifying the attributes).

In other words, “class Foo(object):” is syntactic sugar that creates an object of class ‘type’ with a ’__name__’ attribute of  ‘Foo’, then binds it to the external variable name Foo. We could do this without a ‘class’ keyword altogether, by writing:

Foo = type(‘Foo’, (object,), {‘apple’ : ‘red’})

Note that the external name and the ’__name__’ attribute are completely independent. 

(In fact, not only can Python objects be created without the ‘class’ keyword, they don’t even need to have classes, as long as they are capable of handling all of the messages that an object with a class can.)

Note: the reason this is possible is not that Python is a dynamic language; the reason this is possible is that Python objects don’t ‘inherit’ from classes; they simply contain a ’__class__’ attribute that is a reference to another object, which can be accessed, mutated, and referenced just like any object.

Objects all the way down…. almost

What happens when you get to the prototype of a prototype of an object (or equivalently, the class of a class of an object)?

To avoid getting into higher-order type theory, I’m going to wave my hands a bit and point you towards the concept of a kind; that is, the type of a type constructor.

It gets down to this: all of Python can essentially be derived from one kind – if you follow the turtles (prototypes) all the way down, you’ll eventually reach some common ground. And you don’t even have to go that far to see the benefits – you can access attributes (functions and values) of objects, classes, and values interchangeably, because they’re all objects. Classes included.

Which brings us to Java….

Everything is an object (except if it’s not)

Java fails to be an object-oriented language for one reason: In Java, all objects have a class, but not all typed values have classes, so some values can have a type without being an object.

This is another way of saying that Java supports (and requires) multiple kinds. This is illustrated very easily by the need for the object autoboxing for primitive types. The following code will fail with an interesting error code:

because an int is not an object. You need to provide an Integer, which behaves the same most of the time…. except when it doesn’t. Many people incorrectly refer to Integer as a ‘wrapper object’, but while it’s not a primitive, it’s not an object either; it can be used interchangeably with objects 98% of the time, but not the remaining 2%.

That 2%, ‘except when it doesn’t’ seems small, but it’s the key to understanding why Java is not actually object-oriented. It’s not quite class-oriented either, but it’s more class-oriented than object-oriented, because you rarely (never?) create objects directly; instead, you create classes (named or anonymous) which you later instantiate as objects (sometimes only once).

The fact that Java is (almost) class-oriented doesn’t make it any more object-oriented; in fact, it makes Java less object-oriented, because classes prevent many of the abstraction properties that make OO programming powerful.

If there’s interest, I could illustrate some of those limitations in Java specifically, though for now, I think I’ll save that for a separate post!

How many bloggers does it take to change a lightbulb?

How many computer scientists does it take to change a lightbulb?

None – that’s a hardware problem.

How many industrial designers does it take to change a lightbulb?

None – they just convince you that darkness is a feature.

How many hipsters does it take to change a lightbulb?

It’s an obscure number… you’ve probably never heard of it.

How many Ubuntu users does it take to change a lightbulb?

One. Just run apt-get install -f.

How many Archers does it take to change a lightbulb?

Ten. One two change it and nine to marvel at the Arch Bulb System.

How many sysadmins does it take to change a lightbulb?

None. The first time it broke, the admin scheduled a CRON job to handle all future lightbulb maintenance.

How many Java programmers does it take to change a lightbulb?

Three. One to create a Lightbulb, one to create a LighbulbFactory, and one to create an AbstractLightbulbFactory.

How many Perl progammers does it take to change a lightbulb?

Four, but they can do it in three characters of code.

How many Python programmers does it take to change a lightbulb?

One. Just import anti-darkness.

How many Ruby programmers does it take to change a lightbulb?

Five, but they each figure out eight ways to do it.

How many Lisp programmers does it take to change a lightbulb?

Seven. (Only (one) does (the work, (but he has to bo(rrow) parentheses from the rest.))

How many Windows users does it take to change a lightbulb?

One, but he’ll insist on using 240 volts until it becomes the new standard.

How many Macintosh users does it take to change a lightbulb?

None – they have to take it to their local Apple store to be serviced.

How many Emacs users does it take to change a lightbulb?

Three. One two change the lightbulb, and two to adjust his carpal tunnel brace.

How many Vim users does it take to change a lightbulb?

ne, as long as he doesn’t forget to enter ‘insert’ mode first. [sic]

(I was only planning on posting three, but I was having too much fun with this.)