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.