Why I no longer use MVC frameworks
ebpml.org
ebpml.org
As a bonus, the article discounts React out of hand as one of those "average MVC frameworks" that does too much, then reinvents an incredibly crude version of hand-rolled JS components rendering DOM...the one thing React does.
The takeaway from the article, I think, should be:
1. If you only need some simple React components being fed by a basic Sinatra or Express server, just do that; it'll be ten times easier to develop and maintain. (Edit: Although frankly, the example is so simple I think the author might be better off with a static site generator...)
And:
2. Do your research before reinventing the wheel badly.
I work in a Flask and Jinja shop, so it's not really fair for me to pass judgement one way or another without having actually spent a month using this style. I just can't help preferring the Jinja method of templates that are mostly HTML with some templating code mixed in, vs. executable code that happens to be mostly concatenated strings of HTML.
Drupal 8 still does this. Look at the core modules help functions as an example if you don't beleive it.
> This article has kind of occam's razored me, because I can't
> actually tell if the author is serious.
Let me introduce you to my good friend: https://en.wikipedia.org/wiki/Poe%27s_law(I actually didn't read the article yet, but that's what it sounds like you mean here)
> I know, it sounds like one of these “duh! moments”, but I can’t think of an instance where I saw this pattern explained in some article.
The comment section was pretty quick to point out the article that the author couldn't find. I mean, some readers are pushing back because they legitimately disagree, but I was more so confused because React already does this. And it's somewhat well documented. Though the author coming to a similar conclusion by himself is praise worthy.The first time I started using Django, I was really confused and everything seemed incredibly bloated and complicated. Flask seemed much more attractive -- but as soon as I had a Flask project started to grow a moderate number of features, Django looked better and better. For simple projects, the modest gains from using Django's features don't seem to justify the extra boilerplate and conceptual complexity.
I know someone who insists that assembly language is where beginners should start.
The common thread: It's hard to start working at a high level of abstraction, because understanding the lower level of abstraction first is what gives you the grounding for appreciating exactly what the higher level abstraction does and why you want it to be done.
I think the author of this article is at a point in his web dev learning where working at a low level of abstraction is easier. When he gets to larger, more complicated projects, he'll probably end up writing his own half-baked home-rolled MVC, or having a project implode under the weight of its own spaghetti architecture. Then he'll start to see the advantages of using a framework.
Nothing negative is implied by going down this path -- it provides valuable learning experience and an intuition for what the internals of a good framework do without even using the framework (since you've experienced first-hand things that seem like they would be common pain points and how they're dealt with at the lower level, you'll (often correctly) suspect that standard higher-level tools might have ways to help people deal with those pain points.)
Yes, yes, I know, separating data from code, filters, escape sanitization, there are a lot of good reasons to use templates. If you're a developer just starting out in web design who is creating a very simple project, string concatenation will let you get up and running without the extra complexity.
Of course when your project gets big enough, you'll start to try to modularize things, and then when someone spends 5 minutes explaining templates to the idea, you can immediately see why you want them, because at that point they'll actually reduce the complexity of your project.
https://facebook.github.io/react/blog/2015/10/07/react-v0.14...
He could just change few lines and have JSX, React state management, contexts, property type and all that other stuff available if he ever needs it.
With his own solution he'd eventually need to re-implement bits of React.
Yes. And in React composition is not done through string concatenation and values are escaped by default.
I'm not sure about mercury and others but React is first framework I've seen, and I've seen few, that does the composition (from the point of view of react user) exactly the way I'd do it. I had my own framework in PHP (before Rails happened) that did something similar. My components were server side could be composed freely and bundled not just html and js, but also php, css, images ... and could be extended in a way that allowed derived component to override inherited css, images, html, whatever. Flow of information was accidentally unidirectional (thanks to how HTTP works). But the important thing was idea of freely composable components (instead of pages, resources, views, templates, layouts or whatever)
When it comes to pure old MVC, I feel that it is a bit like Greenspun's tenth rule:
> Any sufficiently complicated C or Fortran program contains an ad hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.
So any UI environment will eventually contain an architecture that more or less embodies the spirit of MVC.
And I think MVC is fine within a single environment. That means, the information travelling from the models to the controllers to the views does not contain intermediary where mediums are crossed. A traditional Rails application crosses from databases to a Ruby program to a web browser, and each bit of logic is dependent of the others.
What makes the backend/frontend separation such a good model is that a front running on a REST API is not inherently dependent on a protocol or a server implementation, and the same applies to the backend. This will work in the post-HTTP world, whenever that comes.
Traditional Rails apps assume they are talking to a web browser. This is assumption is no longer tenable.
sufficiently complicatedComplexity does not grow in all areas. You could have a 3D MMO which is more complex than 99.9% of websites without routing for example. Static HTML can include 100MB of JavaScript that simulates something.
The comment here about the point of MVC frameworks being for communication is true. However, this guy isn't working on a frontend dev team. He is a consultant doing primarily server-side development, building a landing page for his business. The code he wrote in this entry probably took him all of about 15 minutes. Meanwhile, many of the comments here say that he should've used Jade, or Angular, or Knockout, or Flask, or Jinja. How long would it take him to get up-to-speed on that? That's time he doesn't get back, which won't be spent working on the things that make money for him.
I wrote a similar build script to try out different landing page concepts - in about an hour, I'd wired up Babel, PreCSS, and Marky-Markdown so I could write all my marketing text & tutorials in Markdown, my CSS in CSSNext, and have a common page layout for everything. It's a lot cheaper than the MVP generators on the net, it's easier to change and gives me more flexibility than Bootstrap, and it's a lot less code than writing everything from scratch in HTML. No, it bears no resemblance to any living framework, and no, it's probably not intelligible or sane to any other frontend developer. However, it doesn't have to be. If I get to the point where I'm hiring frontend devs, they'll be rewriting everything anyway in the framework of their choice, so my opinion doesn't matter anyways, and in the meantime, the landing page and product description helped me discover that I didn't need a frontend component at all, at least for an initial version.
Optimize for the problem you have, not for the problem other people have. And when other people come up with a solution that's different from what you would've done, try to see how their problem differs rather than saying they're stupid.
I disagree; I don't think there's a lot of "hate" just some gentle mockery.
> What he did isn't insane. It's not exactly what I would've done, but then, the meta-lesson from this post is that you don't have to do what everyone else is doing.
The thing is, he did do exactly what everyone else is doing, just a bit worse than most of the popular solutions.
> And when other people come up with a solution that's different from what you would've done, try to see how their problem differs rather than saying they're stupid.
But his problem didn't differ. He had the same problem everyone else has, and ended up re-inventing the same solution everyone else is using.
If you're working on the web, you'll need to turn data into HTML, and his solution was a JS function to turn data into HTML; it's the single most common problem and the single most obvious solution pattern. The issue is that there are already good solutions for his exact problem, and his isn't one of them.
1. Spend an hour writing 50 lines of code.
2. Spend 3 hours identifying a framework that includes those 50 lines of code, reading the docs for it, finding exactly which call or combination of calls duplicates the functionality that you would've written yourself, writing code to that API, and then debugging where your mental model doesn't match the mental model of the framework authors.
Which of those is better?
I suspect most of the commenters here would say #2. My point is that the real answer is neither: it's "it depends". It depends upon who you're working with and what their background is; how long you expect the code to live; whether you expect to use additional functionality in the framework in the future; how well-documented the framework is; what fraction of the framework will be used in this solution; etc.
A lot of people, particularly more junior ones, look at an established framework like React and think "because it's supported by Facebook and thousands of people use it, of course you should too". I'm saying that it's not always that simple: sometimes it's appropriate, but sometimes, just rolling your own is fine too.
(My perception is colored because when I was at Google, I was frequently the one writing the software that everybody else assumed they should be using, and I was intimately familiar with all of the downsides and weaknesses of said software. I recall running into a post on servo-dev where someone proposed using the Gumbo HTML parser, which I wrote, for Servo's HTML parser. pcwalton's reply was "Just because Google released it doesn't mean that it's suitable for our purposes" - which is exactly correct, Gumbo was never meant to function as a browser engine.)
It's easy to get involved in the ratrace of using the whole shebang for your projects, how big or small these projects may be. I've used some frameworks in the past, but I eventually found out they added more distraction, took forever to learn and they crippled my flexibility. Good old HTML, CSS, PHP (I'm very afraid of saying this here out loud), Javascript and XML worked for me. And programming without a framework was more fun, like a completely blank canvas that makes it very clear that you are the one who has to do it.
If he really wanted to build a nice looking web template solely with front end technologies, he could build it with Jade for the HTML part, Sass for the CSS, and JS/TS/Babel for the behavior part and structure the template in a modular and component-based fashion for reusability, maintainability, scalability, customizability, and above all sanity.
If you're looking to build a web app instead, just pick any framework you feel comfortable and your future self will thank you for that decision as the web gets bigger and bigger, you'd still can keep it together and deliver good results consistently.
Kind of an aside, but I think this might be that presentation:
Yes. That's called separating the Controller from the View. And pieces of HTML with dynamic parameters are just templates (like Mustache and such).
I think you just wrote your own (M?)VC framework, with your own templating language.
The thing that makes it more baffling is that HTTP and HTML are so simple on their own. Almost all these abstractions being built on top of them are vastly harder to understand then the things they attempt to abstract away in the first place.
MVC frameworks took off because they allowed more than one person to reason about an application. I can hire an Angular developer and expect them to have a fair understanding of my application on day 1. If I'm new to a React shop, I can read tons of documentation online, without pestering my new coworkers. My Product Management team likes to change stuff on the fly, so I can use Knockout to build small, independent components which I can piece together like lego.
I don't know why this post irked me so much, but it did.
Also, what happens when you inevitably change jobs 3 years later? "I have 3 years experience with Bob's folder structure." Yeah, that's time in the trash where yes, you learned something, but no, you can't really show value to potential companies.
Once you get to the interview and they want to look at the code from a project, then sure, it will help a lot - assuming you created it.
One reason I like Flask over Django: You can do MVC if you want to, but aren't forced to.
Fully populating a restaurant model and sending it along to a view is costly. A user's requested parameters may not have needed the menu, for example.
That's just scratching the surface of the problem. Okay, let's say I create a model called restaurant that's actually a Python class, where menu and photos are fetched only when called. That's fine and dandy, but now, what if the user's request actually needs to render 10 menus, and it so happens that the API cost of getting N menus doesn't linearly scale? For example, what if I could fetch all those menus in 1 API call and spend only $X? Now all of a sudden our abstracted Python class is terrible at minimizing costs, because it will make a separate call for each restaurant object.
Now add in silly time-based rate limits. Photos API allows upto an average of 10 requests/second in a continuously-moving time window of 5 minutes, while menus API allows 50K requests per day, resetting midnight in Pacific time for American restaurants, and another menus API allows 20K requests per day, resetting midnight in Chinese time for restaurants in China. However, you have nearly unlimited requests for the American menus API if the user has used some login method that gives you a user-specific access token instead your application access token. Oh, and the API that provides Chinese menus doesn't support asking for multiple menus in one call. Also, since you have access limits, you choose to not provide menus for less important anonymous user requests, based on some importance criteria, in order to best serve the users that are most likely to stick. You now have a real mess of a framework.
In general, MVC breaks very easily for practical purposes when you're not in charge of the database, and the people owning the data have business motives and arbitrary access restrictions.
If you own all the data and it's in a nice little MySQL database on your own servers, then sure, slap an ORM on it and go MVC as far as you can, I totally agree.
Lazy evaluation will help to some degree, as will caching data locally once you've retrieved it.
Extending your ORM to invoke third party pay-per-view APIs is obviously the wrong way to solve this problem. That does not mean that MVC or ORM are obviously the wrong way to solve this problem.
MVC will help you with the stuff that it is suited to, as will ORM. Neither are suited to optimising usage of expensive pay-per-view APIs. You need to build the API interaction part separately, and arrange for the MVC side of things to work with thst API-using-API.
Off the cuff, why not have a batching task that takes requests from the last fraction of a second and sends them off to each provider? How long can you stretch that fraction of a second without upsetting you customers? Are they willing to wait three seconds? If you get a dozen requests per minute, three seconds might halve your API bills.
As you said, MVC breaks when you do not control the data. So your job is to get the data into a form and place that you control.
...but what does this have to do with MVC? You're entire argument comes down to "sometimes you need to have some smart models to deal with external APIs". Well...yeah?
https://github.com/ciscoheat/mithril-hx/wiki/Rediscovering-M... https://heim.ifi.uio.no/~trygver/2007/MVC_Originals.pdf
Django's web framework is URL routing plus views, which may use the template engine if they want to. There is also an ORM which is separate from the Web framework and other tools.
> Django (/ˈdʒæŋɡoʊ/ jang-goh)[4] is a free and open source web application framework, written in Python, which follows the model–view–controller (MVC) architectural pattern.[5][6]
And realistically it has models, views, and controllers; it's at least as "MVC" as most frameworks we label that, and more than many. If Django isn't MVC, what is?
Being that, the original conception of MVC was for the user's mental model, not the programmer's mental model.
There are many reasonable ways to split up responsibilities. I know this because many different usable frameworks split up responsibilities differently (although many of them all call themselves "MVC" regardless of the differences).
There is no interchangeable "standard" for that for the same reason there is no "standard" for almost anything in technology: different requirements, platforms, styles, projects, etc
And I wish that was truly the case. Sadly half of all HTML written is to support presentation.
So you render all this on the server, and then the client does what, or are is this only targeting static pages?
React does not have shadow DOM
That's not true as generally as you've phrased it. Rendering HTML on the server is very useful for certain kinds of sites, like blogs. It allows you to generate pages that can be cached and behave like static pages (with appropriate, static-like headers).
For one thing, HTML was originally designed for read-only publishing. User interaction was gradually added over time.
For another, if you expand the scope of HTML to entire widgets, it'll become an incredibly bloated language. At a certain point, it needs to be building blocks rather than a pre-built solution.
Why don't Legos come with cars and boats already built in the box? Because some people don't want a car or a boat, they want a plane.
You might get some pieces that lend themselves to a particular purpose (select box, blockquote, etc.), but the language is not highly opinionated about what you do with them.
The Model can be generated from db schema or vice versa. You don't need to know SQL. The Model informs the ORM (Object Relational Mapper) how to create/read/update/delete (CRUD) your objects to/from the database. The model also validates your data for you. The field is 255 wide? Then 256 chars throws validation exceptions automatically, and so on.
The view is generated by reusable components on the server. Small reusable components ultimately assemble into a full page. Hundreds of components that do everything imaginable exist already.
With no code at all, they Controller wires them together using the Direct to Web (D2W) rule system. In fact, if all you want is an admin interface to do CRUD type operations on your database, you won't need anything beyond the hello world D2W application. These rules allow you to make sweeping changes throughout your entire application. Want to change every component that handles text input in a form page? Create one rule:
100: task = 'edit' and attribute.className = 'java.lang.String' => componentName = "MyNewEditStringComponent" [Assignment]
Or override with other components as appropriate
105: task = 'edit' and attribute.className = 'java.lang.String' and session.user.isAdmin => componentName = 'AdminEditString' [Assignment]
WebObjects allows you to maintain a level of state that no other web based MVC can match. You can nest your tables of data as deep as you like, paginating and sorting any of them at every level. No other web framework can do this. Period.
You only need to learn WebObjects to be full stack.
I have yet to see a JS/* framework that allows me as a full-stack developer to deliver the same content experience (sans interactiveness of course) to clients with or without JS, without having to duplicate templating logic or switch to NodeJS which requires a) a host supporting it, which many "mainstream hosters" don't and b) having to code a server in javascript's callback/promise hell.
Your second point is a tautology. Of course it's impossible to run JS code on the server if you don't want to run JS code and the server and don't want to rewrite it in another language. FWIW, both ES5/6 as well as coffeescript vastly improve 'callback hell'
> b) having to code a server in javascript's callback/promise hell.
Don't really see promises as hell, but with latest versions of Node and this neat little library called co, you can write your async code like this:
function doAsyncOne() {} // returns promise
function doAsyncTwo() {} // returns promise
co(function*() {
try {
let [resultOne, resultTwo] = yield [doAsyncOne(), doAsyncTwo()];
}
catch(e) {
// one of the promises rejected, handle it
}
});
Generators as coroutines are the poor man's async/await.(In fact, you could probably leverage React's server side rendering and JSX to clean up that long chain of function calls in your page function.)
As projects have scaled up and teams grown the lack of formalised framework, combined with the amount of logic-y stuff people apparently LOVE to throw into the templates, has eventually required a rebuild to try to get some structure in there.
Let's take some strings and hardcode them into JS and make the user's browser render this page dynamically every time it's loaded instead of WRITING SOME STATIC HTML... It's all well and good to try a new way of doing things but writing a blog post decrying MVC frameworks for a static site that you're building dynamically with javascript is silly.
It seems to really unnecessarily break any sort of distinction between presentation and content. For example what is the practical reason for using class "white-text" on a text span instead of an inline style?
React is not an MVC framework also, and it could actually make things much easier for this particular job.
If you don't need MVC or frameworks then don't use them, you'll be happy they are available when you need them ;).
I can't stand when people end declarative sentences with question marks. Never again.
That collection is called a framework...