ponyfoo.com

Server-First Apps are a Good Idea

Earlier today, Tom Dale published an article sharing his views on the whole “server-side vs client-side rendered apps” debacle. I was tempted to call this article No. You’re Missing the Point of Server-Side Rendered JavaScript Apps!, but that would’ve been way too long, and kind of childish. I agree with the first sentence in his article, where he states that there’s a lot of confusion about “the push to rendering JavaScript apps on the server-side”. There were many other parts of the article I agreed with, and a few I didn’t agree so much with. There’s also some points which weren’t discussed but I’d like to raise myself.

Improve this article
Nicolás Bevacqua
| 9 minute read | 16

In the article, Tom goes on to explain how applications rendered on the server-side are clumsy when it comes to responsiveness. This is a fair point, server-side rendered applications typically rely on the PRG (POST-Redirect-GET) pattern. They have HTML <form>s, users POST some data, the server processes the request, responds with a redirect to another page, and the client GETs that other page. These are pretty much the basics of the web. What’s worse, as Tom notes, is that as you start adding AJAX calls to this server-side rendered content, you are now a slave to both state (what you initially pulled from the server) and behavior (users clicking on things) when it comes to updating the UI. That is the ultimate nightmare of a web developer.

Client-side rendered apps, in contrast, can be way faster than that. Once the initial payload is downloaded, interpreted, and executed, client-side JavaScript can set up its own smart caching on the client-side, avoiding roundtrips to the server for data it already has, and it can also set up routing on the client-side to emulate incredibly-fast roundtrips. It can even have the server spewing information downstream as soon as it has any fresh data to offer, using WebSockets. The issue of updating the UI as a slave to many masters is long gone, since you just update the UI as the client-side JavaScript engine demands of you.

And so the story goes…

The answer to a productive and maintainable web development orientation, that also favors customers, doesn’t lie in one or the other, but rather in the combination of both approaches. In this article, I’ll explore what all of this means.

Angular, Ember, and React

I’ve already summed up my thoughts on Angular. The more I think of it, the more convinced I am that Angular is the Bootstrap of JavaScript. It’s a great way of prototyping an application or building a backend service, but there’s plenty of reasons why you shouldn’t be building a customer-facing application with it.

I hope 2015 is the year where we take out “dedicated client-side rendering” like Angular’s from our metaphorical best practices grab-bags. React and Ember are doing a good job of bringing people to their senses when it comes to one-sided rendering.

I’m not sure how the initiative to move Ember to shared-rendering, FastBoot will work, but if it hijacks <form> submissions and generally does the right thing with those (both before and after JavaScript gets executed on the client), then I’ll be quite sold on the idea. I’m glad to see that Tom Dale seems to have come around from clamouring that “Progressive Enhancement is Dead”, but I still think developing client-first applications and then rebuilding what should have been the original HTML is just backwards.

React is more of a “shared-rendering” native citizen, which makes it friendlier when it comes to progressive enhancement. It’s shared-rendering capabilities used to be mostly an option for Node.js developers, but Facebook recently revealed react-native as a way to write native Android and iOS applications on React, making it even more appealing as it now enables cross-platform development, a lot like how Google shares code across platforms using j2objc.

Progressive Enhancement

The web is not native, though. React and Ember don’t hinder our ability to develop a progressively enhanced application, but they don’t exactly encourage it either. I’d call them — along with Angular — client-first frameworks. Client-first doesn’t encourage progressive enhancement. Quite the contrary, client-first actively discourages progressive. That’s a real problem.

These frameworks are nice and definitely boost our productivity, but we should never stop thinking about building applications in such a way that they’ll actually work well (not just render well) for people on slow or intermittent networks.

I think these last few months we did a good job of thinking critically about whether the Angular way is the right way. I’m convinced that the web would be a far better place if we developed most applications in a content-first manner.

