The Slack Users’ Code

The bigger a Slack team gets, the more chaotic it can get. These are my ideas about what makes a good Slack team and Slack citizen. These are for work Slack teams. If you have a social Slack team set up, you do you because the expectations, goals and social forces are likely to be very different. Some of these may apply, but I haven’t done as much thinking about which ones.


Whether you work in a widely distributed business unit or just a very large office, from time to time you’ll find yourself interacting with people you don’t see in person much. These are people who do not know you by sight. These four guidelines are to help those people have a chance of recognizing you from #watercooler when they meet you in person.

  • You should set your first and last name in your Slack Profile. If your name is “James”, but everyone calls you “Jim”, it’s OK to put “Jim”, but otherwise, you should put it as if you’re turning in homework. Don’t try to get cute.
  • If your full name is First Middle Last, your user name should be firstlast, flast, fmlast or something similar. Change it in the username settings.
  • Your avatar should be your face. Ideally, it should be big enough that it takes up most of the avatar space. It should be easily recognizable at a small size.
  • Put your job title and your team name in the “What I Do” section of your Slack Profile. For example, don’t put “teh codes”, but instead, “Software Engineer, Product X”. If you’re an administrator, consider using Slack’s custom profiles to make a special space for this information.


Channels, especially, are important to name in a consistent and predictable way. You want channels to be discoverable and obvious so that people have a good chance of finding the right channel for a question or discussion.

General Guidelines

Rename the #general Channel

This one’s just for administrators, really. Consider renaming #general to something else. It’s a special channel that everyone must be in. No one can /leave it. It’s important for people to understand that talking at all in #general can be bothersome to a lot of folks, let alone using @here or @channel. Renaming it to #everyone or #all-hands or something might make that more clear. In a large enough organization, locking down this channel so that only administrators can talk in it (and rarely at that) is a very, very good idea.

Corollary: “General” isn’t a very descriptive word. You don’t need to use it in channel names. #product-general isn’t really any more descriptive than #product.

Don’t Create Private Channels

You might think no one else cares. If they don’t care, they don’t have to join your channel. Private channels silo communication and stymie discoverability. By default, you should make all channels public. If you have something truly secret to discuss—something that even other employees of your company shouldn’t see—consider that you’re technically sharing anything you type into Slack with another company (Slack itself). If it’s truly secret, consider sending PGP signed emails or only talking face-to-face. Much of what you do probably isn’t actually that secret. Flowdock has a great post about the dangers of private channels. Also see Zach Holman’s fine writing about opt-in transparency.

It’s not that creating a private channel is never a good idea. It’s that if you’re making a private channel, you should have a damn good reason.

Don’t Create Extraneous Channels

You might think you’re bothering people in another channel. For some kinds of topics (see below) it might be appropriate to create a new channel, but in general, you should wait until some sub-topic is routinely taking over a more general channel before you create a new one. You don’t want to get into a situation where there are more channels than people in your Slack team. Specifically, a team should not create a new channel for every individual problem they want to discuss. Keep things in as general a channel as folks can stand.

Use Dashes in Channel Names

Just for consistency. Do #austin-lunch-games not #austin_lunch_games or any other ridiculousness.

Know What Kind of Channel You’re Creating

There are two broad categories of channel: Work-Related and Off-Topic. Work-Related channels are the ones that some team is expected to actively monitor. Off-Topic channels are everything else.

Use @here and @channel Appropriately

There are two @mention aliases that notify a lot of people (let’s just forget that @everyone even exists). One, @channel, will notify everyone in the channel where you use it. The other, @here, will notify only those people in the channel who are online when you use it. Both should be used sparingly, and @channel more sparingly than @here. For example, you don’t need to use either one to let people know you’re going to lunch. Either @mention someone specific who needs that information, or just say it in the channel and trust people who need it to pick it up.

This is especially important in managing communication with your immediate team. Your team’s channel may have a lot of guests lurking and listening. If you use either @here or @channel to ensure the 5 other members of your team get a ping, you’ll also be pinging all your guests. If typing out your teammates’ handles is too onerous, you might consider setting up a User Group for your team.

Minimize Use of Bots & Other Toys

Programmers, especially, can become enamoured of chat bots and chat integrations. As a programmer, I feel this too. However, you have to carefully balance this with the costs it can impose on real human communication. Slack is a tool primarily for humans to communicate with other humans. If computers are being too chatty in a channel, the humans will have a hard time getting a word in edgewise. And a chat history tends to be a pretty poor radiator of information. Rather than having engineers initiate and control a deploy from a channel, consider having a different tool that does all that, and have only sparse or summary updates go to the team channel.

As for other toys, let us consider the cautionary tale of /giphy. The images that Giphy serves up in response to any given query are so infrequently relevant to the query that it’s a remarkable event when it happens. I mean that literally: I will remark in Slack “Holy shit. Giphy didn’t fail miserably!” on the rare occasion.

Some people feel that a single gif has a damaging effect on conversation. I like a good animated gif, but people repeatedly typing /giphy over and over at each other hoping for a relevant animation does not constitute human interaction. This same principle applies to almost any fun integration or @slackbot auto-response. They’re very easy to abuse in a way that you don’t realize you’re abusing them. No one should have to ask their coworkers to stop playing a loud game of tag in the hallway next to the bullpen.

Archive Unused Channels

If a channel is no longer needed, a Slack administrator (at any time) or the channel owner (if the channel is empty) should be able to archive it. Get rid of that dead weight.

Work-Related Guidelines

Name it After the Hosting Team

The channel structure should loosely mirror your company’s org chart. Each channel should be hosted by a manager and their team. These channels should be named after the team. The Support team’s channel should be #support and the API sub-team within should be #support-api (thus ordered so they sort together in the channel list).

These channels are hosted by a team and belong to that team, but they should still be public. If someone has a question about something owned by a team or for a member of that team, this channel is the first place they should go.

