Hacker News new | past | comments | ask | show | jobs | submit login
Escaping the SPA rabbit hole with modern Rails (medium.com)
274 points by mparramon 9 months ago | hide | past | web | favorite | 134 comments

I have nothing against SPAs for complex UI interactions. It's sort of like taking anti-biotics; there should be a moment of reflection when you should justify your true need, lest the cure be worse than the disease. Most developers of a certain age have come up when it's SPA by default, and can't truly defend why they need it.

In this thread, there are several claims that it's impossible to write well-organized jQuery. That sounds an awful lot like dogma to me. Also, your inability to write well-organized code says more about your coding and team-management skills than it does about any one approach. Any tech is only as good as the team using it.

A few years ago, Sam Stephenson (who originally wrote the Prototype library, before jQuery was a thing) gave an excellent talk on Turbolinks at RailsConf. I recommend the whole talk (turn it up to 1.5x speed, of course) but at 4:12 he does an amazing job of showing how the SPA path leads to insanity.


Here's a mental exercise for you: the next time you start a new project, instead of deciding which SPA framework to use, start with an assumption that an SPA is wild overkill for the first iteration of your application - especially if few people on your team have working expertise with the SPA in question. Then see if you can argue FOR the tech. It's much harder to justify something you don't need if you start with an honest conversation about how you probably don't need it. (This works for throwing out CDs, too: start with the assumption that they are all garbage, they all go. Then force yourself to make logic-based arguments for each one you keep. Your outcome will be night and day from if you start with everything in a keep pile.)

As a user my main beef against SPA is that most of the time they break basic browser functionalities, like the ability to open links in a new tab, or using the back button. When the UI doesn’t simply break with part of the content off-screen.

Having built some SPA's, I'd argue that at least those two things that you mentioned are the fault of whoever built bad SPA's, rather than issues with SPA's as a whole. It's possible to build an SPA that works well with the browser controls because modern browsers expose a lot of their functionality to JavaScript (like it or not). You can use <a> tags for buttons and links in an SPA (and keep the link functionality) -- you can just intercept the clicks when the link is being opened in the current tab, and you can always hook onto pushState/popState to make the back/forward button work.

It is an issue with SPAs as a concept because part of that concept is that you’re taking on responsibility for things the browser traditionally did for you.

That’s not a bad thing but it’s extra work which someone has to be responsible for, similar to how e.g. using a complex custom widget means you’re on the hook for accessibility rather than the browser vendors.

Surely most creators of SPAs are using some routing library, and I’m not aware of any routing libraries that don’t handle this anchor tag click behavior by default. It’s really a trivial amount of “responsibility” to take on.

Perhaps, but it’s something I encounter fairly regularly, especially when an unreliable network connection or other JavaScript failure breaks something with poor error handling. Again, not a showstopper but it’s a decision point: if you aren’t committed to testing this kind of thing on every release, you don’t have the resources to build an SPA.

It's no different than stuff like not trusting browser input or avoiding a massive session when you're working on a Web app: it's simply basic best practice stuff that you don't even have to think about if you have an idea what you're doing.

Would you say Youtube works better now as it is fully SPA?

There's an army working on YouTube, and it has the traffic levels to justify the investment. They can actually put in the required effort to ensure the application functions seamlessly and meets accessability standards.

It does not. The SPA is so sluggish I’ve learned to just force a page refresh after clicking on anything because a full page load is actually faster than their bullshit SPA.

That's exactly the reason to use a SPA framework where all these problems are solved for you.

At my day job, I mainly build web apps for enterprise customers, and for maybe 90% of them we use ASP. NET MVC or ASP.NET Core MVC, with a smattering of jQuery and vanilla JavaScript on the client side. This is a tried and tested stack that works well, has a huge ecosystem, and has great development and debugging stories.

There seems to be an awful lot of devs now that only know and use JavaScript, consider server-side technologies to be 'old skool', and prefer to use whichever SPA library is the new hotness - but IMO, most web apps just don't have UIs that are complex enough to warrant using a SPA.

.NET is just as well suited for SPAs as any other technology.

I generally agree with you, and as a front-ender-first that feels kind of uncomfortable to say. In my personal projects I do often go for a more conservative server-side first approach.

That said, it really feels like a chasm that quite often I choose to cross simply because it'll be easier down the line. I've been bitten more than once by server-side-first projects where going full-on client-side with the server-side as an API would've probably been better.

Whether it was because I needed a mobile app to communicate with said API, or whether the complexity ended up being more of a client-side thing, the result was often that I had to focus on the back-end as as API and go for the full complexity of a front-end app anyways.

I'm enough of a fan of my preferred back-end languages (Ruby, but mostly Elixir these days) that I try to find ways to keep the complexity there, but truthfully I often opt for going for the full complexity of a client-side JS/TS stack because I'm likely to end up needing it eventually anyways.

I've looked into things like Drab (https://github.com/grych/drab), but ultimately there are many reasons why 'going with the flow' seems like the better solution (even if just because it's so much easier to find JS devs than Elixir ones).

So far I'm not confident enough to make any sweeping statements, but from that lack of confidence I tend to opt for the 'safer' option, which seems to be the SPA route much of the time.

+1 for the last paragraph. I used that technique to quell my desire to use event sourcing everywhere

Thanks for sharing the video. It's really good.

Sounds like you haven't been introduced to reagent.


Okay, I admit it: I honestly can't tell if you're joking or not.

I think that you're joking, but if you're not joking, well, we have different definitions of simple.

I'm not joking. Spend some effort. Challenge me. You build a UI in your favorite framework. I'll use reagent. Document the code. Compare the code then.

Dude, I've got work to do.

You threw down a URL to a framework I don't know that is apparently similar to a framework I don't use and runs on Clojure, which I don't work in and none of my codebases run in. You did that with no context or even taking the time to explain why I would do such a thing.

