Why we re-wrote Ackly in Python from JavaScript

When Ackly was built it was done quickly like all MVPs to get from idea to deployed and in customers hands as quickly as possible.

In making an initial framework decision, we put together a small table comparing a few options from the officially supported/built tools.

Slack Framework Decision: 1–5 rating (least to most favorable)

It was clear that the Java framework was not an option and it was either Bolt or Python.

  • There was an order of magnitude less usage (imports on GitHub: 500 vs. 5000) on the newer Bolt framework as expected since it started in 2016 vs. 2014.

Initially we chose the Bolt framework. Most of Slack’s latest documentation also recommended starting with it. We were feeling adventurous, always up for learning and improving on our 3 score for language that we gave it (reasonable knowledge, not an expert).

This worked great! For the first month.

Here are a couple reasons why we chose to re-write Ackly in Python.

  1. Promise chains became very deep and refactoring them to simplify was a never-ending exercise.

Promise chains

A typical promise chain for an inbound message or reaction would be > 10 promises deep.

.then() gets pretty old pretty fast.

When you refactor and clean this up a bit you still end up with having to resolve all of these (and debug. odd behaviors within).

Resolving Promises

Inter-op. w/Firestore

A typical database operation would be far more code than I would expect for a fairly simple operation (add an item). As more operations were added even with plenty of refactoring this continued to grow. With an ORM (hold opinions) or a better library this could likely be a lot less code and pushing less logic into the application layer itself (eg. check if an object exists). One could argue that this is more about the DB type (NoSQL) and I would tend to agree with that observation (would a separate post on that be interesting?).

Example Firestore Interaction w/JS

Async/Await & Promises

Half the codebase was using Async/Await and the other half was using Promises. Using Bolt you are generally using Async/Await so interactions with Bolt itself you generally try to keep this pattern. Mixing these patterns in a single file is an overhead that becomes illogical pretty quickly and it may break your brain.

For other libraries (Firestore) you may be using Promises and while you can do your best to keep them isolated you will inevitably end up with a mix.

Mixing Async/Await & Promises

Moving to Python

Re-writing to Python took two days of writing, testing, and rollout. Major highlights were as follows:

  • The codebase was cut in half — even when using an ORM (SQLAlchemy).


This post covered a bit about our initial selection of Bolt and our move to Python as our choice of a Slack language framework.

If you are interested in learning more about Ackly, check us out over on ackly.io.

If you found parts of this post interesting or would like to discuss further, feel free to comment/reply or reach out on Twitter at @HeyAckly.



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store