Anyone is allowed to be in any channel, but members of a team are expected to be actively in their team’s channel most of the time. In fact, if each manager hosts a Slack channel, everyone who reports up through them, even indirectly, should probably at least passively monitor every channel up the chain of command from them (imagine, e.g. a place where a VP level person can say “The code for the all-hands dial-in is 9466.” and reach the entire relevant audience).

Caveat: While you’re allowed to be in any channel, be aware of whose dinner party you’re attending. If you’re not on the hosting team, be especially vigilant for when your input is actively welcome and when it might be counter-productive. For a good example, see Holman’s discussion of HR policy changes.

Name it After the Office

There’s a much less common type of Work-Related channel, which is location-based. These channels should be hosted by the head office manager for an office and the people who work in the office should at least passively monitor these channels. They are places mostly for the office manager to announce things or to ask questions about the office. They are not Off-Topic channels, but they are probably more relaxed than other Work-Related channels. They also serve an ambassadorial purpose for people visiting the office from another office.

These can actually be thought of as team channels (for the team of office managers, even if there’s just one), but they deserve to be called out because a potentially large number of people would be regularly in them. These channels should be named descriptively. If you have offices that happen to have cool names, you could get cute and name them after the office building/complex that the host office manager is in charge of: #seaholm, #tide-point, etc. Elsewise, you should use the city name: #austin, #baltimore, etc. The latter is probably better for new folks, but weigh that against how often the offices are called by the other name.

Set the Topic and Purpose

So that people know what the point of a channel is. Especially if the channel seems very similar to another channel. For more general channels where the title really is very clear, emoji can be a fun way to still have a topic without it feeling super redundant.

Stay on Topic

Try to stay on topic. The fewer people in a channel, the less important this is, but still. If people are off topic and annoying you, you can tell them to “:goto: #watercooler” (or whatever appropriate channel, and you should totally alias the :arrow_right: emoji as :goto:).

Invite People to Your Channel

If the #some-product engineers are having a problem with deployment and they think it might be a problem that the #infrastructure folks could help solve, here’s how I recommend they should handle it: Once they make that determination (I assume they’ve been talking about the problem in #some-product for a while, now), they should elect a single one of them to pop into #infrastructure.

That person should see if anyone else has already brought the problem up and, if so, follow that conversation (possibly to another channel, as we’ll see shortly). If not, then they should say something like, “@infrateamlead: We’re having a problem with deployment over in #some-product. Does anyone have time to come over and help us work it out?”

You ask the team lead because, as with any other task you want to hand to another team, you don’t jump the chain of command: you let the leader decide who’s interruptable or appropriate for the task. You mention what channel you’ve been talking about the problem in so that the nominated helper knows where to go, as well as anyone else who wanders into #infrastructure with the same problem.

Then whoever it is from #infrastructure that gets assigned to help can join #some-product and see all the history of the discussion about the problem and get caught up. And then, you know, hopefully help out in fixing the problem. This protocol or something like it is especially important for heavily interrupt-driven teams like Ops, IT, Internal Tools, etc.

Off-Topic Guidelines

Name it After the Topic

Off-Topic channels still have topics, they’re just not work-required topics. This can be something very general like #games or very specific like #long-distance-trail-running (but remember: Don’t Create Extraneous Channels). Try to keep in mind the geographically distributed nature of your organization. If you’re making a channel to find people to play cards with at lunch, maybe put the office or city name in the channel title, as well.

Name it After the Role

There is a special kind of off-topic channel that bears highlighting. You probably want to have a channel for Software Engineers to hang out and talk about their jobs. Or Engineering Managers or whatever. These are related to the work that people are doing, but they’re probably not required to be in the channel in order to get their job done.

These are hubs for people to do frequent, low level professional development. They should be grouped around roles not titles. This is partly so that they can span titles, which don’t always map 1:1 with a role. Also, anyone who has an interest or stake in the topic should feel welcome to join in the discussion. Whether you call it #software-engineering or #programming is a bit of trivia that each role-community can hash out for themselves, honestly.


The code is more what you’d call “guidelines” than actual rules.
Captain Hector Barbossa

There will always be weird outliers. A cross-team task force will assemble and need a channel to talk about their work in. Temporarily, a small group of people will want to have a place to organize while at a conference. These kinds of things are perfectly OK, as long as the bulk of the channels you have adhere to the guidelines. And as soon as these outliers are no longer needed, you should get rid of them. If a channel persists for a long time and doesn’t fit within the guidelines, that’s an organizational smell (or a guideline smell and if you think it is, hit me up on Twitter) that might need addressing.

Dragon Age: Inquisition & Social Justice

So, I’ve been playing Dragon Age: Inquisition. It’s not the newest game on the block and I’d been ignoring it studiously for a long time, but then a friend of mine wouldn’t shut up about it and I finally decided I might as well try it. I almost fell off the wagon, as it were, but then some stuff happened and I got hooked. This post is going to be a big rant about social justice and Dragon Age: Inquisition. There’s a ton of spoilers to follow and I’m also not going to explain all of the context, so if you haven’t played the game, you might want to skip this unless you just love following links to Wikia pages. You’ve been warned.

A while ago, I decided that if a video game has a character creation mechanic, I would create a woman of color. Long before that, I’d decided to always create a woman and I’d noticed it changed the way I perceived the games I was playing and the (lack of) diversity in the cast and the way women were portrayed. I wanted to keep doing that, but also add in improved racial awareness. Therefore, I knew I was going to play, in this case, a black lady.

Then I had to pick a species (and background, but that’s beside the point, just now) and after a bit of thinking and talking with my friend, I decided to play as a Dalish elf. I don’t remember what, exactly, made me decide this, but early on in the game, I decided she wasn’t just Dalish, but she was Super Dalish. She believed strongly in Dalish culture and the Dalish philosophy. They have a saying: “We are the Dalish: keepers of the lost lore, walkers of the lonely path. We are the last of the Elvhenan, and never again shall we submit.” Emphasis mine.