Principles of a progressively enhanced user experience should be commonplace by now. You build an application on pure HTML and CSS, in such a way that it’s able to deliver most of your core experience* right off the bat. This is important because sometimes JavaScript may take a few seconds to download. That’s why I made the point about using <form> elements to allow users to interact with the site, it enables more parts of the core experience.

It’s insane, what we are doing. We are deferring JavaScript and loading it asynchronously and then depending on it to deliver our core experience?

* Unless you’re a realtime video-conferencing service (or anything canvas-based), but even then you could take a progressive approach, where you inline the absolutely necessary JavaScript to enable the video-calling functionality, and defer the rest. Much like you’d do when deferring non-critical CSS.

Suppose you have a TODO list. Checking items off would just be a matter of clicking on them in a client-first application, then the changes would be persisted in the background. In contrast, a server-first approach probably would’ve had a <form> with the TODO list and some sort of Submit button. Right? But what if each TODO item was a <form>? What if each of them was a <button> within its own <form>? Then you could have almost the same functionality as people have come to expect from client-first applications, but in an entirely progressive way!

The HTML would look like this, except with proper form actions, hrefs, and CSS classes for styling.

<ul>
  <li><form><button>This is an option</button></form></li>
  <li><form><button>This is another option</button></form></li>
  <li><form><button>This is yet another option</button></form></li>
</ul>

It could look like the screenshot shown below, which comes from a product I’m building, and doesn’t involve any client-side JavaScript just yet.

stompflow.png
stompflow.png

Not any client-side JavaScript yet? That can’t be good! You must be thinking. Turns out developing applications like its the year 2002 is super productive — you don’t have to spend any time carefully picking a delightful animated loader gif, or debating with your staff about what’s the best way to do data-binding.

That’s the main argument against not using your fancy frameworks, right? But they’re so productive! Well, using HTML and PRG is fast, too! You just forgot they even existed.

Sure, the PRG pattern is “slow”, and client-first is perceptively faster — but guess what? Upgrading an HTML-PRG experience into an AJAX experience is a matter of writing a few lines of code, if it’s done right. From there, turning the experience into a real-time experience is the only challenge left. And, honestly? That’s just a matter of listening for the appropriate events and responding to them!

A Server-First Web

Taunus is a server-first shared-rendering MVC engine that prioritizes content and encourages progressive enhancement. It’s what this blog runs on top of, it’s what the documentation mini-site runs on top of, and it’s what I’m using in Stompflow — pictured in the screenshot above, but yet to be released.

Being server-first has its perks as well, just like client-first does. For instance, I maintain email templates using the same templating engine that I use on web views. Being server-first also means that I don’t have to worry about state vs behavior as much, because I have the same views on both sides and I can re-render them at any time in the client-side.

Being server-first means above all that the application will work well no matter what. It’ll work well if client-side JavaScript takes a few seconds to execute, because it was designed to do so. It’ll continue to do well after client-side JavaScript lands. You can take advantage of the conventionality of HTML forms and hijack form submissions just as conventionally, making the form submission via AJAX and then handling the response by redirecting or rendering some data.

You no longer fight against the disgrace IE8 unleashed onto you, but embrace it. You now fight against the idea that you should cram every single new feature onto users on old browsers.

Server-first is non-commitment to client-side technologies. With Taunus you don’t have to pick a client-side data-binding library, but you can choose to do so. We already agree that it’s easier to deal with vanilla components than jQuery plugins, or Angular directives, or React components, or even Web Components.

So, why not use a framework that empowers you to work this way? Using modular components that aren’t tied to the framework itself, which is more of a glorified “stay-out-of-the-way router” that dictates you how to do shared rendering by convention.

Fine, Taunus is tied to a server-side technology: Node.js (or io.js!)

That’s not an issue for React, or Ember. Not even for Angular.js.

But you know what? That’s a good thing.

Because you are forced to commit to a server-side technology first.

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments (16)

Damon Poole wrote

I 100% agree with this article.

I’ve been making node.js sites and webapps for the last 2 years and have continued to stick to content-first.

There’s a considerable number of people using things like NoScript so your core functionality should always be available through plain HTML.

