Why I Don’t Use Go Web Frameworks

For those who are tempted to use a web framework in Golang, it may not be worth it.

I have had a fair share of writing applications in Go, and in despair I had resorted to a few cool-looking, out-of-the-box shiny web frameworks in the hope of getting things done quickly and efficiently. I was wrong.

Go is a different beast comparing to many other languages. While being general enough, Go was built for the modern web. It has all the built-in tools enough to accomplish most web programming tasks, and if it does not, the modularity of its package system makes it easy to mash up many external packages in a plug-and-play fashion.

IMHO, Go itself is already a web framework. To make this argument clear, let’s compare its HTTP handler’s signature to those controllers in Python’s web frameworks, Django and Flask.

Go:

func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, "Hello world!")
}

Django:

def handler(request):
return HttpResponse("Hello world!")

Flask:

@app.route('/'):
def handler():
return "Hello world!"

It is understandable why Python needs web frameworks. It is a more general language without built-in response and request objects. When it comes to standard patterns to handle HTTP requests and responses in an application, it leaves that to each framework’s implementations.

However, controller functions in Go is already very similar to those in Django and Flask. At the very least, they all expose the HTTP request object. (While a basic Flask controller function does not require a request object as a parameter, it is actually there implicitly when needed.)


EDIT: There are in fact, as pointed out by Sébastien Pierre, native response and request objects in the httplib module. But they are not commonly used.

Frameworks Hide

Most Go web frameworks go all the way to abstract the native controller’s signature completely, hiding the http.Response and http.Request away in exchange of ease of use. Admittedly, it will feel like driving a new fast car for a while until it breaks down on you a few miles down the highway and you pop the hood to find something that’s totally unfamiliar with little resource and support than you had anticipated. Of course, you could always peek into the source code, but wouldn’t that defeat the initial purpose of using a framework?

Here is a controller’s function in Echo, a popular framework on Github.

func hello() echo.HandlerFunc {
return func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!\n")
}
}

While you can easily serve your first web page and JSON by following its colorful guide, it suddenly becomes harder when you have to integrate it with other packages. Also, if you have a basic understanding of basic request-response HTTP architecture (which should be suffice to start working on a web app) the function does not look immediately clear to you how it works.

Let’s look at another very popular framework, Beego:

beego.Get("/",func(ctx *context.Context){
ctx.Output.Body([]byte("hello world"))
})

Does this look remotely simpler to you? Of course, the ease of being able to deal with URL routing and the handling it in one go seems tempting, but that is not something you want to do anyway. URL routing should be decoupled from the controllers as such it is possible to swap and replace them easily.

Ironically, all frameworks tend to advertise with something along the line of “simple”, “fast”, “unfancy”, and “powerful”, because they appeal to Go’s users. But the fact is they are not simple and unfancy. When an augmentation to something seems out of place and counter-intuitive, it is usually a sign that the thing alone is already fine and needs no further simplification.

Everything should be made as simple as possible, but not simpler.
 — Albert Einstein

Checklist for (Not) Using a Framework

Frameworks are especially tempting for newcomers considering most of the time they have a task and/or requirements to work on and not just an interest and time to invest in Go. Here is a simple checklist for you to run down before you consider using a framework:

  • You understand interfaces in Go thoroughly like @rob_pike does.
  • You understand context thoroughly or want to deal with it instead of responses and requests.
  • You intend to build a simple REST web service which might only handle JSON tasks of which a framework makes simple.
  • You work alone or it is unlikely someone will work on your code in the future.
  • You do not often consult online docs and resources when programming.
  • You do not intend to use other packages outside of a framework’s functionalities.

If most of your answers are false, then

Stick to the bare metal until you don’t have to.

At the very least, you will be forced to learn how to write idiomatic Go and learning how to employ interfaces to facilitate repetitive tasks.


If you find this useful, a click or two to ❤ this post or ✪ my latest github projects can go a long, long way for me. Thanks!

Show your support

Clapping shows how much you appreciated Joe Chasinga’s story.