Objectively, there's nothing simple or expressive about the samples on their homepage. Their demos are simplistic (todo?! seriously?) and do nothing to convey why someone would express a complex web app in this manner.

It seriously looks like Matrix code to me.

So just because you don't know German and I ask you to read some German text, you will say this looks super complex, even if it's a simple line saying "Good day!".

Wow! Indeed our definitions of simple are different.

If you want to spend your days learning flavor of the minute web frameworks instead of actually building stuff, knock yourself out.

If you have anything more substantial to add to the conversation that actually relates to my original comment, I'll be here.

Well, I've built stuff in reagent, enjoyed it immensely, and been paid for it. Enjoy your jquery! (and your ignorance!)

sounds like you didn't actually understand the parents point.

I'll give it a shot if there's a stable build of the Reagent<->BrainFuck transpiler working.

Or that you need to be introduced to Reagent. Simple doesn't even begin to describe it.

To the author of the article- Kudos! Well written, well reasoned, with minimal hyperbole or unnecessary “X is dead” style declarations. Hope we see more writing like this bubble up to the top on HN.

I’m not swayed by the argument, but that’s personal bias. I’m the technical cofounder / solo coder of a venture backed startup, and I built our platform on rails 5. I migrated our front end to Vue over the winter and couldn’t be happier.

When we started (my cofounder and I) our company in early 2017, it had been a few years since I coded daily, and I’ve never been a front end programmer. I’m not well skilled in JS, so I punted on using any front end frameworks for the first six months. Our entire MVP was rails 5 server side rendered pages, with a dusting of jQuery when needed. It definitely got me as far as I needed it to, but I felt a lot of pain once I began to try to mix in a lot more interactivity in the app. For me, migrating to Vue made a lot of sense and continues to pay dividends. For others, the author’s arguments are probably far more applicable.

One area where I deeply agree with the author is around how in JS I often don’t know exactly where I should write certain parts of my code. For a long time, I had a lot of model logic in my Vue components, but that quickly became a nightmare and I’ve abandoned that. Now I use ES6 classes to wrap a bunch of my logic, but even then I still find stuff bleeding places that seem wrong.

One thing I also avoided so far was using any state management (a la Vuex). In some rare examples I use a message bus to send information around, but even then that usually triggers a component to go refetch information from the source of truth (the API endpoint). So far this pattern helps to restrict me from making certain lazy choices which will feel good in the moment but become maddening in the future. My app, as such, is not as maximally performant as it could be, but the trade off for the rare update has so far felt worth it.

So, to sum it up, as a veteran coder who spends 12 hours a day writing code, but knew rails really well and not any SPA frameworks, I’m sympathetic to the article but respectfully have a different experience.

> I felt a lot of pain once I began to try to mix in a lot more interactivity in the app

I don't think you're actually disagreeing at all. You're using the right tool for the job. You started with one job and the right tool, and when the job changed you switched tools. That's as it should be!

Use Rails until you can't. That's what you did and I can't see the author disagreeing.

You can generalise this to most technology. I know someone who has gotten it into his head that he needs to write his entire new web app using golang and microservices. I'd suggest that when he actually outgrows Rails enough to require that then he can suggest it to his 50-person-plus engineering team, but in truth I don't think he'll ever actually finish it.

Another plus to this "ramping up" of tools as necessary is when you get to a certain point where your entire UI is sophisticated enough you can cut the views out of your rails app and basically transform it just a REST API with another service responsible for serving the UI layer.

Rails makes a fantastic REST framework, especially if you build your app that way right from the start.

Good point, and this is exactly what I did. I actually was running the SPA + the rails app side by side. Took me about 6 months, but I cut over every page / app one by one till I was done.

And, to the parent commenter, good point. I do think the gist of the author is to use the right tool for the job, and they are not dogmatic about "never write an SPA". Thanks for keeping me honest.

I’m curious, what was the change in the UI which required the move away from Rails?

What are you accomplishing with Vue which was impossible before?

Would love to get a glimpse of the app.

I'm not the OP, but here's how my Rails app is growing after several years:

The first "complex" UI design that we came up with was creating a list view that came with all the trinkets you'd want from a sophisticated list view (pagination, sorting, filters, searching). This view needed to be able to apply easily to all the key data structures our app uses (list of users, list of things user has, list of things users do, etc) which meant due to the scale of some of the data sets most of the operation work needed to be on the backend.

Originally, it was built as a completely normal Rails view requiring a full page refresh (form submit) to perform any given operation. This certainly was "doable" but not a great experience as someone administrating lists of things in our app.

We then wrote a React component that manages all the visual state itself based on the data returned from the backend and replaced the existing Rails view with this React component. By pushing responsibility of view state to the client our Rails codebase get simplified. React fully manages visual state, but where we really benefit is the fact that it forces you to design components in such a simple way that UI abstractions become more naturally fitting. The conventions are easy to understand and result in a codebase that can have a lot of cooks in the kitchen without too many problems.

Could this be written in jQuery? Sure. If it's like most large jQuery projects I've seen with multiple hands on it, it will be hard to keep it from being too brittle.

The implementation is really part of a longer term plan to begin building out new user interfaces in React. We find that react delivers on the promise of UI reusability much better than any backend MVC frameworks view or partial system. A front-end codebase is starting to emerge with it's own developer conventions and processes that are more geared towards frontend requirements. Meanwhile, our backend is simplified to only deal with tasks related directly to data management. The split feels very natural as the codebase grows larger. There is no obvious downside to writing in React besides the minified library code payload.

As a summary: our users expect interactions with complex interfaces to respond quickly. React is designed to build interfaces that fulfill that expectation, and the implementation of React in our codebase allows to slide into a more microservices looking architecture in an organic way as the scale and complexity of our app increases.

