Rodrigo Rosenfeld Rosas
Server-side or Client-side focus?
David wrote a great article on the subject, suggesting that keeping all views generated in the server-side is the way to go for most applications.
If you haven’t read it yet, please do so, as this article was written to approach a few topics that I think are missing in that article.
Web applications can be written in many ways. In the early days JavaScript played a marginal role in web applications, performing some simple form validations and the like but currently more and more applications are making heavy use of JavaScript and lots of them are built as Single Page Applications (SPA).
I’ve been working on SPA’s since 2009, while David’s applications are mostly built around the original concept of web applications, by delegating as much as possible to the server-side.
Both approaches are valid ones, but as the complexity of dynamic browser behavior increases, I do believe that moving the UI to the client-side is usually better than generating them in the server.
So, if that’s the case for your application, please keep reading.
Server-side template and JavaScript generation
In David’s article, he refers to this approach as Server-generated JavaScript Responses (SJR), even if most of the response is actually HTML, not JavaScript, but I’ll keep his SJR terminology in this article to make it easier for me to refer to it.
Here are some spotted advantages:
Sharing templates between server-side and client-side
By rendering some HTML and JS in the server-side, one may reuse partial templates.
This is indeed a valid argument, but it doesn’t apply if:
- All your views are generated in the client-side; (which he mentioned in the article)
- You use some template language that can be shared both in the server-side and client-side instead of ERB.
Less computational power needed on the client
On the other hand devices are becoming faster and faster and it’s cheaper to move the processing to the client-side when scaling your infrastructure. In the long-term I don’t think it worths insisting on server-side processing because of this reason.
Some time ago I was trying to reduce the load time for our application and I implemented server-side generation of a big table in Rails and cached it in the server. It was obvious to me that it would save me almost 200ms (the time it was taking me to render that same template in the client-side - it should save even more for slower browsers/computers/devices).
The previous approach was to embed the JSON (also cached in the server-side) in the HTML (to avoid another request/latency) and render the template in the client-side. I was surprised that the page actually took a bit longer to load after the change. Sorry, I can’t explain the reason, but I gave up on the idea. And yes, I have always been served gzipped content (both HTML, assets and JSON).
It’s supposed to be faster
But it will actually depend on lots of things. For example, if some of the templates don’t need server-side data to be rendered, the network latency will be enough to make the server-side approach for rendering the template slower.
If you’re appending a template that never changes you could cache it in the client-side and avoid the round trip to the server every time you need the template, but if it depends on other data that you already have available in the client-side, the server-side template rendering approach won’t be faster.
Also, if you have to deal with several data state that is not stored in the database, trying to keep (or pass) all that state to the server-side will lead to insane maintenance.
Views can be cached
But this is valid for JSON as well, which David didn’t mention in his article, so it can’t be viewed as a benefit of SJR over client-side rendering.
Also, one can always embed the templates in the generated (minified) application assets and they will be cached naturally by your browsers for all later requests. So, if the template generates lots of HTML, it will be certainly much faster to transfer only the data instead of the full template even when serving the template using gzipped content. The reason why David claims it doesn’t make much difference is probably because his generated HTML are small enough.
Easy-to-follow execution flow
This is really a matter of taste and I find it much easier to debug the template generation in Chrome Developer’s Tool and to follow the flow in the client-side code, so I won’t comment on this.
Also, it seems that the author suggests that a major benefit of this “simplified” flow, is that you don’t have to worry about testing it because it just uses a standard mechanism that’s already tested as part of the framework and that couldn’t go wrong. Which leads me to:
Faster initial rendering
This is indeed a very valid point. Once you serve your HTML the browser will already display it before running all JS code which improves the page load time perception from the application user point of view.
On the other hand, if the user is too fast on clicking on some element with attached behavior (although not yet in the very beginning of the page load), the user experience may not be very good and the user might perceive that lack of behavior as an application bug.
Also, with Rails, if the server-side page takes quite some time to be rendered, by default the browser won’t show anything until the render action finishes because Rails doesn’t render streamed responses by default.
On the other hand, if you send a minimal page, you’re able to inform the user that the page is loading very quickly, while you wait for a JSON response with the actual data, for instance.
It means that depending on how you design your site, the user might have a better experience with the asynchronous approach, but that indeed is not trivial to implement in a good way.
In our application we use the jQuery-layout plugin to render our panes otherwise the application would look badly so it doesn’t help if we start rendering some HTML soon…
So this is very application-specific.
The main reason I believe client-side template rendering is more interesting: Testing
When building SPA’s, lots of your code remain in the client-side, and tools you use to test server-side code, like RSpec and the like, are no longer well suited for testing browser behavior.
Trying to test all your client-side logic as Capybara tests are simply too slow to be a valid approach.
On the other side, testing in the browser is super fast. Much faster than testing the server-side code usually. You may simply mock all your requests to the server-side and test both parts of your application quickly in isolation from each other.
I’ve written rails-sandbox-assets a while ago to allow you to serve all your Rails assets in an easy way and used it as a base for running lots of runners, like Jasmine, Buster.js, Mocha/Chai and my own oojspec. They can even live together.
This way, if all my views are generated in the client-side, it’s pretty easy to recreate my client-side application from the specs without using any HTML fixtures, by simply requiring my client-side code using the Rails Asset Pipeline in my specs and running them after mocking jQuery.ajax to return data the way Rails would do.
Before David wrote that article, we discussed about this topic by e-mail and in my last e-mail I suggested him to talk about how they test their code using this approach. Since he didn’t follow my suggestion (although he followed other suggestions, like coming with a new and less confusing name than RJS) I’m assuming he doesn’t actually have a good response yet to how to test this and I’m assuming they don’t have enough client-side code to worry about this.
But if someone is considering his suggestion of using the SJR approach and has lots of behavior in the client-side, please take some time to think on how you’re gonna handle testing using that route.
Conclusion
By no means the intent of this article is to tell you that you shouldn’t write your application using SJR. It can be indeed a valid approach depending on how you’re designing your application.
The specific design I would recommend against SJR, is for SPA’s, as I’m writing solely those kind of application since 2009 and I can’t think of SJR being used with great benefit in such applications.