JUSTIN SEARLS: Good morning everybody. That was an excellent talk that we just saw from Brandon. Happy Friday. It's been a long conference. Thanks for being here. Friday hug to you all. This, if the house lights were up I'd take a picture. Yes. The title of this talk is The Rails of JavaScript won't be a framework. And the slightly less provocative version of that title is, the Rails of JavaScript will be more than just a framework. My name is Justin. We're not gonna have time for questions afterwards. It's gonna be a very, very fast talk-y slide-decky thing. So please Tweet me with questions, feedback, praise is always welcome, at searls, and critical feedback is always welcome at hello at testdouble dot com. Let's just talk about three of my favorite things. One is cupcakes. Two is the planet earth. And three is monolithic application architecture. So, on cupcakes, say that you own a bakery and a customer walks in and they say they want something sweet. So you bake them up a beautiful cupcake, and they say hey, you know, this is really good but I like a little bit more sweetness. Maybe a little crunch. So you put some sprinkles on top. The customer is, like, digging the cupcake, but says you know, on second thought, I really think I want something like with some hot fruit filling. And then you just think to yourself as the baker, ah god damn it. What they really wanted was a fresh-baked pie. So you throw away the cupcake and you make them a pie. And that's an honest mistake if it happens once. But if your workflow as a baker is to assume everyone needs a cupcake only to have to inevitably throw it away and then bake something else, that's a real problem, you know, for your business. So say you own a software studio, and a customer walks in and says hey, I need a web application, and so you say, oh great. What's its name so that I can type rails new. And you build them a little graph, you know, you render it on the server and they say, hey, you know, this graph is great but I need some zooms and some filters. And so you're like, hey, you know, I, we can do that. Sprinkle some JavaScript on top. And then they say, you know, this is awesome, but let's load all of the data all at once so that the user can really, really like just see absolutely everything at a glance, really dynamically, like an app, you know? And then you, the developer, are like ah, god damn it. Cause there's no logical path from that solution to what they really wanted, which was a fat-client JavaScript application. I mean, Rails is probably still involved, providing API services. But it's not the center of the application. That monolithic approach doesn't work. And it's an honest mistake, if it happens once. But if part of your workflow is to immediately assume that Rails is the solution to every single web application, and then you only realize later that you've guilt a gigantic mess with JavaScript, that's a problem. The reason that I think that a lot of web developers fall into this trap is that Rails is too convenient. When you're a Ruby developer, you have all these awesome tools right at your disposal. We've got this great convention-based framework so I can just add a gem and it, maybe a couple lines, and then I get all this great behavior on the cheap. And when we ask Ruby developers about their favorite client-side tools, they usually come up empty. Nobody hates JavaScript more than Rubyists. So they, they, they just can't think of any. And of course it's not like there's no client-side tools. I'm just kidding. There are plenty of client-side tools available to Rubyists. But this is their reputation, right. They're jagged and rusty and terrible. So, every time a new story comes down the pike, we have to make a decision, right. Where's the best place for this to live? What's the concern here. If a user brings me a, a user interface card, it might be that the best place to write that, the best place for that to live is in the browser. But the second thing I ask when I get a new card is like hey, where's, what'd be the easiest thing for me to actually do to build this? Take the least time? Be the quickest to market? And because Rails is so convenient, the answer is often Rails. So even though the best place for the code to live might be the frontend, I'm incentivised to start solving client-side problems on the server-side, and taken to an extreme that's really unhealthy. So I have a provocative statement to make. Non-Rubyists write better JavaScript. I went to a dot NET conference, my first dot NET conference, last year in Sophia, Bulgaria, and I was blown away by how much we were talking the same language. We were using great, brand new node.js based tooling. Everyone was talking about and excited about Angular, even Ember. But what my expectations were was it's dot NET, this is crusty, you know. And what I found in actually talking to people was, because dot net wasn't so incredibly awesome, they didn't have that same moral hazard, you know. They were willing to solve the problem in the right place. And when I think back over my own experience, before Rails was easy, for me, whether that was before 2005 or when I was doing projects in other tech stacks, JavaScript wasn't hard. You know, I actually really quite enjoyed JavaScript until I was told, you know, to hate it. And granted, we can have a long discussion. We can have a lot, like, screencast here about why, is asking, is JavaScript a terrible language? And I would just like clear the air, right. Yes definitely. I spend most of my time in JavaScript. I agree, it is terrible. But I'm careful not to conflate that with hey, well, is that why writing JavaScript is terrible? The problems I have always had with JavaScript have nothing to do with, have nothing to do with map and parsein and fundamental problems with the language, because I'm usually working at a higher level of abstraction, right. The problems I have with JavaScript are all of the tooling. The ecosystem. The community. So I, I challenge you to ask again later if you think the language is the one at fault. After this talk, hopefully I'll be able to persuade you a little bit. Let's talk about the planet earth. I love Ruby and I love Ruby mostly for the community. I love the language, but I love the community, because they changed the world when it comes to web application development. If you were to chart all of the great new tools for the web that have released over time, starting in 2005, the fantastic gems that were sort of the foundation for, for, for Ruby on Rails and this community. Over time, haml, sass, all of these great extensions. Alternate stacks that we can have an Omakase and a Prime stack. Rspec. Cucumber. These great innovations, helping us build better web applications. The world, Ruby with gems became this mature market place of free stuff that would help us write better code. But then, right around 2012, I started to notice that when a new feature would come out for, like, say, webkit, it wasn't immediately followed by gems that would exploit it. Instead I was finding JavaScript tooling written in JavaScript on node. And that started popping up, and in 2013 it really seemed to take off. And you come into 2014 and a lot of Rubyists, I think, have this latent fear that JavaScript is gonna devour planet earth. And I'm here to tell you that it probably will. Where the best tools? If you were to ask yourself this, you can add up a, add up a bunch of fact values. For example, Ruby's tool ecosystem, it's mature but it's crowded. That's not a lot of room for growth because everyone already has a lot of tools available that they, that they love. But node's ecosystem, it's immature, right. It's innovative, because so much new stuff gets pushed up, and it's frustrating, but it's great, because as soon as a new feature hits a browser, there's a tool to exploit it. I mean, granted, I get as frustrated as anybody else that when I run MPM install on something, like, by the time the install finally finishes at least two of those dependencies have probably had updates pushed. But that's the fantastic, that's what I loved about Ruby in 2006 and 2007. And tool authors are not immune to trends. I read a lot of, like, open source tools and I want to go where the people are. I want to go where I'm gonna have a big impact. And so tool authors are now gravitating to, to the world of JavaScript, because the universe of people who have to deal with JavaScript is about seven billion people, and the universe of people who have to deal with Ruby is in the tens of thousands. Yeah. All seven billion are JavaScript developers. I realize that's flawed. Also, tools, they address the problems of their day. A gem that was written in 2008 was written to solve problems that person was facing in 2008. Not 2014. A tool that was written in 2014 surely must be useful in 2014, and so it's just a better fit for the web as it exists today. You add all that up and I, you know, I really believe that web tools in node tend to better solve today's problems. And this is maddening for those who insist on only using Rails for absolutely everything. But, hey, speaking of Rails, let's talk about monolithic application architecture. Rails won the war, right, on web application frameworks. It came in with a whole bunch of great reasons that we can go into later about why it was just the best. It was, it was fantastic, and all of these frameworks since then have adopted a ton of great ideas from Rails. But what we don't often think about when we consider that phenomenon is to ask ourselves, which war did Rails win? All web applications? Like, generally? Or is there some sub-set of applications for the web that are a better fit for Rails than others? DHH last year at RailsConf said that good frameworks are extractions, not inventions. Extracted from real applications and not just invented. And so when you look at Rails, obviously the story is that the company Basecamp made Basecamp and they extracted the good bits, the common bits that they were seeing across a lot of their projects into Ruby on Rails. And those kinds of bits that are common to many of us, almost all web applications: url routing, to point you to custom actions that you write. Modeling behavior of, of the models in your objects, the validations and all of that at a fundamental level. Persistence. Storing stuff in a database, querying for the stuff. The relationships between stuff. Session management and, in a way that's abstracted from where the session stuff was stored was hugely convenient, obviously. All of those ancillary concerns of the wheels that you don't want to reinvent like mailers. And then there's this last little bit that's like all these JavaScript alternatives. Like there's sort of like the, the means by which to sprinkle JavaScript on top. Like, AJAX erb tags that dump a whole bunch of JavaScript into your on-click handlers in your, in your markup, or later on r.js, or later on unintrusive AJAX erb tags. Or later on, turbolinks, right. It's not that those are bad, that those alternatives are bad tools. It's that they're there to solve, they've been abstracted from an application that just didn't have the problem of trying to solve and, and write JavaScript in the way that I want to write JavaScript. Because if you consider Basecamp, you start a page. It's a traditional web workflow. You start on a page, you click on a thing, you get another page, you click on a thing, you get another page. It's a, it's a multi-break process, and that represents a huge proportion of the web. And that percentage of the web was almost 100% in 2005 but it's much lower now. If your app isn't a one to one mapping of, like, CRUD in the database and you're just exposing that as an interface to users, if there's any layer of indirection you, it might not be a good fit. Yesterday, Sandi Metz made the comment, as an aside, that there are Rails apps and then there are apps that use Rails. I'm finding that more and more, the apps that I'm writing are apps that use Rails. I can love Rails and not necessarily take advantage or, or really find a lot of benefit from the front-end aspects. So Rails promotes an html user interface in the frontend, cause that's what Basecamp needed. And what I mean when I say that is you're writing stuff like html markup. I have an anchor tag here with a, with a ref and, and content, or I might have a form action here with, you know, an input submit, and when you're writing html like this, it feels like you're making the UI. But you're not writing, like, UI programming. What this is is this is the specification of a UI. The user agent, the browser, is the thing responsible for figuring out how to render a link and what to do when you click it. It's how to render and what to do when, you know, how to paint a button and so forth. It's, you're not, you're kind of outsourcing the UI programming. If you're building an application with the browser as your runtime, though, I'd call that a JavaScript UI, and fundamentally the activity is just different and more complex. You know, you're responsible for finding the point and the DOM where you want to render stuff into. Or you're responsible for binding to an event that the user does something, and then you need to take some custom action. You're the one in the driver's seat. They're fundamentally different concerns. But our tools, I think, file, I like tree, to tree stuff out, because I think that tools tend to betray their biases based on the layout of the files that they give us. You know, a naive Rails app might look like this, and it screams MVC and it screams server-side. But, of course, in reality, one of the kind of, like, you know, dust-bin corners is that we have this, this ghetto, right, under assets, and then the most, you know, unfortunately named directory ever, javascripts, and then application.js, and it's telling us, all this stuff at the top - this matters. And this thing at the bottom, just write one big long bowl of spaghetti, and it'll work out. And that's how a lot of people write, you know, JavaScript and Rails applications, still. Some people, though, that's not good enough, and so they, they, they realize that they need to write more structured JavaScript, and so we end up with this new thing, like an html UI and a, and a JavaScript UI combined. And you might notice a pattern here, right. There is a, a, an MVC in the back, and then it's also MVC in the front. It makes command T really difficult, but it, you know, we see this duplication of backend concerns and frontend concerns, and there's also this, this little nit, negging doubt about, do we really need this views here? Right, if we're building a full-blown fat-client JavaScript application, the backend views that Rails provides just are less useful. So those often get cut out now, and we, we just have sort of a JSON API in Rails, and then this deeply-nested JavaScript UI. And so at this point, if like a new person comes to your project and they ask, hey, so what exactly is that thing? Right. I would call that a vestigial appendage. Because it can only be explained in terms of the past. You have to pull up your, you know, your forensics of like, well, in 2008 we were all, you know, thinking this and now it's still like this. What's wrong with that vestigial appendage? Well, what's fundamentally wrong is that, a fundamental problem in, in programming, is that when we move way faster when we can fit the whole application in our head at once, and when, on day one of any project, you can fit the whole thing in your head at once. But on day 1000 of the project that's probably not gonna be true. So if you build a monolithic thing up front, as that app gets bigger, eventually you reach a point where you can't fit it all in your head and you start to page, right. Part of the application that you're working in you can think of, and then over here you sort of page out. And if you don't modularize things well, then that, that, that thrashing is really, really risky. Because it might mean that, like, I'm in this part of the app, and I just kind of have to hope that my tests are gonna cover me. Although by the time you're this big, your tests in a typical Rails app are like ten hours long. So maybe tomorrow you can find out that it worked. But if you, via common concerns, and find a good module point to, to separate on, if you were to identify that you could have, like, a frontend app and a backend app, as those two things grew, even if the net complexity is higher, at some point they're not gonna fit in your head either, but the paging story is much nicer. Because they have a clean, well-defined separate contract. So the application that you're working in the backend application, if you have to work in it, you can work in it, and then when you page out, it's not thrashing, cause there's a clear, understood contract between the two. Relatedly, I like to say that late extraction costs more than early abstraction. Yesterday, Sandi's talk was great at telling us about wrong abstractions that have been found and refactoring away from those, but when we've seen the same project a dozen different times, I would much rather extract seldom and, and, and abstract early, and that's really confusing sounded so I'm gonna talk about yarn now. Imagine you have two balls of yarn. If you decided, like, man, I really just wish instead of these two ugly balls of yarn, I had a big know of yarn all tangled together, that's really easy to do, thanks to the basic laws of entropy. But if I have a big tangled know of yarn and decide that I really would love two nicely-balled, you know, nice balls of yarn, turns out that's very, very difficult to do. That doesn't work. So that's why, what I mean when I say that late abstraction, all of these, like, fancy refactorings that we can do, cost a lot more than just knowing you needed two things in the first place. So, back to this, this two step that I see in a lot of Rails applications, where one project, you've got the JSON API but you also have all the JavaScript. This isn't problematic until you consider this kind of stuff. You, you have a template that renders a script tag at the top, and then in the erb certain bits of data are kind of taking this sneaky back door instead of actually using the, the proper API, to just dump data into the JavaScript application needs. When you see this, it really means your yarn is tangled, right. Even though you think you have separate things. And your API is a lie. Because it means that even though your application is mostly using that API, if somebody were to come and say, hey, I want to build a mobile app for your site, they're gonna have to spend a month figuring out how to get that token, right. But it's hard not to cheat. And I agree. It's very, very difficult, especially given what we talked about earlier, where the tooling is so bad. So my objective in the last four years of, of, of my, my open source contributions, and now at TestDouble, where we spend a lot of our time? We want to help make JavaScript apps easy. As easy as Rails. When you think about Rails and the responsibilities of Rails, there's really three distinct parts. We have an application framework. Stuff that we extend - ActionController and so forth. We have conventions and configurations that are laid out for us, that we learn through the community and the documentation. And we have build automation stuff, like Rails CLI and Rake. And Rails owns the whole stack. If I had to grade them separately, I'd say that Rails as an application framework - when I first found it, I loved it. But I found on, like, many year, five year, six year projects, it encourages a lot of things that problematic. So maybe I'd give that a B minus, if I was grading it separately. But the conventions and configurations, that's awesome. I love that I can hit a new Rails team's project and, because of the tribal knowledge that we have as well as the conventions laid out and the sensible defaults, I can see how is their app different from the norm really easily. Build automation stuff is pretty good. I think it's gotten a little bit stagnant. Fantastic in 2005 and I haven't seen a lot of really cool stuff lately. But it's still solid. What I really want to talk about today is convention and configuration and the value that that can bring to our JavaScript tooling. Also keep in mind that a lot of people that are new in Rails or have only ever worked in Rails just see one big things. They don't see these as separate problems. So if that's you, try to think about these responsibilities separately, because I think they can be solved by separate tools. For example, in JavaScript, application frameworks are everywhere. If I decided I wanted to solve that middle problem by writing another application framework, then I'd have to, you know, go and popularize it against all the other application frameworks. I think that they can be separated. You know, whether I'm writing backbone or Angular or Ember - lately I've been writing a lot of Ember and I love it. But every six months I keep changing my mind. It's a fact. So, so at this point I just wanna be like, eh, I want to write awesome tools that are framework agnostic that anybody can, can exploit. From the build automation perspective, like I said, the community is already in node.js. Worldwide. As soon as stuff is happening, great tools are showing up in node.js first. I just want to be this little guy in the middle, right. I want to be the convention and the configuration, right. And that's why we built lineman. Lineman, like a, like a lineman on a railroad, is on Twitter here, and you can find his url. And you install him with npm. So you have node.js install and you can just say npm install globally lineman, and you create a new app really easily with the cli, just like Rails. Lineman new app. So, here's me typing in lineman new, start a new project, and I get a little. I get a handful of commands that I can run. But first I'm just gonna cd in and I'm gonna tree out all of the files that I have. Like I said, it betrays the biases, right. One way to learn the conventions is see what it generates. So you can see I have an app directory with css and images and JavaScript and then pages that render on the backend and templates on the front. A handful of configuration files. A whole bunch of spec helpers to help you test. And then places for all of your vendored third-party libraries. And it's convenient, right. It's nice to get that bootstrap for you. But our goal is to make it convenient throughout, to switch between projects to reduce duplication to make things more common across all of our work. One aspect of that is our productivity workflow. I want to be able to write some code, save the code, have that code automatically compile for me every time I save. Have it concatenate every time that I save, and then I want to be able to hit command r and refresh and play with it. But I want to be able to do all of that in less than a hundred milliseconds, because I want a fast feedback loop so that I can keep working quickly. In lineman, we do this with a command called lineman run. So you say lineman run, it does a whole bunch of initial build stuff, but then it just starts watching for file changes. So I can hit this server, the dev server. It says Hello, World! I'm gonna make a quick changes, say Goodbye, World! It's already updated. I refresh the page and that's that. Now, this is a simple app, but even on large apps it scales very well. On our large applications it's still roughly a hundred milliseconds. So, this is great. But command-r driven development isn't the whole story, right. I also like to write tests, too. Sometimes I'm doing test-driven development. When I do, I also want the same story to slot in really nicely with, with tests. And I want the same feedback cycle to be super duper fast. Lineman ships with a cool tool called testem, written by Toby Ho, that's really fantastic. What you do is you open up another shell, a second shell, and you run lineman spec. And you get this interactive test runner, launches Chrome here, and here I'm running a test already. Gonna just change the spec to say that I'm specifying that that function returned Goodbye, World! Save it off. Got a failure. That quickly. I can debug cause it's in the browser. I'm just gonna fix it. Save. And that's it. My tests are passing. In addition to the interactive runner, we want a really solid CI story. So you just quit out of testem with the q key, and you can type lineman spec ci, and this is gonna run it all in phantom.js with a nice reporter output. And every lineman project generates a travis.yml file when you lineman new. So you literally just push it to GitHub, and if you use Travis as your CI service, it's a one button thing and now you have a CI build for your JavaScript. Which if we were to ask people to raise hands, I don't think every hand would go up if, if I asked if you have one. The deploy story is similar easy, because since lineman is just a static asset generating tool, can your server host static files? Then yeah, you're good. When you write a lineman build, and then you tree out its dist directory, which is where it puts its built artifacts, it looks a little like this out of the box. You have an html file that references a css file and a JavaScript file and both of those have already been concatted and minified for you and they're ready to deploy. There's a single flag in the config that you can set, and then just like Rails, you get asset fingerprinted that makes it really nice for deploying when you have a CDN. Everything else that ever is gonna end up in your dist directory is gonna be stuff that you added, so it'll be stuff that you understand. It's a really easy build story. Pushing to Heroku is also really easy. We host most of our testable stuff on Heroku, so we just set, we wrote a custom buildpack. You set that up and then you say git push. It'll build it with node.js, but then at runtime we don't need it and so it just runs statically without node. And we also have a whole bunch of starter projects to help get people up and running quickly. Not everyone's just writing vanilla JavaScript, right. We have some people who want to get started with Angular quickly, Backbone or Ember. You can just clone and go. Clone the project and get started. You'll have a little bit of example code. It's a great way, if you want to learn Angular or learn Ember, just to clone our example project, because it'll build right away. Like, you already know how to run it. We also have a, a really cool. It's because it's all flexible, we also use lineman to build all of our JavaScript libs, libs that we maintain, as well as our blog and, and you're free to use lineman, of course, to, to write a markdown blog. It's really, really convenient. So back to planet earth. We're using Grunt. We, Grunt is a build tool descended from, you know, a whole bunch of other build tools, that is used for task definition. There's a lot of different, there's a lot of competition here right now in node.js. A lot of people using Gulp. A thing called Broccoli came out recently. It's really cool. But what we use Grunt for, primarily, is a place to get awesome stuff from the community. All these tasks ship with lineman out of the box. Or are, and, and so many more are available. We really, really love that we're able to so easily pull in new behavior through Grunt in a consistent manner. Lineman itself is comically extensible. We have a plugin system that is built a little bit around this mental model. We'll talk about it in a second. But it's really easy from a user's perspective. All you do is save it. npm install, then you save the, save the dependency. Run, like, lineman-bower. When you do that, after you run lineman run, the next time after you save that, lineman will pick it up from your packaged JSON, know that it needs to load it, and bower will be slotted in at the appropriate step into your build's workflow. No more configuration. It even generates your bower JSON for you if it's not there. Cause deep down, there is an npm module out there, bower, right, published by Twitter, and around it is the, a, a grunt-bower-task that somebody in the community published, and then at the top we have this lineman-bower plugin that we maintain. Bower is the thing that actually does the thing. That's where most of the hard work is. This, this power-task here, from Grunt, it automates the thing. There's a lot of hard work there, too. What lineman does is it just knows, given lineman's conventions, how to configure the thing for you. And so we have this kind of boxed approached to, to how we conceptualize plugins. So you, in your application, you might have a lineman-bower plugin that you use, but you can also have a lineman-ember plugin that's gonna handle all your templates the way that Ember likes to see it. And recently we, we learned and were really excited that RackSpace is adopting lineman for its frontend development, and I encouraged them to write a metaplugin, because you can have recursively arbitrarily many plugins down the line. So this plugin here - name it whatever you want. Maybe your company's stack or something. It can bundle as many plugins at the appropriate versions that you want, but you can also override any of the configurations in those plugins, get them just how you like. That way you don't have all this duplicated configuration across all of your team's files, team's project. Back to monolithic application architecture, I've painted a picture where we can separate into two things. But I want to talk a little bit more about the benefits of doing that. So say that you have a client in the server. One of the first questions that comes up is like, hey, well, how am I gonna run stuff in development, but it still needs to see the server? I'm not gonna build all these extra stubs for my server side. And we agree. That would be really onerous. So we built a feature into lineman that we call API Proxying. Basically, think of the browser hitting lineman, and maybe we have Sinatra in the backend. The browser's only gonna know about lineman. It's gonna make all of its requests to lineman. But whenever they ask for any API routes that lineman doesn't know how to respond to, we've got it configured to call back to Sinatra. Sinatra responds and then lineman proxies that request back to the browser. So it's a seamless environment. It's as if you're developing on one thing at runtime even though the code has all the benefits of, of, of physical separation. It looks a little bit like this. So here I'm gonna uncomment a little bit of configuration that we give you. Change the port to 4567, for Sinatra. My application's real simple. It's just got a simple route hi. It gets it and then it paints it onto the screen, whatever the text is. And my Sinatra app just returns I heart Ruby at that particular route. So when I write lineman run, you can see it, instead of proxying I'm gonna look at Sinatra's logs. I refresh, and it got the request from lineman and it returned through the browser. Super easy. Now there's other cases, too, cause the benefit of separating frontend and backend, a big part of that story is that now development of those two things doesn't have to run in lock step, right. We can make a little bit of extra progress in the frontend, maybe do some prototyping. We can have a separate backend team after we get big. But a lot of times we have, like, you know, it being handy to be able to stub stuff out that doesn't actually exist on the server yet, so we can get faster feedback cycles while we're developing our frontend. And we offered this in lineman with a tool that we called API stubbing. So same situation. We have a browser and it's gonna be hitting lineman. And instead of actually phoning through to Sinatra, we're gonna kind of stub our a particular route and prevent Sinatra from getting it. And we're gonna return that stub back to the browser. So same, same, same exact code base. We're gonna go into config slash server.js. This is a, an express application that's just kind of bundled in. We can define any route we'd like. We can overwrite that hi route. And we're gonna, we're gonna troll our coworkers here by sending that We heart Node Even More. Sacrilege. So run lineman. Refresh the page. And now our stubbing is in place. You can build entire toy applications inside of that express application. We've had clients in the past, TestDouble is an agency, and so we're, we're as consultants. We've had clients in the past who've asked us, hey just give us the specifications of the services that you want, and our specification is a living document of, well, just make it do this. And it's been a really, really seamless - it's certainly better than traditional documentation. Another case that I like a lot is I had a project once with a thirty-minute long test build, and I split it up into, I split the application up into two. A frontend and a backend, just like we're talking about. Then I went to recover that new application with tests, and I found that the frontend tests had a runtime of only four minutes. That made me very worried about the state of affairs in the backend. I figured that might mean that the twenty-six minutes was hiding there somewhere. But as it turns out, I wrote that, and that only took four minutes, too. So then I got really suspicious and I'm like, I should probably have some smoke test to make sure that when this is all plugged into, plugged together correctly, it works. And the smoke test, of course, when you plug it in both, it's a little bit slower, and that ran at a whole two minutes. So this thirty-minute test suite somehow got reduce to a ten minute build, even though the next, the logical and physical complexity of the system increased. And if you understand how build duration tends to build super linearly, any savings that you can get upfront in the beginning are going to mean a big difference, you're going to get a lot longer runway and traction out of the build suite in the far future. And, additionally, it's habit-forming, right. I mean, having a, a, there's a lot of operational problems that you have to solve when you have two different things to maintain and manage and version, as a deploy story, two different projects. You can make it simple, but I mean, once you solve that problem, once, you can have arbitrarily many microservices popping up. And if you're viewing the world as going in that direction, it's a great problem to solve now with a problem that you already understand really well. Frontends and backends. Additionally, this is not a frontend versus Rails talk. It's an and. We love Rails. We use Rails all the time for our services. And lineman and Rails play together really nicely. We've got a gem called Rails lineman and lineman plugin called lineman-rails. You install both those things and you just magically, everything gets auto-configured. And, and your development story is great and assets precompile is just wrapped with a lineman build first. You can learn more about that at linemanjs dot com dlash rails dot html. And we have this fantastic little documentation site put together for us by Derrick Briggs from neo. More recently, you can actually see me do this myself, live coding, unedited, in an Ember screencast that I did - how to get setup, like we would setup a project. And that's at our blog. It's the current, most recent article. So just hit the blog dot testdouble dot com and you'll see the, the embedded screencast. It's a fantastic tool. We love working with it. I also, real quickly, I just want to thank my friend Marissa Hile. She's a visual designer who's available for contract. She did all of the good illustrations in this talk. And, and, you know, we'd love to help you. If these are problems that are, that are, that are new and hard for your team, let us know. You know, we are consultants, and we'd love to like, engage with your company and, and, and work on great stuff alongside you, but we'd also just love to answer your questions, because I think we want to all make an impact and, and move the conversation forward. Also, like everyone else at RailsConf, we are hiring. Just set an email to join at testdouble dot com and we'll respond to you promptly and have, start the conversation. Also, a couple of my fellow double agents, Todd Coffman and Zack Briggs, are giving a, a workshop this afternoon on JavaScript testing. I think they'll probably be using lineman. So it might be a good place to practice both of those things. And I want to thank you. You know, please reach out. I'd love to hear from you. It was an absolute honor and a privilege to get to speak to you today. Thank you very much.