Our core product offering is a fully white glove 360 review process for small to medium business (mostly startups between 10 and 300 employees).

The objective of our process is to deliver highly actionable feedback for each and every participant, so the “review” you fill out for yourself, your manager, and your peers, feels different than a normal form based review. We ask a series of questions, adjust what we ask on the fly, and try to help encourage writing high quality feedback along the way.

We do a part of this process during a workshop we run on site, and that tends to mean a bunch of people packed on a single WiFi node. Having the app as an SPA allows the user to fill out their 360s, even on a dreadfully slow network, and not notice. This could have been achieved with jQuery, but given how complex I know this code is under the hood, I shiver at the thought.

To the questioner, my email is in my profile. Shoot me an email and I’ll point you towards our demo.

If you use Rails until you can't and then start making a SPA you'll have the common pattern of an application where you never have any idea whether any given thing is built in the Rails templates or in the JS or in some combination of the two.

Is that really a common problem? Can't say I've ever had much trouble remembering what's doing what.

If it really was an issue you could just tell one of the environments to throw a banner up the top of the screen or something in dev mode saying where it's from.

It's a pretty common problem for old legacy apps to have. I don't get the banner thing. Often the same page has functionality interleaved from both sources

My experiences are pretty much the same, the important distinction was when we added support for mobile apps, the API design problems had to be solved anyway, and significant differences between the interfaces for both mobile and web made it a pain to work with, we shifted to full API driven back-end and ember front-end and I cannot be happier.

I think the author is missing the fact that it it hard to justify Rails only approach if you have to support mobile interfaces and HTML is not only medium you are working with.

This is what is pushing me to write spa first now - it covers all the consumption bases. You get desktop, mobile web/progressive/hybrid and half of native.

I think that prototyping your software with (insert server side software ) and jquery is a really good way to prototype. It lets you get to market and or fail faster .

Maybe for you. I write React and a web API (using Swagger in Ruby or TypeScript/NodeJS) significantly faster than I do any server-side framework I've ever used. React components are an easier way to frame HTML--here, let me not remember how Bootstrap elements are created and just invoke <Button>--and JSX is the most fluid and flexible templating system I've ever used.

Dealing with stateful and rickety jQuery is why I stopped doing web stuff in the first place. Having React and a halfway decent dev environment in ES6/ES2017 and now TypeScript brought me back.

This is now my feeling as well, after coding in Vue for only 9 months. If I started a project tomorrow, I'd use Vue on day 0 100% of the time. Even if I'm just rendering HTML, the process of using it helps me to separate out my components and break them down into small and understandable pieces. I'm sure I'd get the same benefit from Ember, Angular, React, etc., if I knew those frameworks as well.

My feeling is that I don't experience a startup tax with using a frontend framework, like Vue. To me, it's now as natural as using Rails on day 0.

I’ve used both Vue and Rails. Rails partials does meet my needs for compartmentalizing code.

Don’t really see what benefit would I get for adding the complexity of separating the front end in its own layer.

Turbolinks gives me the speed of an SPA and I get 5x the dev productivity by not adding one.

And I absolutely love Vue.

What am I missing?

You're probably just not writing that much javascript, or needing javascript, so it sounds like you're not missing anything!

I don't find using Vue adds complexity for me anymore, and I enjoy a lot of the benefits of it (component libraries, scoped styles). That might not be enough for you when you're working with mostly vanilla CRUD pages, so I totally get it. If your productivity goes down with Vue, then it should take a big reason to add it. For me, it at minimum is not net negative, and I'd say even for trivial pages it's a net positive.

> That might not be enough for you when you're working with mostly vanilla CRUD pages

> I'd say even for trivial pages it's a net positive

Curious, what do you consider more complicated than CRUD, yet simultaneously "trivial"?

Poor choice of words on my part.

For me, using Vue is worth for CRUD pages, trivial pages (pure HTML), etc. There's enough it gives me that even though I don't need it, I enjoy utilizing it in my workflow.

What I was attempting to express is that I understand that for many, it doesn't give them anything in a basic CRUD page, and in fact can add a lot of complexity when you move away from built-ins with the backend framework (like what rails gives you). So, I can get why someone might say "it's not enough".

Reading this, I am windering if the way I am approaching Vue is more complex than the way others do.

Could you outline your approach to including Vue, to carrying state and changes from the rails api to the Vue-powered views, incl. initial state?

Do you think you could share a code sample?

Hey Andrei! I don't have any clean code examples easily handy, but let me work on it for you. Shoot me an email (email is in my profile) and i'll share a gist with you.

The tl;dr is: [0] Use single file components [1] API endpoints return JSON. Nothing super fancy, just taking rails objects and return JSON. [2] What would have been a rails "view" corresponds with a route in my vue-router config. Nothing special there either. [3] A top level page (think /index or /item) [4] Each top level page calls a private endpoint, which is just its own natural route in the browser, and pulls down data it cares about through the JSON request. Each json object corresponds with an ES6 class which wraps any object specific logic (usually end up having to dupe some code between ruby + js here). [5] Each top level page is broken down into components (widgets, major sections of the page), for code clarity. [6] Anytime I find myself doing a for-each loop, I usually look to see if whatever the sub element is should be its own component. Usually the answer is yes (just depends on whether it has its own independent logic).

Everything is passed top down as an object, but I do break the "cardinal sin" of mutating props on the object. Traditionally, props should be immutable in Vue, which requires use of Vuex or an event bus to change state. I haven't had a case yet where this has been an issue, likely because each page transition reloads whatever data it needs, and the same object isn't being mutated by multiple components in a way that would cause debugging nightmares.

