When the time came to begin the software development cycle for pakpak I was faced with a lot of choices. What do I use to bring our idea to life? These early decisions could shape the future of our product and needed to be made carefully. After some research and a lot of thinking, I came up with three requirements, our stack must:

  1. Allow for rapid iteration
  2. Be easy to deploy
  3. Load quickly

I spent a lot of time researching, browsing StackShare, and asking what others were using. To narrow down my choices, I decided to stick with languages I’ve used before and major frameworks that have strong communities (i.e. lots of answers on Stack Overflow for when I get stuck).

Server Side

Honestly, back-end development is my favorite part of building an app and I was looking for a language/framework pair that I would enjoy working with on a daily basis. Given my requirements above, I was deciding between at the following frameworks:

  • Ruby on Rails
  • Django
  • Express.js

I eliminated Express.js first because I have the least experience with Node.js and writing server-side JavaScript. Having the most experience with Python and because of the growth of the Python community, I decided to go with Django after seeing the growth of the community because there are a lot of packages I can use and in the future, it would be easy to set up a REST API on the side.

Wanting to not reinvent any wheels (ha), I decided to use a database already integrated with Django. The choices are slim, MySQL, Postgres and SQLite. I chose Postgres since it has a great community and there are lots of managed services to use.

Without getting too much into the production setup, in order to serve the app I decided to use Nginx for it’s speed and ease of setup in Docker. It runs in it’s own container, connected to the app container, which is running Gunicorn.

Client Side

I dread sitting around endlessly tweaking CSS to make a design look right. So what did I choose to do? Use a super minimalist CSS framework, where I spent hours tweaking custom CSS to make a design look right. This may sound like I’m punishing myself but there is a reason.

Bootstrap and others impose their design ideas on a site and it takes considerable time fully modify all of the default styles. There’s a reason every bootstrap site looks so similar. Bootstrap and similar framework are also on the heavier side. One of my goals in choosing a stack is front-end speed. To avoid a lot of unnecessary work, I wanted to use some sort of framework. That is how I came to choose Skeleton. It has just enough built in classes to be useful and nothing to impose on our designs.

Ready for a real shocker? I’m not using any JavaScript frameworks. None. Nada. Zip. Zero. Why? Well I don’t have a good reason. For one, I’ve never used any of the big players aside from jQuery. I also didn’t want to take the time to learn and implement a framework I wasn’t sure I needed and that I knew would slow down the app.


Getting code off my machine and into a production environment was actually a bit of a struggle. I tried using tools like Terraform and Ansible to provision, configure, and deploy my code but the learning curve was steep. Over the course of a week I was unable to write configs that were both repeatable and reliable.

I also tried good old-fashioned ftp-over-ssh deploys but that required taking the time manage the server it was running on. Without the ability to automatically replicate the environment, it would mean downtime for our users if there were any issues. This wasn’t an acceptable option for me.

The solution I landed on is building docker images and pushing them to a private registry. From there I used docker-compose to pull and run the images in the cloud. These images are replicated on multiple hosts and sit behind a load balancer. The database runs on a managed service. I also wrote a python script to collect the static files, version them, and then deploy to a CDN.

Lessons Learned

While my choices & requirements were arbitrary and the result of the dubious nature of internet research, they were right for the first version of our app. I was able to work quickly and (sort of) efficiently. I am able to quickly make changes and redeploy with some sort of ease.

We’re using Sentry to track and notify the team of errors. This is absolutely necessary but not a total solution. When a problem happened I have to connect to the app server and review the logs to see what was going on. The whole time, I knew that I should be collecting and indexing my logs. Not just application logs but also docker, server, and access logs. This is one of the first things that will be changed.

My choice to avoid a front-end JavaScript framework was also not the greatest. While fine for our early versions it’s actually become a hindrance to development. It also is a necessary part to make the PWA more interactive offline. I’ve already settled on Vue.js because it looks nice to work with and is growing quickly.

The next step is to move away from server-rendered html. I am still deciding what to use but the next step is to build a GraphQL API for the new Vue front-end to consume (and for out partners to use). The plan to serve static assets over a CDN to speed up initial load.

This won’t be a single page app though. Each unique view will be it’s own html page to preserve the functionality of the browser’s back button. Once these are in-place we can move on to building native apps and our bigger platform.

I’m sure these ideas will continue to evolve as I do. If you have any comments or suggestions, please feel free to reach out.

The great cover graphic is borrowed from rubygarage.org.

This post is part of a series on pakpak, the company I co-founded, learn more.

Joshua Bowen

I am a software developer and product person working on new ideas for the outdoors.