 And welcome back to everybody from lunch. My name is Jake Howerton, and this is my presentation about things you shouldn't do in Rails. At lunch, Ben from Pivotal was saying to me, where are these wide-eyed optimistic presentations? How come nobody's super excited? I said, Ben, I'm sorry to disappoint you, but my presentation is on next. So if anybody else was hoping for that, this is probably not going to be an optimistic presentation. So according to the title of my talk, I guess it falls on me to expose the dirty underbelly of the Ruby and Rails community. Hopefully Francis screened out all the Pythonistas from the attendance list, and nothing's going to get trolled on Reddit that I put up here. So I've been working with Ruby on Rails for the past four years, which is pretty long time because Rails is only five years old. And when I hear myself say that out loud, it's been four years. It seems really strange to me. Seems like it was such a long, long time ago that I went to Vancouver in the first RailsConf, and all these ideas started formulating in my head. And the amount of code that I've written, that the community has written, and that all of you have written over that time, is huge. Millions of lines of code, thousands of different projects, millions of bugs, probably, right? Yeah, was that Paul? Right, Paul. And now we're at the point where we're just starting to have to deal with these sorts of things. Applications that have been in the wild for four years, some for five years. What happens when a Rails application has lived that long, and how do you deal with the problems that we stuck into code? I know the first six months that, I'm gonna pretend like I only wrote bad code in the first six months, but I can remember specifically some of the bad code that I wrote in the first six months that I was working with Rails. And it was horrific, right? And I know that there's applications out there with code that still looks like that in them because I see them all the time. And let's not try and pretend like nobody does this, right? I do it, I've been doing it. I've been working in Rails for four years. The Ruby on Rails and Ruby Gods and the community people that we all look up to, they write total crap sometimes too. It's not above anybody. You're gonna, no matter how good you get, you're gonna write crap in the future. It's just a fact of life you're gonna have to deal with. And the one thing that we can do about that is we can look at ways to recognize when we're making these mistakes. We can look at common mistakes. We can teach each other about consequences that happen from these mistakes and we can just try and do it less in the future and fix it as soon as we start to see ourselves veer off that path. You know, some people might say, you know, you have to work for four years. You have to hit some magic number of hours of working with something to become an expert at it. I hear a lot of people say, you know, 10,000 hours, I think there was a paper about it or something. If you do something for 10,000 hours, you can be an expert. And you know, you get your expert passport, somebody stamps it, they say a little prayer and then poof, you're an expert. Maybe that happens, I don't know. But we also have ways of thinking that can help people who aren't at that 10,000 hour level. I don't know if anybody's familiar with fine arts, but there's a book called Drawing on the Right Side of the Brain, which is basically a system of thinking. It guides people through practice and a pure beginner can use it and at the end of that book, you can come out and draw a little bit better than you did before. And in martial arts, you have the same thing, kata, which are pre-choreographed sets of moves, which all beginners and including and all experts also have to practice over and over and over again. Doesn't mean that those are the only ways of fighting or those are the only ways of drawing. It just means that these are waves that are proven to help beginners or intermediate people learn and take leaps forward, shortcuts basically. So in programming, we have the idea of patterns. And there's some seminal works and patterns, I'm sure, hopefully everybody's familiar with them or at least their names, including the Gang of Four book and Martin Fowler's enterprise, patterns of enterprise, application, architecture. So these software patterns are just ways of thinking. Systems of thinking doesn't mean they're always the right way to do things. And in fact, some of the worst code written is when people read the book, right? They saw the title of the pattern, they're like, this is exactly what I need right now and it's not actually what they need. They end up writing, doing somersaults in order to fit their problem to that model. No, right now, I'm just doing an intro right now. Cool. Okay, so like I said before, we've never been at this point in the community where there's four-year-old Rails applications, so what do we do about it? And the first thing I wanna talk about, so I wanna just give you an overview. In order to define anti-pattern, we should probably define pattern. According to Wikipedia, it's a general reusable solution to a commonly occurring problem in software design. And one thing I just wanna add to that is that typically, the way that we've discovered patterns is through emergent practices. So, you know, you might have one developer in Los Angeles and one in China and an emergent pattern is when people are working on disparate systems, but they come up with similar ways of solving the same problem. And once that happens enough, you start to say, hey, this is a pattern. This is the right way to solve it. It's the easiest way to solve it because these people are converging on this single point. So, with that crush to define anti-pattern, anti-pattern are emergent practices that are actually harmful and prevent us from solving problems. And in layman's terms, that means stuff that people screw up over and over and over again throughout past four years. And in spite of the potential of getting burned, in spite of maybe some blog posts that someone wrote three years ago about not to do something, still gets done over and over again. So, the first thing I kinda feel obligated to tell everybody is this is probably the most important thing. Know your APIs, right? 99% of problems, this is the base problem. People weren't familiar with their APIs. They re-implemented each or some other crazy thing and just because they didn't know. So, there's really not that, the APIs for Ruby and Rails are really not that huge. And there's no excuse not to know them. Read the documentation, become familiar with it. And when you're looking at a code of your own and your coworkers or partners, look at it through the lens of the API and say how could this code be done better if we leverage more of the Ruby API, the Core API. And the last thing on this list is GitHub. And is anybody not familiar with GitHub? Awesome, that's awesome. Does anybody not have a GitHub account? Steven, it's your homework. Yeah, so GitHub has tons of code on it. You can read it for free, most of it. You can follow the projects that you're most interested in, like Rails. You can see the change sets that are coming in, whether it's you follow bug fixes for the stable branches or you're looking at the stuff that Yehuda is doing on the edge. Another thing I do is, whenever you think, hey, part of my project might be generic, what I do is I typically spend a couple of hours a month just searching GitHub and see if anybody else thought that something like that in their project was generic, enough to extract that into a plugin. But that's kind of an off topic, that's another thing. Along these same lines, and bringing me to my next point is kind of the first anti-pattern I want to talk about, which is script plugin and gem installitis. Does anybody know, for a fact right now, that they have plugins inside their application that no code actually ever executes against? Yes, they at least admit it. I'm sure more of you actually have this problem too. Especially if you're working with outside contractors or transient developers, people will just install anything, right? Oh cool, this plugin solves all my problems, install. Oh cool, this gem solves all my problems, install. If you actually have a production application and you're committing code into it, it's your responsibility to know what's inside of that code and know why you need it, right? So if you're working on a team, I think everybody kind of has to come to a consensus about using plugin. Nobody should just throw code into an application if you're working with someone else. You should always talk to the other people, say like, hey, I want to use this because let's come to an agreement on it. Yes, it's awesome. No, there's a method in the core API to do the same exact thing. What are you thinking? So I want to talk a little bit about Ruby style also. I don't think I'm like the definitive source on Ruby style. People who are much more apt to doing that job like David Black or Eric Odle or Ryan Davis probably, they would be much more militant about stuff. But whenever you open up an application that's foreign to you and you start to poke around, a lot of times the most annoying thing is people who didn't follow kind of well-known Ruby convention. So I just want to go through a couple of anecdotes. Some of them are actually not style-related. There's, I'm going to just put kind of some pseudo code up on the screen that are derived from actual production applications, all right? All right, so I have a couple of problems with this. One, I don't like not. I always use the bang, but I don't care if you use not or the bang. You just need to make a decision and use the same one throughout your entire application and talk to your partners and say, hey, we're going to use not or we're going to use bang or we're going to use pipe pipe or we're going to use the word or. The other thing is people lit ourself all over the place, right? It's Ruby. We don't need to, we don't need to lit ourself all over the place. The only place we need self is on assignment. Now, the actual stylistic issue, another actual stylistic issue, this is just ridiculous, right? That's all it's really doing. So there are tons and tons and tons of case statements all over the place that have crazy stuff like this in it. Every time, almost every time someone writes a case statement to do it wrong, I do it wrong too, right? I'll start to write a case statement or a conditional and I'll do it wrong the first time. But that doesn't mean I stop at that point and be like, hey, it works. Yeah, this is another thing, assignment, right? Anybody have a problem with this? So that's a little bit more subtle. People coming from other languages or people who aren't familiar with this operator might do something like that. But as we learn more and more about Ruby operators, Ruby API, we just need to be focused on making things as succinct as possible, but still making them understandable. So this next example is not a style issue, but I thought it was pretty awesome. I'm kind of collecting like a trophy wall of these things. Right, so it's kind of has a hidden problem in it, right? If you're not looking at it closely enough. So unless this is defined inside of nil class, I'm not really sure what, and even if it was, right? So the problem is that this was in production code, right? And it had been running probably for a couple of years and there was no bug tickets open that had to do with this. So that begs the question, is this a feature? Like, is anybody in the application using this method? It's probably defined method in nil class. Yeah, object has nil on it. So unless you're inside of nil class, this is always going to be false. Just for clarity, sorry. A lot of the stuff that I'm showing is like method bodies inside of other methods. So this would be like object.nil, object.nil.nil. So it's in the application, it always came up false. So I guess, you know, in this application, there was never a need for that value to ever be true. Okay, so then I have something called IRB driven development. IRB is awesome, right? It is one of the best learning tools that is packaged with IRB. I use it all the time to just mess around with stuff. What IRB driven development is, you are doing that, messing around with stuff and learning in IRB, and then you decide at that moment to copy and paste something you just did into your application. So this might be a little bit hard to read, but this is in a production application that needed to know the IP address of the server that it was running on. I don't really know much, what much to say about that, but it worked, it worked in IRB, it worked for a year or two. God forbid, myip.dk just unregistered or something, but okay, and then this is like a pure style issue. A lot of people don't like this bang-bang value to force something into true or false. And whenever, like in the past couple of months there's been a couple of blog posts about what NASA do in rails and bad sound things and this always comes up. If this is your worst problem, you should be very happy with yourself, right? And I don't really mind it that much, especially if it's in a predicate method, if it's in a predicate method, I'm okay with it, because you expect true or false to come back. I don't think you should be using that in within a case statement or a conditional itself. Because Ruby has the truthiness factor, I guess, and you can just pass the objects in and they should come back correctly either way. Okay, so I'm gonna shift gears a little bit. Planning is really hard and it's really, really hard when you do it over four years, three years, that kind of timeframe, especially when you're working on not a pure tech application. If you're working with a business, it becomes exponentially more hard, right? I find that a lot of the best, most creative business folks have this kind of disease where they come up with an idea in their head and it comes out their mouth, right? And it's an awesome idea. But the problem with their way of thinking is that as soon as it gets to their mouth, they think it's already been implemented and that the software must already do this thing. They don't think about the history or the future work that's gonna have to go into it to do this thing. But their creativity is just so amazing that that's why they're in the position that they're in. So, they don't think about, hey, three years ago I told you to do the opposite of what I just told you to do right now. But I'm putting this on your project plan and you have to execute that. And don't break the application while you're doing it, right? So two years from now, are you gonna remember what your boss asked you to do? No, I have a hard time remembering what my girlfriend asked me to do yesterday, right? More importantly though is, are you gonna remember why they asked you to do it? And how do we deal with this? The way that I deal with it, and thanks to Brian Helmkamp who's here, is Cucumber and WebRat. Cucumber allows you to take what a business person wants and format it a little bit into a story. And then you can actually execute this against, with WebRat you can execute it against Rails integration tests, against Selenium, Qlarity, and probably some more backends that I don't use. And then this lives on forever in your app. So when someone goes and asks you to change the authentication, two years from now, if there was something special about this authentication example, which there isn't really, but say we wanted to track referral codes. Two years later you can come back and add referral codes to this story, get it to run, make sure it works, and move on without causing major problems within your app or taking a feature away from some other part of the business that has been using it for the past two years and they get all up in arms on a Friday afternoon, whatever, so. Most of the kind of stagnant applications and feeling like you're stuck in the mud that I've seen from a business perspective is that people don't know what they're allowed to break and what they're not allowed to break. And this really helps out. Obviously a really good unit test suite helps out too. So if you want to figure out how bad is your current situation, what do you need to do? How are we going to measure these things and how are we going to improve on them and make sure that we're actually improving on them? There is a gem called Metric Foo, which is a big collection of all kinds of analytics, code analytics tools. Is anybody using Metric Foo? You guys are? Cool. So I highly suggest you guys check it out. It does all kinds of stuff. I'm going to talk about one little part of that, which is a gem called Reek. And Reek looks for code smells and reports on code smells in your application. The other parts of Metric Foo are a little bit more computer science-y and are worthwhile, but this is really cool to just kind of get an overview of what's going on inside your app. You can just run Reek.wafile.rb, you can build a Reek task to run it against your whole site or whatever, and it has these things called smells. So it has a bunch of smells. If you go to their GitHub, you can see each of them, but one of them's a long method, probably the most important one, long method. It finds long methods within your application and tells you, and you can make your test suite fail based on this, right? So with Rails, you might want to change some of these things, especially if you're testing controllers because if you have response to blocks, they're almost always gonna be longer than five lines. But you run it against your app, it comes back and spits out all the methods that are longer than five lines. And then you can go and say, hey, why is this method longer than five lines? Now I know for a fact that every application I work on has, right now, has methods longer than five lines. And I can, we just removed, like I just removed on Thursday, a method that I think was like 80 lines long in a controller. I can remember several years ago when DHH started coming out with all the rest stuff and fat model skinny controller was all the rage, right? I remember all those blog posts. I remember removing a method from one of my applications that I wrote. There was over a hundred lines long in a controller, right? So I came from PHP. I had all these new tools and I wrote like a hundred line login method. I don't even remember what it does, right? Now we have five line long methods. user.newuser.authenticate. And this tool is really cool to find out where they are. I want to talk a little bit about orphans. Orphans are kind of like the plugin issue we were talking about before, right? You have plugins in your application that nobody is using. You also probably have routes in your application that nobody is using. There's no links to the actual routes. There's no links to those controllers. There's no links, maybe there's no execution path to get to certain methods on your model. And this is kind of a hard issue to deal with. You got to deal with it in lockstep with when you're adding or removing features. And there's only a couple ways you can measure. I know that Cucumber has an arc of support. At least they acclaim they do on their wiki. I haven't gotten it to run yet. But I believe that if you could get arc of working with Cucumber, you can probably see where your stories are actually hitting. And then you can decide, oh, I'm missing a story? Or, oh, nobody actually uses this feature on the site and I can remove it and pull it out of the site. Because those things cause problems to eventually down the road somewhere. That's kind of hand-in-hand with disorganization, right? A few Rails apps I've come across and had to work on, people just made folders all over the place. I know we're going to the whole more modular Merb style of things, but I got to say in most of these applications, it was just a harbinger of things to come. If somebody felt the need to make a concerns folder at the app route level, there was probably really, really scary stuff inside of there. All right? You can do most of what you need to do in a web application inside of the Rails structural way of doing things, and it really helps out if you're working with junior developers or new developers to Rails to kind of sweep them into the right spot. And if you don't keep an eye on that, it causes problems. And I treat this more like an indication of what I'm about to get myself into. If people are just blowing stuff all the way all over the place, it's probably a bad sign. Testing, everybody's testing, right? So while testing is awesome and people who want to try to test are admirable, there's also problems with testing that people fall into. This is what I call the valueless test. It provides me no value from an application owner standpoint. It tells me that Rails can load fixtures and select fixtures from the database. All right? And this is kind of like a hyper example of that, but there's tons and tons of tests throughout lots of applications that are essentially just doing that. Count, make sure that there's one more user in the database when I save it. Thanks guys. All right? Then there's a slow test where people want to verify every fixture is awesome. And eventually you have a thousand of these or something. Your test suite is going to be so slow that people don't run it. Then there's a couple of tests. There's actually two types of coupled tests. One is, which you don't tend to see too much anymore because of transactional fixtures and that idea is an internally coupled test. You have one test that does something and then the next test depends on the state the previous test created in the database. If those tests ever get run in the wrong order, they fail or one of them fails at least. The other kind of coupled test is a test that's coupled to an external service, kind of like the myip.dk. If you had something like that inside of a test, means every time someone's running your test suite, it makes an HTTP call or a file system call or who knows what. We actually have, in my current application now, we had some code that was delivered by a contractor that it generates images for cover art for our bands and the test suite actually generated images against ImageMagic twice and then made sure they were the same. All right, so, I didn't even have ImageMagic built on my system so I ran the test suite and it starts copying files all over the place or attempting to copy files all over the place. And I was like, what the hell is going on? And the way that we would deal with something like that is we mock out the actual call to ImageMagic and we make sure that the command ends up looking exactly how we want it. We don't actually want to test ImageMagic and make sure that ImageMagic can generate files. We just want to structure the command appropriately so it's valid and make sure that we get the command that we expect and then we deal with it that way. Another thing is that complex tests mean that the code is going to be complex. If you're having a hard time, a really, really hard time deciding how to test something or setting up all, maybe you're setting up too many mocks, right? It's getting ridiculous. You're going across associations and you're banging your head against the keyboard basically. Probably means you need to back out from it and look at the problem again because either you're testing too much in one test or you're doing it wrong and that you shouldn't design the method call or the object or whatever the way that you're doing it. So, now that we kind of know all these things and we can learn about how to stop these things, how do we improve upon them or what should we do to make sure that we don't fall into the same traps over and over and over again. For your team or yourself, first thing I'll do is make decisions and document them. Write them down, commit to them. So like we were talking about before, bang versus not or pipe pipe versus the word or, if you're going to make decisions like that as a team, talk to everybody about it. Write it down, put it in a style guide and put it in your team wiki or write in your repo at the root level, style guide, read me and make sure that everybody you onboard, that's the first thing they do, they read it. They get familiarized with how your team works and there's no question they can refer to that whenever they have a question about how something should be done if it's legitimate. And then the next thing is, assuming you're testing a write in cucumber specs and maybe setting some minimum metrics in metric foo or in reek or one of those other tools, is you need a build server to make sure that everybody's playing by the rules. So I really like Integrity, it's built on Sinatra, it's kind of cool. There's also cc.rb, cruise control. Integrity needs a little help getting over the next hump, I think. It needs queued builds and a clean way to deal with output from something like reek or argoc. But it's really cool, it's really simple. I highly suggest you check it out. You can run it either on your local machine or on a dev server, really simply. And it takes post backs from GitHub and since everybody has a GitHub account here, except for Steven, you're ready to go. So, and then that brings me to build artifacts. Build artifacts are things like argoc, maybe your wiki, maybe your style guide that are in your actual application. You have some task to run them and produce them every time you build your application. So if you change one part of the code, you change the part of the documentation that's related to that code. If you change a rule about how you guys operate, change that, it gets built and sent into the cloud automatically or wherever you keep it. So if you have an archive, right? Any of the tech managers or yourself can go and see what's my current archive? What do I need to work on or am I missing something? If you have actual metrics like reek or metric foo, you can go and review those reports, see if there's something you can fix. I think a lot of metric foo, I don't know if you can actually put conditions on it. I think reek, you can put conditions on it and say I never want my build to succeed if I have my lines longer than 100 lines. Hopefully you don't have to start there. But I think that's a totally reasonable rule to make. I think some of the more complex smells and complex stuff with cyclomatic complexity or those other metrics, maybe you don't want a failure build based on every time that tool fails. So you can just have a report. With integrity right now, you kind of have to hack it and have like a, I have a rake build task. So within the build task, all the things that I want to do happen. If it exits with failure, the build fails. If it exits with success, we win, right? The last thing is reviews and retrospectives. If you're gonna improve on any of these things, you need to talk about it. I need to show code like this to your team when you find it and you need to also be looking at it as it comes in. GitHub is pretty awesome for that. You can look at all the commits. You can comment on commits. You can say, hey, George, this code, we're not putting it in the application because whatever. And if you don't talk about it, you're never gonna get your whole team. Like I work on a pretty big team for Rails, I guess. I don't know how, we have eight people on the same team. At that size, it starts to get a little bit more difficult. People have ownership of certain aspects of the application that they don't talk to other people about. But you really need to take it upon yourself. Everybody in the team needs to take it upon themselves, including the managers, especially the managers, need to take it upon themselves to review all the code that comes through and talk to everybody about it and sit down, try and have some sort of collective ownership of the system so that when problems do arise or when stuff starts to get stuck in there, somebody catches it and says something about it. Now, I mean, I have some extra time. I was gonna show some more detailed, awesome code, but I don't know if we can actually see it up here. So maybe we just take some questions and maybe we can talk about some more specific code if somebody brings up something. Does anybody have anything heinous they wanna talk about or that they wanna call out? Is there any application code in the RAM? No, that is difficult. Why did it want to delete its own application code? It was trying to write something to a temp directory. It was a test about clearing out cache files. And the temp directory was not getting set properly. It was actually a test that had been working fine that during while we were operating, we was either operating Rails, operating RSpec or something. The thing that set that thing was no RAM problems at the directory. So, I mean, one of my philosophies about kinda dealing with this type of stuff and the image magic thing that I was talking about earlier is sometimes you do need to test that stuff, right? But how do you do it? Well, you probably want a normal spec and test week that never does stuff like that under any circumstances. And that should be your happy place. And then you either need to have a staging server that's specifically set up to break stuff, like a sandbox, or you need to have a server like that where you have maybe like a, what I would call a FlightCheck task that does the nitty-gritty stuff, right? Like, we have some stuff for our FlightCheck task that will put stuff in queues, actually will send stuff to email servers, things that you don't want, like you don't want your specs or your tests to email all your customers accidentally, or post to PayPal or something like that, or to your merchant gateway. So what do we typically do is set up an environment that dangerous stuff like deleting files or running image magic or posting to PayPal or emailing or touching any kind of external service or file system type of thing, we can run that and we don't have to cross our fingers or it doesn't matter if a new developer just check clones of the Git repo and hits rake build, you know? Because maybe that task worked, but it depended on, you know, the home directory being named properly or a file being in some spot and Luke just checked it out, clicked build and deleted his application. Yeah, you can do it. I would say a good technique for mock, basically the mocking problem or the problem where you're like using magic is to have a version of like, instead of mocking directly or trying to do it all the time when the whole staff to have a mock that basically emulates reality really well and then turn that mock off when you want to be sure. So if you ask them to be able to tend to be in for magic, most of your tasks will run fast all the way well, but instead of having to do like another integration test to check to see if it actually works, you just turn off the mock, have it go from normal and then see if it works. Yeah, and that's essentially, you know, that would be set up in your danger environment to do that, right? Yeah, and then problem is you just got to make sure you always put the fake one in in the test environment. Anybody else have anything they want to complain about? No? All right, so I want to show, I want to show it's one of these login methods that I was talking about. Let's see if we can get it up there. All right, so this is one login method. I don't know how many lines that is. I can't see it, but 45 lines long. So not that bad, right? Exactly. Easily accessible. All right, and then so let's see what a normal Rails login method looks like just for comparison. Right, so this is actually, I mean, this application was started in 2005. So that login method's probably been there since 2005. Is anybody currently working on Rails applications that are older than two years? Yeah, so a decent amount of us, right? There's a lot of these applications sitting around now. I don't know how many there are. Maybe 5,000, something like that. But these are kind of pre, like before I started thinking about this, I think before the community actually started thinking about this as a whole. Around 2006 was when everybody started talking about Fat Controller, I mean Fat Model, Skinny Controller. And I started to look at all this stuff in a new light and be like, hey, this is absolutely ridiculous. I was writing it, people around me were writing, were writing stuff like that. And sticking to the REST conventions has just made application development so much easier. But how do we deal with legacy applications where this stuff is still sitting? And how do we change that? When you have new developers coming on, looking at code that looks like this and be like, hey, that looks good. Why don't I copy and paste it? It's 10 other controllers. And then it starts to create a problem. So for those of you in the room who have been working on Rails for a long time, I think we need to look at it as our responsibility to bring, when I first went to Canada on Rails, I think there was like 200 people there. By the next year, there was 1500 people at RailsConf and there's been about that much every time. There's tons and tons and tons of new people coming into the community. And as the core cadre of developers, it's part of our job to show people the ropes and make sure that they're not gonna make these mistakes over and over and over again. And I don't know how much it helps if there was a blog post in 2006 that told us not to do this if we're not talking about it every day and if we're not calling people out, it doesn't have to be a mean thing, but just taking the junior developers' hands and making sure that they know these things and that they're improving themselves every day. And by doing that, we're all gonna improve ourselves every day also. That's pretty much all I have if anybody else has any questions. Oh, cool, thanks.