 by my clock, it's about 1.40, a couple more people are coming on in, but we'll get things started. My name is Jason Clark. I'm an engineer at New Relic. I work specifically on the New Relic RPM Jam, which some of you may have installed in your applications. So that's actually going to play in a little bit in some of the examples that I'm going to use later on, but you don't need to know too much about how that works. But first, I've got to start off with an admission. There's something that I've always wanted to do when presenting in front of a group of people, and I figured that RailsConf is probably just about the best opportunity. So if you just bear with me for a second, just hang on. At New Relic, we have a support hero who is responsible for handling the escalation. So anytime that something gets too complicated for support, they send it to the support hero, and my wife heard that, and she went, if you're a hero, you need a cape. And so she made me this lovely hand-embroider Druby emblem cape, and I've always wanted to give a presentation wearing this. So if that's okay, little unprofessional maybe, but you know, I'm just gonna go for it. So all right, that feels good. Thank you. Thank you for humoring me. All right. So what we're here to talk about today is about something that I call A Vintage Patterns in Ruby. So let's start off with a little bit of a story. This is a little bit of a fabrication, but it might be something that some of you have experienced before. So imagine that you have created an application. Maybe it's something like, something basic for doing a tracking of your cycling statistics, and all of a sudden your application really takes off. It gets on the social media, people find out about it, and you know, you start getting this influx of users that you've got to deal with. You know, as your traffic scales, you've got to do things like tuning your web server, right? You pick your Unicorn or your Puma, and you get that set up, you tune your system, and while your traffic is growing, there's a similar sort of growth that goes on in your code. Your controllers start out life kind of like this. They start out pretty simple. You know, we just create our user when somebody signs up. But then as your application grows and you get more stakeholders in your companies, you know, doubling every two months, all of a sudden you've got other things that you need to add in there, right? You, maybe you want to send welcome emails. So you end up, you know, getting your action mailer going there and cram that into, into your action when someone signs up. Oh, and then maybe it's really important that our business people be able to do analytics. They want to know about who's signing up and track data. And there's some other place that we want to push that data. Oh, and then the sales people, they really want this to be integrated to their sales system. And so they want stuff to get pushed over to their CRM. And maybe, oh, we want to do some sort of posting out to the social networks. So we have a background job that takes care of that. You know, this sort of growth happens in some of those critical points in your infrastructure, those spots where interesting things happen in the domain of your application. Now, that's kind of can get to be a mess, you know, this over time. I mean, this is a short example and slightly fabricated, but I'm sure you all have, you know, I'm sure all of your controllers are like 12 lines or less for an action, right? Nobody has these long methods that go on and do tons and tons of things. You can end up with a massive snarl. You can end up with controllers that are very difficult to test, difficult to reason about, and they go on and on handling all of these different things. So what we're going to talk about is a pattern of using events to handle that and to take those key parts of your infrastructure and break them apart into smaller bits. So first off, we're going to talk about what I actually mean when I say events, the pattern that we're talking about. We'll talk about how that can be used in the coupling of your application, both internally within your app and as it relates to other libraries that you might be using. We'll take a look at a couple of mechanisms that you can use to institute this sort of system, and then we'll talk about some of the responsibilities and sort of how you should think about this type of evented system within your app and keep things flexible and performant. So first up, the pattern. So when I say events, there's lots of different people that think lots of different things when I say that. Some folks thought that this was going to be about event machine. It's not about event machine. So what sort of things pop to mind when I say evented programming? Visual basic event handlers? Anybody? I'm sorry to know I shouldn't do that. No, a lot of people probably think node, think asynchronous sorts of callbacks. But that's not necessarily the core of the type of event that I'm going to describe here today. These events are not necessarily asynchronous. They're not necessarily about IO or about distributing things. They're just a basic pattern to decouple pieces of your application. So it starts off the main term that I'll use, somebody that knows that something interesting happened in your system. I'm going to refer to as a notifier. There's a set of subscribers that also exist. And those are the pieces of your application that care about that event that just happened. And then there's some sort of eventing in the middle, something that dispatches those events from the notifier to all of the subscribers. Now, this is really pretty basic. And you might wonder, like, why aren't these just method calls? Well, it's because of that eventing system that we can get the decoupling. It allows for the notifier and the subscriber to not necessarily know directly about each other. Those classes don't have to interact directly without that intermediary between them. What's the relationship to the to callbacks, you might say as well, there's, you know, an active record, we have a before and after hooks and around hooks to do all sorts of different things. Well, this is similar, but it's a little different from what we're going to describe because of that line where we have to derive from active record base. That's a really tight coupling. And what I'm going to describe doesn't put any requirements on your class, except that it interacts with the event dispatcher as a collaborator. So that's the basics of what I mean by evented patterns. So let's take a look now at how it can influence coupling. So the first example that I'm going to draw is about internal coupling. So when I say that, I mean, things that are within the scope of your application, the code that you own and that you've written. So working for New Relic, the gem that I work on, you install it in your application, and it spins up, starts monitoring performance information, and then sends it back every minute to New Relic so we can give you pretty graphs and alerting and all sorts of insight into what's going on in your app. When this gem was originally created, we would load things up when the app starts and we read a little config file to say what types of things we want to be doing. You know, there's features that you can turn on and turn off and configure. And we knew the story about what the configuration was when the application had successfully gotten running. Well, later on, we added a feature. And that feature was server side configuration. So the application now connects to our server and gets back some additional set of configuration values. And what this means is that the point in time at which we could assume that the application was actually configured changed. If we had put a bunch of logic directly into our app startup, like right there in the initialize where things start running, we now didn't have the right answer for what the configuration was. We have to wait until that connect happens in the background before we can do that. So let's take a look at what happened with that connect method. So we make a call out to the server. And you know, this is obviously a little stripped down, there's error handling in real life, but we get back some sort of configuration from the server. It tells us what those settings are supposed to be. We pass that along to finish setup. And then finished setup starts looking like a little bit of a mess. There's a whole bunch of different concerns here, right? We've got something about naming rules, something about cross application tracing, JavaScript, some sort of beacon. Like, it's not important what all of the inner details of all of these pieces are, but none of them are really related. The only thing about them is that they care that the configuration is ready. They're wanting to respond to that event that happened that the config is set. Now one of the outgrowths of the code being laid out like this is that we would like to be able to write some simple tests, some unit tests like DHH tells us we shouldn't, that look kind of like this. We run our finished setup against a given config and then we can see the results of what came out of that. But in practice, what we end up having to do is we end up having to stub out things. Like those different collaborators that were in there, the cross application tracing, if we don't care about it in this test, but we still need to make sure that that code path can run without tripping anything up or crashing because things aren't filled out the way that it needs it to be. Things can get even worse than this. Now that beacon lying down on the bottom, you know, we're constructing a brand new object. Who knows what that thing might be doing internally? You know, I mean, nobody's ever written code like this, right? It does something bad like that from a constructor for an object. That doesn't happen. But, you know, we end up having to do things like stubbing out new to make it so that objects don't do interactions and things that we don't really want. Well, what if we could take this whole method and just get rid of it in the form that it's in and instead, we notify that an event has happened. We tell our event system that the system is now fully configured. We are ready to go. Everything's locked. We can head on. Now this has some really nice side effects. One of them is that beacon code. Now, in initialize, you still see the code where we're making this HTTP call out. But it's now wrapped in this subscribe block. So it means that that call is only going to happen when the event system lets us know that this configuration event has occurred. That provides a buffer. You can safely create a beacon now. And it's not going to immediately go hit the network. The tests around the finished setup method become very slim and very straightforward as well. All the finished setup is responsible for is firing that event. And we check that that event gets dispatched correctly. And that's all that we need to unit test at this level. And unit testing for the individual effects that occur moves over and gets done in the place that responds to that event. The thing that is going to subscribe to the event now takes the responsibility for testing that. Now, this doesn't cover everything. There is a need for an integration test. You do want something that sees that we wire up to the right events. But you probably have tests that are going to exercise those things anyways if this is in the critical path of your application. So events allow us within our own code to have more focused tests around those individual pieces. More independence between the classes. The configuration, the finished setup no longer has to know anything about the JavaScript instrument or the cross application tracer or the beacon. All of that is pride apart. And we found that this also starts to kind of create a language within your application. A domain language, if you will. Because these are the important events that happen for us. We care as the New Relic Gym that we are configured. That is a critical thing for us. And there's now a name for that. It's not just a bunch of stuff that's tacked on to the end of one of our methods. It's not all roses, though. There is an issue if you have some sort of ordering that's required in the things that respond to those events. And actually, we've had a couple of situations where we've been refactoring code and trying to pull it into event handlers and discovered that there were dependencies between different subscribers that aren't really handled by a really simple event system like this. So that's something that you have to watch out for. If there's a lot of that sort of ordering, you're going to have to deal with that somewhere in your code. It can also make debugging and reasoning about things a little harder. It does spread some of those responsibilities out. Now, you don't see one method that lists all of the things that we do on Connect. You have to go search for things that subscribe to those events. But in the right cases, I feel like it can buy you things with the other benefits that it brings along that outweigh that. Lastly, it is a performance consideration. You know, I would not use this sort of structure in a tight loop that's going to get called a million times a second. You know, if it's something like we're responding to a configuration event, like that we are now ready to go or somebody just signed up, I mean, it'd be great if you had a million people signing up a minute, but reality is it's not happening as frequently as that. So being aware of how this will impact your performance is really critical. Internal coupling, like within the code that you write yourself, though, is not the only place where you can get bound to different things. So in in the New Relic Gym, we have a lot of different functionality that we instrument that work through middleware. So we do JavaScript insertion for doing end user timings. So as your request is going back out, we'll modify your HTML and put things in there. We have error collection. So if there are unhandled exceptions that occur during your call at the rack level, we will actually gather those up and see that those have happened and report them back. And we do things with HTTP requests between applications if both ends of them are running New Relic. And we need to modify headers, HTTP headers that are on those requests. And all of these separate things fit for us very well within middlewares. But that makes kind of an assumption that everything that we want to apply that functionality to is built on top of rack. And while that's a pretty good assumption for a lot of things in the Ruby space, we do support things that aren't necessarily configured that way. We also want to avoid people having to set things up. There are certain cases where maybe you have to manually add the things that we've created. And if we have seven different middlewares that you need to add for all of this different functionality, that's kind of problematic from a configuration viewpoint. So our solution to this was that we standardized on having one middleware that we commonly will install. And we use events to actually do the dispatch from there. So you'll see this is just a very basic middleware when a request comes in and hits call. We notify on the before and pass along the environment that we got, we call through to the app inside and notify after and then return the results. So this allows us to be able to plug things in that maybe are not shaped like rack. We could use some of that code like in the cross application tracing. If we had some web server that was not rack based or some configuration that was not going to run through middleware, we could still have it generated before call from the right point and handle that with this same code without having to deal with trying to create middlewares or insert something at a point that doesn't really fit. Now just for the middleware case, you know, this probably could have been solved with some sort of composition. But for us, it was actually a really powerful technique for keeping our code decoupled from the library that we were building on top of that looser coupling depends a lot on what sort of library and what your interactions with it are, you know, you're maintaining basically kind of a compatibility layer and the more code that you have to put into that layer, the more you should probably think about whether you're approaching it correctly. Obviously you can't do something like this with active record. It's just not going to be plausible. But if you have a small number of points where you interact with another third party library, applying events at those boundaries can be a way that you can keep some separation between your code and the library that you're dealing with. So that's coupling. That's sort of the primary motivator behind using an evented pattern is to decouple the pieces of your application and allow for those to be looser and not as aware of what's on the other end of either firing or responding to an event. So let's talk about what it actually takes to implement this. What does this look like in practice? So I have created a small gym. This is sort of an extraction from what we do in the New Relic Gym. We don't use it directly, and I am not suggesting this for production use, but it's a really good example of how simple it is to implement something like this in Ruby. So there's one primary class, the Simple Events Notifier. When we initialize that, it's going to be the central thing that keeps track of all the events, and everybody's going to talk to this Notifier object. So we hold on to a hash, which is where we're going to store those handlers from the people that subscribe to us. Subscribing gets done, passing in just a key for what the event is. We typically use symbols within our application, some similar things that we'll see later use strings, and then hands in a block, which is the code for it to run at that point that that event gets fired. And then it's just a simple matter of keeping track of that list of handlers. Each event may have multiple handlers, so we make sure the array is there, and add that handler onto the list. Now there's one other line here that we're dealing with, and that's checking for runaway subscriptions. That has to do with the fact that for our usage, there is a limited number of things that should be subscribing to events. This is not something where every single web request that comes through subscribes and hooks itself in, and we'll talk a little bit later on about some of the negative side effects you can have if that's happening. So for us, if more than 100 event subscribers have subscribed to a given event, we actually have a bug, and so we check for that, and make sure to warn that that's going on. Your mileage may vary depending on the structure that you choose to use. Notifying is a little more complicated than subscribing, but not too much more, and we'll step through it here. So first off, we check whether the event's collection has any handlers for the particular key that we just passed in. And this is one of the really nice aspects of taking this simple approach. There's no central registry, there's nothing to set up. An event, I can create a handler for an event that doesn't exist, or I can start firing an event that nobody handles, and it all just gracefully falls out. It doesn't cause any problems if there aren't handlers wired up for things. If we do find that there are event handlers, we simply iterate across those and call passing along the arguments that we received on the event call. For our particular use in New Relic, we trap errors and will log and swallow any exceptions that happen as a result of our direct event handlers. Now this is kind of an artifact of the sort of gem that we are. We're there in the background and these events are things for the agent and for us sending our data back. And the worst possible thing that we could do is crash an application. And so we trap everything that goes through. If you were doing this in an application setting, you may want to log, you may also want to raise those errors and fail quickly in the case that one of your notifiers has something go wrong. But your mileage, you know, you can choose what the right policy is for how you're using events and what setting you're putting those in. So that's it. Like that's an entire eventing system in about 50 lines of Ruby, which allows you to decouple those different pieces of your application. But the fact of the matter is that you might not have to even write that system yourself if you're using Rails. Active support notifications have been baked in from, I think about the 3.0 version of Rails. And it's a system that's very much like what we've described here. I'll abbreviate in the slides a little because active support notifications gets really, really long in the code, so we'll scrunch that down a little bit. But all sorts of things flow through this evented system any time a Rails request is occurring. So we get things about the dispatch at the top level. We get things about the controller and what it's doing. We get notifications about SQL calls. We get notifications about view and template rendering. Like, tons and tons of events are streaming through this active support notification system all of the time. Some common things that you might be familiar with, like the log, the debug log that you get of your queries, that's running through active support notifications that are fired by active record. So what's this look like? It looks very similar to what we've seen before. So subscribing to an event, you give it the name, you give it a block, and then you can see the form of what one of these events was that came through. It'll hand it to us. It's got a name. It's got an identifier. And then it's got this hash that's sort of a payload of data that comes along with it. Active support also provides a simple wrapper for handling that payload and handling those events when they're in a very common form. So most of the things that Rails sends out, they're going to have a name. They're going to have a duration and a payload in a standard format. So this class kind of wraps up that access and makes it a little neater. On the notifying side, the method that you call is instrument. So if you want to fire an event and have that be sent out to the system, you just give it the string for the name, give it whatever payload for the data, and you're off and running. There's also a nice form of it that it has that will wrap your code in a block so you can do something in there. And what that'll do is that will tack a duration on. So it will time what's going on. And this is one of the key things that Active Support notifications are used for within Rails. It's timing how long different things take. Those timings that you see in your debug output are all coming from things being wrapped by this sort of instrument call. As with all things Rails, there's a lot more richness as well under the surface. You can do subscriptions by regular expressions. If events are nested, the Active Support notification system keeps track of that and will take care of letting you know so you could look and see whether an event was occurring within another event. And you can go crazy if that's happened in too much. But there are temporary subscriptions and unsubscribe, which is useful in certain scenarios where maybe you do want to have something hook into the Active Support notifications for the course of a request, but you don't want to have that handle or hanging around and responding for the rest of the lifetime of your application. And there's some really good examples that you can find in Rails itself. So the Log Subscriber class, which is the thing that spits out a lot of your development log, is a great example of how you can hook into that underlying infrastructure. So that's the mechanism. That's how you can build events in or use a library that you're probably already using to get a lot of these things done. Let's talk a little bit more in detail about the different parties that are involved here and what they're responsible for and considerations there. So notifiers have a lot of responsibility. They're kind of the key points in your application. In this scheme, you would be adding events for the things that matter the most. And on that, I think that naming is a really critical thing around this to get the benefit that you're looking for. So in the example that I gave up front, you probably didn't notice, but I named the event configured to say, hey, we are in a state where we are fully configured. I didn't name it connect to server or finish with the setup or binding it to the mechanism of what it was. I couched it in the terms of what mattered to my application. I think that that's something that's really powerful if you do this right. If you, it allows for changes in the location, like in our case, that change of when we were configured. It moved from just plain application startup to a point in time in the future when we may hear back from a server. And who knows when that configured point might change in the future. We're not bound by the event name to some particular method or point in time. We can change that and still have it make sense within the domain of what we've created. It's also important to consider what your payload is, what data you're sending along from the notifier. So Rails follows a convention with active support notifications that I would definitely encourage of sending along primarily a hash of different values that you can pipe through. I learned this the hard way the second time that I needed to add a bit of data onto one of my events and the mechanism, as we saw, just sort of percolates the arguments along that we've given it. Well, if you add another argument, all those other handlers downstream need to get updated. So do it from the start to make these things flexible. Pass your payloads along as a hash that you can then add additional data that old event handlers don't need to care about and that new things can pick up along the way. On that topic of the payload as well, if you're writing some sort of internal application, you can put whatever you want into these payloads. But as a third party, you may want to be cautious if you're having other people, other gems and other codes subscribe to these events to try to keep your payloads as primitive as you can, maybe even all the way down to just base types. The advantage here is that you are, if you put one of your internal classes as something that you're packing around in this event and then broadcast it out to the world for everybody to use, you now don't know who might be getting access to those objects and using them. And depending on what sort of usage you've got with your app, it can be difficult to make changes to things that maybe you consider to be internal details. If you turn things into primitives, you know, they're just strings and hashes and numbers. Those are pretty safe, right? You can maintain that mapping from your internal objects to those primitives and not have to worry about who might be changed when you refactor. So the other end of things is the subscribers. I think it's really important to consider carefully who the subscribers are for a given event. This pattern doesn't fit everywhere. This is not something where every single thing that happens in your application should be an event. And if you're writing an event and there's only one thing that's gonna handle it, you might be misapplying this pattern. You might not get the benefit that you need there. A lot of times you'll find that there is some natural home, some place within your app that is already there that is the right place to be subscribing to that event and responding to what's happening. But if you don't, there's some interesting ideas around how you could create what that location is. So there's this gem that I've run into. It's called mutations. It's sort of building command objects that represent different actions that happen in your system. Now, you might recognize something very like this from earlier in the morning, but it can be an interesting idea if you have key pieces of your system where a workflow or something that occurs is really important. You can write something, a command that encapsulates what that event is, what that action is that needs to be taken. And this can be something that helps in those cases that I described where there may be implicit ordering. There may be ordering between different components. You could create a command that wraps those up in the right ordering to be applied and then have that be what responds to the events. Probably one of the biggest difficulties that you can run into with an evented pattern is if there's too much nesting. If this gets overused and events trigger events and trigger events on all sorts of different things, it can become very difficult. And the main advice that I have there is that this technique works best, I think, at the critical lynch points of your application. The things that you really care about the most to be providing that sort of visibility and language around. And another thing to be aware of with the implementation that we've done here, I've had a number of people come up afterwards and point out they're like, it's all still synchronous. It's all still just running. I mean, this is just, you know, splitting up where those things are. And that's totally true. This is not as described something that will make your application parallel or asynchronous and how that event handling happens. But it might give you good points in time when you could decide to push things off. Things could go to background jobs or things could get dispatched to all sorts of other places if you wanted. It's also important with subscribers to watch out for leaks. There is when you create a block, so like if this subscriber was created for every web request, the fact that we have that block potentially holds on to a reference to this object and keeps it alive past the point in time when you might have thought that it was gonna go away. I've seen this not just in Ruby but in a number of different languages with these sorts of evented patterns with handlers that get subscribed where they can hold references to objects that you might not be expecting them to. And so you gotta watch out for that to keep things from leaking. So those are some ideas around the responsibilities that your subscribers and your notifiers should have. And I hope that maybe this has opened your eyes a little bit to some ideas about how you might be able to partition your app differently. What are those responsibilities and things that happen during your app that would be worth having an event, or worth giving that name to? And as you can see that it's a pretty simple thing to implement that can get you a lot of benefit down the road. Thank you.