Attaching data-binding and event listeners through deferred JavaScript is trivial once you have a product serving content-first HTML rendered on the server, especially if you’re using a framework like Sails.js which generates APIs for you, just make the controllers and views work with regular HTML and later on you can add JS that hooks into your REST API (which typically would map 1:1 with the plain HTML routes) and links data binding later.

Gerard wrote

These technical debates are pointless. Use whatever works for you, being it fancy or not. Only vendors should try to influence us, because they are trying to sell us their product, and thats that. Any competent engineer will never tell you what to do or what to use… because it depends! And at the end of the day you can do everything with any of them. There are no absolute answers kids. Use whatever pays your bills or makes you happy.

Arthur wrote

Yes, I totally agree! No problem is the same, there’s so many factors involved in choosing a subjectively ‘good way’ to do things …

Tony wrote

I agree, there are so many variables to factor in

Ian wrote

Yes, there are always many variables, but articles like this highlight the pros and cons of each approach. Thanks for the great read!

hexx wrote

Nice to see that common sense is still among us

Tony wrote

I agree with hexx, but we should also be pushing the web forward as well. It’s a fine balancing act, I guess it also depends on your target audience.

Tony wrote

Oh great article BTW

Lutz Rosema wrote

Awesome article, thank you very much for pointing this out.

I work for a small company in Lower Saxony, Germany. In 2012, I was sent to a course that covered Knockout.JS and a year later: Angular.JS. I followed the client-side path and the more the app growed, performance was getting to be an issue.

I refactored it to a shared client/server-side approach. Now, I just render the html at the server-side and provide additional features to the UI via JavaScript on top of the markup.

The result: awesome. Shorter load times. No more heavy DOM operations.

Additionally, a great advantage of the server-side approach is that the app can be run in text-based browsers like w3m, lynx and links. Well, at the moment, there are some features missing when there is no JS, but at least, the core functions of the application are accessible.

Andrew Jackson wrote

Security Auditing. In Client-Side rendering, the bulk of the code cannot be vulnerable to exposing something you wouldn’t want exposed. Your server endpoints have clean abstractions that make sense for mobile devices too.

Tracy Spratt wrote

Analogies can be a swamp, but isn’t designing application to work well on slow or intermittent networks like optimizing cars for dirt roads?

Shouldn’t we demand and expect ever improving infrastructure?

Justin Maltat wrote

Just a thought on the checkbox forms sample. It seems to me that it can break page readability notably for blind people

I think that progressive enhancement might be a good solution but that we should not alter readability for technical gain.

Nicolas Bevacqua wrote

Yes, so what I did is use aria-* attributes in order to prevent that from occurring. Here’s the HTML for one of the list items (without classes, for brevity). Using these attributes you can specify that your <button> should behave as if it were a checkbox (in the eyes of a screenreader).

<form action="/forms/bevacqua/stompflow/todos/5/items/3/off" method="post">
  <button role="checkbox" aria-checked="true">
    <input aria-hidden="aria-hidden" tabindex="-1" type="checkbox" checked="checked">
    <span class="ck-checkbox">
      <span>Text item</span>
      <span> </span>
      <time datetime="2015-02-17T16:04:24.535Z"
            aria-label="01:04 PM, Feb 17, 2015 (GMT -3)">
        4 hours ago
      </time>
    </span>
  </button>
</form>
Justin Maltat wrote

Thanks for your answer.

I’m a bit confused by the fact that each checkbox has its own form but it might be an application requirement that I don’t see.

That said, it was an interesting reading.

Sam Armstrong wrote

But you know what? That’s a good thing. Because you are forced to commit to a server-side technology first.

Not any more.

Ivan Vega wrote

I too have been of the server first idea for a long time. Recently I felt like trying going client side first, but the whole time I just felt anxious about what would happen on slow connections.

So yeah, I agree 100%, it’s not that hard to “modernize” a plain old PRG type app after the fact, and the benefits include I sleep better :)