So as part of her personal identity, she wants to improve the lot of elves everywhere (not just the Dalish), and try to undo the oppression many of her people suffer at the hands of humans across Thedas. Having decided this, I tried to get into that mindset when making decisions in the game. Basically: Assume anything Dalish is right until proven otherwise and distrust humans, but especially their institutions.

It turns out, this was a really good call on my part because so much of the game is about all the awful shit the humans (mostly the Orlesians) did to the Dalish elves. Some of the more gut-punchy examples:

  • You have to go to the Orlesian palace at Halamshiral to save the life of the empress. Halamshiral is built on the ruins of the capital of the most recent elven nation, which was ruined in a war that devastated the elven population and was instigated by the nation whose empress you’re meant to go save.
  • You go to a place called the Emerald Graves. It’s a beautiful, giant forest. See, the humans call their holy crusades Exalted Marches, and they did one against the elves, killing tons of them. There is a tree in the Emerald Graves for each elven warrior that fell to the Orlesians. It is a really big forest.

In the Exalted Plains (named after the above-mentioned Exalted March), some humans have taken refuge in an old elven fort. They are taking refuge from some undead. Which have risen because the humans are killing each other in such numbers. So they bar the doors and then, in panic, activate some ancient elven magical defense that they don’t fully understand.

At this point, I was done with humans. I thought, “Just. Stop. Everyone go home. This war thing is over. You are all so bad at life.” Meanwhile, 2 river valleys over, there’s a small band of Dalish and I thought, I should just send all the humans home and give the whole region back to the Dalish (it was originally promised to the elves by the human’s sort of jesus-analog, after all).

And then I realized something of actual importance to the real world. I’d previously intellectually understood people of color being fed up with white folks or genderqueer people being fed up with cis folks or, you know, various people being fed up with people like me by various degrees. Suddenly, though, I had empathy for people who say, “Kill all men,” or, “White people just stop,” or, “Ban cis people.”

Despite all our advantages (which we have gained via oppression, let’s be clear), we are still terrible at shit. The simplest example I can think of is black people looking at the musical artifacts produced by white people and seeing shitty, grainy photocopies of stuff they invented previously.

Now, I don’t want to say that my getting into the headspace of a fictional elven lady and learning about the fictional atrocities perpetrated against her people means I, like, Understand What It Means To Be Black or any shit. I’m saying that the interactive nature of the story telling in this game managed to communicate to me at least some amount, some pale shadow, perhaps, of this one aspect of being a member of some marginalized group interacting with the oppressor group in a world made by those oppressors. And I hope that this additional empathy can make me a better person and help me be less oppressive. Maybe it can help others, too.

The Folly of Fatherhood

Upon reflection, I think I have observed something about fatherhood. Or at least my fatherhood (the one I am doing or having right now, not the one my dad did or had with, on, at or to me—the prepositions, here, are unclear to me). It is this: I am fairly certain I would destroy myself saving one of my children. In fact, I’m pretty sure I’d destroy myself failing such an attempt. Not infrequently, I think of a specific incident. (This may get a bit dark for some readers. There is talk of hypothetical death and dying: both my own and my children’s. I won’t think less of you if you skip it).

When L was about two years old, my family and I were at the Texas Renaissance Festival. They have, there, a little side-path where you can kind of get away from the hubbub of the main festival. There are a few nice plants, some statuary, the odd set of benches and a majority of the path is adjacent to a little water. Optimistically, it could be called a stream, but realistically, it’s a murky, stagnant mosquito breeding pit.

As we walked, L decided it was the thing to do to throw sticks into this mosquito pit. Naturally, I thought, “Sure. This is a mysterious yet universal drive among primates, as far as I know. Knock yourself out, kid.” At one point, however, in order to do this, my toddler had to step off the path and onto a small shoulder populated by some kind of viney ground cover. No sooner did I think, “This probably isn’t going to end well,” than did the “not well,” in fact, begin.

Standing at the top of a sloped, roughly 5-foot drop to the water’s surface, something went wrong with his feet and he pivoted about the ankles, planking face-first into the slope, then pivoted about his head, planking again and slid feet-first down the rest of the slope and vanished into the water. In fact, roughly two and a half years later, now, I’m not sure that’s entirely accurate for two reasons: 1. Memory is fallible and that seems entirely too cartoonish and 2. I’m pretty sure I was running before he finished the first stage of the fall and that my next conscious thought wasn’t until I was mid-leap into the water after him.

I want to unpack that leap in a second, but first, I want to tell this from the point of view of some very nice people who were walking up the path from the other direction. They’d entirely missed L’s presence at all. Their first thought was, “What could have possibly possessed this scrawny, balding kilt-clad man to fling himself into this gross wat—OH MY GOD HE’S PULLING A BABY OUT OF THE WATER!

The water was colder than I expected and much deeper (it was certainly taller than L could stand up in). My wife appeared uphill seemingly instantly and took our confused and frightened toddler from me, then the folks mentioned above and a friend of ours helped me scale the slope and get everyone sorted. Later, someone asked L something along the lines of, “What do you think just happened?” and he replied, “Daddy saved me from the alligator water.”

Let’s go back to the leap, now. When I said that I think my next conscious thought was mid-leap into the water, what I mean is that if there had been alligators in there, or even machine-gun wielding, right-wing extremist water cobras, I’m pretty sure I would have been in mid-air and committed before I could think something like, “The gun show snakes have taken my son and if I jump, too, I will join him in death.” I might have had a similar thought with the ending, “…and I am about to join him in death,” but there would have been nothing to do to change that fact.

