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.