Brandon:Oh, hi.
A hush falls over the room because I'm not paying attention.
My slides came up. Hi.
Really quick first,
there are seats in the middle if people can squish together,
otherwise people are going to be sitting in the
aisles and the fire marshal is going to get angry.
I don't know that, I'm not a building guy.
Hi everybody, sorry to make you move around
but also maybe that will wake you up a little bit.
This is going to be a shot of espresso,
we've got to go, go, go, go.
I have a very serious talk about the heart of architecture.
As you know, as DHH said at the first talk, we are engineers.
What we do is build bridges with code.
We are architects, we build centuries old castles.
We are craftspeople, we are old-timey metal workers.
And we live in the cloud.
I think Javascript is ready for all of these things.
I feel like Javascript is ready for Cloudgineering.
If anybody knows what any of the things
I said with the pretty pictures are,
please grab me after the talk and explain them to me.
I just say them to sound smart and serious
about programming, it is serious business.
Hi I'm Brandon Hayes,
I work with Charles actually at The Frontside.
I'm a dedicated Cloudgineer and no one ever asks which of
us is the smart one when we converse together,
which is a little weird.
These are my credentials.
As you can see I'm highly credentialed and
ready to tell you all about programming.
My wife gave me a few of these,
most of them are actually true.
I'm not here to talk about some
core ideal or some big fancy thing.
I live in the real world.
I have to write programs that people want written fast and
want them yesterday and it's very challenging some times.
I understand that architecture is great but
I don't have a lot of use for ivory tower people,
I think the universe has plenty of uncles in it.
We live in a place,
and I'm going to tell you a tale about a couple of places.
It's actually a meta talk about the
ball of mud architecture pattern,
that's one I can really get behind.
If you're not familiar with this, Brian Foote,
I believe in the late 1970s, described an architecture
pattern that everyone here has seen called the ball of mud.
To do that I need to talk about city planning.
Most cities are not designed for growth.
Salt Lake City would be a rare exception.
You'll see it handled its eventual growth pretty well.
From layout to infrastructure it seems to have avoided
many of the problems that plague large cities.
Our code does not live in Salt Lake City,
they don't work like that.
My current home town of Austin is a lot more typical.
I look at that every day on my drive home while
Charles rides his bike home, which is great.
I get to sit in that every day for
about 45 minutes on the way home.
The city layout and infrastructure was not prepared
for the kind of growth that they've experienced.
That results in the dreaded urban sprawl.
But we don't actually even live here.
Let's be honest about our code for a minute people.
We live here.
It's not a sprawling metroplex
or a beautifully planned city.
We live in a favela.
A favela is a Brazilian slum, basically.
It looks like cool though, right?
It's the definition of a walkable city -- well, hikeable.
Let's zoom in.
A favela is a Brazilian shanty town made permanent.
The structures require little skill to create and they
pop up everywhere out of whatever materials can be found.
The problem is these structures are
difficult to grow, to maintain or protect.
There's little police presence or fire presence,
and safety and crime issues are pretty rampant.
Forget architecture stuff,
we're going to go in to a code favela,
it will look familiar to you.
You've probably had some that made you
nearly go crazy trying to maintain it.
I apologize in advance for making you look at
this but I really need you to feel my pain.
That favela is a manifestation of the ball of
mud pattern, which is really easy to create.
You just need to build something temporary,
add to it, and then rely on it for your business.
They're so easy to create that it's the dominant
architecture pattern, I would contest, in software today.
Let's talk about how this happens.
Should be pretty easy right,
you can probably make this happen this week.
I need a show of hands. How many of you hate being
asked to raise your hands in a talk?
I should see no hands, that is insane.
How many of the rest of you have a
prototype that is shipped to production?
Pretty good balance there.
They say, "This is a two week feature,
"let's ship this thing in two weeks."
I don't believe in two week features,
I don't think that's actually a thing.
We do try to cram features in to two weeks and then make
sacrifices to get them out the door, or we inherit code from
less experienced developers and it has to ship.
But mostly these shanty towns start as a quick prototype.
Let's go ahead and build a shanty town.
It starts off like pretty much any other.
Let's say we're all working on Giffindor.
It's a social network for animated gifs.
The founder is a huge Harry Potter fan, cosplayer,
the whole thing. Has the glasses, it's adorable.
Personally I'm more a Hufflepuff,
this is not my website though.
It's a vanilla server-side app in Rails.
One note on pronunciation. I'm going to stake a stand.
I'm going to say that gif is pronounced like GitHub Gist.
I do the same thing with JSON and [JAY-sin].
I like to make everybody mad.
Mix tabs and spaces, people love me.
Back to work.
Let's just sprinkle in a little interactivity.
Let's start with sprinkles, they're fun,
sprinkles are fun, yay!
Your boss calls. She says, "We want a better experience
"on the site. Our users demand it. They should not
"have to go through a page refresh all the way
"to the new page to submit a new animated gif."
You look at your Javascript file.
Nothing there, undaunted you march forward.
Easy right? Just make a little HTML form
on the page with show hide, all done.
That worked, except it submits and
does a full page refresh on submit.
"Can you do that by AJAX,
"it's kind of irritating to our users?"
All right, that's what AJAX is for, right?
We submit this thing via AJAX.
That seems to work, all right.
But now you actually have to add that new POST
to the list of POSTs that are on that page.
All right, no problem.
Okay, a little bit of a problem.
We're starting to duplicate some DOM code here in your
Javascript so you get to edit stuff in two places.
A little duplication. We know, we don't de-duplicate first.
You're agile so you agile that code right
in there until this whole thing is agile! (laughter and applause)
By the way that's a trademark of Cloudgineering Inc.
so do not use that without written permission.
So this sprinkle is starting to turn in to a little more
of a rain shower, a little bit of a steady rain.
But cheer up Keanu, we shipped some software, right?
Okay, sport. The product manager, who tends to look
like Fred MacMurray for some reason, is really happy.
He has more ideas. He wants users to be able to click
a cancel button so that they zero out the form,
because if you open it it's just stuck there.
Dutifully you implement the cancel button
and zero out the form with jQuery.
Awesome, except now users are hitting submit on
empty and invalid forms, so we need some sort of
client-side validation to prevent that from happening.
It shouldn't be too hard to tell if
somebody has attached an animated gif link.
It wasn't super, super easy but it was relatively
straight forward. We disable the submit button unless
it's valid and show messages with jQuery.
This is starting to look a little weird, right?
It's starting to really come down.
Poor Al Roker.
Your CEO comes in to congratulate you
on all the great work you've done.
You've really shipped a lot of code and agiled everything
and you just need a couple more enhancements.
Let's add an inline preview for that image so users know
what they're about to post before they post it,
and a little character count that doesn't ding them
for long urls. We want a smart character count.
That's working but actually broke a couple of
other things about the state of this form.
We do some double checking and enable or disable submit.
Now you're caught between these two worlds.
You want to craft code that you can be proud of and that
lets you feel good about the things that you do,
but you also want to be able to ship stuff.
Your business needs you to move fast and break things.
You need to get stuff done, GSD. Craftsmanship, ship it.
I say craftmanship it.
(laughter)
(hesitant applause)
It's a good thing you're a cloudgineer and you
can straddle these two worlds just perfectly.
Look at all this code that we've craftsmanshipped.
Sandy Metz talked yesterday about code shape
and the squint test as an indicator.
When I squint this code has a shape and
that shape is a sack of hot garbage.
(laughter)
I don't know if Chicago has this but in Manhattan
in the summer time you get this nice smell
wafting off of the hot garbage, it's great.
That's kind of how it feels.
Here we are, a total tsunami of entangled jQuery code.
(laughter)
Let's ship a feature against that.
Please, it's really important!
Your CEO is now putty in your hands,
you are a superstar developer and the expectation
is now that you just shipped so fast.
And a light button, let's do it.
Here's the thing. I was going to implement this in jQuery,
I was going to do it but there was already so
much double checking and interwoven states that
I physically couldn't without getting really ill.
The thought of touching this code made me want
to quit writing the talk and just be like,
"You know what RailsConf, thanks anyway."
Now what, what do we do?
Actually Brian Foote has prescriptions for
dealing with the ball of mud pattern,
and it's not always what you think.
You don't necessarily dive right into a refactor.
Addressing a ball of mud is pretty difficult.
We can sweep it all under the rug,
or put it inside of a black box.
You can reconstruct it,
tear the whole thing down and raze it and rebuild it.
You can renovate block-by-block,
which he calls keeping it working,
or you can quit you job, which in some cases,
sometimes it's the thing to do.
Black box is fine if you know you're never
going to have to touch that code again.
If it's some complicated math equation or
something I've seen that done, where you
just hide it in the closet and that's fine.
A rewrite is a great way to learn really amazingly
hidden lessons about your business logic.
Things that are encoded in very strange places.
It's a really great way to make something that
sounds like it takes two weeks take six months.
I feel like you always discover that hidden
business logic so let's talk about a refactor.
Why would we do that?
We decided that refactor is probably the right
thing to do because the feature has to be
maintained but it's now too expensive to manage.
Users are starting to actually have a bad time with
it because the longer they stay on the page the
more likely they are to have problems with it.
And more importantly to me personally is
that you are tossing and turning all night.
You cannot sleep because you're dreaming about the JIRA
tickets that are waiting for you in the morning.
Why are we still using JIRA, why is that a thing?!
Okay, anyway, separate deal.
You think about your frustrated users, your gut is
telling you to fix it and your gut is totally right.
You have two paths out of here.
I think the person in this room, super smart guy, is like,
"Why don't you refactor this to smart Javascript objects?"
He's largely right. That's an ideomatic way to dig out of this.
He also asked me if I did that as a strawman
of how to build really terrible jQuery code.
I was like, "Yeees. I was not doing my best."
The other option is to use a framework
to abstract away the DOM and handle data.
Our goal is to get the heck out of
the DOM as fast as humanly possible.
That's our biggest pain point right now.
For me I'll choose a framework.
The framework will manage the DOM and
we'll just manage the underlying data.
All we need to do now is five steps to get out.
These steps will probably apply for people that
use plain Javascript and don't use a framework,
or any framework that you choose.
It's just nice to build up against one,
personally I certainly prefer it.
On our blog we'll talk more about why
we choose Ember and why we like it,
and you heard Charles mention earlier if you were here,
about why we like Ember's model layer.
I feel like it's a really strong model layer for
the case that we're trying to accomplish now.
It has really great bindings and managed state,
and it's got a great drop in component
library to tie it all together.
Step one, let's rap it. Rap it, rap it, rap it, wrap it.
A little sidetrack, a lot of people don't realize
that you can sprinkle Ember into an app.
A lot of people think that Ember only works if you want to
start an app from scratch and build up from the ground up,
from floor zero all the way to the top, but you can actually
apply it to a lot of codebases and it's really
great for refactoring existing codebases toward it.
That's just these three steps right here.
At The Frontside we do that pretty often where
we take an existing Rails application and move
it towards Ember, but it's actually not that hard.
First things first it's time for some justice.
We're going to put that terrible code in code jail.
That code jail is this initLegacyCode function.
We're going to create an Ember component, we're going to
put the stuff in initLegacyCode, which is not a special name,
I just chose it to tell me that this is the jail.
It bootstraps the old code inside the component.
We do not alter that code at all.
Also we move the HTML in to a handlebars
template associated with this component.
No structure of that HTML actually changes,
we're just isolating.
Then we can sprinkle. Now we use jQuery to stuff all of
this old stuff that we had before back in to the DOM.
Another thing Sandy said yesterday that I hope
it's self evident, it's certainly made itself self evident
to me over the course of the last year or two doing this,
that you have to test it.
If you do not test your code a refactor is
essentially impossible, I cannot imagine trying to do it.
I was not a big testing advocate earlier.
I was very skeptical, let's say, about testing.
I was raised by cowboy coders in my first
place when I was learning to program.
But we're going to do it and we're going to see that it's
actually not that hard to actually test the thing itself.
We're going to test that it shows up and it passes.
I'm doing a little bit of a hand wave
here over Javascript testing setup.
Javascript test setup story for getting Ember applications
bootstrapped in Rails can be a little challenging.
There's a growing body of knowledge about it.
I want to give you guys a quick note on that.
On its own, Javascript testing is pretty easy
but when you add in frameworks and tie it to Rails,
add in the asset pipeline,
things can get a little complicated.
It's a little bit of a wild west,
there's a lot of choices out there.
There's a little bit of paralysis of choice I think.
It's really wide open, but not like home on the
range wide open, more like this kind of wild west.
It can lead to that, you look at the thing of,
"I don't know what brand of toothpaste I want,
"I just want some toothpaste."
There's not really a truly accepted happy
path just yet but it is getting better.
Things are maturing, we're building schools,
we're building hospitals still.
There's a lot of a need for libraries and blog
posts and people finding these happy paths.
Taking aside for 15 minutes, there are screen casts
being released right now, there's a thing called
Ember Sparks where he's teaching people how to
set up and bootstrap your application environment.
We're all still figuring this out there, so be prepared
for a little bit of rough take off on this still.
Another thing is testing AJAX can feel a little
intimidating when you're trying to test Javascript
but it's actually pretty simple.
There are multiple libraries to do this kind of thing
I like ic-ajax.
It intercepts AJAX calls and allows you to inject fixtures in.
Here we're going to test each path through the experience.
In this one we're testing that clicking
submit shows a success message.
We just want to go through and verify that all the
things that the code says it does it's actually doing.
We're not changing any code,
we're just wrapping it in test existing.
And that passes.
Okay. At this point we repeat for each path
to create an integration test for the entire
application stubbed at the API level.
This took several hours but it's really important.
As I said if you don't have a test harness
I do not know how you can refactor.
Maybe if somebody has another answer we can discuss it,
because testing is not my favorite thing in the world.
We can now move forward with some confidence.
Go ahead and take yourself a victory lap, you earned it.
This is, however, just the start.
Step three is to identify models.
You have this blob of code, how do you find models in here?
Your server MVC might give you some hints.
I don't believe that your models will map one to one,
but it's a really great place to start.
In this one we actually get to start driving with the tests.
Sometimes I test drive, sometimes I don't,
I'm not an expert at either style, but I do think that
in this case it was pretty good to say, "I know that I
"have a model and I know part of what a model is
"going to parse out an animated gif url
"and tell me whether it is one or is not one."
With no code that thing should fail, and it does.
Now let's extract it.
We can actually extract some of that logic to a model.
And we can extract the animated gif link from
the POST body and give it a property here.
This is called a computed property where you see parsedUrl.
It does some functiony stuff and then it has a little
declaration at the end that says property body.
It means that we're going to depend on the body,
which is the blob of data that somebody just types in,
the text that they type in.
At any time a person changes that,
any time that changes it's going to observe and
update this parsedUrl property on this object.
Now those unit tests will pass and we can start turning that
static content into the dynamic content using handlebars.
This lets us kill some code, that's pretty awesome.
This should get the older acceptance test passing again.
It is the coolest feeling in the world to write some tests,
take some code, scrub some garbage out of it,
do something really dangerous feeling,
like jump off the cliff and know, when you rerun
those tests and they start passing again,
and you start getting green again after a refactor,
it's really fun.
In this case we didn't do that much,
we didn't have to write that much code because
we let the framework carry our matched luggage
for it which we cannot live without.
The models hold onto your data,
they keep it up to date and the changes in the DOM are
just going to automatically propagate out of that.
Now we're going to lean even harder into the framework.
It actually is sort of the fun part, identifying the
states is more fun than identifying models, I think,
because we get to go back through the
app and pick out what these states are.
In this little widget the first state is
a blank state, a initial state where the
button is just visible and nothing else is.
When we click it the button goes away and
the thing is in a ready-to-save state.
While data is in flight we're going to disable
the post button, leave everything else the same.
On an error state we're going to leave
the text intact but display a message.
On success we're going to display a
success message and hide the form.
After five seconds we want it to reset to that initial state.
That's kind of the business logic that we wanted
in the first place but we incrementally built it.
That's an okay way to find out what you want but
not a great way to ship to production, as we found.
The component starts in this initial state.
We bind that state to a class on the component's DOM,
and then we'll use that later to let CSS
manage what is shown and what is hidden.
We want the DOM to just be a representation of the
state of the app. The DOM is just there to represent
the app's state at any given time.
It's kind of almost read-only.
Now instead of managing the DOM with jQuery
we're going to have buttons fire off
actions that just push the state around.
"You go here, you go here,"
they're like the train conductors in a Japanese train station.
It's kind of a lazy developer's state
machine but it's going to do for now.
Step four, that's done.
That was all the code we needed for state.
Step four is to break up the remaining code left in code jail.
The states and model are in place and are tested,
but there's a couple of ugly things left.
Let's look at it. Code jail is not empty.
The legacy code still reaches outside the
component to delete things in a wonky way.
And, heh heh, hi, how are you.
I want to rub your nose in this code,
even though I'm the one that wrote it.
What could possibly go wrong here, right?
This POST is pretty scary. It's painful to modify,
it invites pain for the user but listing POST
is outside the responsibility of this component
we've created so what can we do about it?
Actually we have a pattern that we've already laid out.
Let's create another component and
sprinkle it in for listing those POSTs.
Another quick detour in to Ember Data.
At this point I have a choice to make.
Do I want to make sharing this information with you more
complicated by talking about Ember Data and I think I do,
it actually made the next steps much easier,
and this detour actually took me about 20 minutes to
replace the model with an Ember Data model.
Ember data is basically a wrapper that talks to AJAX
for you and converts to an Ember model for you.
It buys us lots of good things.
Basically took just a few minutes to do.
That's it, we just declare it as a model on Ember Data.
I like to wire in an ic-ajax, just like we did before,
to Ember Data and this is all the work that it takes to do.
Fixtures will still work as written.
This was all it took to get the tests passing again.
That's pretty much it for the list component.
As you can see I have a delete function,
a place to reference the list, that's it.
It has a list of those posts and a way to delete one of them.
All I'm doing is destroying a model record.
The second set of tests here is pretty
much going to follow the first. This test shows
that the animated gifs show up as expected,
and from here we can drive out the delete functionality.
We have a second template to replace the server-side markup
and then we sprinkle it in just like the first one.
We say, "Hey, jQuery, take this component and stuff it in to
"the DOM for me where that list of posts used to be,"
and Ember is going to show that for us now.
That's interesting, we have two components.
How are they talking to each other?
Well they both react to changes to the underlying data.
There's a pool underneath that is the
same shared data set but the components
are completely isolated from one another.
They can only communicate by altering
that pool of underlying data.
Changes in one place can affect the other.
There's a lot of boilerplate code we did not write here.
We just trust that the data layer is going to do
its job and the DOM will represent it properly.
One thing that happened though is because
we're not doing stuff with jQuery UI animation
stuff any more we lost show hide functionality,
so let's put that back.
We're going to use CSS transitions
which buys a lot of benefits,
including hardware acceleration on more modern browsers.
Remember how we bound class name to form state earlier?
We said there was a thing there that says form
state is bound to the class name for this component.
Now we get these classes for free automatically,
Ember is going to stuff that in to our
component every time the state changes.
It pushes the state, it changes the name of the class.
I like to start by creating placeholders
for the various states in a given component,
and then put different behaviors under those states.
In this you can see it almost tells a story.
We start an initial state with a height of
zero px and an opacity of zero.
Then once it's in another state it actually expands.
Everything except initial it will transition to that state.
We transition open to visible
with a 200 millisecond delay and a ...
You know what, I'm just going to show it to you.
It's not great to try to explain how CSS animations work.
Let's do that.
I think I need to make that window smaller.
That's great. Thanks Obama.
We're going to submit and now it expands.
Here we're in a validation error state.
We have the gif preview.
We have zero characters because that smart preview is
telling us that we're not using up any characters.
And we'll post it.
Oh, I just got trolled by chrome caching.
This one is just great. Julie Andrews is so awesome.
I have many of these that I really love very much.
Instead of doing that all day maybe
we should go back to the talk.
What we're not doing is we're not
manipulating the DOM directly.
If we want our tests can actually relax about the DOM
a little bit, we don't need to necessarily test the framework.
What we can focus on is application logic.
We can still integration test if we want
but let's look back and see what we've done so far.
There's some old code right here.
Let's see if you can locate the business logic in here.
Right? You can't.
That's why I'm introducing a powerful
encryption algorithm called jQCS, 512-bit.
It scatters your business logic across
hundreds of lines of jQuery code.
You can stop worrying about whether hackers
are going to access your business logic in your
front end because even your programmers can't.
(laughter)
That's cloudgineering folks.
Also a trademark.
That turns out not to be such a super hot idea.
We've now refactored this into a place where
we've moved that encrypted logic and exposed
it via computed properties, states and models.
The business logic is actually front and center now.
We've got from this sack of hot garbage to a
tested and documented reliable implementation.
It's not perfect but now it begs to be extended and reused.
From here what happens next is really up to you.
From here, most of the rendering that's
happening on the page is being done by Ember.
If you want to replace it and get all the benefits of
having a router underneath your app, great, go nuts.
You can actually now take application handlebars and
have it render those to components for you, and you're maybe
a few hours from having a full single page application.
Or you can continue to sprinkle in more components
and let your Rails app do all the driving and let your
components do the more dynamic pieces of your application
for you with that pool of shared data underneath it.
Now my brain is tired.
Why did we do all this stuff, what even is my life.
We had one job to do, a job that we were just about to quit,
but right before you became millionaires in the IPO.
I found out a couple years ago I quit
a job that just recently IPO'd. I would be on some yacht.
But we didn't quit, because we love our users,
we love our coworkers, and we want to love our job.
Software development, it really is fun.
It can be frustrating but it shouldn't give you night sweats.
Let's try this one more time against
our new and improved code base.
Once we know the API it's a small test to just
verify that this thing does what we want.
We can add a little favorite or like feature.
We stub out the data, test that a favorite makes it favorite
and an unfavorite makes it unfavorite.
Build a little favorite model that talks to
the server and it has many relationship here.
You can see DS belongs to gifPost
and it has many on the other side.
And add some dynamic content
to the handlebars template.
Then we write a toggle action to create or
destroy the favorite and that's pretty much it.
If chrome caching will smile upon me
We'll demo that as well, I'm going to switch my branch.
Everybody knows this trick, right?
Also everybody knows the trick of typing rails s.
It's a little known thing, most people don't know.
It's how you load a Rails server up.
(laughter)
You can see my responsive design is so badass.
Woah, star just flies all around.
Now we can favorite this thing.
It's actually talking to the server on the back end but
it was so easy to do this that we actually were like,
Well, do you want me to filter these favorites for you?
I can do that and just show you my favorite ones.
This one, this is legendary.
(laughter)
Now we have favorites. If I unfavorite something
it will automatically pop out of the list.
I'm not managing any of this stuff. I just built a
little tiny filter that took like five minutes to do.
This stuff buys you so much and extending
this actually becomes very fun.
We've changed our relationship now to this code base,
where we actually like working on it.
We wake up in the morning instead of feeling
sick about what's going to be in our inbox we're
actually really excited about what we get to do next.
I just want to tell you as an addendum to this that my
personal story about, my first conference was about
four years ago and I think a lot of people, can I get a
show of hands of who's hear that's their first conference?
That's a really great portion of the room.
My first conference,
I went to a hack night the night after the conference.
It was put on by some really great people
but I walked in, I looked around and I didn't know anybody.
I listened to some people talk.
I was just learning to program.
I was listening to people talk and they were so smart
and they were people that were so well known in the
community and I was so nobody that I immediately
turned around, left, ran out of the room as fast
as I could, got in my car and cried and drove home.
Which is pretty awesome, I'm like super cool guy.
(laughter)
After that point the community picked me up and
dusted me off and said, "Get back in there kiddo."
Many people in that community that I didn't know in the
room at the time became some of my closest friends.
These people in this room, if you'll look around, are some
of your future closest friends and colleagues and mentors.
The community is the reason that
I get to do this for a living,
when before I was doing just horrifying things.
If you can imagine what it would be like to do
marketing for a multi-level marketing corporation.
Just imagine the existential hell and imagine programming.
We're pretty lucky to get to do this and I want
everybody to have as good a time writing software
as I get to have when I'm doing stuff like this.
The other thing I want to say, the last note
I want to say on community is we have a tendency
to do this tent pole thing where we raise some
people up and then gather around those people.
That's not really what a community is about,
a community is a mesh, it's not like hub and spoke.
Every person in here has something to
contribute and something amazing to do
and I can't wait to go to your talks later.
I'm told I'm pretty good at hugs ...
(applause)
I'm told I'm pretty good at hugs so come
say hi to me and thank you so much. (applause)
(energetic big band music)