Looking into the Flask web framework for python I discover some bewildering code that makes me reflect about patterns. I find the focus on design patterns insalubrious to a healthy code base, and explain why I think so, using the Model View Controller Pattern (MVC) as an example. I see this linguistic code pollution as the main source of bad code.
Flask used to be my favorite web framework for a while now, because it allows you to create web apps without much noise, much like Sinatra does in ruby, but in the last couple of days my heart has started drowning in doubt. It appears that flask just hides the ugly away by wearing too much makeup. On the surface there are a couple of kawaii-esque decorators; yet if you look closely, you will start to notice how the application in the background consists of a massive 2000loc file that just does too much and has no clear separation of concepts and concerns. The testability is crappy, since a lot of stuff is being imported from the main module. This in itself isn't too bad, but the problem is that many aspects of the application are imported to be global, partially mutable state, that can't be injected from the outside. This significantly reduces readability, and creating or requesting app contexts in the tests is tedious, noisy and error prone - just what you hope not to receive when you settle for Flask. I should have listened to the signs a while ago. What buggs me most right now is this:
Before I explain why, let's step away from Flask itself for a minute, because I really still love flask and don't want to make this article a flask bashing. In fact, this very simple website is built with Flask. But to me, there is another very fundamental problem in the way: Patterns.
Patterns, as is often claimed, are ment to communicate with other people. In my experience they only show up as a replacement for a conversation. They lead people to consent on very implicit definitions of what something is or what it should do. These definitions become the assumptions of the people working with the code and in fact create a hidden profile (make sure to have a look at the sources).
In the document, they describe the "views". This is another very good example of how simple patterns might be misunderstood, rendering those patterns not so simple after all. Of course they are just patterns and effectively you can invent your own and call your stuff whatever you like to call it, but then at least don't leak the pattern names into your code or your docs.
MVC? More like WTF
Let's reconsider for example MVC. It starts out with the M - the model. The funny thing is, that with MVC the application never starts with M, but with C - the Controller (except for when you use something crazy like ASP.NET Derp-Forms, where everything starts with a view). The routing mechanism is fired up by the webserver and receives input, that is a requested resource's path. Depending on that path the MVC framework will decide which controller handles the whole thing (i.e. 'routing'), pass it to the controller method. The controller will invoke the model and the model will help to generate and populate the view. The view is then returned.
There are many parts where understanding this can go wrong, the first part being that this should actually be CMV and not MVC to account for the order of calls. In old java diagrams the arrows tend to point in both directions between the boxes indicating the components, but for most applications the data flow is quite normally the same - The controller is invoked by a request. The controller then invokes the model and handles it all the data it received. It already did some routing at this point, as it interpreted the path of the request. It then handles all the posted form data or request parameters. Therefore, as Martin Fowler agrees, it should actually be called the input controller :
The presentation part of MVC is made of the two remaining elements: view and controller. The controller's job is to take the user's input and figure out what to do with it.
Just to add more confusion, browsing Martin Fowlers patterns yields more distinctive controller patterns, for example:
- Page Controller : The input controller is a static html page. The routing is done without a central module but by handling resources as the webserver intended.
- Front Controller : Requests are channeled through a single handler. In my mind this is what the ASP.NET MVC Framework does, where it is vaguely named a "pipeline". There you can register functions for marshalling, internationalization and security.
- Supervising Controller : Let the controller do as little as possible.
Also note that a controller and a presenter might or might not be the same thing ...
So there you go. The term controller doesn't say anything and is therefore a weasel word . Without further differentiation the intention and shape of a controller won't become clear. The details vary depending on where it sits, when it is called and what it really does. None of these aspects can actually be infered from the term controller. Therefore I would like to promote calling controllers "input controllers", as far as they are the thing that...
- is a class
- comes after routing is done
- handles input data
- has no logic other than invoking the model
- and returns a view
Model != Data Model
This distinction might sound arbitrary, but bear with me - I have seen a lot of people mistake a controller for the thing that "controlls" the application and therefore should make decisions about what goes where; thus putting tons of conditional logic in it, but I'd argue that the controller is an input controller and should only decide on what path input arrives, what calculations are done and what view gets returned, none of which is really a conditional thing.
The actual logic - deciding whether a user is logged in, checking the sorting order of returned lists, generating news articles, and so on, are all handled in the parts that are called the model. Here the most amazing fallacy appears to come from: for most people the term model is a synonym for data model, thus being some form of direct representation of the data in a (relational) database.
I would like to put forward that a model is not only a declaration of or schema for a certain structure, but that a valid model also contains operations and processes. All things that are conditional are therefore parts of the processes within that model. "Model" appears to be a synonym for data model, therefore often controllers have a direct dependency on repository classes and already start to deal with data filtering, cleaning and retrieving rows and columns, projecting and selecting data from a database - thus rendering the controller a part of the business or logic layer instead of as a part of the overall model.
The distinction between models often includes qualifiers as Domain Model or Anemic Domain Model (a data model). On its own, the term doesn't say much. And no, the DDD book didn't help to make this better.
Views - See for yourself
What is left are the views. These can hardly be mistaken for something else, right? Wrong. The views in my mind should be the XAML or HTML or AWT frames that are being returned, display the data that the controller decided they should publish; but often they are mistaken for viewmodel classes or, as for the hook of this rant, for controller functions. Have a look at the url that I posted above . In the example it states:
Now that the database connections are working we can start writing the view functions.
But the first method already shows what's wrong with the whole conception:
@app.route('/') def show_entries(): db = get_db() cur = db.execute('''select title, text from entries order by id desc''') entries = cur.fetchall() return render_template('show_entries.html', entries=entries)
Here, the show_entries function is activated by the app.route decorator. This is essentially creating an entry for the routing table. Note that in python/flask there is no need to put this function into a controller class (it's a "first class citizen" function rather then a method on an object instance). Therefore I would argue, that this function is a controller function . In ASP.NET MVC they would be called Actions . There is no finer granularity in the pattern name, MVC does not say whether the controller is a function, a class or a module, as it is in this case. There is also no mention of the actions.
Here there is no object, as in python the module can house all sorts of things. Of course, it returns a view - which is probably why the authors claim that it is a view function. But this still is exactly what a controller does in MVC.
So, in the abbreviation MVC all three characters are lies . The model does not contain operations, the views are mistaken for controllers and the controllers contain logic. There are two ways to treat this situation. Since patterns are not handled scientifically - there appears to be rough concensus about the hows, but everybody can cook and claim their own - I should describe different points of view here.
If my conception of MVC is right:
- The authors got MVC wrong
- The views functions are controllers or actions
- The pattern is misinterpreted and not helpful to communicate intent or implementation
If the author's conception of MVC is right:
- I got MVC wrong
- So did Microsoft and many others
- The pattern is misinterpreted and not helpful to communicate intent
- The functions are views - then what is the template being returned in the end?
show_entries()is a view, then what, in your mind is
Patterns get in the way
My intention here is not to point out the bad code in Flask or a deficits in the pattern-knowledge of its authors. I love Flask and have a deep respect for the skills and contributions of the people behind it.
Yet this is a perfect example of how patterns can break, if they are forced into the conversation about code. Of course, nowhere on the site the authors claim that they are doing MVC, and might try to weasel out from the discussion - yet calling something a view should not be without consequence. It should mean the same thing to me as it does to anybody else. With patterns I often observe that people name things after what they think a pattern name means, without actually ever looking up the definitions. I have seen this with "Data Transfer Objects", "Data Access Layers", "Anti Corruption Layers" and the pervasive POCO.
The latter is the worst of all. It should mean "object without crazy database dependency, decorators or inheritance when dealing with an ORM or intersystemic calls", but for many people it means "Data Structure", which is a class without functions but a lot of public data. A struct-by-reference really. I am mostly amazed that this distinction (Object vs. Data Structure) never occurs in a discussion with people who claim to have read and understood Robert C. "Uncle Bob" Martins very nicely written book Clean Code . I am really frustrated about these naming decisions that many developers do. To me, the lack of attention to intent and the focus on patterns is what makes code hard to read.
What is the solution to this babylonian multiplication of the languages? I don't know. I usually start with what I might call language markers - that is putting tiny hints in my language, so that people may tumble from time to time when discussing these issues. If I say "Model-View-InputController", someone might ask me why I don't just call it "a controller". This is usually where good conversations start with fellow developers. Conversations like that, if held passionately and loudly, can empty whole taprooms full of normal people.
Let's think about more markers. For example, the Controller is the InputController, the Model should capture the business logic, and the views should be the thing that displays stuff. And since in software development we all can make stuff up, I could go over to call this the IDD pattern - input, domain, display. Or how about IIV ? For Input, Intent, View? Maybe I will just go with FYP-S , short for fuck your pattern, stupid. I will have to make sure to make a confusing acronym. Or hell, let's maybe call it a ServiceStrategyFactory , just to mess with people. It is a service, since a website provides a service, the functions on the controller are the individual strategies and it creates views (i.e. it renders html), so it's a factory. After all, noone can really define these, so here you go. The FFS Pattern.
I am sorry, I got carried away.
Although it might sound different, I don't see why my opinion should be absolute. I would just like to say that my definition of MVC is biased by my ASP.NET MVC Background and is as good as any other's. Still this renders patterns a poor decision to communicate about or within a codebase, because there are as many understandings of the patterns as there are devs on a project.
- Patterns are misleading
- Even simple patterns will be misinterpreted
- Neither are they good recipes nor is their emergence easily detectable (since their components are not easily defined)
- Object oriented patterns are exactly that: Concering Objects
- They don't solve anything
- Flask is ugly in the background and this misunderstanding of patterns, lack of consistency and arbitrary usage of terms might be some of the reasons why
- I still love flask
As you can see, there is no commenting function on this website. If you wish to contribute, please write me an email or message me via twitter. I will add what you wrote to the article manually. This tiny obstacle is there not to censor but to prevent spam and unnecessary trolling.