MVC frameworks aren't dinosaurs but sharks
david-dahan.com
david-dahan.com
When it's needed, fine.
But there are so many SPAs that just don't need to be. Rendering HTML server-side is just nice. It's simple and easy to work with. Weird states are unusual. The user gets a really normalized, predictable experience. And done well/quickly, there's little actual difference.
Maybe I'm just showing my age. This falls really close to my "I miss the old web" type sentiments. The last thing I built, and the next thing I will build, are purposely doing full page renders for any actions (no jQuery or React/SPA stuff). I don't think I'm going to have any javascript at all. It's really fun and lean. I don't know, it's just got me going lately--reminds me of when I was starting out.
My last project is 300 lines of python, 270 lines of php, html/css of course, postgresql, and cron. Some scrapers run, ingest data, and the php sorts and displays it.
The issue I have is we had a great idea to refresh parts of a page with AJAX and then we went overboard and tried to move the entire application to complex frameworks which add more problems then they solve. We became so scared of screen rendering we avoided at all costs. This is bad UX as users actually get good confirmation that something has happened when there is a screen refresh.
The solution in each of these cases is the same, though. To simplify the state.
In general, I think a lot of the pain in web development comes from attempting to have shared mutable state between backend and frontend. Shared mutable states are almost always messy. You can get around that by pushing it all to the frontend, or pushing it all to the backend. It's when it's straddling both you're in for a headache.
No, rendering html server-side is not nice and never was. Why on earth you will send markup template for every list item over and over again instead of sending just data and only one code-template (to render data on a client) ? Suppose you need to show to user a list of books on your web-page. Server side rendering means you need to send to user a markup consists of html elements for every book
<div> <div class="book"> <div class="book-title">Book 1</div> <div class="book-author">Author 1</div> <div class="book-description">..description..</div> </div> <div class="book"> <div class="book-title">Book 2</div> <div class="book-author">Author 1</div> <div class="book-description">..description..</div> </div> <div class="book"> <div class="book-title">Book 2</div> <div class="book-author">Author 2</div> <div class="book-description">..description..</div> </div> </div> ...
Don't you see something wrong with this? Why you need to duplicate over and over again html template for every list item resulting of significant increase of size of page to download if you can send only one template-component like this
<div> <div class="book"> <div class="book-title">{book.title}</div> <div class="book-author">{book.author}</div> <div class="book-description">{book.description}</div> </div> </div>
and a data in a more compact way
[{title: "Book 1", author: "Author 1", description: "..."}, {title: "Book 1", author: "Author 1", description: "..."}, ...]
or more compact like this
[["Book 1", "Author 1", "..."],["Book 1", "Author 1", "..."], ...]
or even in more compact binary-encoded format resulting in more than magnitude size compaction comparing to over-duplication html-approach. More size means more traffic for users to download over network and users which use data-roaming will "thank" you for your hundreds of kilobytes instead of dozens
This is why server-side rendering approach was flawed from the beginning (not because of page reloading but because of data duplication and traffic consumption)
but yeah, gzip or the more recent ones such as brotli have been taking care of those things for 25 years....
so HTML server-side has always been nice.
Especially semantic markup cough cough
Also I know there’s the promise of sharing code between the front and backend but the reality is that you’re probably more likely to reimplement one or the other and then have to keep them in sync.
The overhead for doing it just the once on the backend and sending compressed HTML over the wire is pretty low for a small team in comparison.
I see what you're saying, but I think server-side rendering is simpler, and the concern about repeated HTML tags in the content is likely much easier to address by using gzip over the wire.
Also, in your example, don't forget the code required to render that data, which is often a second fetch and is, you guessed it, utf-8 / ascii/ unicode. Now we've double startup costs or forced http/2.
There's some context with these opinions. I concur that rendering server-side is often much, much simpler, but acknowledge that might be because that was what came first; and I acknowledge that some of the hate against client-side is b/c modern web often feels bloated and JS takes the blame.
When doing frontend rendering you usually work against a REST(ful) API to fetch data, the idea is to reuse endpoints for multiple frontend components, because of this generalization you usually end up sending more data than necessary, not only between the database and the backend, but also between the backend and the frontend.
And not only that, you start doing JOINs over HTTP and JavaScript.
With server side rendering I can write an exact SQL query to render that component.
- to turn the JSON into HTML, you not only need the template you mentioned, you also need code to execute that template (potentially lots of it); preact is 10KB ungzipped (other frameworks, like React/Angular/Ember, are way larger), so your HTML solution is already 10,000 characters ahead (by comparison, the markup you demoed is ~90 bytes per book, so you’re ahead until at least ~100 books on the page, without considering the framework, your code, and the following points)
- HTML compresses amazingly well because it’s repetitive so the overhead is less than you think
- HTML stream renders, so you can start rendering the first book immediately; JSON streaming is technically possible, but not built-in, and quite difficult to implement (and it requires even more JS)
- the same KB of JS is way more expensive than it would be as HTML (or images) because parsing, compiling, and executing is slow
- latency is often a larger problem than bandwidth, especially on mobile, so saving bandwidth is less important than (a) streaming and (b) client-side blocking time
- a large number of users visit one page and bounce, for typical websites, so the promised savings once the SPA is live doesn’t materialize
- the naive way to implement a SPA is _full_ of footguns; first of all, you’d naively load the template for all the pages, making the overhead problem even worse, naively you wouldn’t render anything until the JS has arrived, delaying the TTFMP enormously, naively you’d mess up routing, etc.
- it’s relatively trivial to preload/precache HTML pages, including in a service worker to support offline, making performance on par or better than a SPA
I happily work on a huge SPA daily, for context.
- about SPA - in my comment I said no word about SPA, it's a more complex layer on top. I only arguing about template-data separation approach to decrease data duplication and traffic consumption. And no, you don't need to rewrite your app as SPA and no react/preact/javascript frameworks required. You can use your server-side rendering and just change format of what you are sending to user. Instead of sending index.html with repetitive html markup for every list item you can basically send script-tag where you loop over data and build html-markup directly on a client
<doctype html>
<html>
<body>
....
<div id="books"></div>
<script>
const data = [{title: "...", author: "...", description: ""}, {...}]
document.querySelector("#books").innerHtml = data.map(item=>`
<div class="book">
<div class="book-title">${item.title}</div>
<div class="book-author">${item.author}</div>
<div class="book-description">${item.description}</div>
</div>
`).join(``);
</script>
</body>
</html>Yes, it lacks http streaming but - less repetitive html markup -> smaller size -> less time to download -> http streaming becoming less useful
And again - you can use your favorite http compression (gzip, brotli, etc) on top of this template-data separation approach to compress even more
https://pastebin.com/8CM1eUKQ the HTML version https://pastebin.com/ujrai58n the templated version
Even I was surprised by the result. The original size is what you’d expect: 5.3K for the full HTML version, 2.4K for the JS template version. Once Brotlied (default compression) however, the situation changes completely: 127 bytes (!) for the pure HTML version and 197 bytes for the template version. This is even true for Gzip, 213 vs 284 bytes.
I don’t know if Brotli (and Gzip) are somehow optimized for HTML, but yeah it really doesn’t make sense to use templates here.
You have a point, but not everything needs to be black and white. We had this nifty technology called AJAX even before SPAs were a thing. Now I understand that SPAs are built on AJAX calls too, but it is also possible to render (most of the) HTML on the server side and only use AJAX using off-the-shelf components such as Datatables when you absolutely need that functionality.
Also, is it really easier to everything on the server? I don't think it is so by definition. You could argue that a stateless REST API with client-side state management is less complex than doing everything server-side. It's a much more scalable solution and creating interactive user interfaces is very easy.
Ofcourse it could be that interactive user interfaces is not something you are aiming for. That's fine. But do understand that most applications are actually usually very interactive.
Almost all applications that are written in the world today are glorified forms.
That's reality because 95% of apps are written for the business world. Most don't really do much apart from take some form data, apply business logic to it and show the results/send some messages.
Even most consumer apps like Facebook/Twitter/TikTok/Pintrest/etc. are basically glorified forms.
You can do save/load state all in nanoseconds, any competent programmer can easily aim for 50ms page loads, well under human detection.
This is incredibly basic stuff and how it was done for decades before SPAs.
Writing a stateful front-end that just asks for what it needs from a well-built API when it needs it is enormously simpler than trying to store all state in some server session and having to work around your own framework whenever you need a dynamic dropdown list.
We all seem to have collectively forgotten how awful web frameworks used to be, and how little interactivity the user actually expected. Things are way better now.
It's also possible to store ViewState "on the server side" instead of on the client side. So instead of sending megabytes up and down with every request, the client just gets a unique identifier. The downside is increased memory usage, but that's often better, especially for internal enterprise apps.
Yes, you would need multiple pages. But that is how most form-based SPAs work today anyway, and avoiding a page reload isn't always preferrable to just reloading if the SPA version requires heavy amounts of JS and the good-old-static version loads in the blink of an eye.
Yeah, but our users like interactive forms. When a widget is changed, they like feedback instantly.
Just about any shop that reloads the entire page when you change a single filter gets annoying pretty fast.
Imagine an online computer store: tick the box for "16GB RAM", wait for page to reload, tick "32GB RAM", wait for page reload, tick "512GB SSD", wait for page reload, tick "1TB", wait for page reload.
Now you may argue you still have to wait if it is an SPA, but then you're only waiting for the results. You can quickly tick all four boxes in an SPA and each one may cause a background request, but that doesn't matter because you don't have to wait for each request to complete to make your next selection.
Tick all the boxes and then click "Apply filter".
>
> Tick all the boxes and then click "Apply filter".
Many places do that, but it's not as user-friendly as not having to click "apply". If there's a large number of filters (Buying a computer on Amazon, for example), the "apply" button is off-screen most of the time - scroll to either the last filter or the first one to even know that there is an "apply" button.
Also, some fields do not work too well by having a separate "apply" filter step. You drop-down the manufacturer selection, choose "Lenovo", click apply and now there is a new drop-down for "Model".
The better experience is one where both those drop-downs exist, and second one is populated only after a choice is made on the first one. In all the pages I've seen that have drop-down #2 dependent on drop-down #1, those that got a JSON list via AJAX were much more pleasant to use than those that reloaded the entire screen just to add 5 items to the drop-down #2.
As the creator of the software, it's more important to have happy users than have an easier maintenance burden.
Doesn't that still reload the entire page when a checkbox is clicked?
maybe 50ms is under the "conscious detection" threshold (debateable, IMO...) but it will definitely feels "laggy"
Example:
I have an application where a form input expects an URL. As soon as any URL is entered, I need to:
1) Provide feedback on wether that's a valid URL or not, before the user submits the form
2) Show a suggestion for a page title, which is usually the <head> title extracted from that URL. If the user clicks on the suggestion, that should become the value of the next input in the form.
Other than this, this is a pretty basic form. But how do you give a decent experience without JavaScript?
Right, a bit of jQuery would do it in this case... but then more and more similar small tweaks are necessary, and before you realise you're swimming in spaghetti.
I can't make that logical jump. If you can't keep that tiny bit of code organized, why do you want to pile on the entirety of react and why would that be more organized?
Maybe you're saying it's a snowball of these things. I've seen that happen, but it didn't have to.
But, the worst part in my experience, is that without one of these "opinionated" frameworks such as React or Vue, each new developer that joins the team (after others leave) have a total different idea of how to organize the code, or they have a hard time understanding the "custom" organization and ideology behind the structure you've had to invent to keep in maintainable.
Again, I'm not a fan at all of frontend heavy frameworks, but they do solve a real problem, specially in large apps and large teams or teams with a lot of turnover.
I'd say it is the exact situation in the backend regarding using Flask vs Django, Sinatra vs Rails, etc... having a set of imposed opinions and structure have long term benefits as soon as you're not the only one working on the codebase.
In my experience with hiring, the only reason it has become easier to move a lot of logic and state to the frontend is because frontend developers are plentiful and easier to hire. I'm not dissing them: it's very easy to find great frontend devs that know their tools inside-out and also know the fundamentals of software engineering.
On the other hand, good backend developers are becoming rarer and rarer, and most of the new breed struggles to do virtually anything beyond a cookie-cutter REST API. Very few are knowledgeable about databases, for example. Very few know about deployment. Some of them aren't even familiar with HTTP as a protocol. Any backend dev that I interview that is as knowledgeable about their niche as the frontend devs I interview often gets two or three other offers and we have to raise offers very very often.
I'm pretty sure there's lots of great backend engineers who could do SSR like we did back in 1990-2010 with one hand behind their backs. But there just isn't enough of those. Most of the ones you see will have no idea how to deal with it.
On the other hand... maybe not, for more conservative industries? You don't need a full-blown frontend team to be very productive. A great frontend engineer (easy to find) and a cookie-cutter backend code-monkey (also easy to find) working together and getting paid 1x each are probably as productive as a great backend engineer you're thinking of paying 2x.
But the thing is that the 2x will bring some extra experience, less bugs... but that's not what companies are after.
So yep you have a point.
OTOH, for stuff like Facebook they absolutely prefer the interactive interface.
In fact, I don't know anyone that doesn't.
It has also been forgotten that people used to complain about 100ms of latency. Since then, modern users (especially mobile) have been trained to accept horrible latencies that would have gotten you excoriated back in 2000.
100ms of latency is MUCH more difficult to deal with server side than 2-3 seconds of latency. 2-3 seconds is an eternity with modern clouds and modern network connections.
These older frameworks have been honed to a razors edge for producing hypermedia (HTML) server side and delivering it to clients efficiently. As people begin to realize just how much you can achieve with this approach (and the simplicity it brings back to web development) I expect interest in these frameworks to soar.
Bullish on 2005 tech books!
For applications its hard to see why this model wouldn't be more preferential. Most .NET applications are monolithic in nature (though you can enforce really good module separation with relatively minimal effort IME). You can look at Rust too, for its developing some Blazor-like frameworks. I could imagine for example, the next GMail being written like this, or other deeply interactive applications.
I think people want to work in a singular language / framework more than anything else. One of the reasons I think JavaScript still prevails today, is it was the first language community to largely achieve this in an accessible manner. Others are now coming forward.
I think pre-rendering is still the best approach to truly static content though, using web components to progressively enhance features of a page for light interactivity, this is one area they really shine.
I could be very wrong though!
Isn't that just "GWT-like"?
In practice though, its also flexibility. GWT shoehorned you to do certain things a certain way and only that way, where as Blazor only limits you based on what calls and modules can be safely converted to run against the WASM driven runtime. Which means you aren't limited to a specific list of ways to solve a problem, its more (and increasingly so) flexible than that. So for instance, GWT has specific widgets[0] that you should use to represent the use interface, Blazor doesn't limit you to just Blazor compatible widgets (there are some though, because at some point the abstraction runs out of juice). You can use regular conventions and classes too, like the normal .NET HTTP client stack, regular data classes etc. You can also re-use Razor components, most of the time.
To be clear though, Blazor isn't a panacea, it has its own caveats and downsides, however I think its really innovative in terms of concept and execution. For anything behind a login its a pretty sensible choice IMO. I wouldn't go making your marketing / info / purely static pages with it though. server side rendering or pre-rendering is a much better choice there.
Also worth mentioning, on top of all that, is Blazor can cross compile to native applications too, like iOS and Android, with (largely) the same codebase.
[0]: https://www.gwtproject.org/doc/latest/DevGuideUiWidgets.html
1. As you described, compile C# to WASM, download a blob and run client side
2. Run the C# server side, send the client a thin page and a SignalR pipe back up to the server
With 2 it's more like react SSR (as in the mode where react components run on the server, not SSG where they run on the server and just emit static HTML). When i looked through the docs, 2 was the primary mode for now.The benefits claimed were you don't need a modern browser, i think the thin shell + signalR combo works gracefully back as far as IE9 or something silly, also you don't need much processing power on the client because the signalR pipe is just a conduit for pre-rendered HTML generated by a blazor component running server side.
The down side is that for every client, there's a websocket (or long polling connection) for every client to the server.
If you setup the compiler with trimming enabled[0] it gets significantly smaller. You can also lazy load assemblies by route[1] to further restrict the upfront cost.
Of course, this is not acceptable for the average web page by any means. This is really intended for behind the login type applications where you load up the initial runtime once and its cached heavily for the rest of the applications lifecycle by the user. This is really targeted at true applications-in-the-browser type situations.
Blazor server side works too, though everything then has to run via a SignalR connection and can be a bit more flaky at scale.
Runtime performance however, I actually don't find it to be a bottleneck. The apps I've built with Blazor are pretty fast. I haven't worked with it in 9 months though.
[0]: https://docs.microsoft.com/en-us/aspnet/core/blazor/host-and...
[1]: https://docs.microsoft.com/en-us/aspnet/core/blazor/webassem...
Unfortunately Blazor hype has really died down the last couple of years and I'm starting to get Silverlight vibes from it, which doesn't bode well...
I don't work at MSFT though, so YMMV? I don't think its going to end up like Silverlight. They seem pretty committed to not back pedaling anymore like that, they know it hurt them so much, at least thats the message I been getting from MSFT developer relations, is an some admittance they really borked their DX by going through such rapid turnover of UI frameworks and such.
MAUI by itself is Xamarin ported to run on top of .NET Core (now .NET 5+), with WinUI as backend on Windows.
In what concerns UI Frameworks coming out of Redmond, it looks like pretty messy civil war right now.
Having used NoScript with temporary allowances, it's glaringly obvious how much of the web doesn't show anything without JS enabled. If there's a trend to not make everything render on the client, I'm not noticing it.
Even if there is, we may ultimately end back in the same place we were in say 2011 (or ~2014 depending on how you look at it). We could very well end up back in dumping grounds of abstraction spaghetti bad object-orientation.
The weakness of backend MVC frameworks is that it's way too easy to munge business logic with the view. Yeah, Model-View-Controller suggests a separation of those concerns, but now it's up to the human to follow that convention and... yeah...
SPAs can be just as bad in a lot of ways, but at least they are more suited to dealing with view logic and not so much of the data transaction stuff behind the scenes.
Personally, I often find frontend JavaScript projects easier to figure out, and I think that my be due to MVC being a flawed concept. It might be okay for hammering out a prototype, but in the long term so many things need to happen in order to keep it intact; Rails introduced concepts like "concerns" exactly for this purpose, because an MVC structure in a pure OO language like Ruby is very rigid.
Server frameworks should do themselves a favor and divorce themselves from ideas like MVC and find ways to create structure in ways that aren't merely meant to scratch the itch of design-pattern enthusiasts. I find it dubious that a concept of a "model" is even necessary as a thing to always think about; it's a weird implementation detail that's treated as if it's a design pattern. And when you're left with just the View-Controller part, it's dubious why they even need a formalized concept in the first place.
https://developer.valvesoftware.com/wiki/Source_Multiplayer_...
Are you saying you find it dubious that what you're displaying should be predicated on a well-defined collection of data? Because this is what a model is.
If that's what you're saying, I'm not seeing it. Care to expand on it?
With complex business rules that cannot be easily implemented via database constraints or triggers, or where the same rule is located on more than one data entry screen, then there is a justified need for an intermediate "model" layer for business logic. However, many applications out there just don't have this complexity. In these cases, having an intermediate model accessible via JSON API may be over engineering. You have to double your mappings. A new feature requires that more code be touched, in different parts of the application. For applications with simple business logic and screens that closely map the database structure, this additional layer may not be worth it.
I don't disagree that models are pointless if they're not doing anything other than aping the DB. Why waste your time creating another layer of required translation if it doesn't buy you anything?
With that said, I do think there are some benefits to using statically typed models in languages line C# with larger codebases. It seems like it makes it easier to refactor the application code.
It’s using an ActiveRecord-style ORM (or any ORM) without grokking what lies beneath.
A database layer IS a model. It’s just not a class or an object.
ActiveRecord is a really nice trick when it works … but it can create some really performance-killing side effects.
Ruby’s Datawrapper ORM and its siblings in other languages requires understanding both sides (the object system and RDBMS) but can let you get your class/object semantics to play nicely with your database.
And just passing around database connections and arrays of hashes can get you awfully far.
But, if you want to not think about the database layer, ActiveRecord-style ORMs are a real win for developer ergonomics.
And that’s part of the win of Rails/Django/etc. You can live in a single mental model (classes/objects with references to each other) and ignore the database layer.
Except when you can’t.
One reason (not a criticism) that NoSQL can be such a win is that the semantics are closer to class/object semantics. So you’re not trying to manipulate data with an abstraction that doesn’t quite fit.
But most of our projects aren’t Twitter or FaceBook or Google or anything else functioning at galactic scale.
That and "model" is tricky to define well when we're talking about data backed by a relational database which can (and should be) be sliced in any number of ways. I've yet to see a good relational->UI mapping that works without badly fossilizing everything into a static and undynamic OO "model" inbetween... In fact this is made even worse in SPA-type systems by having an ORM (or similar) and a REST/GraphQL type layer inbetween the view and the DB. Layers and layers of transformation. Each stripping out the richness of the relational model.
> In fact this is made even worse in SPA-type systems by having an ORM (or similar) and a REST/GraphQL type layer inbetween the view and the DB. Layers and layers of transformation. Each stripping out the richness of the relational model.
What about GraphQL that is quite literally just your database structure? IE, verbatim columns and foreign key relationships.I have this issue too -- you can make an infinite number of onion-ey layers of abstraction over your data. But at the end of the day, there's only one canonical representation of it -- in your data layer.
This is why I am against marshalling naming conventions across programming languages. If your database has snake_case columns, keep the values snake_case when working with them from API responses in your code. If you change the casing, you now have something that doesn't represent what's in your database anymore.
Want data that doesn't exist in a table? Make a view or call a function.
Right, and the amount of effort spent by devs working within layers of abstraction can outweigh the effort they'd otherwise spend working with pure data, even if other issues arise; said issues would be faster to solve without lots of code in the way.
People forget that an abstraction doesn't make things easier to understand, but this is how many new devs are taught and think about abstraction. Abstractions are only simpler so long as you don't ever need to worry about what that abstraction is doing. As soon as an abstraction is misbehaving mysteriously, inevitably you have to open the hood and see what's up with the engine.
It doesn't even matter if the abstraction was made by really smart people with distinguished titles. At every Rails job I had, there was at least one problem with an abstraction in either ActiveRecord or other things like Rails Engines that were totally inexplicable by anything – they only were solved by hours upon hours of mid-level devs digging through framework code until they came up with a monkeypatch.
Part of this also comes from what I believe is a very misguided desire to leave the door open to switch databases. During my first two Rails jobs, senior developers resisted to use any raw SQL queries anywhere because "what if we switch to Postgres?" Never did that pan out, and in the meantime devs were forced to do weird things with ActiveRecord to make things work, often inefficiently.
I remember when I was momentarily the most senior dev at one of these jobs, once the lead had left, and I decided to just use SQL where it made sense. Not only did this cut down on lines of code and method calls, but those queries ended up being significantly faster, reducing page load time.
Sure, I didn't go through the trouble to force that raw data into an ActiveRecord model, but so what? All we wanted to do was display the data to the user. Why introduce a bunch of ORM gobbledygook for read-only? Because we might want users to edit articles in some hypothetical future where we just let any rando write stories? lol
That codebase was never great, but after some of those kinds of adjustments we somehow didn't get much if any emergency calls after hours anymore. Hmmm...
Abstractions can be great, but I've come to think they rarely have value with persistent data. In a game engine, it can make sense to have model-like objects for things that are ephemeral in gameplay but need to know about one-another, and this is usually easier to implement in a custom way because games usually aren't written like web apps.
> Want data that doesn't exist in a table? Make a view or call a function.
Yes.
That's so familiar. I've also been trough this more times than I'd like to admit. Often five or six files of ActiveRecord code that could be reduced to a View.
However I don't think it's just desire to change databases, there's also a lot of resistance against using different languages. SQL is bad, it's ugly, it's old. I see the same sentiment against Bash in younger developers too. They don't want to take the time to learn, so they just reject it.
And ... I'm old and that's how I learned that :-)
That said, GraphQL is not a relational query language, and works in the world of hierarchical/graph database land. I think Date & Codd did a good job of critiquing that model and showing its faults the first time around (the 1970s).
> It's just a fundamental problem with MVC that the lines are difficult to demarcate well no matter how you define your layers.
Yes.
> That and "model" is tricky to define well when we're talking about data backed by a relational database
And that's why I find it nearly useless to even make it a "thing" other than perhaps for n00b coders who've yet to touch SQL or write many of their own classes/modules, or I guess just have enough experience working with data. Thinking in terms of models for data, IMO, can and I think almost always does pigeonhole data into moving and existing in ways it doesn't need to. In many cases, a formal model makes no sense for the data at hand, and if developers only think in terms of models then everything inherits a ton of complexity that may be of no benefit. It's premature optimization hidden as a convention or pattern.
> I've yet to see a good relational->UI mapping that works without badly fossilizing everything into a static and undynamic OO "model" inbetween.
At which there's no point in using strictly OO or a model paradigm. This is what happens when those highly accustomed to OO realize that their conception of OO is unsafe. Keeping data frozen, static, immutable, or whatever is right thing in more cases than is appreciated, but even when devs acutely realize it after the fact, they often resist giving up using models. If some concept of a model is more of a drawback then a benefit, just get rid of them. I don't care what framework or ORM people are using. Any developer can learn to work with data in a functional way that doesn't involve making data act as an ooey gooey object that can morph (and get messed up) and take on a taxonomy that wouldn't otherwise exist in the real world.
"Having used NoScript with temporary allowances, it's glaringly obvious how much of the web doesn't show anything without JS enabled. If there's a trend to not make everything render on the client, I'm not noticing it."
You're not noticing it because JS SPA frameworks have been the new hotnessTM for ~10 years. "We could very well end up back in dumping grounds of abstraction spaghetti bad object-orientation.[...]it's way too easy to munge business logic with the view. Yeah, Model-View-Controller suggests a separation of those concerns, but now it's up to the human to follow that convention"
This is a problem with modeling and coupling that happens on SPA's as well, unless you've somehow solved that pesky human problem :D The fact that there's an API layer helps....sometimes...but many times your munging of business logic just ends up being in two different layers instead of one. "...MVC being a flawed concept. It might be okay for hammering out a prototype, but in the long term so many things need to happen in order to keep it intact; Rails introduced concepts like "concerns" exactly for this purpose, because an MVC structure in a pure OO language like Ruby is very rigid."
Agree. IMO one of the main issues with MVC was that the layers were somewhat ambiguous, which caused bloated controllers or munged up models. In the past I found that "splitting" MVC to be more like MVVM with dedicated backend and view model layers resulted in a much cleaner separation of concerns without the need to go full SPA just for the side benefit of having an API layer.TBH having worked on multiple high traffic, large-ish MVC apps and high traffic, large-ish react SPA's, I'm a fan of "the old way" of building apps. It felt faster, easier, and much cleaner. I can't wait until things like blazor, hotwire, and htmx help server side templating become a thing again. IMO it would help clean up the state of the web dev industry immensely. Maybe I'm looking at the past with rose colored glasses?
> TBH having worked on multiple high traffic, large-ish MVC apps and high traffic, large-ish react SPA's, I'm a fan of "the old way" of building apps. [...] Maybe I'm looking at the past with rose colored glasses?
That bias exists in all of us, but I wouldn't guess you're looking back with rose colored glasses.
I'm actually more of a fan of "the old way" than I might be letting on. My work for the last 4.5 years has been almost entirely on SPAs, so I'm part of the problem, but I think I've seen the weakness in it as well.
All in all, I'd like for us all to try and avoid complexity from the get-go. That means starting with sites that are server-rendered and to try and not immediately jump to fancy SPAs and other tools. Maybe not everything must be containerized. Maybe monoliths and relational databases are A-OK for most purposes, and scaling up in response to financial success is something that can be handled when the time comes.
At the same time, if we're going through a sanity adjustment as an industry, let's make sure we reexamine the old assumptions that we ran away from in the first place. Otherwise, it's just a pendulum swing.
My main concern about the new/coming generation of tools is whether we also see a similar brawl we witnessed at the Cambrian era of frontend frameworks. A lot of things that seemed like innovations turned out to be headaches and even universally reviled. I can just picture the blog headlines of the next 5 years: "Why we moved away from Phoneix Liveview"
This doesn't seem any better to me than the Perl+CGI / PHP world that Rails replaced. And we've traded the risk of munging view and model, or breaking conventions, for no guardrails and no patterns and no conventions beyond the most popular library to show up in the last 6 months.
I've personally seen an old, terribly uncool dinosaur MVC decomposition turn into 50+ microservices, with 10+ front-end apps, each with their own toolchains, libraries, peculiarities and hidden dependencies. That doesn't seem to be a win either. It feels like we are all collectively missing a more integrated approach to development, and eventually the pendulum will swing back in the favor of more comprehensive frameworks.
Counterpoint: I generally browse with JS disabled and there's a strong association between sites for which this is existentially problematic and sites whose content or utility are garbage.
> If there's a trend to not make everything render on the client, I'm not noticing it.
This trend is not so strong as suggested. Far from server-rendered websites being "fetishized", this remains the standard.
I recommend SPA-first development to all my competitors. Crystallising architecture around the front-end is one of those anti-patterns my grandmother warned me about. "You'll struggle to pivot," she said. "Spikes, prototypes and reimplementations are much easier to develop in proximity to business logic and persistence schema." What a wise lady. See also: nosql and microservices.
My first thought was to add a format/output parameter to specify the format. In that case of HTML output, you could possibly use the JSON that would normally be rendered and insert it into a jinj2 template for example.
Agree with the first statement but, not necessarily on the second.
People dismissed React for being "too new" or "the latest stupid shiny new framework" for a long time because they didn't understand it. But when I read about it for the first time, I understood the problem it was solving with the VDOM. It made perfect sense for me to start using it immediately because it quickly starts saving a lot of time formerly spent on writing DOM setting/resetting code and making sure it never breaks. It was something I was already thinking about: "how could I avoid writing all this tedious DOM manipulation code". And there it was, and I knew it would become big. It took a while for the rest of the world realize it, but eventually it caught on.
Sometimes tools pop up that make perfect sense. So you shouldn't dismiss any technology for its age, whether it's old or new.
And that’s why author wrote "But as a general rule" instead of as an immuable rule.
The "React as a framework" thing came later, which I personally think is a misstep. I'm not into frameworks in general.
It comes with a reasonably good internal pubsub system and vm linking right out of the box. And the built in application supervisor makes it trivial to spawn thousands of threads on one machine, each with their own independently allocated heap, that can be mounted under a supervision tree.
Want to create a microservice? just make a file, inherit the GenServer and add it to your application tree in your application.ex. Add a library like horde and you can create singletons in your codebase that are microservices. they run as a thread somewhere in your cluster. Just send it a message by nmae and the vm will know where to deliver it.
The end result is the overhead of creating and maintaining a microservice in elixir is about the same as the overhead for adding a new controller.
All is well and good until it isn't. We opted for leveraging different mix release permutations deployed on k8s as needed instead.
Definitely takes more effort than what you describe, and has its own issues... But imo definitely better understood than fighting weird state with horde
Should play with it a bit more.
I'm putting the finishing touches on my second app in about a month and a half. It's a "total rewrite" app; just like the previous one (which is already out there, and has had over a thousand downloads already).
I did these apps alone. After this one is out the door, I'll return to the app I've been working on for a year and a half. These were just "side trips," because I was getting burned out.
UIKit was designed as an MVC framework. If you use a different pattern, then "you're holding it wrong." You are using the framework in a manner for which it was not designed.
That is not always bad. I can't actually think of any examples, right now, but I'm sure that some of the new methodologies are more effective.
I strongly suspect that some of the new development patterns (I won't name them, because holy wars) were developed specifically to break up projects that are really best done by one or two skilled engineers, into ones done by a fairly large team of relatively unskilled engineers.
Might work out. I don't know. That's not how I work. YMMV.
I think this is mostly a way to flatter ourselves about things we don't like. It's perfectly fine to not like things but as an argument, it is pretty poor. It's at also at the core of PG's 'blub language' thing, a mistake at the time that's aged even less well.
I wasn't railing against anything that "I don't like." I was simply stating that I use MVC, on a regular, daily basis, and it gives me the results that I require.
And, I know, for a fact, that some of these patterns are used for exactly the reason that I stated. I know this, because I have talked to the managers that decided to use them, and that was the motivation. I don't even have an opinion on whether or not that is bad. Many of these teams do great work.
Maybe things are better, done in ways beyond my limited, saurian, comprehension.
All I can say, is that I'm able to churn out a lot of stuff, of extremely high Quality, in a remarkably short time, using these prehistoric patterns. I know that Apple developed the patterns they use, in order to allow very small teams to create high-Quality, high-performance apps, in very short time (again, because I've talked to some of the folks involved in writing UIKit). People like me, working the way I do, were what they had in mind, as they developed their frameworks.
SwiftUI looks pretty cool. I haven't used it much [yet], because I have yet to be convinced that it is suitable for ambitious, shippable projects. I'm waiting for it to develop a bit of momentum. At first glance, it doesn’t seem to be designed for MVC (but it may work great. I don’t know enough about it, yet, to be sure). I’m happy to learn up on whatever methodology works best for it. I learn quickly, and adapt extremely well. Been doing exactly that, for quite some time.
Nope, I just think you're wrong, sorry it came across as something more than that! I don't think this has much to do with the specific qualities of MVC (they're a lot of good things about MVC) or the problems of newer approaches (declarative UI doesn't fit everything, implementations are newer and buggier, etc). The 'made for chumps, not artistes' mindset/explanation ends up being statistically wrong, over the medium-ish+ term, just about all the time (60% of the time!) - a pretty great track record of wrongness which is interesting and useful in itself.
That seems pretty insulting, to me. It might help, if you reached out, personally, instead of deciding my personality, based on a single post on an internet forum. I’m actually a pretty decent chap, and I’m not particularly up for online catfights. BTDT. I’m an old troll, and feel that I have some atonement in store.
You've gone from "I strongly suspect" in previous comment, to "I know, for a fact"...
New methodologies are not necessarily designed for large teams of "unskilled engineers", just like old methodologies were not necessarily designed for "one or two skilled engineers"...
As it turns out, I needn't have bothered. This was declared a p****ng match, anyway (I didn't mean it that way).
I guess the difference is who gets upset.
I wasn't talking about how they were designed (I apologize for unclear language in my initial posit that indicated that). I was talking about how they are used.
I've always thought of microservices (or services) as a way to make your organization rather than your code scale. Past a certain size, you won't have an uniform group of developers. According to Conway's law, this will impact your codebase. Better embrace it in your organization.
I write fairly humble apps, though. If things got a lot bigger, I'd hire someone to do bigger work.
In any case, it's really easy to toss out a codebase that took one guy, two days to write (I do exactly that, all the time). The advantage that I have, is that I write really good code, in those two days (feel free to check out my work).
The big app that I'm writing, is a native Swift app. The server is written in PHP. This is not because there's an inherent value in that, but it is because that is what I do, and we can't get anyone else to do the work for free.
You use the tools at hand.
If you're busting out an iOS app in a day alone then of course MVC is going to be fine for your needs.
That’s the whole point of separating the code into layers: so you can have multiple implementations existing concurrently at the same layer.
For example you can have models talking to Postgres and models taking to Elasticsearch or Cassandra. Or as everyone knows you can have different controllers which all talk to the same models or use the same view for output.
And if you were to abstract beyond the framework level, MVC can apply to software written in totally different languages.
I consider my code to be high level MVC and it’s controllers in Elixir talking to Java model layers and outputting JSON views, HTML, or even Excel files.
#1 - Organize and implement in a manner that adheres to some standards, so someone can always be found to maintain and fix it.
#2 - Create some interfaces that break components apart.
What standards and what interfaces (and how many) are an order of magnitude less important than that they exist at all.
Not only when writing actual code, but there's less bike shedding and "fundamental" discussions.
Yes and I'd argue it makes sense in most contexts for small startups.
Also, Monolith is sometimes synonymous with tangled spaghetti code but it doesn't have to be. If code is kept organized, it can be split into microservices when/if the need arises.
If you aren't familiar, I find The App Continuum [1] to be fantastic for structuring these kind of conversations with my teams :D
You can even just run multiple copies of the monolith with feature flags to enable/disable different parts of the code.
It's also perfectly possible to split those things up, and to have them share the same database.
This causes microservice extremists' heads to pop off..
The truth is, most things can be made to work - though there are various trade-offs ("shenanigans") involved.
e.g: In my current project, there's a bit that loads large-ish files, parses/converts the data, and loads them (order of tens of thousands of rwos) into SQL tables.
For reasons that best escape me - since after the files are parsed the entire dataset is _literally_ in memory, instead of doing a bulk sql update there- and then, thousands of messages are enqueued to be consumed by a practically unlimited number of lambda functions that then... bomb out as the SQL database hits it's connection limit and keels over.
I guess those shenanigans have better buzzword compliance!
Batching is the way to go, 100%. Remove the network as much as you possibly can.
(still, that doesn't change the fact the code is badly designed)
So much nicer to expose a documented and versioned API (and/or published event stream), so that the consumers of data your service manages have some flexibility at which moment to migrate to the new schema.
I can't tell if this is facetious. I hope it is.
I work at a small, early stage startup and I'm about to create a new repo for our Slack bot. I'm going to use the Docker image another of our repos generates as the base Docker image for this new repo, and it's going to be just fine.
If you've got separate docker images, you have separate services. OP is saying that most startups that think they need to split out their code into independent services actually just need to organize their single service better.
> One or many repos, it's just an organizational question, not some Super Serious Big Decision.
When people talk about monoliths they're not usually talking about repo structure, they're talking about deployment structure. One or many repos is just an arbitrary organizational question. One or many services is a really big deal: It's the difference between running a distributed system and not.
It's not a boolean, it's a spectrum, and where precisely you land on that spectrum is not as important if you're actually focused on getting work done.
Getting work done is important, but it's not an excuse to avoid thinking through the long-term implications of your decisions. If you shrug and say "it's just one more service" every time you're tempted to add a new docker image, you'll not just end up with microservices, you'll end up with poorly planned microservices.
These solutions are often solved in environments that are running at a scale not most companies operate at, BUT think they will, so they invest in them early for future, potential, needs. It's no surprise many of the core contributors / founders comes from Facebook/Google/etc.
I don't mind the idea for a SPA for a big social media type of site, but for ordinary sites, I feel like it's overkill in most cases. If you enjoy it and it works best with your team and workflow I'm not trying to knock on you. I just prefer not to add more layers and points of failure to my web application.
I love back-end work and I prefer front-end code to be as vanilla as can be. If I want a UI I pull in Bootstrap or some CSS framework because I'm not a designer.
It's one of the great show pieces for what the Elixir makes possible.
Microservices, in most patterns, or even SOA will put more-than-arbitrary separation between code and databases. Without that more-than-arbitrary boundary then code gets spoiled because it's easy to import the other services library directly, it's easy to make that DB call yourself rather than route it through another controller, etc...
Edit: Inadvertently, this is why I also like to call these things "patterns" rather than architecture. Architecture being the idea, and pattern how you implement it.
Not saying it's true, but when you cut through the marketing bs that's the claim.
Once things are validated, opportunities compound to rewrite "properly" (^Wtemporarily) things around or aside the monolith.
If you gap services or microservices by a Git repository, then it makes it harder for them to import each other's code; you also will probably have code duplication. If you have repositories for the shared code that's safe then you have new overhead problems. If you keep them in a monorepo then it's just as tempting as in a monolith to cross domains; the only inhibition is resistance to ease of access and the only way to catch it is in code review.
These are all tradeoffs. Fwiw, I still run a monolith project, and part of code review is checking imports, and part of our documentation talks about shared code standards and locations. It can be done, there's just no natural guard rails present.
Just build services that are not too small, avoid dependency hell between services and never build platforms.
A lot of monoliths reach end-of-life because everything is glued together. I even worked with partners that have systems where each database table is dependent on a single table in the database. It failed. A design doomed to fail from start.
Deployment is more complicated, changes can be more complicated, performance is more complicated. Its a great way of splitting up teams, but when you are a startup and have a single team for a long time, why would they do this?
> Just build services that are not too small, avoid dependency hell between services and never build platforms.
This is basically "code without bugs and you will be alright". Avoiding dependency hell is difficult, sizing up the services at the perfect size is also difficult as hell. Everything is a lot more difficult.
Microservices can be amazing, I'm not saying they aren't, but acting they are just better than monoliths is not seeing difficulties where there are many.
Going with microservices from day 1 will initially mean that you have one team maintaining many services. They have to deploy them separately. If you're doing it "right" you have separate databases per service. None of that is useful for a team that's just starting out.
If you want separation of concerns, the language's module system and a bit of discipline will get most teams as far as they need without introducing distributed computing into the equation.
Individual deployment of services is the single best thing with microservices. If the services are not highly coupled that is. For example. To be able to fix a bug in the search function in a system without affecting anything else speeds up things. Such a deployment can take minutes instead of the hours as some of the monoliths I worked on takes to deploy. It also gives the possibility of rolling forward instead of always having to rollback.
EDIT: replied to the wrong comment.
Which is exactly what separation of concerns achieves:
> It is a nice way of separating concerns.
It's also why Uber got to "thousands of microservices" and found it terrible...for the same reason managing thousands of developers is a nightmare. The overhead eventually catches up.
I upvoted you both btw.
And this is from 2016.
My current work has put a load of developer resources into a kubernetes setup. It makes troubleshooting slower and I don't think we have ever scaled beyond the default two pods, except when some bug was playing up.
Many people have a fear of microservices. They are afraid of dependency hell, they are afraid their app will lock up, they are afraid it will make the app more complex. In my experience, that is not the case if the architecture is done well.
You can still keep a client interface, but in the monolith impl you can just have it call code directly instead of transport data over a wire. Then, when/if you separate, the only code changes you need are the transport layer (not necessarily non-trivial, but it's just a single point of code that needs major overhaul).
I find usually when people say they are pro/against monolith/micro-services, they are using very overloaded terms.
When I hear "anti-microservice" my brain thinks "wow, this person is against code that separates concerns into their own logical buckets - they must love entangled messes of code that take months to make changes in" when usually they are thinking "I'm against severe premature optimization, and rolling out/maintaining orchestration for all 5 of my miniature services when I can really just build this out in a single repository that is able to maintain those concerns for me without duplicating work/effort."
Honestly we probably just shouldn't talk about being pro/against any of these patterns dogmatically, and really should talk about the specific issues present in each and when those are worthy trade-offs.
... Then you're not really listening.
Especially in this day and age of cheap machines capable of doing thousands of requests per second and hundreds of thousands of IOPS... almost nobody needs 'microservices'. Hell, I worked at Google and that's not how they solve scaling problems and their scale is bigger than yours... So why does the industry reach for this as a tool?
Microservices != separation of concerns or designing for modularity. It's actually a pretty terrible way of designing for that.
(Sometimes I feel like if I see another client-side join in my life, blatantly abusing and/or ignoring the presence of a relational database in the stack, I'm going to cut my fingers off with wire snips, throw out all my computers, and leave this industry forever.)
Yeah, I hate this false equivalence. When did we start assuming that monoliths couldn't be modular and have clear package boundaries?
IMO how you deploy your software (one binary vs many services, all on one box vs distributed) should be an incidental detail that is automated away.
You have two packages that are very chatty? Your infra figures this out and deploys them in the same binary. Two packages that rarely talk? Deploy them as separate binaries and maybe even on separate hosts.
>You have two packages that are very chatty? Your infra figures this out and deploys them in the same binary
Are there any libs for doing that? Seems to me that that should be pretty complex.
This is my favorite thing about the nature of Elixir actually because it happens automatically.
With functional, no-side effects code you ensure that your logic is free from the entanglements that would otherwise complicate the separation. You take one function, you move it somewhere else and it works exactly the same.
The ability to cluster BEAM nodes allows you to call that function you just moved by just pointing to the node where it lives and then calling the function. And you'll get the response back just as if it lived in the same place it always did.
"For many organizations, the modular monolith can be an excellent choice. If the module boundaries are well defined, it can allow for a high degree of parallel work, while avoiding the challenges of the more distributed microservice architecture by having a much simpler deployment topology. Shopify is a great example of an organization that has used this technique as an alternative to microservice decomposition, and it seems to work really well for that company."
"Unfortunately, people have come to view the monolith as something to be avoided—as something inherently problematic. I’ve met multiple people for whom the term monolith is synonymous with legacy. This is a problem. A monolithic architecture is a choice, and a valid one at that. I’d go further and say that in my opinion it is the sensible default choice as an architectural style. In other words, I am looking for a reason to be convinced to use microservices, rather than looking for a reason not to use them."
Sam Newman, Building Microservices, 2nd Edition
You can see the same thought rephrased by respected people - start with monolith, grow organically from that into services or microservices. It can take years. It may make sense not to do 100% transition ever. Just use common sense, your context etc.
Devs write without a framework, but complain that they have to spend a lot of time working on the structure of their application. There's a desire to use a third party framework that handles the broader structure, and the devs just have to slot in their application specific code into pre-defined places.
Devs then work with a third party famework for a while, but get frustrated when their application needs don't match up with what their framework is good at. They then have to write hacky workarounds to add the functionality they need. There's a desire to ditch the prescriptive framework, and design the code structure in a way that meets up with the application's specific needs. And then the cycle repeats itself.
Application frameworks, whether MVC or something else, are a useful tool. But there's no perfect framework, and it's easy to feel like the grass is greener on the other side.
I forget who had the quote that went something like:
"If SQL is so great why have people been trying to replace it for decades?"
(the failure to replace it is of course the punchline, in case anyone misses that)
Since 2015, I've always rendered final HTML server-side, whether that HTML was travelling over a complete http request/response cycle (big page load or XHR or fetch), or over websockets.
The only JSON ever involved was stuff similar {"markup":"you html code here"} and a few other more subtle bits to make up for a dumb/blind client. In other words, the client does as it's told by the server. (my client is Azatoth)
Opinionated? Yes.
Full-of-bad-suprises-after-release-oh-shit-what-did-I-do? No
Then again some light stuff works (flask vs django). But as (more than) hinted in the article, a hello world may satisfy this immediate need to get that shiny first HTTP 200 from your new website/api/whatever. But doesn't do much insuring a certain level of quality, sanity and stability in the long(er) run.
my 2pence.
Hell, Microsoft has a framework literally called "MVC" that has only a passing similarity to them, but is completely different on practice.
"Framework" is also too overloaded to my tastes, less so than "MVC", but you will still get confused people if you use it without context.
Using those terms make ideas less clear, not more. I do really avoid using them, and I would recommend doing the same for anybody.
(Anyway, it's nice to know that getting the region's HTML and applying it to the innerHTML of an element, like I was doing with JQuery decades ago is called "HTML over the wire". And it's coming!)
1 - "And many others" that I'm sure was added to the text just to avoid angry email from wrong people, because there aren't many others like those ones, and the few I know about wouldn't get called MVC.
Business logic can be handled on the control plane with replication/subscriptions/whatever mechanism. Small, stateful services that react to the event stream and perform whatever actions needed based on your business policies: send notifications, insert new records, call external partner APIs, etc.
For server-rendered UI I think there's still a strong case for these frameworks but they could probably take some lessons and generate their data-layer models from the database DDL, push business logic down to the control plane, and focus on rendering current state from read-only models/streams. I've been meaning to try something like this in Haskell (I've written some foundational libraries to enable this on Postgres [0]) but there are frameworks that do this like Phoenix in Elixir.
[0]: https://hackage.haskell.org/package/postgresql-replicant-0.1...
I can stand up a REST API server with PostgREST and a database in a couple of hours. I can deploy new models with a SQL migration.
Like I said, if you want to do server-side rendering it's still a place where Rails/Django/etc shine but I think they could learn a thing or two there to make them better. They could improve so that folks can write/maintain even less code.
It depends on the framework. In .NET the only difference between MVC and API is the base class of the controller. You either return JSON or you return a view. Database connections, migrations, routing, serialization, error handling, exception handling, authentication, authorization, Swagger specification, Docker file generation, can be handled by the framework if you so desire. Also, you can mix MVC controllers and API controllers in the same project if you so desire.
>For server-rendered UI I think there's still a strong case for these frameworks but they could probably take some lessons and generate their data-layer models from the database DDL
I find it better to just generate the database from the domain entities using code first approach. It's faster and the ORM will generate proper indexes and also provide optimized SQL queries.
I think there is AdonisJS : https://adonisjs.com/ which could be the Rails / Django equivalent you're looking for.
The JS ecosystem has had a long time to come up with something equivalent.
2) Dinosaurs are still around in the form of birds and have found amazing utility, so even the analogy lacks nuance ;)
I just build mostly from scratch now, (update) [using MVC monolith] feels icky because I’m not trying to start a company or working at a startup. Frameworks are bad suggestions in mid/late stage company.
It’s nice to drop some value bombs, but if you intend to stick around for many years and you got more than 10 engineers in your organization, don’t choose a monolithic framework because it just makes the politics of getting your framework broken out into logical parts (ie micro services) a PITA. That’s my two cents.
Of course a monolith is a great choice for a team of 4 devs for example. It could be great even for a team of 20 devs. But when you have 30 teams of N devs, then the monolith maybe is not the best idea.
Businesses scale in different ways, and different stacks exist for this reason.
As I get more experienced, I try to find the easiest, most profound solution to a problem. At the same time I "design" escape scenarios. If that business will scale in that x way then I will be able to do y. Most times the need for scale never comes.
As I said in the previous comment, you have to design your way out of the thing you are building. Not easy at all, and sometimes, not possible to predict.
I mean successful companies do grow, but a lot of times they pivot, etc.
The problem with rails is it encourages you to not think about your architecture, and after years of putting every model, controller, or view in literally the same folder, you have a giant pile of shit.
Modularize by feature. And under each feature, you modularize by layer. Slicing your code N ways will scale better with your team than slicing your code 3-4 ways.
Sounds like Vertical Slice Architecture combined with n-layer or onion architecture.
I didn't realize it had a name like that. I've always just called it "package by feature" (Java). Been using it for over 10 years at this point.
But it's not an issue. If you chose tech X because it was the easiest way for the small team to produce an working prototype, when you find success, you might afford to rewrite using tech Y like Twitter switching to Java or alternative approaches like Facebook doing their own PHP version.
It's not like being microservice based and modular from the start will save you from rewrites and architecture rebuilds. Google rewrote parts of their services and modified their architecture hundreds of times. Of course, if the architecture is modular, rewrites and architectural changes are easier.
Let's say you work for a small /medium company and it has a few monoliths. But if more than one needs to manage user authentication and authorization, needs to send mails or SMS, it kind of makes sense to build an user management service and an alerting service.
Can you give an example or two of a software product where 30 teams of N devs are working on the same single codebase? Seems hypothetical. Bank/IRS type systems on a mainframe/AS400 maybe.
From .NET Core 2.1 + Angular 5/6 to .NET Core 6.0 Web API + Angular 12/13 on the front-end = Total Win.
No need for changing what works. Svelte? React? Web Components? Naaaah, I am good.
They complains the framework you use isn't shiny enough. While in practice, things they write using these shiny frameworks performs outright painfully.
It's really a weird trend that everyone just run for the newest thing and forgot why these are invented for at first place.
But the reality, the issue is them not 'understanding/knowing/being able to build semi-good software.
Think about it - you have the Fed literally printing money, then many VCs giving MILLIONS to half-assed, barely functioning prototypes.
The idea is not there, the craftsmanship is not there - it's just a bunch of kids on Adderall slapping some nice-looking UI and getting paid.
Guess what the thing they like to talk about is - the technology behind it because sure as hell it doesn't solve any business need.
It is hilarious.
If other people are doing the Frontend, I don't care what they use. I just show them the data contracts and wish them good luck.
The big advantage I see for MVC applications, if that it is a well understood pattern. JS frameworks, on the other hand, come all ~3 years with some new innovative way to structure your code, while even the last approach isn't fully understood by many people.
I can't give you an perfect answer, because I am not aware of a practical example. But I think its quite doable. In a very naive way you can just store the results locally and use them when requested while offline. That potentially increases the storage size of individual items due to the HTML overhead of course. A fairly small app with little offline content could be quite simple. An advanced approach could be to push template parsing to the frontend. HTML fragments could use i.e. micro formats to retrieve data from the HTML and store it for later use. The question in this case how much logic you have to duplicate. I.e. template parsing should be very simple, unless you can share the template engine.
Sounds more like a JS view/vue ;-)
Sure, it is possible, but then you are probably better off using a proper JS framework with SSR (server side rendering) support.
But I don’t really see why you need a MVC framework for doing MVC.
Was the shark perfect at its inception or did it adapt as all things do?
Doesn't its shark-ness come by virtue of surviving against the best efforts of challengers through time?
Isn't that continual evolution at least in part dependent on a continuum of challengers?
Don't we implicitly give up on searching for something that could potentially overtake the shark by dogmatically accepting the shark's shark-ness?
The bar for success in that case is pretty high, and the challenge significant.
I also would advise against using Hotwire for Rails, some of our worst bugs have come from the desyncing of HTML and JS from Hotwire, as well as unexpected network status code handling. And most people only run Hotwire in production, so bugs are easy to miss.
eh?
Aren't you confusing the full "Hotwire" suite with just Turbo? I don't think you cannot run "Hotwire" in development.
Add SPA performance to a multi page app thanks to guided pre-rendering. I came away from it thinking that's one less benefit an SPA holds over MPA now.
IMHO, "MVC" is the catch all term for anything defying neat summary and categorization.
Consequently, I assume any and all usage of "MVC" is an admission of ignorance, intentional or otherwise.
Originally coming from a Java rich client world and moving into JS in ~2013, it always surprised me how much historical context the JS world was missing.
> There exists in such a case a certain institution or law; let us say, for the sake of simplicity, a fence or gate erected across a road. The more modern type of reformer goes gaily up to it and says, “I don’t see the use of this; let us clear it away.” To which the more intelligent type of reformer will do well to answer: “If you don’t see the use of it, I certainly won’t let you clear it away. Go away and think. Then, when you can come back and tell me that you do see the use of it, I may allow you to destroy it.”
[0]: https://yew.rs/
Then maybe just maybe, you will all have more time to work and become millionaires, just saying.
You should try, because now there is almost no difference between MVC and WebAPI. You just have controllers with different base classes.
Sometimes a monolith makes sense. Other times, a microservice architecture makes sense. Sometimes a "just right" sized repo makes the most sense, neither a monolith nor a microservice.
Why does it have to be so tribal? Why is there a #monoteam and a #microteam?
I think it's just a symptom of "When the only tool you have is a hammer, everything looks like a nail."
RDBM is optimized for file size; it is very much an artifact of its time, when hard drive space was limited. I don't buy it for a second.
People think in dictionaries, so just use one. If you are making a simple app and don't need transactions, aggregations, or multiple connections, then just use JSON in an S3 bucket or something. If you are going a step farther, JSON-based databases are quite feature complete these days. For monolithic business logic applications, relational databases are the right tool IMO, but they are used for every use case when they are absolutely not needed.
Controversial claim: Joins are a foot gun. It is so easy to make too many tables and mis-use unnecessarily complex table structures because it feels safe and "engineery" to do it. I don't know how many young startups I've seen that absolutely struggle with RDBM performance, and almost always they have gotten themselves into some horrible situation joining five tables deep with a spaghetti ERD and no clear pathway forward. It is hard to make the same mistakes with a JSON foundation.
I see a need for relational databases, NoSQL, data lakes and all other storage strategies. You chose based on the type of data, the way you acquire it, the way you process and deliver it, based on security and reliability needs.
In many non trivial application there is more than one data storage solution implied. Since I work with large microservice based apps, it's a long time since I have to use more than one data storage strategy in the same app.
It's like using a 20-piece multi-tool for something that only needs a regular kitchen knife.