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) (laughter) (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)