RailsConf 2014

The "Rails of JavaScript" Won't be a Framework

The "Rails of JavaScript" Won't be a Framework

by Justin Searls

In his RailsConf 2014 presentation, Justin Searls discusses the limitations of using Ruby on Rails as the sole solution for web applications that require heavy JavaScript interaction. He argues that while Rails has been highly successful, its framework has led developers to rely on server-side solutions for problems that are best solved on the client-side.

Key points from the presentation include:

  • Monolithic Application Architecture: Searls emphasizes the issue of monolithic applications, which can lead to complications as more features are added. The workflow often defaults to using Rails for all web applications, which may not suit JavaScript-heavy needs.

  • The Genesis of Rails: Rails was created to solve specific problems identified by Basecamp. However, its design caters primarily to traditional web workflows, hindering development for modern, dynamic applications.

  • JavaScript and Client-Side Tools: Many Rails developers tend to overlook modern JavaScript tools due to a lack of familiarity and experience. Searls notes that it is essential to seek better tools and frameworks that align with current web application demands.

  • Comparison with Other Frameworks: Searls argues that non-Ruby developers may be better equipped to handle modern JavaScript environments, as they are not bound by the Rails’ influence.

  • Lineman.js Introduction: To address these challenges, Searls introduces Lineman.js, a tool designed to improve JavaScript development workflows. Lineman provides rapid feedback and supports modern JavaScript practices, enhancing productivity compared to traditional Rails approaches.

  • Separation of Concerns: He advocates for separating front-end and back-end development, which can simplify the complexity of applications and allow for better alignment of tools used on both ends.

  • Modern Build Tools: Searls underscores the importance of build tools like Grunt, which can streamline the development process and integrate well with modern JavaScript libraries.

In conclusion, Searls calls for a shift in how developers view Rails not as a one-size-fits-all solution, but rather as a framework that shines for applications akin to Basecamp. He encourages embracing JavaScript’s potential and leveraging tools like Lineman.js for better application development practices.