I hope I can limit my engagement of the actual “destroying myself” part of this to when my children are in literal mortal danger, but I suspect that whatever processing goes into that decision happens faster and at a lower level than my conscious mind. A part of me finds this observation slightly dismaying. Another part of me finds it incredibly reassuring.

Thanks to Carl Youngblood, Andrew Harrison and Kevin Lord for helping edit this post.

I Will

As of about a month ago, I am officially in the business of house protection.

That’s a really terrible joke way of saying I’ve joined Under Armour Connected Fitness to work on the API team. I’m really excited about the team’s mandate from the company and where the Connected Fitness division is going, in general.

In my previous post, I outlined some things I was looking for in a new job. As a refresher: Ruby, social justice, APIs, hypermedia, service oriented architectures, practical design, not moving away from Austin. UACF hits all of those except the first two, and it hits them hard.

The UACF Platform is a HAL(ish) API, so the company has been doing hypermedia in one way or another for a while, now. And I think there’s high-level buy-in about the benefits hypermedia can bring to a public API like ours. In a similar vein, there’s serious work being done on the SOA-front across the company. Having the technical leadership interested in going where I want to go and in using the tools that I want to use is great.

One thing I’ve been particularly delighted to see in practice and talk about with my new teammates, is how Under Armour’s dedication to quality and doing sound engineering transfers to the world of software. The philosophies that govern how the company has thought about building their physical products dovetails very nicely with my thinking about what good software engineering is and what I’ve described as practical design. Specifically, the API team isn’t tasked with making a platform so we can check off a box; we’re being asked to make a best-in-class API. My personal goal for the team is to make an API that other companies envy and want to emulate in every facet, from documentation to performance and I feel like we’ve got the backing from the top to make that happen.

As for not moving away from Austin, UACF just moved into new offices in Austin’s old Seaholm Power Plant. While the space is amazing, the bigger deal, to me, is that Austin is Under Armour’s Connected Fitness HQ. It is obvious to me that Under Armour is seriously invested in the Austin office and team.

I won’t, however, probably be using much Ruby. The code bases I’m interacting with today and will probably be interacting with for the immediate future are all in Python. It’s likely the new code bases I mess with will be in Python or Go (neither of which language, I should say, I hate). There may be a little room here or there for Ruby, but I don’t expect it to factor heavily. I did some real soul searching on this topic before I accepted their offer. It came down to this: I am more interested in APIs and SOA than I am in sticking dogmatically with one language, however much I may love it. I think that strategy also has longer legs in terms of career viability. Computers will probably be talking to each other long after Ruby and all the languages we use now are out of fashion.

Under Armour also didn’t score especially high on the social justice front. There are bright spots and dark spots and I think having a large retail marketing segment of the company has a weird effect on things (Cf. general media representations of marginalized people). However, I think this is something that can improve and that I can be helpful in making that improvement. Our entire industry (our entire society) has a long road to walk on this one, so it’s not like I was going to find a place where I’d’ve felt comfortable resting on my laurels.

At any rate, now I work for Under Armour. Which is weird to me, in some ways, but I’m really looking forward to seeing what awesome stuff we can get up to.

Looking for a Job


I left Return Path where I worked on Context.IO in September just before my daughter was born. Since then, I’ve been spending time at home, doing babby-related things. Now that the family front is more stable, I’m looking to get back into the swing of things with my career.

Hopefully, my new gig will hit some of these concepts: Ruby, social justice, APIs, hypermedia, service oriented architectures, practical design, not moving away from Austin. Only the Austin thing is a deal-breaker, and I don’t expect that I’ll find a place that I like and that likes me that hits all of these. It’s also probably not an exhaustive list, given how human brains seem to work.

If you know of someone I should be talking to or some place I should look into, let me know via email or on Twitter or whatever. I’d greatly appreciate it. Also, if you’re in Austin and just want to grab lunch or something, I, uh, have some time these days. Read on for more details.

Social Justice

I’ve talked about it a bit here. I’ve talked about it a lot on Twitter and in chat rooms and in person. Over the last few years, I’ve had a growing interest in, understanding of and concern for social justice. It started with feminism and has grown more intersectional as I’ve learned more.

This doesn’t mean I’m necessarily looking to work for a company that directly works towards social justice (though that doesn’t sound bad). I’d consider this criterion met if a company is taking active steps to hire and retain employees that don’t all look the same and supports diversity efforts in the community.


Ruby and I think the same way about things. It’s the least-bad programming language I’ve met. I’d like to use it more and I spent more time than I liked at Return Path writing not-Ruby.

This isn’t to say I’m opposed to other languages, especially where they meet a specific design or business need (Go and Rust come to mind most readily). I just… really like Ruby and think it’s a really smart default choice when picking a language for a new project.

SOA, APIs and Hypermedia

First off: I think SOA (or “microservices” if you’re not into the whole brevity thing) is showing itself to be a solid way to meet scaling demands in a cost-effective, maintainable way. The thing is, I don’t think we, as an industry, are really good at services yet. There are some exciting things going on in this area and I can see some powerful stuff coming down the pipeline (especially as this intersects with DevOps).

I have a theory that HTTP APIs are one of the best ways to get your SOA organized. It’s a well-understood, widely-used protocol with tons of library support in any language worth using in production (I don’t know if brainfuck has a solid HTTP library, though). As an industry, we’re really good at making HTTP requests fast, measuring them, optimizing them, etc. And, if you exercise the full range of the spec (all the response codes and headers), it is very expressive. I see this as a point of stability to lean on in an area that we’re still trying to figure out how to do well.

Further, I think that hypermedia has some really strong selling points when it comes to HTTP APIs. The original REST paper addresses problems that are still solved in mostly-inconvenient ways in many HTTP APIs. This is a big topic that I don’t want to get deeply into here. It’s worth mentioning that I feel like there’s some promise, here, but enough about hypermedia hasn’t been widely tested enough to have developed a range of best practices about it.