A few patterns I use to keep myself sane are wrapping objects with their own save methods (so I can just .save() ) an object and persist it back to the server.

I dunno, probably a lot more there, but I haven't given this any deep thought. Reach out, and let's exchange thoughts!

This is also exactly how I build Express APIs. One thing I'd add: when building an API, use Swagger (or something similar, but Swagger/OpenAPI have basically won, just do it). It makes API clients way, way easier to wrangle and removes a lot of the surprise from your application development. I sometimes forget that not everyone using React or Vue uses Swagger-based APIs that really do just kinda work, but they're a large part of why, for me, writing a fully-featured frontend is way better than entering Rails template hell or whatever. It's really, really easy: just a bit of state in the React component, kick off a fetch during componentWillMount, and drop a spinner that remains 'til you get an error or your data. If you're using TypeScript (and you should be), you'll have some pretty happy autocomplete based on the contents of your state and can just write code off the returned objects. Life's fun this way.

On the server side I use Express in Node and either `tsoa` or `inversify-express-utils`, while in Ruby I use my own Modern[0] library to autogenerate a Swagger document from the controllers I specify.

[0] - https://github.com/lukeautry/tsoa

[1] - https://github.com/inversify/inversify-express-utils

[2] - https://github.com/modern-project/modern-ruby

Thanks Eropple!

I'd love to take a further look at your modern-ruby library. Hope you're able to continue to flesh out examples and documentation :)

You're missing that writing TypeScript, for a lot of people (myself included these days, if we're being honest), is a lot faster than writing Ruby. My productivity has spiked a ton by moving almost exclusively over to Swagger APIs in TypeScript and continuing that by writing a (relatively easy, relatively quick, not-magic-Rails-junk) React frontend is just the path of least resistance.

And I like Ruby.

I think both sides are doing something different.

If you want to prototype / start new project with complex UI (think filterable lists / tables, communication apps, dashboards, ...), you are building the app around the client and SPA is natural choice

If your app is more like (simple) CRUD app, then you probably don't need SPA features, and they might even slow you down.

There is no clear line between those two, so lot of the time you can do both approaches, but in the end your desired UI complexity drives the tradeoffs.

This makes sense, for the few views which contain the complex UI. What I’m having a hard time with is the suggestion to replace all views. I don’t see the benefit in that.

I think that quickly becomes untrue if you have any significant amount of front-end functionality.

Can you expand on significant amount of front-end functionality ?

Writing jQuery to accomplish a feature like hiding one element if another is checked is significantly more code and more error-prone (not to mention difficult to test) than doing the equivalent thing with a tool like Angular is.

It's 1 line with jQuery, so I guess "significantly more" is relative?

Every spaghetti ball starts with these one liners. Using just one line implies no structure or separation of concerns (needed for anything complex), which is why nobody is talking about this case, and immediately jumping to theoretical "SPA-like functionality, but implemented in jQuery".

EDIT: as for your original question ("significant amount of FE functionality"), from my experience jQuery loses a lot of its appeal when you have over 1k lines of JS, and I guess over 5k JS frameworks (React, Ng, Ember, Vue) start to be significantly better. When over 10k jQuery would be crazy mess (I have seen one such project, it was fun trainwreck).

Alright, fair, you could just assign a toggle on click, but if the interaction is any more complex than that (check some other form value, see if multiple different boxes are checked, etc.) it's not.

I’ve had a wonderful experience using Vue in Rails applications and there are ways to do this without building a full blown SPA. The philosophy towards JS frameworks has usually been full throttle or not at all. I think there is a happy medium where you can use Vue when it makes sense to. This is a great application especially for existing projects that need to be more interactive.

