How We Built a Slack App in a Day

The Journey

As a growing agency, with a quasi-distributed team, we needed a way for team members to quickly know if someone was on PTO, and do so with as little friction as possible. Since we already lived in Slack, having this functionality live their was a no-brainer. We evaluated a few existing solutions, but all of them were a bit heavy-handed, with features such as manager approval...etc. This really felt like it went against the ethos of our culture, so we did what any good engineering team does, we rolled up our sleeves and set out to build our own!

The Requirements

First we asked: what do we really need? Some way to enter time and list it? So we got creative, throwing together some mocks showing how we could leverage interactive messages to collect the data. Then we thought, people can make mistakes, so we need a way to remove it as well; oh, and who wants to add an entry for every single day? What if someone takes a week off? Oh, oh, oh... what if I want to know if a teammate is out? We should have something for that too.

So we settled on a few interactions that would be easy to create:

  1. Add (Start Date, End Date)
  2. Remove (Start Date, End Date)
  3. List () - Shows everyone
  4. List (@userName)
  5. IsOnPTO(@userName)

We recognized we'd need to make it nicer in the future. Entering dates in text fields isn't fun, but this is v1.

The Setup

The most commonly known language here is JavaScript, so Node it is. One of us setup a node project, and got to it. Nothing too fancy for now, just Node and Express. We had no idea what to expect, so we just went to the Slack API page and created a new one. We added a bot and a slash command.

The commands needed public URLs to post to, so we setup ngrok locally and added the routes. It worked! Well, we could see traffic. If we sent the command /pto-add to the bot we logging the response to the console and could see what we were working with.

Divide and Conquer

We fought through the docs and some examples, for 30 minutes or so, and figured out how to get some dialogs to show with text inputs and buttons. So one Rocketeer worked some basic validation for dates (come to find out, you can return an errors array that specifies the filed and message) and the other started hooking up a DB. We don't need much for now, so we started with Mongoose and mLab.

It was glorious. Actually, it was kind of a pain, since we only had a single file with all of our code. So the next commit was to start breaking out the routes, services, etc.

It Lives!

A few hours later we had the add functionality and the ability to list all PTO working. So far the new Slack app was both smart and loyal. We were psyched and showed off how it'd work, to get more feedback if needed.

The Logic

Calendars, scheduling, etc, is kind of a PIA, so we went with a simple approach. Our document looked like: {username: string, date: Date}. Whenever someone requests to add a range of days we call a service that gives us back an array of dates for the start and end date. We then try and save each one for the given user and if it fails... well it fails. Same for the remove, if someone tries to delete something and it doesn't exist, who cares? It's an atomic operation. If you tried to delete an entry and if it existed, it's gone, if not, it's not there either, so to the user... you still got what you wanted, right?

Finishing Up

We added the remaining commands, namely ways to show PTO by user, check if someone was on PTO today. We then went on to add pm2 to ensure it would stay running when hosted in the wild. We pushed it to Heroku, and updated all of the slash commands in the Slack app to point to our new Heroku instance.

Success and Summary

There's still a lot of work to do. The interactions and UX could use some work, formatting and new features, but we are happy with the progress made. The keys to success were to:

  1. Quickly create a plan of action and not over think it
  2. Being okay with calling this version one and trying it out before iterating.
  3. Being okay with the unknown, we weren't even sure what the Slack APIs looked like.
  4. Getting feedback early.
  5. And lastly, refactoring early and often, so we could divide and conquer; making sure as the project grew we separated concerns. More files = less stepping on each others toes and merge conflicts.