I’d love to be at a place that was interesting in investigating the above triplet of concepts and pushing the industry forward in this area. I have ideas and opinions and I want to test them in the real world. I could be totally wrong about all or part of the above… and I want to find out.

Practical Design

Ever since I read POODR, I’ve had the growing conviction that good design doesn’t have to cost your project tons of time; that there’s a right amount of thinking and talking about software design that will save you time in the not-so-long term.

Often, people talk about the dichotomy between developers who want to craft a beautiful cathedral and those who want to toss up a rickety prayer tent. I think there’s a middle ground such that you avoid the never-ship “architecture astronaut” but also avoid painting yourself into a corner by getting underwater in technical debt (so many analogies). And I think Sandi Metz was talking about that middle ground in her book.

I’d like to work at a place that has a similar sense to me about what that right amount of thinking and talking is. I don’t know how to describe the amount, exactly, so I’m kind of hoping that this is something that will reveal its self in interviews.


I was born here. I grew up here. My wife did the same. Our parents and siblings live here. It doesn’t snow here. The food is yummy here. I own a house here. The Ruby community in specific and the startup community in general agree with me here. I could go on and on, but I don’t foresee my moving away from Austin without radical changes in my personal situation.

Also, with communication technologies being what they are, I find it sort of silly if a software company can’t figure out how to do remote reasonably well. It’s something my business unit at Return Path decided we wanted to be good at and were then surprised at how easy it was: most of the problems evaporate in the face of any attention at all. Heck, using Slack alone solves a giant chunk of the problems if you use it religiously. Good email culture solves another huge swath.

Scenes From the Post-apocalypse

I’m on a bit of a hiatus from role playing because we have a new born at home, now. Until she’s easier to deal with in the evenings, I don’t really want to stick my wife with bed time for the 3-year-old and the 3-month-old all alone while I tell stories with my friends. Seems like kind of a jerk move.

But I’ve been jonesing really hard for it. And since I learned what Apocalypse World was, my group hasn’t actually gotten a chance to give it a good, honest play.

So, since I’m supposed to “daydream some apocalyptic imagery” and be “developing [my] apocalyptic aesthetic”, as well as “to cultivate an apocalyptic aesthetic in [my] players too,” I started emailing random snippets of Apocalypse World inspired imagery to my players.

In an earlier stage in my career running role playing games, I might have hoarded these, worried that I wouldn’t be able to come up with something similarly cool later, and confident, for some reason, that I’d be able to remember this stuff well enough to use it at the table. But, like, what?!?

At any rate, I thought someone on the internet might find them interesting, entertaining or useful. I’ve cleaned them up just a little from the original emails.

The Ghost in the Jungle

The vegetation here is dense. Everything smells like rotting plant matter. The light level varies wildly, based on how much wan, green sun filters through the canopy. Everything that’s not a dark brown is tinted some shade of green. The trees dwarf everyone. They’re definitely taller than any building in the hardhold, and wider at the base than Vee-dubb’s van is long. The air is still as death; the only things moving are the bugs, bzzzing and stinging, nearly invisible to the naked eye.

The lot of you hike on. The heat is oppressive. It’s not like the sun bearing down from on high out in the Tire Wastes. This is a more encompassing, much wetter heat. It is hard to breathe, and sweating does no good at all. Everyone is drenched and gross.

Fleece is the first one to spot it: pale white and hard as rock, covered in fine spiderwork of cracks but feeling no weaker for it. Beneath the turtle shell of ceramic is a mass of black machinery, dead and busted with grubs and mushrooms growing underneath. After that, the frequency of seeing smooth white amid the vines and roots increases steadily; you’re headed the right way.

Your little group walks in silence, minds on your feet and the stifling humidity. No one is in the mood to talk any more. Then there’s a funny snicker-snicker-snicker sound and Jollyby cries out, blood erupting from exit wounds in his chest. He collapses into a giant fern, staining the leaves red and doesn’t even gurgle. Everyone freezes, and you can see a white dome, with black metal peeking out from underneath it swiveling slowly away from where Jollyby was standing, not as dead as you thought.

What do you do?

This was the first one I sent out, and I didn’t explain to my players what I was doing, so one responded with this callousness:

Shit. Not again.

A flare to the “face” always fucks with the heat-sensitive abominations. At least for a few seconds.

Like bouncing a baseball off the wall in the hardhold. Hit the same spot, again and again. Practice makes perfect, they say.

I visualize that spot as bein’ right in the center of that black maw of metal and put the flare right on the money.

Should buy me a few seconds. At least enough time to get under the ferns and start circling my way around to Jollyby.

I like that necklace he been wearin’.

First come, first serve.

Savages, Cannibal Savages

So, Jav, Kartak, you’re out there, now, among the Tire Wastes at mid-day. Sucks for you. The hidden mouth of the tunnel recedes at a pretty good clip, if you do say so yourselves, given your current state of abuse. The heat rolling off the piles of half-melted black rubber starts to get to you real quick and you realize that, while the tunnels were full of murderous, howling savages, bent on eating and cooking you (in whatever order), at least they kept the sun off. That shit is brutal.

Then you hear it: the hue and cry of a cannibal pack calling for your blood. Looking over your shoulders, you can see between mounds of rotten tires a group of a half-dozen or more of the fuckers, armed up with random bits of sharp and heavy instruments of violence.

If you’re quick, you could maybe squeeze in under some of the local “geography” and hide it out, but it means getting in there among all those tires that have been baking in the sun for hours and hours: even if you weren’t dehydrated from your imprisonment, not a pleasant experience. Other than that, it’s mostly either stand and fight, or hope to outrun them to where Vee-dubb’s waiting with her van. If she’s waiting with her van.

What do you do?

Another player responded this time, with this visciousness:

