RailsConf 2014

Where did the OO go? Views Should be Objects Too!

Where did the OO go? Views Should be Objects Too!

by Andrew Warner

In his talk at RailsConf 2014, Andrew Warner discusses the rethinking of views in Rails applications, emphasizing that views should be treated as objects rather than mere templates. He argues that the traditional separation of client-side and server-side views results in development inefficiencies and inconsistencies. Warner introduces the concept that the ideal user experience combines a seamless, single-page application feel with developer-friendly practices while advocating for a unified front-end framework that can share templates and logic between the client and server.

Key points of his presentation include:

  • The Holy Grail: Warner defines this as the combination of the best user experience and the best developer experience. Users should enjoy a rich, interactive interface akin to that of a desktop or mobile app, while developers should have access to an efficient and cohesive framework.
  • Current Challenges in Rails: He highlights that Rails applications often rely on separate view templates for client and server, leading to unnecessary complexity and heightened chances for errors during updates.
  • Existing Node.js Solutions: Warner cites Node.js frameworks as a current best practice for achieving these goals, focusing on solutions like Airbnb’s render framework, which allows for a unified development experience that Rails currently lacks.
  • Perspective Library: He proposes a new solution involving a library called 'Perspective' that facilitates sharing templates and logic across client and server. This involves using Mustache templates, which avoid logic complexity and enforce data separation, ensuring that UI elements can be rendered uniformly in both environments.
  • Benefits of the Perspective Approach: Warner argues that this approach improves separation of concerns, enhances testing capabilities, simplifies caching strategies, and allows developers to effectively manage data flow between the client and server.

In conclusion, Warner advocates for a shift in how Rails applications are designed, emphasizing thick-client experiences, shared templates, and logic-less views to ultimately enhance both user experience and developer productivity. His perspective highlights a long-term vision for strengthening Rails' tooling to better compete with modern JavaScript frameworks.

