Some articles will tell you about the best way to do something. This is not one of those. This is an article about experimenting, making bad decisions, and getting the best out of a bad situation.

SongButler is one of After Hours Solutions’ apps — actually, at the time of writing, the only app (if you haven’t tried it out, now is a good time to do that at https://songbutler.app). Let me start by telling you right now that both the landing page and app is costing us $0.00 to keep alive. But that wasn’t the original idea.

When I first started this project, I had a goal in mind: learn Go. And so I did. But by restricting my goal to that, we didn’t think much about deployment — we figured we’d just deploy it in a cheap virtual server and call it a day. Rookie mistake, eh? So, the project was finished in about a week, and we had a big ol’ Go binary, using almost no external libraries and the default net/http package serving all requests. I was happy about it! But then I had to deploy it, and that’s when the (late) idea of serverless surfaced.

It can’t be so hard, right?

You must be new here GIF


Serverless, even if an afterthought, should be easy (well, that’s what I thought). I just need to deploy this binary as an AWS Lambda or something and have a good night of sleep. (Nope.)

First of all, you don’t have the concept of a web server running and accepting requests, so scrape everything you think you know about HTTP request handling and whatsoever. Serverless consists of a function (or a series of functions in a project) that takes an input and outputs something (normally, at least). Oh, and, yeah, of course that function runs in a server, so great job with the name serverless, whoever thought about it. It’s more like manageless, since the only difference is that you don’t need to actually manage a server. But having said that, how in the world am I supposed to handle requests, you ask? Well… something does that for you.

Being a serverless novice, I went with what everyone uses (and is more Googleable…) — Amazon Web Services, or AWS, as everyone calls it. A serverless function is called a lambda function in the AWS world, and there’s really not much more to it. And a lambda function can be ran in response to a signal from something, and that something can be a gateway that basically routes HTTP requests. Perfect.

Kind of.

I already had a perfectly good app, with routing built-in. That doesn’t really fit the serverless model. Fortunately, I found a nice little library that could be used as a drop-in replacement for go’s net/http library.

Here is the app’s entry point before:

func main() {
	cfg := cmd.Init()

	http.HandleFunc("/slack/help", web.SlackSlashHelpHandler)
	(...)
	http.HandleFunc("/slack/webhook", web.SlackEventHandler)

	if err := http.ListenAndServe(fmt.Sprintf(":%d", cfg.Port), nil); err != nil {
		panic(err)
	}
}

And here’s the after:

func main() {
	cmd.Init()

	http.HandleFunc("/slack/help", web.SlackSlashHelpHandler)
	(...)
	http.HandleFunc("/slack/webhook", web.SlackEventHandler)

	gateway.ListenAndServe("", nil)
}

Not too different, right? And… it basically works. The issue is that we still have a single binary serving everything. It’s serverless, sure, but I wanted each endpoint to be divided into a separate binary. I guess I should have thought about that earlier though, eh? You can’t have everything going your way unless you plan things accordingly.

Of course, I also ran into some problems — for example, debugging code when it isn’t running in a machine you control is a pain — but Go turned out to be the right tool for the job, along with serverless.

Jim Carrey Programming


There is some stuff that I haven’t talked about in this post (like how to group everything in AWS, the creation of an API gateway, etc.) but that’s a bit out of scope. The giveaway here is that serverless is, in my opinion, a nice choice for apps that don’t do a lot of work and don’t need to be actually running (processing stuff) all the time, only at regular intervals or in response to an event. Pair that with the generous free tier of AWS, and you have got yourself free, reliable (most of the time) hosting!