Jav slips a holdout from the small of his back and puts a round through Kartak’s femur while his former friend stares at the hounding madmen. Tears trace ephemeral trails across filthy cheeks as he pushes towards the pickup. With body and lungs burning from exertion (the ambient vaporized rubber helps too), he promises the world will know the noble end of Kartak and how he sacrificed himself to save his dear friend Jav.

The Market

So you’re sitting out there the rest of the night, watching Imam’s store front. Eventually, the angry red circle of the sun starts to creep up into the sky, pouring pink light over everything. Before the sky is much light at all, people start to trickle into the market space in ones and twos. Some are setting up shop, there’s Ula, getting water from the well for her folks; her dad’s been sick recently with a fever. Dustwich rolls his food cart up next to the news board and starts getting it going. Slowly, the market comes to life.

It’s a while before the first strangers show up, mostly folks staying at Chin’s flophouse. The first travelers won’t arrive until late afternoon, generally.Then you spot it: someone you don’t recognize, a scrawny bald someone in a nomad’s poncho, looking around furtively. They back casually down an alleyway next to Imam’s that you know for a fact is a dead end with no doors on it.

What do you do?

The Mead Hall

You open the doors and there Swiss Miss besits her throne: leather clad and radiating danger. At her feet sit two waste hounds, snoring with eyes open. The air is smokey from the torches lining the walls and the large rectangular fire pit that runs the center of the room. At two long tables, her gang sits at their leisure. All are men and women of violence, armed with guns of wide description and pointy instruments of death both vile and various. All eyes turn to you as you enter.

What do you do?


They call it opening your mind, but it’s more like the maelstrom burns the world away around you. Your body turns to ash and blows away in a furnace wind. Everything around smells of charcoal and gasoline, the light is all orange and red with dark, oily shadows.

As smoke billows through your consciousness, you see that Keeler isn’t as alone as she looks. She’s got a line of compatriots lying low just behind the rise she’s standing on, five or six of ‘em, all armed.

And now that the flame has shed some light, you have to feed the fire: When was your first kiss? With whom? Why don’t you like to think about them?

The Settlement

The top of the ridge is hot and dry under your chests. Passing the rifle between you, you can see some better detail about the settlement through its scope.

There’s some amount of walls, but not all the way around: either not finished being built or some damage done. There’s a collection of buildings inside, adobe (the same color as the surrounding wastes) and scrap metal, mostly. Not of uniform heights, but all one story.

There’s a kind of square in the middle of town. Around a well and a market, maybe. A complex arrangement of canvas and plastic sheeting suspended, taught, between ropes and wires like sails provide shade to the square. Or would, except that substantial portions are ripped and busted, hanging down and blowing limply in the hot wind.

And that’s the other thing: There’s no people in sight. Did they see you and they’re hiding? Are they all gone? Did something bad happen here? Is it still happening? If anyone’s left, would they assume you’re here to help or hurt? Would they cower or attack? From this distance, there’s no way to know.


Do you go on down there, or try to work your way around and move on or what? What do you do?

HAL Client Update: Cetacean

After writing my last post, I used the code presented therein in production a few more days and realized I wanted just a smidge more power. Specifically, I wanted it to handle HAL’s embedded resources. So I added that and then the other night, I pulled it out of that project, broke it up into files, named it after sea animals and pushed it to Introducing: Cetacean.

Now, I realize my last post was all, “Do we need HAL clients?” and shit. But let’s be real, even 42 lines is a HAL client. Or… whatever, depending on what your definition of “client”. In fact, the design of Cetacean is basically driven by thinking about what “client” means and what I felt like I needed a tool for with respect to HAL documents.

Basically, Cetacean helps you deal with HAL documents, it doesn’t really help you with hypermedia APIs. The general work flow is that you make a Faraday client (configured however seems best to you) and make a request to some URI. You feed the response to Cetacean and then operate on it. You might get a URI out of it (from a link, say), which you can then feed back to your Faraday client, which response you can feed to Cetacean, again, etc.

Perhaps an example would be helpful:

api ='') do |faraday|
  faraday.headers['Accept'] = 'application/hal+json'

root =

At this juncture, you can ask root about some stuff. It’s an instance of Cetacean::Responce. It proxies some methods back to the Faraday::Response, and otherwise is mostly sugar for getting things out of the HAL document.

root.success? # => true
root.status # => 200
root.response # => The `Faraday::Response` you passed in.
root.body # => '{"foo":"bar","_links":{"self":{"href":"/"},"users":{"href":"..."}}}'
root.hal? # => true
root.attributes # => { 'foo' => 'bar' }
root['foo'] # => 'bar'
root.links # => { 'self' => { 'href' => '/' } }
root.get_uri(:self) # => A `URITemplate` object for you to manipulate.

So if you want to follow the ‘self’ rel, you use get_uri method to get a template, do whatever you want with it (probably to_s and expand are the most common cases). And then… do whatever you want with that. Make another HTTP request? Get it tattooed on your stomach? Cetacean doesn’t really care.

Continuing on, imagine further interactions with an API. Notice that at each stage, Cetacean deals with the HAL, and then gets out of the way.

users =
user = users.embedded(:users).first

Assuming that the ‘users’ rel was some document that embedded an array of documents under the ‘users’ rel, user is an instance of Cetacean::EmbeddedResource. It behaves mostly like a Cetacean::Response except is doesn’t have a request object to proxy or refer to. Ideally, you shouldn’t have to keep track of which came from where once you’re dealing with a document.

important_blog_post = 2)))
interesting_blog_posts = 'interesting')))

Just another couple of examples of following different links, both of these requiring expansion.

This is certainly more wordy than using a more featureful library like Hyperclient or whatever. I feel that this gives you a lot more control over how you deal with the documents you get back. If you unexpectedly get back an invalid body, Cetacean won’t barf trying to parse it like JSON, if you get back 'image/jpeg' instead of 'application/hal+json', Cetacean makes it easy to deal with that however is most appropriate. If you need to do some fancy, weird-ass configuration of Faraday that’s super specific to your use-case, then you don’t have to worry about what a middle-man library might do to your connection configuration.