00:00:17.730 Good morning, everybody! That was an excellent talk we just saw from Brandon. Happy Friday!
00:00:22.990 It's been a long conference, and thanks for being here. A Friday hug to you all.
00:00:28.480 This talk is titled 'The Rails of JavaScript Won't Be a Framework.' A slightly less provocative version of that title could be 'The Rails of JavaScript Will Be More Than Just a Framework.' My name is Justin.
00:00:40.809 We are not going to have time for questions afterward as it's going to be a very fast-paced, talky slide show. So please tweet me questions, feedback, or praise at @Searls. Critical feedback is always welcome at [email protected]. This talk is about three of my favorite things: cupcakes, the planet Earth, and monolithic application architecture.
00:00:58.150 Imagine you own a bakery, and a customer walks in wanting something sweet. You bake them a beautiful cupcake. They taste it and say, 'This is really good, but I would like a bit more sweetness and maybe a little crunch.' So you add some sprinkles on top.
00:01:17.140 The customer enjoys the cupcake but then insists they actually want something with hot fruit filling. In your mind, you realize that what they truly wanted was a fresh-baked pie. So you throw away the cupcake and make them a pie. That's not a mistake if it happens once, but if your workflow as a baker is to believe that everyone wants a cupcake, only to throw it away repeatedly to bake something else, that's a real problem for your business.
00:01:39.670 Now, consider software. If a customer walks in and says, 'I need a web application,' and you respond, 'Great! What's the name?' so you can type 'rails new' and build a little graph, the customer might then say, 'This graph is great, but I need zooms and filters.' You think, 'Sure, I can sprinkle some JavaScript on top,' but they might then want to load all the data at once so users can see absolutely everything at a glance.
00:02:07.479 As a developer, you might think, 'God dammit,' because there's no logical path from that request back to what they really wanted, which was a fat client JavaScript application. Rails could still be involved, providing API services, but it is not at the center of the application. The monolithic approach doesn’t work.
00:02:30.170 It’s an honest mistake if it occurs once, but if your workflow is to always assume that Rails is the solution to every single web application, only to realize later that you've built a gigantic mess with JavaScript, that’s a problem. I believe a lot of Rails developers fall into this trap because Rails is too convenient. When you are a Ruby developer, having all these great tools at your disposal is amazing.
00:03:07.390 With our convention-based framework, it’s simple to add a gem—maybe just a couple of lines—and gain great behavior quickly. But when you ask Ruby developers about their favorite client-side tools, they usually struggle to find any. Nobody hates JavaScript more than Rubyists; they often can’t think of any good tools.
00:03:24.320 Of course, there are plenty of client-side tools available. This is their reputation: they're jagged, rusty, and terrible. Whenever new stories emerge about tools, we have to decide where the best place for things to live is. If a user brings me a user interface card, it may be that the best place for it to live is in the browser.
00:03:47.980 However, the next thing I ask when I get a new card is: what's the easiest way for me to build this? How can I take the least time and get to market quickly? Because Rails is so convenient, the answer is often Rails. Even though the best place for the code to live might be on the front-end, I am incentivized to solve client-side problems on the server side, which can lead to unhealthy extremes.
00:04:18.769 So, I have a provocative statement to share with you: non-Rubyists write better JavaScript. I attended my first .NET conference last year in Sofia, Bulgaria, and I was blown away by how much we were speaking the same language. We were discussing great, brand-new Node.js-based tooling, and everyone was excited about Angular, even Ember.
00:04:33.170 What I expected from .NET was crusty, but what I found was that because .NET wasn't incredibly awesome, they didn't face the same moral hazard. They were willing to solve problems in the right place, and I recall my own experience before Rails. Before 2005, I was working on projects with other tech stacks where I actually quite enjoyed JavaScript.
00:05:04.850 Even though we can have an ongoing discussion about whether JavaScript is a terrible language, I will say that yes, it definitely has its flaws. I often find that the problems I’ve had with JavaScript have little to do with the language itself and more to do with the tooling, the ecosystem, and the community.
00:05:29.570 I challenge you to reconsider what you believe about the language being at fault after this talk. Let's talk about the planet Earth. I love Ruby and especially the Ruby community because they changed the world of web application development. If you were to chart all the great new tools released for the web over time starting in 2005, you’d find fantastic gems that became the foundation for Ruby on Rails in this community.
00:06:03.020 Over time, tools like Haml, Sass, and others have emerged, enabling us to build better web applications. RubyGems developed into a mature marketplace of resources that help us write better code. However, around 2012, I started noticing that when new features came out for something like WebKit, they weren't immediately followed by new gems to exploit them.
00:06:29.320 Instead, I saw JavaScript tooling written in JavaScript on Node start to pop up. By 2013, it really seemed to take off, and by 2014, many Rubyists seemed to harbor a latent fear that JavaScript would devour the planet Earth. I'm here to tell you that it probably will.
00:06:56.790 If you were to assess the tool ecosystems, you’d find that Ruby’s ecosystem is mature but crowded. There's not much room for growth because everyone already has tools they love. On the other hand, Node's ecosystem is immature yet innovative, pushing out new tools rapidly.
00:07:20.819 It can be frustrating, but it’s great because once a new feature hits a browser, there’s a tool to support it. Yes, it drives me nuts when I run 'npm install,' and by the time it finishes, a couple of those dependencies have updates, but that's what I loved about Ruby in 2006 and 2007.
00:07:39.660 Tool authors are not immune to trends. I read a lot of open-source tools and want to go where people are. Tool authors gravitate toward the JavaScript universe because it encompasses around seven billion developers, whereas Ruby’s universe is in the tens of thousands. Admittedly, this perspective has its flaws.
00:08:00.480 Tools must address the problems of their day. For instance, a gem written in 2008 will address problems that were relevant then, not in 2014. A tool created in 2014 should be relevant today. Thus, tools in Node may offer better solutions to current web challenges.
00:08:20.700 This reality is maddening for those who insist on using Rails for absolutely everything. Speaking of Rails, let's discuss monolithic application architecture. Rails won the battle in web application frameworks, coming in with many compelling advantages.
00:08:46.740 All other frameworks have adopted great ideas from Rails, but we often overlook asking which applications Rails truly suits. Is it that Rails won for all web applications, or is there a subset of web applications that fit Rails better than others? DHH remarked last year that good frameworks are extractions, not inventions.
00:09:12.060 These frameworks are extracted from real applications, not just invented. When you look at Rails, you can see that Basecamp created it and extracted its effective components, which are relevant to many web applications: URL routing, model behavior, validation, and database persistence.
00:09:37.260 Those ancillary concerns are the things you want to avoid reinventing, like mailers. Meanwhile, all these JavaScript alternatives serve a similar purpose—providing avenues to sprinkle JavaScript on top, like Ajax tags or TurboLinks.
00:09:57.200 It’s not that these alternatives are bad; it’s simply that they address problems that modern applications face differently than JavaScript applications do.
00:10:25.900 If you consider Basecamp's application flow, it follows a traditional web workflow where you start a page, click on something to load another page, and so on. This multi-step process once accounted for nearly 100 percent of web applications but has significantly declined. If your app doesn’t map one-on-one to CRUD in a database and just act as an interface for users, it may not be a good fit for Rails.
00:10:46.530 Yesterday, Sandi Metz made the comment that there are Rails apps and then there are apps that use Rails. I've found that more and more of the applications I create are not directly utilizing Rails' front-end aspects.
00:11:07.800 Rails encourages an HTML user interface in the front end because that’s what Basecamp required. I mean that when you write HTML markup—like an anchor tag or a form action—you are specifying what the user interface looks like, but you're not actually programming the UI. It's the browser that determines how to render a link or what to do when it’s clicked, and so forth.
00:11:35.790 When you're building a JavaScript application with the browser as your runtime, though, the activity becomes fundamentally different. You're responsible for figuring out where in the DOM to render elements and binding to user events to take actions.
00:12:04.290 These two tasks involve more complexity. I believe our tools reveal biases based on how they lay out files. A naive Rails app might exemplify MVC architecture, strongly signaling server-side, but in reality, one of the corners has a ghetto labeled 'assets,' with a directory terribly named 'JavaScripts,' and a single large file of spaghetti code.
00:12:31.590 Therefore, many developers recognize that writing structured JavaScript is essential. However, we often end up combining an HTML UI with a JavaScript UI. You might notice that there's an MVC architecture on both the back and front end, complicating things.
00:13:06.510 This duplication of back-end and front-end concerns raises the question of the necessity of backend views if we're striving for a full-fledged fat client JavaScript application. Typically, the views provided by Rails become less useful, and we resort to using only a JSON API and a deeply nested JavaScript UI.
00:13:37.170 At this point, if a newcomer arrives on the project and asks, 'What exactly is that thing?' I would call it a vestigial appendage, as it can only be explained in terms of the past.
00:14:06.630 Building a monolithic application upfront means that as it expands, eventually you won't be able to fit it all in your head easily, which leads to excessive page thrashing. This can be a dangerous scenario, as you might find yourself relying on testing to cover you.
00:14:31.860 However, if you can identify common concerns and separate your application logically, you may end up with a front-end app and a back-end app. Even as complexity increases, their clear separation allows for better management.
00:14:57.370 Relatedly, I want to state that late extraction costs more than early abstraction. I appreciate Sandi's insights into bad abstractions that need refactoring, but if we revisit the same project multiple times, I would prefer to abstract early.
00:15:22.580 Now, let’s talk about yarn. Imagine you have two balls of yarn and wish you had a single, beautifully tangled ball of yarn instead. While creating a big knot of yarn is easy due to the laws of entropy, untangling that knot into nice balls is quite challenging.
00:15:44.910 This notion illustrates that late extractions and refactorings can be more difficult and costly than recognizing you need distinct parts from the beginning.
00:16:07.860 Returning to the two-step process I've observed in many Rails applications, you get a JSON API while also maintaining the JavaScript infrastructure. While it may not be problematic at first, it raises concerns.
00:16:29.490 For instance, template rendering might involve inserting script tags on the page, resulting in data being sneaked in rather than utilizing the proper API to feed data into the JavaScript application.
00:16:54.680 This situation clearly indicates that your yarn is tangled, leading to misleading assumptions about your application's API.
00:17:02.310 It's easy to cheat—it’s tempting to cut corners, especially with poor tooling. This has become my objective over the last four years in my open-source contributions.
00:17:25.469 At Test Double, we aim to make JavaScript apps as user-friendly as Rails. Think about the responsibilities that Rails encapsulates: application framework, conventions, configurations, and build automation.
00:17:49.720 If I had to grade them individually, I'd give Rails a B-minus for its application framework. I loved it initially, but I've found that over time, it promotes practices that can be problematic. Its conventions and configurations are excellent; I appreciate how newcomers can quickly adapt because of community knowledge and sensible defaults.
00:18:14.670 However, I feel Rails' build automation has stagnated. While it was fantastic in 2005, I haven't witnessed remarkable advancements since.
00:18:40.889 What I want to discuss today is conventions and configurations and how they can be enhanced in JavaScript tooling. It's essential for newcomers to Rails to understand these as separate problems.
00:19:04.640 JavaScript application frameworks proliferate everywhere. If I decide to tackle that middleware challenge by creating another app framework, I would have to compete against all the existing frameworks.
00:19:21.099 I'd rather develop tools that are framework-agnostic, allowing anyone to use them, regardless of their chosen framework.
00:19:34.107 Regarding build automation, I believe the community is already shifting towards Node.js. As soon as significant events occur, great tools seem to emerge in Node.js first.
00:19:50.890 I want to play a role in bridging conventions and configurations, which is why we built Lineman. Just like a lineman on a railroad, you can find Lineman on Twitter and install it via npm.
00:20:05.000 You can quickly create a new app, much like in Rails, by running 'lineman new app.' This generates files stripped down to their essentials and highlights prevailing biases.
00:20:21.720 You will have an app directory for CSS, images, JavaScript, backend-rendered pages, templates, and many configuration files to assist in testing.
00:20:44.440 While it’s great to have bootstrap for starting out, our goal is to maintain consistency across projects, promote the sharing of experiences, and minimize duplication in setup.
00:21:08.440 One significant aspect of this is our productivity workflow. I want to write some code and have it automatically compile upon save, along with concatenation, resulting in a rapid feedback loop of less than 100 milliseconds.
00:21:31.580 In the Lineman environment, we achieve this with a command called 'lineman run.' This initiates a build process and continues to monitor for file changes, allowing instant reloading on server-side.
00:21:55.130 It's straightforward; after making a small change, simply refresh the page to see updates. This applies even to larger applications, where it scales effectively.
00:22:19.470 Command-driven development isn't the only focus; I also prioritize writing tests. When engaging in test-driven development, I want that feedback process to be seamless.
00:22:42.390 Lineman comes packaged with an interactive test runner called Karma. You open a second shell and run 'lineman spec,' launching Chrome to execute tests interactively.
00:23:06.240 You can adjust the functionality, save your work, and quickly debug errors since everything runs directly in the browser.
00:23:27.490 In addition to the interactive setup, we also offer a robust continuous integration (CI) process. You can exit the test runner and run 'lineman spec CI,' which executes everything within PhantomJS.
00:23:50.830 Every Lineman project auto-generates a Travis configuration file when you initialize it, making it easy to set up with GitHub.
00:24:12.470 The deployment story is simplified as well; because Lineman operates as a static asset-generating tool, it can easily integrate with servers that host static files.
00:24:37.530 Simply run 'lineman build,' and you'll receive a directory filled with an HTML file referencing your CSS and JavaScript files, all of which have been concatenated and minified ready for deployment.
00:25:00.120 There's even an easy option for asset fingerprinting, making it convenient when deploying CDN-like services. The final output is a directory of files that any developer can easily understand.
00:25:24.200 Pushing to Heroku is just as simple. We host most of our Test Double projects on Heroku, using a customized buildpack. You push your code, it builds using Node.js, and runs statically without Node at runtime.
00:25:47.920 Additionally, we offer a plethora of starter projects to help newcomers get acquainted quickly, whether they want to dive into Angular, Backbone, or Ember.
00:26:09.650 Just clone our example project, and you'll find included code that incorporates all essential elements to help you hit the ground running.
00:26:27.800 Lineman is even versatile enough that we utilize it to build our JavaScript libraries and blogs as well. This flexibility contributes to its appeal for various project types.
00:26:45.460 Let’s return to the planet Earth concept. We've adopted tools like Grunt, which is an expansive build tool for task definition, among various other competitors like Gulp and Broccoli.
00:27:03.080 We primarily use Grunt to access remarkable community resources. Many of the tasks included in Lineman come pre-packaged, making it simple to bring in new functionality.
00:27:19.760 Lineman is designed to be extremely extensible. We have a plugin system centered around this mental model, allowing you to rapidly integrate functionality.
00:27:40.320 To utilize this, simply save it via npm, and after you run 'lineman run,' it will recognize the change within your package.json file and apply it seamlessly. There's no additional configuration required.
00:27:57.390 This automated process even generates Bower.json on its own if necessary, taking some of the burden off developers.
00:28:15.420 Deep down, Lineman integrates various tasks into its ecosystem, allowing the tough work of dependency management to happen under the hood.
00:28:31.770 The approach with Lineman is effectively boxed; while you might use a lineman Bower plugin within your application, you can also have other plugins like lineman ember for specific templating needs.
00:28:49.040 We're thrilled that Rackspace has recently adopted Lineman for its development purposes, encouraging their team to create a meta-plugin that bundles various plugins together.
00:29:05.440 This meta-plugin can house as many plugins as desired at the right versions, pooling together configurations to avoid redundant setups across teams.
00:29:24.980 Returning to the topic of monolithic application architecture, I’ve illustrated a need to separate applications into front-end and back-end and want to further clarify the benefits of doing so.
00:29:43.380 Whenever a client-server relationship arises, one of the initial points raised is about developing each end without needing to maintain constant synchronization.
00:30:03.640 Our platform allows for faster development cycles, with the front end incorporating stubs for routes not yet available on the back end. Lineman simplifies this with API stubbing, ensuring real-time prototyping.
00:30:22.680 Through Lineman, we can define routes in a straightforward Express application, easily returning specific stubs while keeping everything functioning seamlessly.
00:30:40.180 This brings an efficiency to our processes, significantly enhancing our workflow compared to traditional documentation methods by creating a living document.
00:31:06.000 In one project, I encountered a 30-minute test build, which I managed to reduce to four minutes by separating the app back into front and back components.
00:31:30.670 Surprisingly, when everything was pulled together, the lowered complexity resulted in a total build time of just 10 minutes. This shows that even as logical complexity increases, the response time can improve.
00:31:51.680 This also creates opportunities for microservices to emerge efficiently, having no doubt that we can leverage our expertise in both front-end and back-end development.
00:32:08.680 Keep in mind, this is not a front-end versus Rails standoff. We embrace Rails in our services in conjunction with Lineman, and the two work together harmoniously.
00:32:26.890 We offer a gem called 'rails-lineman' and an associated plugin, 'lineman-rails,' which automatically configures your environment and streamlines the development process.
00:32:47.560 You can discover more at linemanjs.com/rails.html, and our documentation features live coding examples and guides for setting up projects.
00:33:09.370 I want to thank my friend Marissa Heil for her fantastic visual design work for this presentation. If these challenges are new or complicated for your team, reach out! We’re eager to collaborate and provide assistance.
00:33:25.230 Lastly, like everyone else at RailsConf, we’re hiring. Just email [email protected], and we’ll respond promptly.
00:33:30.990 A couple of my colleagues, Todd Kaufman and Zach Briggs, are conducting a workshop this afternoon on JavaScript testing and will likely be using Lineman.
00:33:42.660 Thank you all for your time! Reach out; I’d love to hear from you. It was an absolute honor and privilege to speak to you today.