A place to cache linked articles (think custom and personal wayback machine)
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

index.md 15KB

před 4 roky
12345678910
  1. title: Server-First Apps are a Good Idea
  2. url: http://ponyfoo.com/articles/server-first-apps
  3. hash_url: ff89062d4ecd5c0bc3396a78462ae5cc
  4. <p>Earlier today, <a href="http://tomdale.net/2015/02/youre-missing-the-point-of-server-side-rendered-javascript-apps/" aria-label="You&#x2019;re Missing the Point of Server-Side Rendered JavaScript Apps">Tom Dale published an article</a> sharing his views on the whole &quot;server-side vs client-side rendered apps&quot; debacle. I was tempted to call this article <strong>No. You&#x2019;re Missing the Point of Server-Side Rendered JavaScript Apps!</strong>, but that would&apos;ve been way too long, <em>and kind of childish</em>. I agree with the first sentence in his article, where he states that there&apos;s a lot of confusion about <em>&quot;the push to rendering JavaScript apps on the server-side&quot;</em>. There were many other parts of the article I agreed with, and a few I didn&apos;t agree so much with. There&apos;s also some points which weren&apos;t discussed but I&apos;d like to raise myself.</p><p>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 <a href="http://stackoverflow.com/questions/tagged/post-redirect-get" aria-label="Questions tagged POST-Redirect-Get on StackOverflow">PRG <em>(POST-Redirect-GET)</em> pattern</a>. They have HTML <code class="hljs">&lt;form&gt;</code>s, users <code class="hljs">POST</code> some data, the server processes the request, responds with a redirect to another page, and the client <code class="hljs">GET</code>s that other page. These are pretty much the basics of the web. What&apos;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 <em>(what you initially pulled from the server)</em> and behavior <em>(users clicking on things)</em> when it comes to updating the UI. <strong>That is the ultimate nightmare of a web developer.</strong></p><p>Client-side rendered apps, in contrast, can be <em>way faster than that</em>. Once the initial payload is downloaded, interpreted, and executed, client-side JavaScript can set up its own <strong>smart caching on the client-side</strong>, 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, <a href="http://socket.io/" aria-label="Socket.IO is one way to use WebSockets">using WebSockets</a>. 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.</p><p><em>And so the story goes...</em></p><p>The answer to a productive and maintainable web development orientation, <em>that also favors customers</em>, doesn&apos;t lie in one or the other, but rather in <em>the combination of both approaches</em>. In this article, I&apos;ll explore what all of this means.</p></section><section class="md-markdown at-body"><h1>Angular, Ember, and React</h1><p>I&apos;ve <a href="/articles/stop-breaking-the-web" aria-label="Stop Breaking the Web">already summed up my thoughts on Angular</a>. The more I think of it, the more convinced I am that Angular is <em>the <strong>Bootstrap</strong> of JavaScript</em>. It&apos;s a great way of prototyping an application or building a backend service, but there&apos;s <em>plenty of reasons</em> why you shouldn&apos;t be building a customer-facing application with it.</p><blockquote><p>I hope 2015 is the year where we take out <em>&quot;dedicated client-side rendering&quot;</em> like Angular&apos;s from our <strong>metaphorical best practices grab-bags</strong>. React and Ember are doing a good job of bringing people to their senses when it comes to one-sided rendering.</p></blockquote><p>I&apos;m not sure how the initiative to move Ember to shared-rendering, <strong>FastBoot</strong> will work, but if it hijacks <code class="hljs">&lt;form&gt;</code> submissions and generally does the right thing with those <em>(both before and after JavaScript gets executed on the client)</em>, then I&apos;ll be quite sold on the idea. I&apos;m glad to see that Tom Dale seems to have come around from clamouring that <a href="http://tomdale.net/2013/09/progressive-enhancement-is-dead/" aria-label="Progressive Enhancement is Dead">&quot;Progressive Enhancement is Dead&quot;</a>, but I still think developing client-first applications and then rebuilding what should have been the original HTML is <strong>just backwards</strong>.</p><p>React is more of a &quot;shared-rendering&quot; native citizen, which makes it friendlier when it comes to progressive enhancement. It&apos;s shared-rendering capabilities used to be mostly an option for Node.js developers, but <a href="https://www.youtube.com/watch?v=KVZ-P-ZI6W4" aria-label="&apos;Introducing React Native&apos; talk at ReactConf">Facebook recently revealed <code class="hljs">react-native</code></a> 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 <a href="http://arstechnica.com/information-technology/2014/11/how-google-inbox-shares-70-of-its-code-across-android-ios-and-the-web/" aria-label="How Google Inbox shares 70% of its code across Android, iOS, and the Web">Google shares code</a> across platforms using <a href="https://github.com/google/j2objc" aria-label="google/j2objc on GitHub">j2objc</a>.</p><h1>Progressive Enhancement</h1><p><strong>The web is not native</strong>, though. React and Ember don&apos;t hinder our ability to develop a progressively enhanced application, but they don&apos;t exactly encourage it either. I&apos;d call them &#x2014; along with Angular &#x2014; <strong>client-first frameworks</strong>. Client-first doesn&apos;t encourage progressive enhancement. Quite the contrary, client-first actively discourages progressive. That&apos;s a real problem.</p><p>These frameworks are nice and definitely boost our productivity, but we should never stop thinking about building applications in such a way that they&apos;ll actually work well <em>(not just <strong>render</strong> well)</em> for people <a href="http://ponyfoo.com/articles/critical-path-performance-optimization" aria-label="Critical Path Performance Optimization at Pony Foo">on slow or intermittent networks</a>.</p><p>I think these last few months we did a good job of thinking critically about whether the Angular way is the right way. I&apos;m convinced that the web would be a far better place if we developed most applications in a <strong>content-first</strong> manner.</p><p>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&apos;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&apos;s why I made the point about using <code class="hljs">&lt;form&gt;</code> elements to allow users to interact with the site, it enables more parts of the core experience.</p><blockquote><p>It&apos;s insane, what we are doing. <strong>We are deferring JavaScript and loading it asynchronously and then depending on it to deliver our core experience?</strong></p></blockquote><p><em>* Unless you&apos;re a <strong>realtime video-conferencing service</strong> (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&apos;d do <a href="http://ponyfoo.com/articles/critical-path-performance-optimization" aria-label="Critical Path Performance Optimization at Pony Foo">when deferring non-critical CSS</a>.</em></p><p>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&apos;ve had a <code class="hljs">&lt;form&gt;</code> with the TODO list and some sort of <kbd>Submit</kbd> button. Right? But what if each TODO item was a <code class="hljs">&lt;form&gt;</code>? What if each of them was a <code class="hljs">&lt;button&gt;</code> within its own <code class="hljs">&lt;form&gt;</code>? Then you could have almost the same functionality as people have come to expect from client-first applications, but in an entirely progressive way!</p><p>The HTML would look like this, except with proper form <code class="hljs">action</code>s, <code class="hljs">href</code>s, and CSS classes for styling.</p><pre><code class="hljs xml"><span class="hljs-tag">&lt;<span class="hljs-title">ul</span>&gt;</span>
  5. <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-title">form</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-title">button</span>&gt;</span>This is an option<span class="hljs-tag">&lt;/<span class="hljs-title">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">form</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
  6. <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-title">form</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-title">button</span>&gt;</span>This is another option<span class="hljs-tag">&lt;/<span class="hljs-title">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">form</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
  7. <span class="hljs-tag">&lt;<span class="hljs-title">li</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-title">form</span>&gt;</span><span class="hljs-tag">&lt;<span class="hljs-title">button</span>&gt;</span>This is yet another option<span class="hljs-tag">&lt;/<span class="hljs-title">button</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">form</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-title">li</span>&gt;</span>
  8. <span class="hljs-tag">&lt;/<span class="hljs-title">ul</span>&gt;</span>
  9. </code></pre><p>It could look like the screenshot shown below, which comes from <a href="http://blog.stompflow.com/articles/iterative-prototyping-for-the-web" aria-label="Iterative Prototyping for the Web">a product I&apos;m building</a>, and doesn&apos;t involve any client-side JavaScript just yet.</p><p><a href="http://blog.stompflow.com/articles/iterative-prototyping-for-the-web" aria-label="Iterative Prototyping for the Web"><img alt="stompflow.png" class="js-only" src="http://i.imgur.com/NqHl1zm.png" /><noscript><img src="http://i.imgur.com/NqHl1zm.png" alt="stompflow.png"></noscript></a></p><p>Not any client-side JavaScript yet? <strong><em>That</em> can&apos;t be good!</strong> You must be thinking. Turns out <em>developing applications like its the year 2002</em> is super productive &#x2014; you don&apos;t have to spend any time carefully picking a delightful animated loader gif, or debating with your staff about <strong>what&apos;s the best way to do data-binding</strong>.</p><p>That&apos;s the main argument against not using your fancy frameworks, right? But they&apos;re <em>so productive!</em> Well, using HTML and <strong>PRG</strong> is fast, too! You just forgot they even existed.</p><p>Sure, the <strong>PRG</strong> pattern is &quot;slow&quot;, and client-first is perceptively faster &#x2014; <em>but guess what?</em> Upgrading an <strong>HTML-PRG</strong> experience into an AJAX experience is a matter of writing a few lines of code, if it&apos;s done right. From there, turning the experience into a real-time experience is the only challenge left. And, honestly? That&apos;s just a matter of listening for the appropriate events and responding to them!</p><h1>A Server-First Web</h1><p><a href="http://taunus.bevacqua.io/" aria-label="Taunus: Micro Isomorphic MVC Engine for Node.js">Taunus</a> is a server-first shared-rendering MVC engine that prioritizes content and encourages progressive enhancement. It&apos;s what <a href="https://github.com/ponyfoo/ponyfoo" aria-label="ponyfoo.com source code on GitHub">this blog</a> runs on top of, it&apos;s what the <a href="https://github.com/taunus/taunus.bevacqua.io" aria-label="taunus.bevacqua.io source code on GitHub">documentation mini-site</a> runs on top of, and it&apos;s what I&apos;m using in Stompflow &#x2014; pictured in the screenshot above, <a href="http://www.stompflow.com" aria-label="Stompflow: Hassle-free Project Management">but yet to be released</a>.</p><p>Being server-first has its perks as well, just like client-first does. For instance, I <a href="https://github.com/ponyfoo/ponyfoo/blob/master/views/server/emails/article-published.jade" aria-label="This template will be running hot when the article gets published!">maintain email templates</a> using the <strong>same templating engine</strong> that I use on web views. Being server-first also means that I don&apos;t have to worry about <strong>state vs behavior</strong> as much, because I have the same views on both sides and I can re-render them at any time in the client-side.</p><p>Being server-first means above all that the application will work well no matter what. It&apos;ll work well if client-side JavaScript takes a few seconds to execute, because it was designed to do so. It&apos;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.</p><blockquote><p>You no longer fight against the disgrace IE8 unleashed onto you, but <em>embrace it</em>. You now <strong>fight against the idea that you should cram every single new feature onto users on old browsers</strong>.</p></blockquote><p>Server-first is <em>non-commitment</em> to client-side technologies. With <a href="https://github.com/taunus/taunus" aria-label="taunus on GitHub">Taunus</a> you don&apos;t <em>have</em> to pick a client-side data-binding library, but you can choose to do so. We already agree that it&apos;s easier to deal with vanilla components than jQuery plugins, or Angular directives, or React components, or even Web Components.</p><p>So, why not use a framework that empowers you to work this way? Using modular components that aren&apos;t tied to the framework itself, which is more of a glorified &quot;stay-out-of-the-way router&quot; that dictates you how to do shared rendering by convention.</p><p>Fine, <a href="https://github.com/taunus/taunus" aria-label="taunus on GitHub">Taunus</a> is tied to a server-side technology: Node.js <em>(or io.js!)</em></p><p>That&apos;s not an issue for React, or Ember. Not even for Angular.js.</p><p>But you know what? <em>That&apos;s a good thing.</em></p><p>Because you are forced to <strong>commit to a server-side technology <em>first</em></strong>.</p>