00:00:16.640 Hello everyone, I am Andrew Warner, the Director of Engineering at RapGenius.com.
00:00:23.760 You can follow me on Twitter at @warner, and also follow Rap Genius on Twitter at @rapgenius.
00:00:29.119 Feel free to tweet at me during the presentation, after the presentation, or even tomorrow—I'm open to it all.
00:00:35.280 This is really exciting for me, as this is my first RailsConf speaking engagement.
00:00:40.480 I'm honored to see such a full room, and I really appreciate that you all chose my talk over the other two.
00:00:49.039 It feels great, though I find it a bit surprising since you have no idea what I’m going to be talking about—my summary was rather vague.
00:00:57.039 I have a slide on the screen that says 'Rails Holy Grail'—who knows what that even means?
00:01:03.120 Nonetheless, I'm thrilled that you've chosen to be here, and today I'll be talking about the Rails Holy Grail.
00:01:10.800 I must admit I'm a little disappointed that DHH stole my thunder with his own Holy Grail slide, but I'll go ahead and use it regardless.
00:01:21.759 So, what will I be discussing? First, I’ll explain what I mean by the Holy Grail.
00:01:27.520 I’ll show you some existing Rails solutions that come close to this concept and offer a new solution for your consideration.
00:01:38.640 So, what is the Holy Grail of the web? I liken it to the song 'Holy Grail' by Jay-Z.
00:01:45.360 The Holy Grail represents the best possible user experience combined with the best possible developer experience.
00:01:51.520 It should be very easy for a developer to rapidly develop an application that is also user-friendly.
00:01:57.119 What constitutes the best possible user experience? I'm talking about a single-page app with a thick-client feel.
00:02:03.600 You shouldn't have to reload the entirety of the page each time a link is clicked.
00:02:10.399 When Rails first launched in 2004, it enabled developers to quickly create websites, but these were essentially thin clients that required an entire page reload with each click.
00:02:18.080 Around that time, Google introduced Gmail, which exemplified a single-page app experience; every action occurred without requiring a full-page reload.
00:02:24.480 This was a significant improvement, eliminating the need for full page reloads and creating a user experience similar to that of desktop or mobile apps.
00:02:30.800 The best developer experience should also characterize this Holy Grail; developers should be able to use a friendly framework that allows for rapid development.
00:02:41.840 Things that are simple should remain simple, meaning you shouldn’t have to reinvent the wheel.
00:02:48.080 Ruby on Rails is one such framework that embodies these principles.
00:02:54.080 Following the DRY principle—'don't repeat yourself'—is crucial, but in this context, I would rather emphasize DERP.
00:03:00.159 What is DERP? Simply put, it means you shouldn't have to repeat views.
00:03:07.600 You shouldn't be writing one set of views for the client's browser and another set for your web server.
00:03:14.560 Ideally, you should be working primarily in one language, especially concerning views.
00:03:21.680 Context switching between Ruby on Rails and JavaScript can be costly; it’s challenging for developers.
00:03:28.480 Moreover, your website must remain SEO-friendly, a crucial aspect I learned through my work at Rap Genius.
00:03:36.480 Content and SEO friendliness are vital, especially after we experienced a significant drop in traffic when we were banned from Google.
00:03:41.280 Your site should be able to present a search engine crawler with indexable HTML content.
00:03:46.720 So, what is the closest thing to this Holy Grail available today?
00:03:51.520 I believe it's the node.js solution.
00:03:54.720 There’s the Airbnb render framework, which allows you to render your Backbone.js apps on both the client and the server using node.js.
00:04:02.160 This framework is relatively easy to use; you can write a Backbone.js client-side app while allowing it to update the page incrementally, akin to Gmail.
00:04:08.000 The server can also render complete HTML pages for deep links, ensuring that users accessing pages directly can still see them without issue.
00:04:13.600 Moreover, search engine crawlers can access HTML, which is vital for SEO.
00:04:19.680 I think this is currently the best available solution.
00:04:24.720 Here, I built a demo app using Render to demonstrate its effectiveness.
00:04:29.520 This app is a mini version of Rap Genius, where you can view documents and read inline annotations directly on those documents.
00:04:35.520 The annotations provide valuable context and explanations for complicated topics, adding depth to the text.
00:04:42.240 I have built a Rails Genius app that allows you to add context to Rails talk abstracts.
00:04:48.480 In this app, I've added inline annotations, and the goal is to provide a better user experience.
00:04:54.000 For instance, when I click a link to app views, which is an annotation, it should not refresh the whole page but instead load only the relevant portion.
00:05:00.000 With this functionality, if I click the link, it simply loads the updated part of the page.
00:05:07.920 This user experience is comparable to what you’ve likely encountered when using similar apps.
00:05:15.040 It's somewhat challenging to achieve this experience in Rails, though.
00:05:20.560 Moreover, users should be able to edit content right there without any complications; it should integrate seamlessly.
00:05:29.200 The technology should allow for a straightforward build process to create the app.
00:05:35.920 Although the Render solution is promising, I still find it takes considerable effort to create a quality app compared to Vanilla Rails.
00:05:46.720 Rails inherently allows for faster development of simple applications, even when not utilizing scaffolding.
00:05:53.440 Therefore, while we have some good solutions like Render and its alternatives, I'm genuinely worried that Rails might be left behind in this arena.
00:06:02.720 We need to establish a strong approach to building a thick client experience with Rails applications.
00:06:09.440 Next, I will share some existing solutions that are partially effective.
00:06:15.520 One option is somewhat of a running joke but is used in practice; creating one version of your app for the client and another for the server.
00:06:22.960 In this example, you'd write ERB or HAML on the server and create an API that returns JSON to the client.
00:06:30.560 The client can then render new parts of the page using a front-end framework like Handlebars or Underscore.js.
00:06:37.360 This approach seems reasonable at first, but it carries risks.
00:06:41.920 If you forget to update both templates simultaneously, it can create inconsistencies between the client and server, leading to hard-to-identify bugs.
00:06:50.640 We all recognize that adhering to the DRY principle is essential, and unfortunately, this method does not comply.
00:06:58.560 It's SEO-friendly, can feel like a thick client, but still requires us to write code in different languages.
00:07:05.600 Working across both client and server side creates additional complexity.
00:07:12.080 Next, we have Turbolinks; you may be thinking that it offers a quick solution.
00:07:18.880 Essentially, it allows you to write one set of views, and when a user clicks a link, it can pop in the new page without reloading.
00:07:24.480 By maintaining the browser instance, it saves time parsing and compiling CSS and JavaScript.
00:07:31.520 This saves a considerable overhead, making your client relatively simple, requiring little to no JavaScript on your part.
00:07:36.000 However, Turbolinks leads to limitations; if you need to snap in a new part of the page, you'll have to custom code a controller action.
00:07:42.640 Moreover, you'll rely on your page structure, which makes it less than ideal.
00:07:48.720 But it does function well for specific use cases. It's DRY and SEO-friendly, but it doesn't deliver a true thick client experience.
00:07:56.320 Moving on, the Ember, Angular, and Backbone frameworks represent a significant shift in how we build Rails apps.
00:08:04.720 The entire app experience is predominantly on the client, communicating with the server via JSON APIs.
00:08:10.960 An initial visit requires downloading a significant JavaScript bundle, which boots up and manages the site’s rendering.
00:08:18.560 A similar situation arose with Twitter in 2010 when they introduced a new experience that aimed to enhance user engagement.
00:08:25.440 They found it took up to 10 seconds to display a 140-character tweet due to downloading all necessary assets.
00:08:31.680 This situation highlighted the weaknesses of such an approach, leading to a subpar experience for first-time visitors.
00:08:35.760 The implementation may be DRY, but it struggles with SEO, although there are methods to make it more SEO-friendly.
00:08:43.440 Ultimately, for most websites, SEO remains a critical factor.
00:08:51.440 The architecture predominantly relies on JavaScript; thus, we only receive half-credit for Rails integration.
00:08:59.280 The point I want to emphasize is that each of these frameworks has notable trade-offs that can be challenging.
00:09:07.680 Now, let me provide you with a potential new solution; perhaps it will prove beneficial or perhaps not.
00:09:14.080 But first, I want to admit something—I previously gave you the impression that I built this app using Render, but the truth is I don't even know JavaScript.
00:09:21.280 I read about it; in reality, I created this app using a new technique called Perspective.
00:09:29.440 Here's that same app again, which demonstrates how effectively things can load.
00:09:37.360 This is a simple example where sections of the page update incrementally.
00:09:44.160 The objective of using this Perspective library is to enhance our approach to shared templates.
00:09:51.760 To do this, we need to explore how we can genuinely share what is rendered between the client and server.
00:09:59.840 We must find the lowest common denominator when it comes to sharing templates.
00:10:06.720 If you've taken calculus, you might recall that finding a lowest common denominator allows us to combine fractions.
00:10:13.280 In this case, we need a very simple template that is quite limited in functionality.
00:10:20.960 Mustache templates fit this criterion as they're designed to be quite simplistic.
00:10:27.680 You might have heard them described as logic-less templates; however, I prefer to call them codeless because you can't run arbitrary code.
00:10:35.920 This means that Mustache templates are very flexible across various languages, allowing rendering in both Ruby and JavaScript.
00:10:41.840 To illustrate how to create a Mustache template, let’s take a look at the Rails Genius app.
00:10:48.560 In the lower left-hand corner, we have an annotation related to Node.js.
00:10:55.280 This annotation highlights a specific line of text, which we will call the 'referent.'
00:11:01.680 The body can contain arbitrary HTML—including links to various resources like nodejs.org and Ruby on Rails.
00:11:08.240 You may include hypermedia here for seamless navigation through your content.
00:11:14.640 Furthermore, there’s an edit link, which should be visible to certain users based on their permissions.
00:11:20.000 The whole template would look similar to this.
00:11:26.720 To render this, all I need is a JSON data hash.
00:11:34.000 If we can't run arbitrary code in Mustache, how do we include data in the markup?
00:11:41.040 We utilize tags within the template. For instance, to reference a specific section of JSON, we can use either double or triple braces.
00:11:48.320 Double braces escape HTML, while triple braces let the HTML render as raw, which is crucial for creating functional links.
00:11:56.400 The structure of Mustache allows us to control the logic through a specialized format.
00:12:04.080 For example, using a double-brace hash block allows for conditional logic that acts like an if statement.
00:12:10.640 If an 'edit' property is true, it will render the associated link; otherwise, it won't display it at all.
00:12:18.000 For managing other conditions, Mustache provides a caretag to execute logic if a specific condition remains unmet.
00:12:23.680 If 'edit' is false, it can display a message indicating that editing isn’t allowed.
00:12:31.920 So why is this workflow beneficial? Because of the potential to transport both templates and data across environments.
00:12:40.640 If we can generate a JSON hash, we can render the template wherever we need.
00:12:48.480 To facilitate this workflow, we'll utilize the Perspective library, enabling the splitting of ERB templates into Mustache for rendering.
00:12:56.240 The perspective object helps create a hash of data, which is essential for leveraging shared templates across the client and server.
00:13:02.400 This allows for rendering regardless of which environment the app is running in.
00:13:11.520 The Perspective library facilitates creating a structured method for generating the hash data.
00:13:17.680 The goal of this should not be to replace existing frameworks like Ember, rather it can be utilized for situations where separation of concerns is fundamental.
00:13:24.320 By using data-centric approaches, we eliminate unnecessary logic from templates, asserting their cleanliness.
00:13:31.920 I strongly believe testing becomes easier with this library, as each element can be tested without relying on string matches with the rendered output.
00:13:38.960 You can create test doubles for perspectives, making it simpler to ensure logic behaves as intended.
00:13:45.920 Another feature of this library is caching—an essential aspect of performance optimization.
00:13:54.080 Using caching macros, you can easily establish cache keys for perspectives without over-complicating things.
00:14:01.600 Cache keys are generated based on the objects with which you're working, automatically invalidating cache as necessary.
00:14:07.920 The methodology for working with nested perspectives allows maintaining clear relationships easily.
00:14:15.440 Each time a property is updated in any related perspective, the cache will remain synchronized.
00:14:22.000 So, are we ready to sail off into RailsLand with this new approach?
00:14:28.720 Not necessarily; this library is still in its nascent stages, emerging from ideas I had in mind to address certain challenges.
00:14:36.400 Although I strive to assist Rails in capturing the thick client experience, further work is undeniably needed.
00:14:44.080 I wish to enhance this project so it can take on the node.js alternatives more effectively.
00:14:52.000 The wedding of client and server-side development within Rails is truly achievable.
00:14:58.000 So that’s my talk—check out the Perspectives library on GitHub, or visit the Bit.ly link for more details.
00:15:05.920 And remember, if you're interested, we're hiring at Rap Genius, so reach out to me via email at [email protected] or hit me up on Twitter.
00:15:11.920 I think we have time for some questions.