Skip to content

Latest commit

 

History

History
227 lines (154 loc) · 10.8 KB

README.md

File metadata and controls

227 lines (154 loc) · 10.8 KB

Slack Developer Experience Surveys on AWS

Box-ready serverless solution to run developer experience surveys on a scheduled (or one-off!) cadence


This project enables you to easily set up and run developer experience surveys on Slack.

Overview of the developer experience survey with standard settings in Slack

While the core logic around calling Slack and configuring your questions is based on the library devexbot, the rest of the code bundles all the rest of the stuff into a complete solution and offers some extra functionality like:

  • Read survey results back from the database in a readable fashion (see more below)
  • Slack slash command support for opting in and out of the survey
  • Optional: Write results to Google Sheets for easy visualization in Looker Studio

The questions (and number of them) is also configurable — see the devexbot documentation for more.

Solution

Solution diagram based on the system use-cases

Code is written in TypeScript, is bundled with esbuild, and gets deployed with Serverless Framework. Privileges are scoped down to the bare necessities. Errors are logged with mikrolog.

The architecture is based on serverless components (Lambda, DynamoDB, EventBridge) and should be frictionless to manage and cheap to run.

Note that the functions for the webhook and slash command may be run quite frequently, as (especially) the webhook function is run every time a user interacts with elements in the Slack survey, such as clicking on a button.

Responses are not anonymous: They contain both the user ID and the user's name. Slack has a somewhat unclear model around names, but it seems to respond to the displayed name, at least.

Behaviors

  • Only users who have opted in (and are stored in DynamoDB) will receive a survey when it gets opened up for responses.

Opted in Opted out

  • When getting the survey results, you will get back a nice, question-keyed response. Please note, however, that the response's question keys will map to the current questions, not any historical questions at the time of answering (as these are not stored). This also means that if you are changing questions (especially if these are totally different) between two points in time, then you should never trust any results from a period of time that crosses multiple question sets.
  • It is not possible to close surveys in the current state of the implementation. Once a survey is opened, it stays open until the user acts on it. This does not seem like something that needs to be implemented - see below.
  • The timestamp for each response is logged when it's caught by the function that handles it; this is very likely less than ~1 second after the user has submitted their response.
  • When you retrieve responses you provide a from and a to parameter in the call. Effectively, if a user does not respond in a period of time it's simply not a response at all - there is no need for any complex logic around survey IDs or such to track responses to certain iterations of a survey.

Usage

Installation

Install the dependencies with npm install or your equivalent command.

Configuration

You will need to do a few things before actually deploying the code. If you want to support Google Sheets, make sure to read everything first (including the special steps below) before doing anything.

devexbot configuration

Use src/config/SurveyConfiguration.json as per the devexbot documentation.

Setting up your DevEx app in Slack

  • Create a Slack app. Set it to whatever name you want.
  • In Interactivity & Shortcuts, enable this as well. Once the solution is deployed, you'll need to set your endpoint to the "ReceiveWebhook" function here.
  • Create a new slash command. I suggest using /devex as this is what the solution is looking for. Here too you will need to set the request URL to the "SlashCommand" function when you've deployed the solution.
  • In OAuth & Permissions, make sure that the following scopes are enabled: chat:write, commands, and users:read. Note down the "Bot User OAuth Token".

AWS secrets

  • Create a new secret in AWS Secrets Manager, in the same region as the system will be deployed to. Make it an "other type of secret".
  • Add two lines with their corresponding value:
    • SLACK_AUTH_TOKEN - The key to authorize your call to Slack
    • If you need to support Google Sheets, see below, before saving!
  • Name the secret DevExSurvey.

Support for Google Sheets

If you want to output responses to a Google Sheets document, you need to do yet additional steps.

  • You need a Google Cloud Platform account with a project.
  • In that project, enable the Google Sheets API.
  • Create an API key. Download the key as a JSON file.
  • Copy the private_key and client_email values, and add these to the secret in AWS Secrets Manager:
    • GOOGLE_SHEETS_DOCUMENT_ID - The ID of the document (you see it as a long random string in the URL bar)
    • GOOGLE_SHEETS_SERVICE_ACCOUNT_EMAIL - The client_email from the JSON file
    • GOOGLE_SHEETS_PRIVATE_KEY - The private_key from the JSON file

