Chris James - Software Engineer and other things

Go back to basics with MVC

25 July 2019

This is another follow up post to an episode of Go time I listened to the other day which seems to get my creative juices flowing.

It talked about web development in Go and a few things stuck out to me

A cautionary tale of generating HTML

Early on in the episode it was described how the built-in template library wasn't very expressive and described that the Go Buffalo framework uses Plush

Powerful, flexible, and extendable, Plush is there to make writing your templates that much easier.

Enter Jade

8ish years ago I worked on a pretty major project which was written in Scala. We decided to use the Jade template engine to generate our HTML which, like Plush allows you to do a lot of clever coding inside your templates.

This felt amazing at first but quickly became a nightmare. With the flexibility Jade gave us we made a bit of a mess. Our templates became ugly, hard to understand and difficult to test as more and more business logic leaked into our templates

In software I often see flexibility as rope that a team can hang itself with and I tend to prefer very opinionated and constrained things (like Go!).

What did we learn?

Software engineers are doomed to relearn things. We had forgotten about separation of concerns, in particular the guidance the Model-View-Controller design pattern prescribes.

MVC

It's quite surprising how badly people misunderstand MVC. If you go on Reddit or Twitter you will hear people telling other developers that "MVC isn't suited to Go".

Often people seem to think MVC is about folder structures, class names, or other fairly superficial concerns. So when developers from say a Rails background show their Go code with an array of folders they get derided and thrown to the lions.

MVC does not prescribe folder structure and I worry a lot of people seem to miss the point of the principle.

Model–View–Controller (usually known as MVC) is an architectural pattern commonly used for developing user interfaces that divides an application into three interconnected parts.

Controller

Intercepts "requests" (such as HTTP), parses them and then calls the appropriate "Model", getting some kind of data as a result and then sends it to a "View". In the Go world, that's usually a http.Handler

Model

Loosely, it's where your domain logic lives. I personally think it's quite poorly named but the important thing is the separation of concern. It must be decoupled from the Controller and View, so if you see anything HTTP related passed through from the controller it's likely you're violating that decoupling. They should also know nothing about views.

View

It doesn't know anything about controllers or models. It should probably get passed to it some kind of ViewModel which is just a collection of data it needs to render a view. A well designed view is simple and doesnt have domain logic; because templates are very hard to test cheaply.

What do these principles buy you?

Your domain code is cleanly separated from the rest of the system so it is easy to test and can be "plugged in" to different uses beyond your web server; for example a CLI tool, or just as a package for others to use.

It is trivial to create and edit views as they are merely mappings from a bundle of generic data into HTML (or whatever). It also makes them more accessible for frontend developers et al.

Your controller has clear concerns and are also easy to test.

Circling back to the start, I would be very cautious about something that allows me to write very expressive code for my view. These kind of tools trick developers with promises of convenience and power but often lead to leaky abstractions unless you are very disciplined.

Now have a think about all the tutorials you may have read around HTTP servers and Go. The good ones will recommended all of these principles without perhaps just calling them out. Rather than the community dancing around the idea of MVC, just embrace it. It's a tried and tested pattern and most people advocate it anyway, just not explicitly. If we were explicit then maybe there wouldn't be a new post every week about how to structure a HTTP server!

How to structure your web app

  1. Understand the idea of MVC.
  2. Your http.Handlers are your controllers, make sure they only do things controllers do according to above.
  3. All your other business logic (Model) lives elsewhere, in packages centered around real things. If it's a bank i'd maybe have packages for Account, Currency, Customer e.t.c. Your controller will call things in your packages to do useful stuff.
  4. Depending on what you're building you can just use the encoding packages to spit out XML or JSON, or if it's HTML just use template/html.