9:59:59.000,9:59:59.000 Thanks Mike. 9:59:59.000,9:59:59.000 Thanks for the invitation. 9:59:59.000,9:59:59.000 I want to start with a picture from this[br]building, which I have to say 9:59:59.000,9:59:59.000 I love this venue,[br]and especially this building. 9:59:59.000,9:59:59.000 And especially when it's not on fire. 9:59:59.000,9:59:59.000 And I think we were really dumb yesterday. 9:59:59.000,9:59:59.000 So if it starts beeping,[br]I will be leaving this time. 9:59:59.000,9:59:59.000 If you have not done it,[br]I suggest you walk up this round arc— 9:59:59.000,9:59:59.000 you can walk all the way up to the top— 9:59:59.000,9:59:59.000 and on that walk you will see that stairs[br]somewhere that says "The Beginning". 9:59:59.000,9:59:59.000 I want the beginning of my talk to be the[br]end of my last talk on a very similar topic. 9:59:59.000,9:59:59.000 And that was an idea that I was proposing 9:59:59.000,9:59:59.000 and that was the realization first of all[br]that every gem that you start, 9:59:59.000,9:59:59.000 the gem starts with a namespace. 9:59:59.000,9:59:59.000 When you develop a Rails app,[br]you never start with a namespace. 9:59:59.000,9:59:59.000 And so if you compare the two,[br]a gem is like a box. 9:59:59.000,9:59:59.000 You put a little label on it. 9:59:59.000,9:59:59.000 And a Rails app is a[br]gorgeous infinite nothingness 9:59:59.000,9:59:59.000 with all the bells and whistles of[br]Active everything. 9:59:59.000,9:59:59.000 To get a gauge of how relevant that is,[br]who writes Rails apps on a daily basis? 9:59:59.000,9:59:59.000 That's about two-thirds, maybe three-quarters. 9:59:59.000,9:59:59.000 And who writes Ruby,[br]but never touches Rails? 9:59:59.000,9:59:59.000 That's way less. Okay.[br]But still a few. 9:59:59.000,9:59:59.000 So I have a feeling that for the second[br]group, what I'm going to say is going to 9:59:59.000,9:59:59.000 apply a little bit less. 9:59:59.000,9:59:59.000 Maybe because of Rails not being around. 9:59:59.000,9:59:59.000 So the idea from my last talk was:[br]the next time you start an app, 9:59:59.000,9:59:59.000 just put everything in a namespace. 9:59:59.000,9:59:59.000 And I end it with what I found to be an[br]awesome finishing slide, 9:59:59.000,9:59:59.000 give yourself a box so you can start[br]thinking outside of it. 9:59:59.000,9:59:59.000 With the idea that if you have a gem,[br]and you give something a name, 9:59:59.000,9:59:59.000 and you put things inside of it,[br]you can open that box, 9:59:59.000,9:59:59.000 and you can go WTF when you find something[br]that obviously doesn't fit in the box. 9:59:59.000,9:59:59.000 If you try to do that with a Rails app, 9:59:59.000,9:59:59.000 you don't have a box—[br]you don't have a name— 9:59:59.000,9:59:59.000 so everything is going to fit. 9:59:59.000,9:59:59.000 The best game you can play is[br]what doesn't belong with the others. 9:59:59.000,9:59:59.000 Red. Green. Loud.[br]What doesn't belong with the others? 9:59:59.000,9:59:59.000 And you're going to know that it's Loud. 9:59:59.000,9:59:59.000 But if you look at your typical Rails app,[br]what are you going to have? 9:59:59.000,9:59:59.000 You're going to have a User, a Company,[br]Roles. 9:59:59.000,9:59:59.000 And then, the Tulip pricing engine that[br]you wrote. 9:59:59.000,9:59:59.000 And then the marketing part for that[br]and a store. 9:59:59.000,9:59:59.000 You're going to tell me that you can still[br]play that game and find out what may or 9:59:59.000,9:59:59.000 may not belong to this app? 9:59:59.000,9:59:59.000 It's very hard, because it kind of pushes[br]us in the direction of just putting all of 9:59:59.000,9:59:59.000 app in there. 9:59:59.000,9:59:59.000 So what I want to talk about today is[br]Component-based Ruby 9:59:59.000,9:59:59.000 and Rails Architectures. 9:59:59.000,9:59:59.000 I promise you I put this slide in before[br]that happened. 9:59:59.000,9:59:59.000 (Laughter) 9:59:59.000,9:59:59.000 I may want this button more desperately[br]than you. Trust me. 9:59:59.000,9:59:59.000 Stop me if I'm going too fast. 9:59:59.000,9:59:59.000 Because I want to talk about[br]large applications. 9:59:59.000,9:59:59.000 And one thing I heard about them is[br]you just never build them. 9:59:59.000,9:59:59.000 So I work for Pivotal Labs, and we[br]start a new project every few weeks, 9:59:59.000,9:59:59.000 and many of them are greenfield,[br]so many of them are tiny when we start. 9:59:59.000,9:59:59.000 But you heard from Matt yesterday,[br]we have pretty big apps as well. 9:59:59.000,9:59:59.000 And for every app, since our definition[br]of success is that a client can stay 9:59:59.000,9:59:59.000 successful after we leave,[br]what we have to strive for is some kind of 9:59:59.000,9:59:59.000 architecture where you can develop an[br]application well over time. 9:59:59.000,9:59:59.000 So we have to think about the app being[br]larger than it is, while we develop it. 9:59:59.000,9:59:59.000 Despite TDD and all. 9:59:59.000,9:59:59.000 Sandi Metz wrote her awesome book last[br]year and gave a few talks. 9:59:59.000,9:59:59.000 And at the one that I was at—[br]I don't know if she said it in other talks as well— 9:59:59.000,9:59:59.000 but she said, "Your app is out to kill you". 9:59:59.000,9:59:59.000 The growing complexity of your app is[br]going to chase you 9:59:59.000,9:59:59.000 and if the app were a bull,[br]you might feel like that guy. 9:59:59.000,9:59:59.000 And that is very exciting. 9:59:59.000,9:59:59.000 For the next second that is exciting. 9:59:59.000,9:59:59.000 For the next hours or days that is painful. 9:59:59.000,9:59:59.000 Okay, maybe this is a bit drastic,[br]but who has felt like their app was 9:59:59.000,9:59:59.000 behaving like that bull to them? 9:59:59.000,9:59:59.000 I have felt like that as well. 9:59:59.000,9:59:59.000 They are not typically that fast. 9:59:59.000,9:59:59.000 Quite the opposite. 9:59:59.000,9:59:59.000 But they behave like something[br]that is too big to handle. 9:59:59.000,9:59:59.000 So what I want to get to, is for us to[br]be more like this guy. 9:59:59.000,9:59:59.000 Calmer. In control.[br]With sunglasses and a hat. 9:59:59.000,9:59:59.000 (Laughter) 9:59:59.000,9:59:59.000 But I don't really like bull fighting,[br]so I actually want us to be this guy. 9:59:59.000,9:59:59.000 (Laughter) 9:59:59.000,9:59:59.000 Just hanging out. 9:59:59.000,9:59:59.000 I want to go home at five on a Friday night. 9:59:59.000,9:59:59.000 And I think this guy is probably the one[br]who is going to do that the most successfully 9:59:59.000,9:59:59.000 because he is just fine[br]probably all week long. 9:59:59.000,9:59:59.000 This "never build large apps" is part of a[br]larger quote from Justin Meyer: 9:59:59.000,9:59:59.000 "The secret to building large apps",[br]he says, "is never build large apps." 9:59:59.000,9:59:59.000 "Break your applications into small[br]pieces. Then assemble those testable, 9:59:59.000,9:59:59.000 bite-sized pieces into your big[br]application." 9:59:59.000,9:59:59.000 But how? 9:59:59.000,9:59:59.000 He was—I think—talking about JavaScript. 9:59:59.000,9:59:59.000 I'm talking about Ruby on Rails. 9:59:59.000,9:59:59.000 You can tell from the font that you're[br]supposed to read this slide. 9:59:59.000,9:59:59.000 (Laughter) 9:59:59.000,9:59:59.000 I'm going to use a tiny sample[br]application throughout this talk. 9:59:59.000,9:59:59.000 And this is where you can find it. 9:59:59.000,9:59:59.000 If you can't read this after all, just[br]search for github and the next big thing 9:59:59.000,9:59:59.000 and I think it comes up first. 9:59:59.000,9:59:59.000 I promise this thing is tiny 9:59:59.000,9:59:59.000 and it does only one thing. 9:59:59.000,9:59:59.000 It's an announcement page. 9:59:59.000,9:59:59.000 You can announce whatever you have to[br]announce. 9:59:59.000,9:59:59.000 And people can sign up for updates. 9:59:59.000,9:59:59.000 I spell it with two Ns but I don't know[br]if my Twitter handle is only one. 9:59:59.000,9:59:59.000 That's how often I tweet. 9:59:59.000,9:59:59.000 So the service thanks you for signing up[br]and I just press return. 9:59:59.000,9:59:59.000 And when I made this sample app[br]I had to come up with 9:59:59.000,9:59:59.000 a little bit more than just that[br]to actually have something to move around. 9:59:59.000,9:59:59.000 So I realized pressing return makes it[br]really easy for me to do that 9:59:59.000,9:59:59.000 many, many times. 9:59:59.000,9:59:59.000 But of course I only want my email address[br]to be registered once. 9:59:59.000,9:59:59.000 So I thought I'll give the server the[br]ability to kind of feedback the level 9:59:59.000,9:59:59.000 of annoyance that it feels while you're[br]just continuing to press return 9:59:59.000,9:59:59.000 and annoying it. 9:59:59.000,9:59:59.000 At some point it'll just freak out. 9:59:59.000,9:59:59.000 The freak out picture didn't come. 9:59:59.000,9:59:59.000 Let's try again. 9:59:59.000,9:59:59.000 It's an awesome picture of a guy with[br]a lot of hair. 9:59:59.000,9:59:59.000 I need your help though. 9:59:59.000,9:59:59.000 I need you to imagine something[br]really big. 9:59:59.000,9:59:59.000 Because that app is tiny[br]and I'm going to make examples 9:59:59.000,9:59:59.000 of refactorings or rearchitecturings that[br]don't make sense in that app. 9:59:59.000,9:59:59.000 So bear with me and always imagine[br]something very big. 9:59:59.000,9:59:59.000 I'm going to go through eight ways of[br]architecting this application. 9:59:59.000,9:59:59.000 And I have roughly two minutes for[br]every one. 9:59:59.000,9:59:59.000 Let's start with number one. 9:59:59.000,9:59:59.000 If you checkout that GitHub project,[br]you will find those eight steps as tags 9:59:59.000,9:59:59.000 and you can roughly follow the steps that[br]I'm taking. 9:59:59.000,9:59:59.000 The first one is a normal Rails application. 9:59:59.000,9:59:59.000 It's all-in-one. 9:59:59.000,9:59:59.000 Let's look at what's happening. 9:59:59.000,9:59:59.000 There is a TeaseController here. 9:59:59.000,9:59:59.000 It has two actions: new and create. 9:59:59.000,9:59:59.000 Let's briefly see what happens. 9:59:59.000,9:59:59.000 No surprises. It's not a well written[br]method. John would refactor this. 9:59:59.000,9:59:59.000 We're trying to find the entry that you[br]gave this form. 9:59:59.000,9:59:59.000 If we find it, we update tries on that[br]entry. 9:59:59.000,9:59:59.000 When we put it into this annoyance meter[br]it'll tell us how annoyed we are 9:59:59.000,9:59:59.000 at this point, and we'll feed that back[br]to the client. 9:59:59.000,9:59:59.000 If we don't find the entry,[br]we'll just say, "Thanks for signing up." 9:59:59.000,9:59:59.000 And then there's a bit of catching[br]unexpected cases. 9:59:59.000,9:59:59.000 That's pretty much what's going on in[br]this controller. 9:59:59.000,9:59:59.000 There is a model back in this. 9:59:59.000,9:59:59.000 It's Entry. It has the email address[br]and a number of tries. 9:59:59.000,9:59:59.000 And there's this AnnoyanceMeter,[br]which is not really important. 9:59:59.000,9:59:59.000 It just derives new strings[br]out of these counts. 9:59:59.000,9:59:59.000 I suspect that everyone has seen this. 9:59:59.000,9:59:59.000 And I will—for this talk—assure you[br]that it every one of these stages 9:59:59.000,9:59:59.000 you can run the tests, and—if I didn't[br]pick the wrong commit—they will pass. 9:59:59.000,9:59:59.000 So I have tests, but I won't show them. 9:59:59.000,9:59:59.000 I will just be moving them around for[br]every stage 9:59:59.000,9:59:59.000 and adding new ones where there is a new[br]test to be written. 9:59:59.000,9:59:59.000 Now remember, I said at the beginning of[br]every Rails app it's kind of this infinite void. 9:59:59.000,9:59:59.000 A good picture for that is probably[br]a big dump site. 9:59:59.000,9:59:59.000 I've already asked you if you ever felt[br]like the guy in front of the bull, 9:59:59.000,9:59:59.000 and maybe you also felt like the driver[br]in that bulldozer or whatever that is. 9:59:59.000,9:59:59.000 The reason I'm saying that about this tiny[br]app is that there's two things in there 9:59:59.000,9:59:59.000 that are now indistinguishable—if you look[br]at it from 30,000 feet—as to what they do, 9:59:59.000,9:59:59.000 how they're connected,[br]if they have any structure. 9:59:59.000,9:59:59.000 It pretty much doesn't exist. 9:59:59.000,9:59:59.000 So for all intents and purposes—[br]if you just multiply, extrapolate from these two 9:59:59.000,9:59:59.000 classes to, say fifty or a hundred—[br]you have no clue 9:59:59.000,9:59:59.000 who's interacting with whom,[br]what's going on, and why. 9:59:59.000,9:59:59.000 Unfortunately this doesn't[br]look very chaotic. 9:59:59.000,9:59:59.000 But if I were to write a hundred class[br]names here, it would be chaotic 9:59:59.000,9:59:59.000 and you would not be able to assess any[br]sort of structure 9:59:59.000,9:59:59.000 just by looking at those classes. 9:59:59.000,9:59:59.000 A first way of getting structure[br]into this application is modules. 9:59:59.000,9:59:59.000 The plus we get from that is[br]a higher level structure. 9:59:59.000,9:59:59.000 And you've all probably seen this one too. 9:59:59.000,9:59:59.000 Not much changes. 9:59:59.000,9:59:59.000 The controller doesn't change at all,[br]except it now references to Entry and 9:59:59.000,9:59:59.000 the AnnoyanceMeter within their[br]namespaces. 9:59:59.000,9:59:59.000 In the AnnoyanceMeter, Annoyance left the[br]class name; it's now in a module. 9:59:59.000,9:59:59.000 I moved some other stuff around[br]that was mainly for testing. 9:59:59.000,9:59:59.000 We now have this structure. 9:59:59.000,9:59:59.000 And if we come back to this analogy[br]then maybe we have moved 9:59:59.000,9:59:59.000 from a dump site to a recycling yard. 9:59:59.000,9:59:59.000 Recycling yards are awesome. 9:59:59.000,9:59:59.000 I should know this because I remodeled my[br]house, and you visit those places very 9:59:59.000,9:59:59.000 often when you do. 9:59:59.000,9:59:59.000 You can point to a corner of the recycling yard and say, "That's where the scrap metal is." 9:59:59.000,9:59:59.000 However if you've ever gone to such a place, you also know that you stick the hard-to-recycle stuff under your car because you're not a nice citizen 9:59:59.000,9:59:59.000 and then you try to pawn it off to the recycling yard because you just want to get rid of it and it's so hard to get rid of. 9:59:59.000,9:59:59.000 People do that all the time. 9:59:59.000,9:59:59.000 Just stand in front of the clean wood and then suddenly, not-so-clean wood gets thrown on top. 9:59:59.000,9:59:59.000 What does that mean for code? 9:59:59.000,9:59:59.000 It means there is structure. 9:59:59.000,9:59:59.000 I have now an EmailSignup module and an Annoyance module. 9:59:59.000,9:59:59.000 And in that is more classes. 9:59:59.000,9:59:59.000 But there is no guarantee that these classes are a) independent, or b) actually doing what they say. 9:59:59.000,9:59:59.000 I can't prove it. 9:59:59.000,9:59:59.000 That's why I put the rectangles over each other. 9:59:59.000,9:59:59.000 But at least I didn't have to write Entry anymore because I now have a higher-level concept, that being this EmailSignup module. 9:59:59.000,9:59:59.000 If I want to improve on this, I would like to go to the next step, which is prove that these two pieces are independent. 9:59:59.000,9:59:59.000 I call it the gem component app. 9:59:59.000,9:59:59.000 I may need to explain a little bit more about this step. 9:59:59.000,9:59:59.000 First off, you're not seeing that engines folder right there. 9:59:59.000,9:59:59.000 We're not looking at that. 9:59:59.000,9:59:59.000 We're looking at the annoyance gem. 9:59:59.000,9:59:59.000 I made a folder gems and I put an annoyance folder in there. 9:59:59.000,9:59:59.000 Actually this is a complete folder structure of a gem. 9:59:59.000,9:59:59.000 We have a gemspec; it defines our annoyance gem—and I should probably fill in this data—but there is a Gemfile which tells us that we are running tests with RSpec and magically—this may be the only time we need to look at tests—I have tests now in this gem. 9:59:59.000,9:59:59.000 If I go into that subfolder, I can now independently run. 9:59:59.000,9:59:59.000 Because of the way RSpec will load these files, I can prove to you that these tests for the levels and the meter of the annoyance will pass without knowing about EmailSignup. 9:59:59.000,9:59:59.000 Again, it doesn't matter here; it matters a whole lot if you're dealing with tens of hundreds of files. 9:59:59.000,9:59:59.000 I can prove that this thing is independent. 9:59:59.000,9:59:59.000 How many have seen shoving a gem like this into the subfolder of an app? 9:59:59.000,9:59:59.000 Everyone else should start doing that. 9:59:59.000,9:59:59.000 You could ask me two good questions: one is why am I not using git submodules? "I'm not smart enough" is the answer to that. 9:59:59.000,9:59:59.000 Why am I not using a different repository? 9:59:59.000,9:59:59.000 "I'm too lazy" is the answer to that. 9:59:59.000,9:59:59.000 You can just do this. 9:59:59.000,9:59:59.000 So how do I use it in the application? 9:59:59.000,9:59:59.000 The Gemfile of the main application is now just pointing to an annoyance gem and it's just referring to it by its path. 9:59:59.000,9:59:59.000 That's all there is to it. 9:59:59.000,9:59:59.000 This will be loaded. 9:59:59.000,9:59:59.000 I can access it like before. 9:59:59.000,9:59:59.000 And if I look into the TeaseController, we are still down here just loading that AnnoyanceMeter. 9:59:59.000,9:59:59.000 Nothing else special has happened. 9:59:59.000,9:59:59.000 The only thing that happened is we now have provably independent tests; we have provably independent code within that one component that we just extracted. 9:59:59.000,9:59:59.000 In the words of Eric Evans, "Choose modules that tell the story of the system and contain a cohesive set of concepts." 9:59:59.000,9:59:59.000 We are now able to prove that a set of concepts—namely within that gem—is independent of the others. 9:59:59.000,9:59:59.000 I think that is of great value. 9:59:59.000,9:59:59.000 I was in Iceland last weekend and I found something funny so I wanted to put these slides in. 9:59:59.000,9:59:59.000 It's good for push and pull to be so explicit, but if you look at the doors, it's actually not that explicit as to what they do. 9:59:59.000,9:59:59.000 They denote how to operate this door, but now look at Icelandic signs. 9:59:59.000,9:59:59.000 You know how to open these doors. 9:59:59.000,9:59:59.000 They scream at you, "This is how you open me." 9:59:59.000,9:59:59.000 You might also rip them apart, but you know. 9:59:59.000,9:59:59.000 (Laughter) 9:59:59.000,9:59:59.000 For the structure of the app, now there is a second component. 9:59:59.000,9:59:59.000 So we've got a little bit more structure. 9:59:59.000,9:59:59.000 Is that cool so far? 9:59:59.000,9:59:59.000 Gems make up a portion of apps, but if I have dependencies towards anything Rails, I have to do a lot of homework myself. 9:59:59.000,9:59:59.000 In the next step—what I want to call the Rails component app—I'm still going to do that for a Rails component. 9:59:59.000,9:59:59.000 So I want provable structure for Rails. 9:59:59.000,9:59:59.000 The way to do this easily is with Rails engines. 9:59:59.000,9:59:59.000 If a Rails engine were actually a train engine, then a Rails application would actually be a train. 9:59:59.000,9:59:59.000 So you might want to reconsider to call the whole thing Ruby in Trains. 9:59:59.000,9:59:59.000 But I still have to clarify a thing that engines have still this wrong perception of being for pagination and generic administration and authentication. 9:59:59.000,9:59:59.000 They are not. 9:59:59.000,9:59:59.000 If you look at the docs it says Rails engines allow you to wrap a specific Rails application or a subset of functionality and share it with other applications of within a larger packaged application. 9:59:59.000,9:59:59.000 I should know because I pushed that change last time I gave a talk like this. 9:59:59.000,9:59:59.000 It's very good that it says that now. 9:59:59.000,9:59:59.000 Let's look at what that means. 9:59:59.000,9:59:59.000 Now next to this gems folder we also have an engines folder. 9:59:59.000,9:59:59.000 Now you're allowed to notice that the app folder went away. 9:59:59.000,9:59:59.000 Since we only have one controller, there is no longer any necessity for this app to contain any code itself. 9:59:59.000,9:59:59.000 It only contains gems. 9:59:59.000,9:59:59.000 Let's start with the more self-contained one: EmailSignup. 9:59:59.000,9:59:59.000 If we go in here, there is still that Entry and it's now within a module and within a gem, which is also incidentally an engine. 9:59:59.000,9:59:59.000 If you don't know a lot about them check out this source code or find out about them. 9:59:59.000,9:59:59.000 I can't go into more detail but I'm happy to do that in Questions. 9:59:59.000,9:59:59.000 So essentially this means I have my database migrations in here; I have tests for this; it runs independently. 9:59:59.000,9:59:59.000 And the main app, as before, just includes those gems and references them. 9:59:59.000,9:59:59.000 Let's quickly look at the Teaser because the Teaser is now what contains the controller. 9:59:59.000,9:59:59.000 Actually I also want to point out that the Teaser contains assets, controllers and views in my example here. 9:59:59.000,9:59:59.000 It does not contain models because it doesn't have any data itself. 9:59:59.000,9:59:59.000 EmailSignup only has the model. It only has this entry thing. 9:59:59.000,9:59:59.000 The Teaser thus must be getting that data from somewhere else. 9:59:59.000,9:59:59.000 And indeed it does. 9:59:59.000,9:59:59.000 It too requires EmailSignup to be present. 9:59:59.000,9:59:59.000 And it references that dependency of course in the gemspec so that it's actually a valid gem definition.