Anyway, I guess I wrote another gem. If you use it, I’d be interested to hear about it. If you want to help, feel free. It’s on Github.

Thinking About HAL Clients

More and more, at work, we’re talking about service oriented architectures. Mostly, these are very small apps that deal with just a few concerns. Since we foresee having lots and lots of these little mini-services, we decided we’d need to make some decisions up front about how they’re inter-operate. This is sort of in the spirit of convention over configuration.

More to avoid having to re-make the decision about what shape responses from these services should take every time we start a new one than for any other reason, we decided that all these services should speak HAL. This way, we can get good at dealing with HAL and once you grok how to talk to one service, that knowledge will transfer readily to others. We picked HAL over other formats we considered basically by typing out an example response off the top of our heads and then seeing which existing format looked the closest. So scientific.

Since that time, I’ve spent a fair amount of time monkeying with HAL and related hypermedia issues. There are a lot of angles, here, but I wanted to start off by writing about the idea of a HAL client.


Initially, I started using a Ruby library called Hyperclient. It basically abstracts parsing and navigating HAL documents and making requests to the links in them away from the developer using it. At first, I thought this would be great. However, the more I used it, the more I felt like it was doing more to me than for me.

In it’s effort to keep the developer from needing to know the HAL spec front to back, it is pretty complicated and has a lot of corners for edge cases to get stuck in. And, really, since HAL is so readable, it ends up just mapping hash access to method calls in a lot of cases.


I really hope I don’t have a NIH complex, but… I do use Arch Linux because of the level of fiddling it allows with how my laptop behaves… and I tune and tweak my .vimrc and .bashrc so my environment is just so. Thus, it shouldn’t really be surprising that when I wanted more control, I decided to build something from scratch (sort of).

The other day, after encountering some weird interaction between Faraday, Hyperclient and certain features of WebMock, I decided to see how hard it would be to rip Hyperclient out and replace it with something dumber and simpler. After talking it over with the team, we decided the best course would be to time-box it to a day.

Here’s the 42 lines I replaced Hyperclient with:

require 'forwardable'

class HalResponse
  extend Forwardable

  def_delegators :response, :status, :success?, :body
  def_delegators :hal, :[], :fetch

  attr_reader :response

  def initialize(response)
    @response = response

  def hal?
    response.headers['content-type'] =~ %r{\Aapplication/hal\+json}

  def links
    hal['_links'] || {}

  def get_uri(rel, expansions={})[rel.to_s]['href']).expand(expansions)

  def attributes
    hal.except('_links', '_embedded')


  def hal
    @hal ||= parse_hal

  def parse_hal
    self.hal? ? JSON.parse(response.body) : {}
  rescue JSON::JSONError, TypeError

The way this works, is you build your own Faraday object, you make the requests yourself, then you feed the response into a HalResponse constructor to monkey with it. If you want to follow a link, you call get_uri and feed that result to your Faraday object. A short example:

client ='')
root =

posts =
search_results =, q: 'Ruby')))
new_post =, title: 'Blah', body: 'whatever')))

It’s important to note that my 42 lines don’t deal at all with embedded resources and are tailored to handle cases presented by a specific API of a specific service I’m coding against. But that’s actually part of my point: Do we need HAL clients? Is the document format that hard to grok?

Since HAL (and other hypermedia types) rely on the semantics of HTTP pretty heavily, it seems much more important to have a robust HTTP client. Dealing with the specially-formatted response bodies seems like a separate issue to me. I may expand the above class as I continue to use it in production, but I kind of like the wordy, do-nothing-for-you kind of way it works.

Ben’s Gem Maintainer Handbook

At work, recently, we were discussing internal gems and how to deal with releases and crap. Of course, because this is a topic, I have opinions on it. I can’t help myself.

Actually, someone was like, “Why do we do it this way,” and someone else was like, “I don’t know, ask Ben,” and I was all, “Ranty rant-ra–You know what? I’ll just write a blog post.” So, now you’re all inflicted with this. You have Bob and Ryan to thank for it.


So this is pretty simple, and other people have explained it better than I can. You should be using Semantic Versioning for your gem. You can read the full spec, but I’ll break down the general idea real quick.

Version numbers are 3 segments in the format major.minor.patch. You increment the major version if you’re shipping any backwards-incompatible changes. You increment the minor version if you’re adding backwards-compatible new features. You increment the patch version if you’re just doing bug fixes. When you increment one segment, all the segments to the right reset to 0.

This way, a consumer of your gem can tell by looking at the difference in version number whether the changes should be backwards compatible or not (major version changed) or whether that new exciting feature they’ve been waiting for might be in (minor version changes).

Version Number

If I’m in a REPL with your gem loaded, I should be able to ask it what it’s version number is, so put the version number in the code. Ideally, I think, it should be a string of the numbers. Some people seem to like to have MyGem::VERSION be how you get it. Personally, I like to provide MyGem.version, as well.

If you do this, you can then refer to it in your gemspec, where you officially set the version of the gem. You should put it alone in it’s own file, though, so you don’t have to load your whole gem just to interleave your version number into the gemspec.

Keep a changes file. There are a few file names that seem to be widely recognized, but I like the best. I prefer not to keep this information in the README just to avoid cluttering that file for people who are interested in documentation or contribution guidelines.

My file has a <h1> at the top that just says ‘Changes’. I don’t have strong opinions on that part. However, the following bit I have very strong opinions on.

You have several sections, following the title. Each section is an <h2> that is the version number of a release followed by a bulleted list of the changes since the previous release. Each item in the list should be a brief summary of a bug fix or feature–no reason to replicate your entire commit history here. Personally, at least for publicly available gems, I like to also credit the author of the change by name.

