Instructive insights on launching Slack apps you need to know — Part 2
By: Josef Hertl
Tags: Tech, Slackbot, Slack, DevOps, Kubernetes

Instructive insights on launching Slack apps you need to know — Part 2

Motivation

In the first part of our Slack miniseries, we’ve introduced our app Facehunter and explained the basics of Slack API for developers. In this part we’ll go through the application itself, i.e. we’ll explain in more detail how exactly it works.

The app is open-source and thus available online at ROI Hunter repo. Feel free to go through the code or even develop new functionality for it — that would be much appreciated.

While the code should largely be self-explanatory, we are going to explain it more, particularly in relation to Slack.

Development

Now that you know your way around Slack API, it’s time to jump into our development process. We’ll go through it step by step.

DevOps part

Application deploy setup is usually done by DevOps — you need to set up the domain, prepare the app deploy, etc. For us, it was super easy, as our DevOps team has prepared a process for us called Simple Deploy. The name says it all — it’s simple and it handles deploy for you.

All we needed to do was copy-paste three files: Dockerfile, cloudbuild.yaml, and all.yaml. Now I just had to configure a Cloud Build trigger to get the deploy fully working. The most time-consuming part of this process is waiting for your new domain to get propagated.

Here we should also mention the secrets. When you go to the code, you can notice that the app sometimes reads secrets from environmental variables. This is another DevOps magic done via all.yaml file — in the envFrom property we define which secrets we want to read from our Vault and it automatically handles everything for us. Yes, we do use Vault for secret management.

Flows

The application code itself is self-explanatory. We structured the code by layers (this is not always ideal, but we believe it to be the better choice for such a small microservice as Face Hunter).

Pretty much all application logic is kept in Flow classes. Essentially the app works in the way that a Controller gets an outside input and initiates a Flow that processes the input. In a few rare cases, the Controller handles the input by itself. Let us explain the individual flows to you.

ExchangeVerificationCodeFlow

This is the first working flow, as it handles oauth so that we can connect other Slack workspaces to the app. It handles step 3 in Slack’s oauth flow.

Note that we store workspace’s access token, which seems unnecessary at first because we use a bot for everything. However, as you may remember from the Slack API part of this article, there is one particular method where using bot’s token is a bad idea — message.postEphemeral.

Secrets used in this flow are extracted from the Vault via the cool DevOps mechanics described above.

NewGuessFlow

Let’s move to the core flow. The point here is to get one random user photo and four false names to prepare a guess from.

First, we start by reading workspace’s bot token from the database. After that, the most time-consuming part of the flow arises retrieval of all employees from the given Slack workspace. We have yet to test this method with workspaces bigger than 200 users, but at least for us, it’s working pretty fast and usually is done faster than 1 second. Still, we are running this flow in a new thread (using Kotlin’s coroutines) just to be sure.

When we have downloaded the list of users, we filter it for the ones that are actually usable. Only human users that are active and have a custom image are eligible for guessing.

Here we discovered one strange issue in the past: Slack downloads gravatar images for those who use them but doesn’t consider them to be a custom image. Thereby some users won’t show up, even though they seemingly should.

Then we shuffle the filtered list. It is an easy and elegant way to randomize the choice.

After that, we take first person in the shuffled list (correct guess) and four more (wrong guesses). We build blocks from the selected data and finally, we post the guess to Slack.

Note the special logic for setting up buttons’ value param. It is so that every button carries all the information needed when it gets clicked on, i.e. we don’t have to do any third-party API calls on button evaluation. Thereby each button’s value includes info on whether the guess was correct, who the person really was and what was the person’s position in the company.

EvaluateGuessFlow

When a guess is made, it must be also evaluated. After a button gets clicked on Slack, it sends a POST to our InteractiveController, which initiates this flow. Part of the logic is in the controller, as it splits the value of the clicked button and only sends the data to the flow.

The logic in the flow is very simple. If the guess was correct, it reveals the person’s position and offers the next guess. If the guess was wrong, the correct name of the person is revealed and the next guess is offered.

The next guess option is done via a button, as that is far easier than having to type /facehunt again. Button for support/feedback initiates another flow.

SendHelpInfoFlow

This minor flow does only one thing: sends support/feedback information to the user. It also has to include the Next question button, because users tend to get slightly confused without it.

SendEphemeralReplyFlow

Ephemeral replies have been discussed quite a lot above and in Face Hunter, they have a special flow just for them. Note that we’re using workspace’s access token instead of bot token.

Other interesting parts

Database

Face Hunter uses a database for a singular purpose: to store workspace info. In the future, it would be theoretically possible to use it to store usage info, but we decided against that for now.

Logs

Face Hunter is open-source and available to be installed by anybody on Slack. That is why we were not quite sure how to handle logging in there, as we would be working with information about pretty much anybody. Ultimately we decided to go without logging in order to be safe on the privacy and personal data side. This is a decision we may change in the future.

The only logs we have now are the ones in our Kubernetes when an exception is thrown. As a matter of fact, that’s all the logs we need at this moment, so fingers crossed.

Obstacles

During the development process, we encountered a few obstacles and believe some of them are worth mentioning here.

Different OS

In my first implementation, after the user correctly picked the name, they got this icon in response: :heavy_check_mark: On wrong answer, this came: :negative_squared_cross_mark: Here is what they look like on Linux desktop Slack:

Green for right, red for wrong, exactly as everyone would expect. That is why I was surprised when my colleague who uses Mac wrote to me that the icons were wrong and I should be using a green one for the correct choice and red for the wrong one. Puzzled, I sent him the icons and got the following screen from him:

I.e. almost the exact opposite of what we actually needed. We discovered that many of the default Slack icons appear completely different on different operating systems. Finally, we settled on these two icons for the right and wrong answer: :tada: :x:

Now we can just pray the some Slack version doesn’t show the big red X as green.

Who is that guy?

When testing the app, I had this photo shown to me:

Weird thing is, there were five name options and none of them matched the photo. I even went to manually check them all to see their profiles and all were very different from this photo.

I had even searched our user list for this photo and didn’t find it. At this moment I thought there either is an insane bug on Slack or that we have a ghost in our company. Funny thing is, the guy in the picture looks very similar to the father of one of our colleagues, so I even asked the guy how his father could get to our Slack.

Only a few hours later did I find the truth: one girl in our company likes to put funny pictures to her photo and this was one of them. She had already changed the photo when I looked at her, so that’s why I didn’t realize the connection. Also, it means Slack is somehow caching employee photos for a short time.

Conclusion

We would like you to take one message from this article: developing apps for Slack is pretty easy and quite a lot of fun. If you would like to create new pull requests for Face Hunter, feel free to do so, we’ll be more than happy to take a look at them. Enjoy Face Hunter & have fun!

Thanks for reading!

➡ Find out our other articles on tech{hunters}.

➡ We are ROI Hunter, if you enjoyed this article, have a look at our job offers.

⬇ Be sure to 👏 below if you like what you read. ⬇