 So I'm here to talk about breaking down, or as the conference zeitgeist would have it, the service-oriented safari. So I have friends with Joe and Brian who runs Edgecase, and the first time I gave a talk on this sort of topic, he came to me afterwards and said, we have to talk. Because four or five years ago, I think it was at the first real scuff, I got up after David Hansen had his profanity slide, and gave a talk about SLA and rails, and I was virtually laughed out of the room. And what's happened is that Joe saw, and a lot of us have seen, is that we're sort of coming back around to this approach of essentially service-oriented architecture. And it's no longer the sort of bad word that's associated with enterprise and all that stuff that it once was. So I want to talk to you about that. First, the mandatory, I work for Living Social, the equal time, we're also hiring. So if you're interested, you can get in touch with me. But with that out of the way, let's do some science or something kind of science-like. So the first question I think is, why should we even care about services in our rails environment? We're used to building in a certain way, where everything's sort of slapped together. And it's worked, right? We have huge applications and very successful businesses built on these principles. So here's a series of five dates. Who can tell me what these dates are, right? Who can tell me what happened on these dates as opposed to what they actually are? Your mother has five birthdays? That is awesome. I want to space them out a little better. Yeah. So Rails 1.0, Rails 2.0, Rails 2.3, Rails 3, and Rails 3.1. Now, I did some not-in-all research and found that when Rails 1.0 was released, there was one legacy app in Rails. It was called Basecamp. That was two came out. There were 200 of them in the app. All the way up to now, where we have way more than 25,000 apps that are essentially legacy in Rails. What happened is more people started building. And when you build, you create legacy code, right? No one can tell us about testing it. But over time, everything becomes like. So in fact, most of it, I would say every app is legacy. And as legacy apps get bigger and bigger, you run into the big ball of mud, which no matter how much you polish it, and you guys know this, this is awesome. You should look up pictures of it and videos of it. It's a trend in Japan, I guess, called Durango, where they take a ball of mud and they polish it until it's this gorgeous, shining jewel of a ball. And they did it on Mythbusters, but not with mud. It turns out you can polish a turd. And it's as beautiful as the results of this practice are. It's a lot of work, and it's still a ball of mud, right? So I think what we see is that there's a tendency for things to get bigger and more stuff gets bolted on. And as we allow apps to grow organically, they just, yeah, I always think of Job of the Hut when I think of this, right? It's like this giant blob sitting there, and it does stuff, right? It yanks on chains, and it sentences people to be frozen in carbonite. But they just keep getting bigger. And like Robo says, I don't even know why we have the square cube law if things can just get bigger infinitely. So what I want to do is point out that there's a different way, right? And it's thinking small, right? And if the big organic growth blob thing is one approach, then we could also look at it the exact opposite, where we have lots of little things that all work together, right? And the reason we should bother is because small things are easier to design. It's way easier to plan out the application that only does one tiny thing, right? It's only for user authentication than the application that does 50 different things. They're certainly easier to build. When you have 18 different things going on, or 50 different things will be my number for this talk, I guess. 50 different things going on, you've got 50 different interacting processes that can all interfere with your build, right? They're easier to test. Big code is hard to test. Little code is easy to test. Look at methods alone. Unit testing a big method is always going to be harder than unit testing a two-line method, right? Debugging, if you've ever had a problem occur, some random spot, the smaller the pool that you're looking in, the easier that's going to be fine, right? So I was working on an app at a consulting agency about two years ago, and it took us three days to find why purchases couldn't go through. When, if purchases had been separated out with their own application, we would have known this one, right? You just zero in on it. They're easier to scale because they're only doing one thing, right? Why is it easier to scale an application when your database is on one box and your application servers are on another than when they're on the same box, right? Because they're separate, right? You can just add more database boxes. You've already got that interface there, and it's easier to spread out to multiple than when it's all one chunk. They're easier to replace. So if you find out that somebody has been building a better video encoding site than you were building for yourself, then you can just slap in their solution instead of your own. And they're easier to reuse. So you can actually, if you have built authentication as a separate app using you've got your own OAuth service provider or something, then you can use it to provide authentication to all of your apps instead of having to build that each and every time. And you can also sell it for yourself. The Heroku add-on catalog is a great place to go to look for, I used to work for Heroku, so sort of sideways plug for the Heroku add-on catalog. But there are tons of services there that people have built that you can reuse because they built them as tiny single-function applications. So hopefully that's at least a negative of why you might want to think small. But if you're looking at your giant ball of light, your drop of the height, your 50 different things happening in one app, there's a real question about how do you start? How do you split something off? Because I think we saw, it wasn't Zach's presentation, but it was early on when, as coupling goes up, the pain to test and the pain to do anything with goes up, right? If everything is sort of intermingled, it's hard to see where to start on yanking something out and making it its own service. So the natural question is what should I do, right? And the overall answer is follow the single responsibility principle. Apps, just like other units of code, should do one thing. And when you're talking about a method, the one thing they're doing is very, very small. When you're talking about a library, the one thing might be better. So it might be a method might pluralize a string. A library might provide all kinds of inflections, but it just provides inflections on strings, right? When you get an app, it should still do one thing, but the thing is going to be better, so it might be authentication. It might be semantic analysis. It might be any number of things that we'll see in a minute. It might be walking if your legs have been split off into a separate application. But the key is to find that one thing, right? So if your app does 50 different things, that's potentially 50 different apps. So here are some good places to start. I've already talked about authentication, and OAuth is I think the sort of banner trial for this, right? If you want to provide an OAuth service from your platform, then split it off into its own application to provide that, and then, you know, farm it back into your app and give it to other people as well. Administration, right? There's no reason that the administration interface needs to be the same actual app code base that your end user is looking at, right? And in fact, you're slightly more secure if they're not the same, because there's no chance that a user will stumble on it in the course of their action. Reporting, as data gets bigger, the demands it places upon your application and your code, they get more unrest, right? So imagine running gigs of reports on the same server through the same code base that you're serving hundreds of millions of hits a day on. It's never going to work. Search is one that I go back and forth on. There are a couple of, and the reason I include it is because there are people who are doing it, right? You can get searches of service now with thinking sphinx or flying sphinx, I guess. There was index tank, which recently got acquired. There are other options where you send out the data to be indexed and then you send searches to that service and get it back, right? So it is something, again, that's computationally intensive. Maybe it's not your core currency. You just need to provide it something you can split up. Payments. Who here has written their own payment processor? Who did it when they were not working for a payment processing company? I'm sorry to those of you who read it, because I'm sure that was not an enjoyable experience. For some domains, the sheer pain of dealing with legal requirements and logistical requirements makes it not practical to do it in your app. There's no reason that you should have to deal with payment in your app. Another reason to separate certain things like this out, when there are legal requirements on a domain, including them as part of the big ball of mud, can impose those legal requirements in a larger context. For example, if you have to be PCI compliance, you actually have to have the trusted developer, shitty developer divide that Zach had upon earlier. Because not everybody can commit if you're PCI compliant. As you bring on new people, they're legally not allowed to. Close to my heart, which is why we're kind of living social, is email. There's no reason email needs to be part of your app. Your app is most likely doing something on the web. Email is a separate communication channel. Form that up. There are dozens of email service providers out. Eye contact, contactology, contact email service provider, MailChimp. All of them that will happily handle this for you, or you can write your own if it's something that you need to. But it doesn't need to be part of your app. I think what a lot of these domains have in common is that there are different indicators that point you and say, look at this as something possible to extract. The first one that I noticed was, I started working on an app that had seven or eight different namespace routes in the routes box. The routes box is huge, and they were split up into all these different namespaces. There's admin, there was a thing that is redacted so that you don't know what app this was, and another thing that was redacted. Each one of those should have, in fact, been its own application. The namespace was like the flag waving saying, hey, extract me. I'm already separated. I need to be more separate. Users are another place. So if the audience that's using a particular set of functionality is well-defined, that might very well be a place to split it out. So something like Lexus Nexus, which is mostly used by academics, as it comes to more public and non-academics use it, they're going to have different needs, and so it can make sense to split out their functionality into a separate code base so that you don't give them the same functionality because they don't need the same functionality. As teams grow, so as applications grow, teams usually grow too. So at Living Social we have something like 60 developers now. We can't obviously all work on the same code at the same time. That's a lot of people to be working on one thing. So we have split up into teams. And at a certain point, it can make sense to have those teams work on separate applications just instead of separate parts of the code base. So we have a merchants team, we have a payments team, we have my email team, we have the consumer web team, we have internal applications. By all of these, there's no reason for them to be working on the same code at all. We don't touch the same code, and when we do, those things are generally better split out into gems and other things that are shared. Or you can have teams that come together to form giant robots later. Vendors, I've already mentioned looking at services that are offered for sale as an option. If you're not sure whether you can split out a sort of application, a single responsibility into its own application, chances are somebody's already done it and they're charging money for it, there's no reason you can't. And then if you need to reuse something, so this is kind of once you've already started, you've already got like three apps and you're seeing duplicate code between them, that's the time to think about something you're on. And this is where authentication comes up, right? Because every app we write has authentication. Maybe we shouldn't be writing it 12 different times for 12 different apps. But the real lesson is that for any situation, you're the person who knows your domain. You're the person who knows what's big enough or small enough to be a single responsibility for a full application. So you make the rules. Maybe for me, like six different apps make sense. Maybe for you, you know, one hole blasts through the middle by a couple seconds with a lightning gun makes sense. But it really is, it's up to what fits your needs. I mentioned for small units of code the single responsibility is very small as you get larger, right? That's all subjective and it depends on what you're doing with the code and what you're doing with the application. So how do you go about doing it, right? If you've sort of got an idea of I'm looking at my application and clearly administration doesn't want anything else. As a whole separate set of controllers it hits different models in some cases. There's a different authentication system for it. I'm going to split it out. What do I do? Or how do I do it? I think the first thing to realize is that you already are splitting it out. If you look at, we've already split out authentication in a number of different places. A lot of people already have payment split out. If you're paying for any service and who here is using something as a service provided by somebody else in their application? That's actually smaller than I would expect. We're already doing it, right? We already have certain models. So you ask the question, how did you do those? I think the first step is testing, right? So when you're looking at your big ball of mud hopefully you have a nice test suite that sort of exercises the full path taking an authentication example where you see a login form, you submit some stuff, comes back maybe using Cucumber, maybe using Rails integration tests. Doesn't really matter. The first step is that you have a test suite that exercises the path that's going to hit all of the applications you're worried about. Once you have that, you're able to isolate the code that you're looking to separate, right? So you don't go ahead and do Rails new over here immediately. Instead, you make sure that you separate using namespacing at the module level, using APIs, using internal communication tools to make sure that the code isn't coupled anymore, that it's not calling into the code that you want to replace. Once you do that, you test again to make sure that the test suite still passes and then you can go and replace it, right? So if I've got authentication, let's use the standard authentication that everybody has always done in Rails where I hit sessions new and that does a user.findbypassword or whatever, and then it checks the hash findbyemail checks the hash passwords and then it returns authenticated setSession or whatever, right? The first step for isolating is you move that out and you say you need to authenticate pass in the prams, right? So you've already isolated the internals of the findby into the model. Then once you've done that, you can pull out user authenticate from the model and replace it with a service call into your authentication service and make sure that it returns the same thing. You run your test again and they pass and that's it, right? I kind of feel bad about proposing this talk because it's not actually a hard process, right? It's test, isolate, replace, repeat, right? And that really is all there is to it. Who here has an application that they need to replace a part up in the service? What's the part? Email. Okay, so how are you sending email now? Through a third party? Okay, so you've actually, so if we're going to replace email being sent through a third party, you've already got some of this stuff, right? Hopefully you already have a test suite that exercises the connection to the service provider. So if you're looking, are you looking to bring it in-house or to another provider? More options. More options? You want more messaging options. So you need to build, right now you have a certain sort of layer in between your application and the email service provider. So you need to support your extra options to find the appropriate provider that can read them, right? So you have your test suite, you add the options here, you run the test suite, the old provider still doesn't meet them, you replace it, and then you run the test suite and it meets them, I guess. That's an interesting case of replacing one already service with another already service. Anybody else? So problems, this is not sort of the panacea, right? If you're writing Sinatra apps on the free planet of Roku, you probably don't need to do this. If you're writing giant evil computers that that scheme instead of just looking like little boxes, you probably don't need to do this either. But there are some real issues with service-oriented architectures that you need to be aware of. The first one obviously is latency. Actually, this might not even be the first obvious one, but it is an obvious one. When you're talking to other services, there are risks inherent in having them not be part of the same application, or on the same box, not be in the same data center. And the ways to get around the latency issue are with monitoring and defensive coding. So you can't guarantee you're going to know where your apps are going to run. So you need to be aware of what's happening and you need to code it in such a way that it handles interruptions. At one point, I think Amazon was running a couple dozen services to populate its homepage. And if any one of them did not return a response in some sub half a second time frame, that little module would just be dropped out. And the page was designed such that if any piece didn't return in time, it still made sense. If all of them failed, it wouldn't work. But if only one of them failed, it's fine. The same thing goes for reliability. Our applications fail. We're imperfect developers. It just happens. And so, when you multiply the number of applications, you're multiplying the number of opportunities for failure. Again, defensive coding and monitoring are really important. You want to know as soon as it happens so that you can fix it. You want to be as fault tolerant as you can be. But then integration testing is the other piece here. You guys know the Chaos Monkey from Netflix, which is a series of processes now. It's multiplied. It's like a Chaos Monkey family. That essentially goes in and breaks stuff at random. I think they do it in production, which is crazy. It is what it is. The original Chaos Monkey would just throw out Network Connect. It would roam around their boxes. It's not an actual monkey. It's just a process. It would simulate monkeys yanking ethernet cables out of boxes in their data center. They would have monitoring all the time so they can see when this happened and how they responded to it. We can simulate that without, again, actual monkeys with integration testing. You can integration test the normal path and you can integration test the failed path by mocking out your service and having it return something bad. Complexity is an issue that I think services are kind of near the rails in general. I think that we don't appreciate the complexity downside of them as much as we might need to. Where I see this happening most often is in development. At work now, I have to run five different applications to get the full user experience of using my production site. I have to run them on my box. Not counting services like MIMCASH and RENAS and things like that. One of the ways to deal with this is a tool called Foreman, which came from Baroku. It's a gem that gives you a proc file where you define certain processes and then you say, like, WebIsRailServer and Rescue and whatever MIMCASH is, you type form and start it reads the proc file and starts all the processes for you. So what I have is in my root directory I go form and start and it descends into each of the applications that I have to run reads their proc files and starts all the services that I need. So instead of having to rail start or rail server in a bunch of different places and RENAS start and all that I have one command for a complete experience and I don't have to think about it anymore. The other way to deal with complexity is specialization. So I say I have to run 500 apps to replicate the full production experience as the team lead for mail I don't actually care about the full production experience I care about email. So I generally just run one app and I'm specialized into that app. Other people generally just run the mail tracker app or the consumer web app they run the one app they need to. So specialization is a way to reduce complexity of the individual developer as well. Then the last major problem with this is redundancy. Don't machine yourself drilled into our heads times have again that when you start splitting things out into services you're going to be repeating yourself. If you're building a bunch of rail services or a bunch of snatch services or whatever you're at least repeating the framework code you're doing a lot of the internal code as well. And the ways you're in there are code review to see where the representation is having. Use automated tools I think it's not flawed. Flay, does that do the code duplication checks? Yes. So Flay and other tools can be used to find repeated sections of code and then more extraction you pull out more services you pull out gems. This is a way this is sort of don't repeat yourself writ large. So when everything is in a single application you're kind of repeating everything the whole way. You've got code being used in multiple places when it shouldn't be. When you split that out you have to reduce that duplication again. So to recap you should buy a tonic remote which is the comic that these images have come from and it's amazing available at finer comic stores nationwide but also look at your application if it's turning into a big ball of mud or if it isn't, if it's just getting big think about the ways in which you can split it up it's not always going to make sense certainly but it's not something that we should dismiss out of hand as we have for the past five years of the Rails community it's the less we see as application developers the bigger things we're going to be building and the more mature and varied our approaches to building those things is going to have to be. Questions? So the question is having used administration as an example of this obviously you're going to be sharing the data model to some extent between the two how do you tackle that? So the data model is rarely identical to the one in the user for one so at a certain level there's not going to be that much of an equation you are going to have for instance models pretty much the same thing in both that I don't know how harmful that is you could if you wanted to go sort of crazy with this which is probably a degree to which I would not recommend you could extract the model layer itself into a gym the common stuff and include that in both apps and then just have things that sit on top of them that are the specializations required for each piece but I don't know when that would be recommended never that would be recommended never do that Yes I don't know about never back into yellowpages.com we used to use there's a service layer there that does just that all of those back-end business models get used by native iPhone apps they get used by four or five different websites right the back-end Oracle databases and search engines are all abstracted so yeah it's a service layer that's used by a bunch of different apps and is completely separate so that's actually the I actually had this in an earlier version of the talk and I completely forgot about it so making the model layer or service layer and that actually isn't that doesn't contrast with the never because the never was actually crazy like gemifying your model layer and including it or repeating code so service layering the data layer is definitely an option and as you look at I think we don't often think about because we're used to using relational databases but as you start looking at object databases and graph databases and things those actually make a data layer a data service layer a little more natural what's our question over here in the corner question over here okay I think that does it and thank you