Each of those sections should go in descending order of version number so that the newest stuff is at the top. There’s also a special version: ‘Unreleased’. Between releases, you don’t yet know what your next version number will be. Will you add a new feature? Break backwards compatibility? Who knows. So I log changes as they’re merged to an ‘Unreleased’ section of This way I don’t forget what’s in and it’s easy for someone to see what kind of stuff is coming in the next version (or what’s in master that isn’t released).

Rarely do people sending me Pull Requests add their own entry to, so usually, I’ll merge their code, and then go add an entry for their change myself. However, I would be delighted if a contributer wrote their own entry.


The point under discussion at work fits into this category. I always bump the version number a lone commit, apart from any feature branch or other changes. I feel like there are a couple of advantages:

  1. It provides you an opportunity to review in it’s final state as you decide how you need to change your version number for release.
  2. It means that you can add a feature that, as you write it, seems like it’ll be the last one before a release and then at the last minute think, “Oh, just one more,” and still have the version bump be the last commit before release.

Relatedly, tag your release commit. I just tag mine with the version number, but you can put a ‘v’ in the front if you like. I don’t care. The point is to make it easy for a consumer of your library to go to Github and easily find the commit that matches whatever released version they’re using. Make sure to push that new tag up to Github.

When I’m ready to release, I do like this:

  1. Review and select a new version number.
  2. Update the version number in the code.
  3. Change the ‘Unreleased’ heading in to the new version number.
  4. Run gem build my_gem.gemspec. If it doesn’t build right, stop and fix it. Don’t commit the new version number as part of that fix.
  5. Commit the version bump changes.
  6. Tag the new commit with the version number.
  7. git push && git push --tags && gem push my_gem-1.2.3.gem
  8. rm my_gem-1.2.3.gem.

I’m sure the above could be automated, but it never seemed like enough of a pain in the ass to be worth my while.

So them’s my opinions on gem maintenance. If you tweet or email me questions, I’ll update this post with answers.

Never Type Bundle Exec Again

Sometimes people complain about having to type bundle exec before every freakin’ command in a Ruby project. Honestly, I think the benefits Bundler gives you outweigh that downside by a huge margin. However, there is good news: You can use this one weird trick to never type bundle exec again.

OK. It’s actually an option of two weird tricks. And then a bonus trick. This joke is ruined.

Somewhat Involved, Works Everywhere

If you’ve got Ruby installed, you can do this trick. It’s a little hacky and comes with some downsides.

First up, make ~/.bundle/config look like this business:


This will tell bundle install to always run as if you passed the --binstubs=bin option. Now, when you bundle up a project, it’ll drop wrapper scripts into the bin directory of your project that ensure the correct Bundler environment is set up before running their normal stuff.

As a courtesy to everyone you share a project with, when you do something like this which will litter your project up with files to do with your personal set up, you should make sure you don’t commit them to anything. So go to your global git ignore file and make sure it includes this:


Here’s downside number one: You will probably have to override this for specific projects. For instance, gems often ship with a bin directory with files to do with the gem. You’ll want to make sure those aren’t ignored. If you explicitly git add them, they should be tracked by git thereafter, but you have to go out of your way. In particular, a Rails project contains wrappers for rails, rake and bundle in the bin directory and those should be committed to the repo… and not over-written by your bundle install binstubs. So take care, there.

At this point, you could stop, except you’d have to type bin/ in front of every command, instead of bundle exec. Sure, it’s shorter, but still annoying. The next thing to do might be to prepend ./bin to your $PATH so that your command line looks there for commands first. Downside number two is that there are some negative security implications to this, so I for sure don’t recommend it for servers, but I’ll leave it up to you whether you do it on your personal dev machine.

Less Involved, Requires rbenv

“But, Ben,” you say, “I want to be just like you so I use rbenv.” Well, you know, that’s flattering and I have to say you make some good life decisions, friend. Let me tell you about some nice tools.

If you use rbenv (and I like it so far), then you can take advantage of it’s plug-in system. Probably you’re already using ruby-build as a plug-in to install Rubies. I have two more for you: rbenv-gem-rehash and rbenv-binstubs.

You can read more in the READMEs of those projects, but in brief, you install them to your ~/.rbenv/plugins/ directory, then make your ~/.bundle/config look like this business:

BUNDLE_BIN: .bundle/bin

Undo any steps you may have taken above (like ignoring bin) and shit should be taken care of for you. Now you won’t have to rbenv rehash or bundle exec! Rockin’.

Note: The .bundle directory of a project that uses Bundler should already be ignored in git, so tossing your binstubs in there should protect you against barfing them into a repo unintentionally. Rbenv-binstubs handles making sure they’re in your path for you.

Bonus Trick: alias be

I kinda lied to you. I’m sorry. You may still have to type bundle exec on occasion, even with nifty rbenv-related goodness. Things that aren’t gem commands don’t get binstubs from Bundler: notably, the gem command. For me, this most commonly comes up when I want to see what the gem list is that Bundler’s resolving.

Doing gem list will show you all gems installed for the active Ruby. No help. So you can do bundle exec gem list and Bundler will do it’s path-related mojo and then execute gem list for you. Nice, but typey. So the bonus trick is to add this line to your .bashrc (or .bashprofile or whatever madness your system might use):

alias be='bundle exec'

Now you can just be gem list, which sounds sort of like an existential confusion to me, but involves less typing, so… win!

Final Caveat To All This

One last thing that’s important to remember with all this: whenever you do this kind of optimization of your local system, whether it’s installing vim plug-ins or putting set -o vi in your .bashrc or whatever, you have to keep in mind that it’s not portable. When you shell into your alpha server to tail some logs or debug something, you won’t have this stuff. So while you may never type bundle exec again locally, you should remember that it’s still there in the background, and remember that on machines you didn’t set up, you’ll still need to type it.