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.
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
- Understand the idea of MVC.
- Your
http.Handler
s are your controllers, make sure they only do things controllers do according to above. - 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. - 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
.
Top comments (8)
Your description of the controller is actually very much more like the description of the "presenter" in MVP.
It's a subject with quite a lot of conflicting information, but this is how I recall it from the 2000s.
The presenter gets info from the model, then serves it to the View. The view has (as you say) no idea who the model is, to ensure decoupling. It does however know how to send inputs back to the presenter.
In traditional MVC, the view DOES know the model and DOES receive data from it directly. The view comes first, so to say and displays the data. UI events on the view will then call the controller who manages these inputs and calls the model as appropriate.
I assume there is quite a confusion with the terms
MVC
going on:Rails
framework (which is referenced here), where yourControllers
(or oftentimes calledendpoints
- although this term has a history of itselves) are where your requests are routed to (from the front controller), and which -the term as well as the architecture - was adopted by most of the frameworks after thatI would not say that the classical one is the correct one, but that one has to clarify what is meant. And comparing what is referenced in a conversation to one of the other meanings might not always be helpful.
I have the opinion that as long as nothing is wrong with a definition, we shouldn't change it.
There was nothing wrong with MVC; it was just different than MVP, yet we inject the meaning of MVP into MVC and call that the new meaning of MVC. All that while the original meaning of MVC is now lost and now both things mean the same thing.
Also that last sentence is kind of eye opening, because it implies that as long as I reference something, even when everyone else has a different definition in their heads, my definition trumps theirs...
Basically we change defitinions of things we misunderstood because that is easier than solving our cognitive dissonance internally
Some ideas can be taken from Iris too, github.com/kataras/iris/wiki/mvc. Source: github.com/kataras/iris/blob/maste...
Well MVC doesnt necessitate any kind of framework
Also... florinpatan.ro/2016/10/why-you-sho...
Also dev.to/chromadream/comment/b8o2
Great post!
How would you apply the same principles to a framework like Express?
I dont think Express is too frameworky in this respect, it doesn't really tell you how to architect your application.
Have your handlers... handle. They are your controllers. :) Delegate business logic elsewhere. Handlebars for views I guess?