Example of responses being written to Google Sheets

Need more info? See this article.

Bonus idea: Visualize responses in Looker Studio

If you already have the Google Sheets integration working, it's easy-peasy to take an extra 15 minutes and visualize the results in Looker Studio.

Visualized responses in Looker Studio

Setting the schedule

By default, the schedule is set to open the survey at 15:00 UTC/Zulu time every Friday. It's quite possible you need to change this time to be appropriate for your needs and your own time zone.

You can change this in serverless.yml under the OpenSurvey function, where the default value reads as:

- schedule: cron(0 15 ? * FRI *)

See AWS's page Schedule Expressions for Rules for more. You can use the online crontab guru to test your patterns since cron patterns can be a bit wonky if you haven't worked with them before.

Deployment and last fixes

  • Update serverless.yml with your AWS account number in custom.config.awsAccountNumber.
  • Deploy the solution with npm run deploy.
  • Once this is done (should take 2-3 minutes), you'll end up with a set of URLs to the public synchronous functions. Note down the values for ReceiveWebhook and SlashCommand.
  • Back on the Slack API page, set these URL values in the Interactivity & Shortcuts and Slash Commands pages, respectively.

Deployment

Deploy the solution with npm run deploy or your equivalent command.

Remove project

Run npm run teardown or your equivalent command. Note that DynamoDB tables are set to be retained, so that they aren't mistakenly deleted—these need to be manually removed afterwards.

Example API calls

Open the survey for all opted-in users

This is deactivated by default and uses a schedule (see above).

You need to uncomment the section in serverless.yml to make this work over the API.

curl {{BASE_URL}}/open

Opt in/opt out user (Slack "slash" command)

This is an example of how the payload from Slack looks. Notice that the text field will be optin or optout.

curl {{BASE_URL}}/slash
{
  "token": "SOME_TOKEN_HERE",
  "team_id": "TXXXXXXXXXX",
  "team_domain": "teamname",
  "channel_id": "CXXXXXXXXXX",
  "channel_name": "some_channel",
  "user_id": "UXXXXXXXXXX",
  "user_name": "sam_person",
  "command": "/devex",
  "text": "optin",
  "api_app_id": "AXXXXXXXXXX",
  "is_enterprise_install": "false",
  "response_url": "https://hooks.slack.com/commands/TXXXXXXXXXX/1234123412341/RANDOM",
  "trigger_id": "1234123412341.1234123412341.SHA"
}

Get survey responses

You will need to supply a period with from and to values in YYYYMMDD format.

The from value counts from the first millisecond of the UTC/Zulu time, and to is from the last millisecond of the provided day.

curl {{BASE_URL}}/responses?from=20230601&to=20230630

You can also add a positive or negative offset in hours, with the offset value.

curl {{BASE_URL}}/responses?from=20230601&to=20230630&offset=4  # Positive offset
curl {{BASE_URL}}/responses?from=20230601&to=20230630&offset=-2 # Negative offset

An example response could look like:

{
  "*1. How has your day been?*": {
    "negative": "50.0000%",
    "positive": "50.0000%"
  },
  "*2. Did you make progress toward your goals today?*\nConsider the clarity of goals, how engaging the work is, your control of the structure of work...": {
    "negative": "33.3333%",
    "neutral": "33.3333%",
    "positive": "33.3333%"
  },
  "*3. Have you been able to focus today?*\nConsider the number of meetings, interruptions, unplanned work...": {
    "negative": "33.3333%",
    "neutral": "16.6667%",
    "positive": "50.0000%"
  },
  "*4. Is your tooling working well and fast?*\nConsider CI, code tools, platform tools, build and test times, code review times...": {
    "negative": "33.3333%",
    "neutral": "50.0000%",
    "positive": "16.6667%"
  },
  "*5. Is the cognitive load manageable?*\nConsider project complexity, friction, processes, communication...": {
    "negative": "50.0000%",
    "neutral": "16.6667%",
    "positive": "33.3333%"
  }
}

Feel free to contribute!

This is a version 1.0 of this. If you find it useful, or if you find odd cases that aren't handled, just go ahead and make a pull request so we can look at a solution together.


References

Developer experience surveys

Slack