I've used the same approach on some web apps, but combining ASP.NET MVC Core with Vue. I think it's quite common for web apps to have only parts that have a complex UI (even if it's the main part), so this pattern makes a lot of sense for some teams.

How do you handle SSR for SEO? Or do you not need SEO?

I don't need SEO for what I've released so far, and the pages are properly indexed by Google, despite being SPAs. Our product is primarily B2B, so the website isn't a destination at the moment.

If I needed to have SEO friendly pages, there are SSR solutions I would look into using (like nuxt) or just pre-rendering the pages myself (I already use puppeteer for PDF rendering elsewhere in the product).

If you use PHP and you like turbolinks etc. then look at this:


It has pages and AJAX out of the box, and works with existing web tech. Turn your website into an SPA.

Are you building a website? The practices espoused by the author will be ideal.

Are you building a web app? Will you have a mobile client alongside your web app? Using a javascript framework for your client(s) and decoupling your data from it's presentation will be a fruitful investment. All of these frameworks and their associated happened for reasons, and they didn't involve traditional MVC being good enough for everything.

As an aside, I find this viewpoint prevalent in the Rails community and the Rails job I had (so, caveat, I'm coloured by my personal experience). It also lead to a culture of staunch refusal to learn or do anything new in that job, and the quality of the product suffered. It consequently led to me leaving the job, and being much happier for it.

> It also lead to a culture of staunch refusal to learn or do anything new in that job

I find one of the most difficult aspects of software is the very powerful "local minima" of effective (but not optimal) techniques combined with entrenched knowledge. People are so incredibly biased towards what they know well, and that bias is backed by objective evidence: when they do it X-way they are objectively faster AND better, and what's more, X-way has many objective benefits. This is the local minima in a vast multidimensional space of the benefits and tradeoffs of different possible technical approaches. The multidimensional problem of overall comparing X-way with Y-way is nearly impossible to accomplish, so we nearly always fall back to our intuition (aka bias) which nearly always leads us back to what we already know. And consequently most organisations are stuck in some version of a local minima that is very hard to escape, but ultimately represents a big disadvantage over time. But the question of when is the right time to move out of that minima - and incur the expense of navigating the hills between where you are now and the better minima - is really hard to solve.

> but ultimately represents a big disadvantage over time.

That presumes that Y-way is inherently advantageous to X-way. There's still plenty of sites that can and are market leaders using an out-of-flavor framework like rails/spring mvc/.net. New frameworks do not necessarily supersede old ones - they are usually a response to new use cases that have cropped up. These use cases may or may not be important to your business.

If new developers start at Y-way, we can assume they'll add more advantages to Y-way like improved tooling etc..., so maybe Y-way will eventually surpass the X-way.

In tech, it's not what one particular developer thinks but the consensus among the contributors which decides which one out of X or Y will end up having more benefits.

> In tech, it's not what one particular developer thinks but the consensus among the contributors which decides which one out of X or Y will end up having more benefits.

It's always the people using the tools that decide whether X or Y will have more benefit. You don't easily get contributors without first having users. Or did I misunderstand your point of view?

I totally agree, but I thought it was funny that you invoked the concept of local minima - I have only ever heard that concept in terms of local maxima, ie locally-but-perhaps-not-globally maximal productivity, comfort zone, etc. I assume you are referring to a locally/globally minimal resistance, time taken, or some such?

Anyway I just thought it interesting that you might make valid reference to a very useful concept I've heard and used many times, and yet in your expression the "polarity", as such, is totally inverted! And yet I understood you anyway. A computer would be totally confused.

Local minima come from optimization problems as you encounter for example in Machine Learning. You usually want to minimize some error function (e.g. misclassified objects). Unless you take great care these functions are riddled with local minima where naive optimization gets stuck.

Ah I see - of course. Should have thought of that.

For comparison, I believe my usage arises from evolutionary fitness, where one might discuss local maxima on a fitness landscape. The challenge is perhaps much the same as in ML, with one strategy being to introduce random mutations in order to escape the same kind of trap.

Heh, it is interesting how people can have inverted mental models of the same thing.

Actually, my preference for minima vs maxima is because minima translate readily to the natural world where you can imagine balls rolling down surfaces or water running down hills and getting stuck in local "minima" even though there is a lower energy state available to them. It makes a much easier mental model for me than thinking about maxima.

This is an interesting point - my limited experience has been that with successive generations of hires, each attempts to update the practices and tools used to build the application. This leads to pockets of properly functioning Y-way code and many layers of inefficient and difficult to support bridging between X-way and Y-way.

Overall, in each one of these scenarios my gut is that it would have been more efficient to attempt to optimize X-way, rather than layer Y-way on top. It always seems the goal is to incrementally migrate from X-way to Y-way, except we never seem to quite finish and frontend moves quickly enough that Z-way starts to look enticing midway through the painful migration.

I think it is extremely important to differentiate between the benefits of building a fresh application Y-way initially, and the (often extremely painful) friction of migrating from X-way to Y-way. One great example of this is the recent AirBnB departure from React Native. It seems like the majority of their complaint with the framework was that it was difficult to integrate with the rest of their app - had they built from the ground up in React Native, they likely would not have experienced such integration challenges.

> decoupling your data from it's presentation will be a fruitful investment

Very good point. You'll be building an API anyway if you want a mobile app. However, you can probably get away with a much smaller one, for only the most interactive parts of the app - I've gotten a lot of mileage out of simply embedding web pages for fiddly things like settings pages and other complex forms in mobile apps, saving the native API-driven section for only when needed. The hybrid approach can actually save on mobile implementation time in that way, too.

> a culture of staunch refusal to learn or do anything new in that job

Sigh. I have encountered this too. But I think it's mainly a person-by-person, or perhaps team culture, issue, coupled with the fact that Rails has been around a long time. I've been using Rails since it's in beta and am very happy to use React et al when called for.

Sadly, when (if?) React gets to 10 years old, you're going to see the same thing on that side of the fence! There's a certain type of person who's always going to be grumpy about learning something new.

> There's a certain type of person who's always going to be grumpy about learning something new.

I resemble that remark :). But I hear you, sometimes you have to invest to figure out if something is any good, and one way to do so is to build something real with it.

However there's danger on the other side too--a company with 5 different apps in 5 different frameworks or languages that all have to be supported by a small team of developers. That can't leverage deployment or performance tuning knowledge across apps. Where work is siloed because "Dev X doesn't know golang and Dev Y doesn't know rails". And where you can't rewrite the app because the business leaders wonder what they'd get.

I have to admit, I do not know Turbolinks well, but I feel like the author misses something fundamental about the benefits of modern frameworks. It's not just about building a giant SPA - component-based design is a huge value proposition.

The problem I see at the moment is that client side "apps" - however they are rendered - hit a wall in complexity that is really hard to overcome without a a sane and sensible way to break them down into pieces. Just like every sane regular programming language has concepts of classes or modules or some kind of system for divide-and-conquering problems into pieces, your front end needs that too once it gets complex. And that's what these React/VueJS frameworks are doing for me. What I like is that they make the right solution - breaking a piece of logic or code into its own component - the easiest solution. So I tend to do the right thing, not because it's "the right thing" but because it happens to be the easiest thing to do.

I know this is a bit of a parallel argument with respect to whether you build a SPA or not (especially Vue can live in either world just fine). But I feel like the author is throwing out the component-baby with the SPA bathwater.

Components aren’t a well defined thing. Most people mean “React class” when they say component. React apps are much more than components. Some components have their own state, some don’t, some touch global state, routing and data fetching are often not components.

“Component” web apps are by no means simple.

> Just like every sane regular programming language has concepts of classes or modules or some kind of system for divide-and-conquering problems into pieces, your front end needs that too once it gets complex. And that's what these React/VueJS frameworks are doing for me.

One question which should be included in that is whether you need a huge framework and supporting toolchain or just ES6 classes. There’s a good argument that using standard features will last you longer than frameworks which rapidly go in and out of vogue, and it avoids the constant frictional support costs of regular forced upgrades and debugging complications.

You can do the same with server rendered apps. I don't think reacted and co invented components

> For your SPA logic, you will want a rich model of objects that represent your domain and its rules. And you still need the same for your server logic. And this recipe is just a duplication waiting to happen.

Great article overall but one premise I question is: how often do you really need a non-jQuery JS framework at all in the client?

It seems to me that most apps are simple CRUD apps and server-side rendering is sufficient. Sprinkle in jQuery for simple client functions. Use jQueryMobile for the SPA framework which improves performance by making an AJAX request for any navigation and replacing the page body (instead of doing a full page reload).

I recommend only moving to a full non-jQuery based framework if the design or functions require it (and question that) or the app evolves to require it. As fast as computers, phones, and the internet are today, doing server-side rendering seems good enough for most apps.

In jquery programming there’s a huge difference between how the stuff that shows up when loaded is programmed (on the backend) and how the changes you make after it’s loaded are programmed. This leads to a lot of weird inconsistency if you’re doing anything more than showing and hiding existing content. Also, with jquery everything involves a lot of imperative programming and stashing state in random places in the DOM. If you’re doing anything more complex than drop downs and modal windows, use a frontend framework or your code will devolve into a huge pile of spaghetti.

It's not necessarily the case that jQuery code devolves into a huge pile of spaghetti. It's very possible to stay organized without a framework, even for fairly sizable JavaScript apps. It takes a bit of foresight and thinking ahead and discipline, (usually resulting from having written piles of spaghetti in the past). But most large jQuery in the wild is indeed spaghetti, with that I will concur.

Yea, you can write your own framework to avoid it becoming spaghetti. But most developers are going to mess it up. I've seen a lot of bad jquery apps and a lot of bad react apps. The bad react apps, they might be hard to understand, but at least they behave consistently.

> by making an AJAX request for any navigation and replacing the page body (instead of doing a full page reload).

This sounds like the "pjax" idea. I did this recently in a prototype; it's about 30-40 lines of JS (not including a shim for the pushstate-API) and maybe a dozen lines in the backend. It just works(R), and makes things as fast as the backend can deliver stuff. Much faster than stuffing hundreds of kB of framework CSS/JS down the browsers throat for each click, and far more simple than any JS-SPA-frontend-bingo-stack.

You can go one step further and ask, if jQuery does the job for you, why do even need it? The core problems it solved (cross-browser reliability and DOM selections) aren't really problems anymore.

Not that your point is invalid - many people do jump into modern frameworks for sites and apps that are simple enough to not need them. And SPAs don't need to be anywhere near as complex as this article proposes. But if you are going to go down the road of recommending simpler architectures, without a framework approach, then commit to it fully, and just go with vanilla JS.

jQuery makes it easier though, particularly if you know it well.

Without any input from me and several other js devs in our org, it was decided that we'll do a complete rewrite of our Ember.js app in React. The primary reason stated was hiring and the secondary was build times. The first should have been performance but they've been pretending like performance doesn't matter and that it's good enough. It's not.

Since it's easier to develop, our backend admin system is built in .NET's MVC framework and it's lightning fast compared to our frontend. Like ridiculously fast. I'm not currently a backend dev but I have extensive experience with Rails and I've seen the same with Rails. It's fast.

Despite the fact that I'm a front-end dev and it's not in my best interest, my un-requested recommendation was to do the rewrite in MVC, thus delivering everything from the server side. Here are my stated reasons:

• The site will load and responds incredibly fast

• The "build time" problem disappears

• The "hiring a lot of specialized javascript developers" problem disappears

• Backend devs suddenly become full-stack devs

• Deploying is easier

• Testing, both automated and manual, is easier

• SEO is easier

• You can now hire junior developers who are productive and don't create a mess in a new js framework

• It's going to be supported for a long time, unlike the latest javascript-framework-of-the-day

• Our website is a website full of mostly content and CRUD forms, not an app.

We actually have very little "highly interactive" parts of our site and those that we do have can be a light-weight framework or simply a sprinkling of javascript. It should have never been an app in the first place.

If everything had been build in Rails from the beginning, instead of .NET and Ember, we would have been twice as productive with half as many developers and wouldn't need QA at all if we wrote tests.

This opinion was basically scoffed at with no valid counter-arguments given. They will move forward with a complete rewrite in React, which will solve none of their problems, except MAYBE hiring, and likely create more. They'll also probably do it without me. I'm not against SPAs or React when used for the correct reasons, especially considering I've been focused on front-end for the last 5 years, but I am vehemently opposed to bad decision making.

"We actually have very little "highly interactive" parts of our site"

That should have been your determining factor as to whether or not a SPA was appropriate.

We've had the opposite experience; our new react SPA is noticibly faster than our current rails site, but it is due to the nature of the pages, not "X is always Y compared to Z"

>> Backend devs suddenly become full-stack devs

this is the reason we moved in the other direction, in my limited experience, people would should really backend devs doing frontend work because you framework/ arch is full stack and requires it, has been terrible

I think if the conversion is led by a very experienced React developer this could be a good decision. We decided to write all our sites in React a long time ago and couldn't be happier. It doesn't have to be a SPA because it's React, we have static sites too.

Judging by how your org made the decision without the devs input though, I'm not too confident it won't be disaster. It's depressing but I've been offered too many contracting opportunities to rescue a project after a similar conversion that is a total dumpster fire.

No one on the team has ever used React.

> wouldn't need QA at all if we wrote tests.

If this is true, you’ve been doing QA wrong. A good QA team will catch gaps in the developers’ thinking, not just click buttons like robots.

Why you had to rewrite Ember.js to React? Ember.js is fast, modern and easy to work with. The Ember ecosystem is matured and reliable. It doesn't really make sense.

OP said the primary reason was hiring -- "The primary reason stated was hiring and the secondary was build times."

I was initially skeptical, but this article nails the issues 100%. His experience mirrors my own and I don't think I even had a single place where I disagreed with him.

All I would add is that rails can be made to work wonderfully with SPAs if you're willing to do some metamagical programming to auto-follow standards like JSON API.

Replacing the entire body with every request seems a bit overkill. If you want SPA interactivity without moving control to the client side, try intercooler.js


A very well thought out and articulated article.

I love Rails and the power it offers in development productivity and quality. It's code is very maintainable and actually enjoyable to develop in; even when it's someone elses codebase.

Oddly enough, I finally came upon a use case in a project where an SPA frontend (Vue) / ruby backend make more sense given the platform nature and operational needs (runs on a pi, no "models")

9/10 Rails is the way to go though for developing something.

Has anyone used jquery mobile?

It was an amazing project that let you write normal css/html/js without modifications THEN rendered the html+js into a SPA. It was fast, preloaded pages, clean, easy to write and really well documented - and maintained the root dom element. BUT! The project is mainly(opinion) dead. Instead people want to write in a new language (react,vue,etc) then deal with adding a massive layer of complexity.

I've used JQM for a SPA for years and it's old but works fine. I'm dreading the day they release the new version and finally remove deprecations (for good reason: to improve performance) because many add-ons and hacks will surely break.

> The project is mainly(opinion) dead.

I don't think it's dead so much as they are really worried about backwards compatibility (rightly so), so they're taking their time. It could also be argued that, for its purposes, it's not so much dead as nearly complete.

On top of JQM, there's PhoneGap which I've also used for years and created both an Android and iOS app in the app stores. It allows you to access most native APIs through JavaScript shims.

Overall, I've enjoyed the simplicity of JQM+PhoneGap (I use Rails as the backend). You can still layer on any other JS framework on top, so it's not limiting. My friends and I use the app daily and performance is fine on a modern phone.

Having the same code (and I'd argue, look and feel as well) for web, mobile, and native is the best way to go for a small project trying to contain time and costs.

I dunno, my experience was that JQuery mobile was slow, bloated, and glitchy.

Perhaps it was simply ahead of its time, and 2011-era browsers couldn't keep up with it, but either way I much prefer using its successors.

This is the first time I've ever heard of jquery mobile described as fast, and I used to work for a medium sized consultancy / agency (as in upwards of 50 front-end devs) that did a lot of projects with it.

In fact, I don't really recall anyone speaking positively at all; at best it was a necessary evil.

I wonder how the argument changes if you know you need an API for your mobile application that's almost identical in features to the web page.

If you go the "Rails/Django way" with server side rendered templates and, say, a bit of jQuery for fancy stuff -- you'll end up duplicating lots of code for the API (validation, routing, maybe even business logic).

Anyone got experience with swapping your models/controllers for an API while keeping the rest of Django's/Rails' niceties? (authentication/sessions, Django's forms system, CSRF, etc.)

OTOH having Django/Rails merely as a template system you probably could also go for very simple, self-contained client-rendered JS pages (e.g. .vue files). Not much difference there I guess?

I think it should still be possible to seperate view from the service at the backend, even if that means defining more routes. I am talking from the hiccup(clj) point of view though

Rails is a deeply flawed framework, and we need to stop using Basecamp as the example of a well designed monolith. Basecamp is terrible software, and the crappiness of the user interface appears to be a direct result of not being able to build rich interfaces as its coupled to legacy Rails designs like this article suggests. Basecamp being fast while getting a trickle of traffic and working with very little data is not a selling point against SPAs (I'm not pro or con SPA).

What are the deep flaws in Rails? What's crappy about Basecamp UI?

I feel like seeing more and more post about criticisms for workflow or framework that it is becoming unhealthy with the developer community.

There is always short comings on every tool and library, and part of responsibility of a good developer is discerning trade-offs.

The main problems addressed in my opinion:

- Code duplication between server and client side

- Added complication threw data transmission between server and client (REST/json)

I think, both problems can be addressed by:

- having (a single) code that works both on server and client-side

- having transparent transport mechanisms for information between client and server.

I am sure, I could implement such a thing for Python/Django, using the already existing tools. But I am not sure, if such a thing would be appreciated by the community.

What do you think?

Using a framework like the F#-to-JavaScript transpiler Fable, along with an application framework like Elmish, provides a really good solution to some of the pitfalls cited in the article (prescriptive architecture, front + back-end code sharing) and gives you some moderately strong type safety to boot.

However, the article author's list of SPA pitfalls is really good, and are probably not all surmountable by a framework/platform.

Anyone have good experiences with an SPA architecture?

Try developing Slack or Discord with Rails and turbolinks. The point is, some apps are naturally SPAs. For those that aren't then it is unneeded complexity to make them SPAs. Also personally, I have had great experience with Vue in an SPA.

Yep, it's my go-to for any not huge web project. Plays well with any server-side tech you want, though I find Python (Flask, again with the right architecture, is a good experience) to be quite easy and enjoyable. The key is a sane and simple enough architecture from the start, which comes with experiences (aka making mistakes). But I personally go with Vue/Angular 1 consistently, trying to go more Vue now that Angular 2+ has IMO gone off the rails (heh).

Ember.js follows similar principals than Rails. Modern, matured, great ecosystem. You can move really fast with a Rails API and Ember.js frontend. Really, really fast.

Yes. I/we are using AngularJS to update some applications (apps, NOT sites) that manage state forms from initiation within private organizations with a workflow through the counties up to the state. There is quite a bit of interactive validation and input formatting / lookup support in a small number of very long forms, so it helps to have most of the interaction on the client side.

Also on the plus side, the back end requires less code now. IMHO, where Java is concerned, less of it is better. (There is still WAAAAAAAY too much of it, compared to equivalent Rails code)

Javascript might not be quite as good of a “Simula 67” as Java is, but it’s a much better Smalltalk or Scheme than Java is :-). (A comparison which probably doesn’t hold for JS vs Ruby)

Elm + Scala works for me. I'm using the same elm source with minor variations for both web & mobile (wrapped with cordova). So far, it's been working wonderfully.

That's an odd choice given Scala.js, any reason you're not all-in on Scala?

The elm architecture removes the need to make decisions when it comes to structuring the app. The tooling is first class. While I'm not sure, I think elm has a larger community.

We used Elm + Erlang and have been very happy

Like others comments , Kudos to the authors.

I'm an SPA Lover ( Angular , Vue ) , but still most of the points raised here a coherent from a back end perspective.

That said , a lot of the arguments are basically summed up as :

"I don't like Front End Dev. because it's not as mature as Back End".

I will not lie on this point , JS is a fast evolving ecosystem that sometimes has issues to stabilize. Hence , there is a lot of marketing and self promotion mixed with frameworks sometimes ( Growth Hacking ) pushing for unnecessary tech that dies a few days after they have leaved the Github Trending page.

For beginners , when a framework reach a certain threshold ( Github Stars most of the time) they feel like they should hurry and use the framework to stay relevant while most of the time they don't need to and the tech is just fluff.

My point here is very simple, you are ROR or Django or ASP.NET dev and you love what you do ? As long as you find jobs keep doing this , don't bother with Full Stack Fluff.

Now that said , I can only encourage the author to do the Angular or Vue tutorial to discover something different. Rails is great ( it's empowering a lot of website Github , Airbnb etc... ) but SPA are different and when used properly it's hard to go back , the experience is delightful.

Most importantly we are getting closer to the serverless era where backend will be completly different from what it is compared as now, and SPA and SSR will likely be the standard in the future.

I think you've missed the article's point:

> I don't like Front End Dev. because it's not as mature as Back End

No, he says don't do FE and BE when the tools for back end-only (well, Rails is full stack, actually) are so useful and productive. And in the rest of your comment you seem to forget that a front end is completely useless without a back end.

> you are ROR or Django or ASP.NET dev and you love what you do ? As long as you find jobs keep doing this , don't bother with Full Stack Fluff.

Rails is the "Full Stack Fluff".

> SPA and SSR will likely be the standard in the future

How, exactly? What serves your SPA? And who is using "serverless" for anything other than querying other backends (eg Slack bots) or accessing AWS services? I mean, sure, it's nice to not have to stand up a server to resize images coming from S3 but it's hardly going to replace, well, servers. You couldn't implement even the simplest CRUD app.

Uh, you can definitely implement a standard CRUD app with one of the serverless platforms. You can even throw an entire expressjs application into a lambda function with minimal modification if you want.

> You can even throw an entire expressjs application into a lambda function

This is the first general misconception with serverless.

Serverless is not lambda . If you think serverless == lambda, it's like saying cloud == ec2 . You're missing the point of it.

than please define serverless for us.

using lambda and its equivalent is - in my understanding - the definition of serverless. You might not be able to utilize the biggest advantages of serverless infrastructure if you combine it with a standard ACID database backend, but it should still be a serverless deployment.

Serveverless is not lambda. If you think so , you are mistaken , it's like saying Cloud == EC2 .

Well what is it then?

   > JS is a fast evolving 
Alas, it is more revolving, than evolving :(

I had this same experience. SPAs, especially for small teams and solo developers, hurt more than they help.

Turbolinks to the rescue. Slay the Javascript overlords!

There was probably a few valid points, but the article was too long with too many flimsy, "try-hard to convince" arguments.

Speaking of code duplication in a traditional web app every page is an example of code duplication. How about that?


> this attachment that older developers have for MVC is a ghost that really needs to be addressed once and for all. Seriously. MVC is dead and we need to let it stay dead

What needs to die is this grounded-in-fantasy contempt for mature, very much alive, performant technologies with huge ecosystems.

Isn't the problem in your rant of SPA architectures vs MVC the fact that plenty of SPA architectures are client-side MVC architectures, and most of the rest are slight variations in the MV* family (MVP, MVVM, etc.)

No. That's exactly wrong. We need to stop even thinking in terms of MVC. React, Vue, Angular all used component based architectures and if you think component based architectures can be labeled as MV* then you're not understanding why this pattern is lightyears better than MVC.

MVC was a hack of a pattern that developers adopted to get server side rendering architectures to even work. Good developers recognized its many flaws and when front-end development became decoupled from the server, tried and true practices and patterns such as modularity, reusability, and separation of concerns were adopted to the front end and the results of those efforts are the front end frameworks and libraries we have today. They are not variations of MVC. If you work with them as such, your SPA architecture will look just as brittle and shitty as a server-side architecture.

> MVC was a hack of a pattern that developers adopted to get server side rendering architectures to even work.

MVC wasn't even developed for networked applications, but for desktop GUI applications; it was later adapted for web applications,

And server-side rendering existed and the worked before MVC was a popular pattern to use for it; MVC was a step forward in making applications doing it maintainable, but want chosen to get it to work at all.

> Good developers recognized its many flaws and when front-end development became decoupled from the server, tried and true practices and patterns such as modularity, reusability, and separation of concerns were adopted to the front end

MVC came from application of exactly those principles to desktop development, and was adopted precisely to bring those to web development. Sure, it wasn't the end of the road in that, but it wasn't done kind of reversion from it, either.

They're in stage 3-4 of denial. Denial cycle.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact