1 00:00:18,160 --> 00:00:22,539 JASON CLARK: All righty. I think, by my clock, 2 00:00:22,539 --> 00:00:25,239 it's about 1:40. A couple more people 3 00:00:25,239 --> 00:00:29,250 are coming on in, but we'll get things started. 4 00:00:29,250 --> 00:00:32,860 My name's Jason Clark. I'm an engineer at New 5 00:00:32,860 --> 00:00:35,890 Relic. I work specifically on the New Relic RPM 6 00:00:35,890 --> 00:00:38,090 gem, which some of you may have installed in 7 00:00:38,090 --> 00:00:41,640 your applications. So that's actually gonna play in a 8 00:00:41,640 --> 00:00:43,109 little bit in some of the examples that I'm 9 00:00:43,109 --> 00:00:45,510 gonna use later on. But you don't need to 10 00:00:45,510 --> 00:00:47,250 know too much about how that works. 11 00:00:47,250 --> 00:00:50,210 The first, so, I, I've got to start off 12 00:00:50,210 --> 00:00:53,510 with a, an admission to something that I've always 13 00:00:53,510 --> 00:00:56,149 wanted to do when presenting in front of a 14 00:00:56,149 --> 00:00:58,559 group of people, and I figured that RailsConf is 15 00:00:58,559 --> 00:01:02,260 probably just about the best opportunity. So, if you'll 16 00:01:02,260 --> 00:01:09,159 just bear with me for a second. Just hang on. 17 00:01:09,159 --> 00:01:14,610 So at New Relic, we have a support hero 18 00:01:14,610 --> 00:01:18,590 who is responsible for handling the escalations. So any 19 00:01:18,590 --> 00:01:22,429 time that something gets too complicated for support, they 20 00:01:22,429 --> 00:01:24,450 send it to the support hero. And my wife 21 00:01:24,450 --> 00:01:27,880 heard that, and she went, if you're a hero, 22 00:01:27,880 --> 00:01:31,270 you need a cape. And so she made me 23 00:01:31,270 --> 00:01:36,349 this lovely hand-embroidered Ruby emblem cape. And I've always 24 00:01:36,349 --> 00:01:40,340 wanted to give a presentation wearing this. So, if 25 00:01:40,340 --> 00:01:45,289 that's OK. Little unprofessional, maybe, but, you know. I'm 26 00:01:45,289 --> 00:01:47,679 just gonna go for it, so. 27 00:01:47,679 --> 00:01:51,799 AUDIENCE: Look in the sky! It's a bird! 28 00:01:51,799 --> 00:01:55,060 J.C.: All right. That feels good. Thank you. Thank 29 00:01:55,060 --> 00:01:56,869 you for humoring me. All right. 30 00:01:56,869 --> 00:01:58,429 So what we're here for, here to talk about 31 00:01:58,429 --> 00:02:01,209 today is about something that I call evented patterns 32 00:02:01,209 --> 00:02:04,079 in Ruby. So let's start off with a little 33 00:02:04,079 --> 00:02:05,819 bit of a story. This is a little bit 34 00:02:05,819 --> 00:02:08,508 of a fabrication, but it might be something that 35 00:02:08,508 --> 00:02:10,750 some of you have experienced before. 36 00:02:10,750 --> 00:02:14,069 So, imagine that you have created an application. Maybe 37 00:02:14,069 --> 00:02:17,310 it's something like, something basic, for doing tracking of 38 00:02:17,310 --> 00:02:22,099 your cycling statistics. And all of a sudden, your 39 00:02:22,099 --> 00:02:24,969 application really takes off. It gets on the social 40 00:02:24,969 --> 00:02:27,760 media. People find out about it and, you know, 41 00:02:27,760 --> 00:02:30,290 you, you start getting this influx of users that 42 00:02:30,290 --> 00:02:33,110 you've got to deal with. As your traffic scales, 43 00:02:33,110 --> 00:02:35,000 you've got to do things like tuning your web 44 00:02:35,000 --> 00:02:38,599 server, right. You, you pick your, your Unicorn or 45 00:02:38,599 --> 00:02:40,180 your Puma and you get that set up. You 46 00:02:40,180 --> 00:02:44,849 tune your system. And while your traffic is growing, 47 00:02:44,849 --> 00:02:47,280 there's a similar sort of growth that goes on 48 00:02:47,280 --> 00:02:49,560 in your code. 49 00:02:49,560 --> 00:02:53,340 Your controllers start out life kind of like this. 50 00:02:53,340 --> 00:02:55,680 They start out pretty simple, you know. We just 51 00:02:55,680 --> 00:02:59,450 create our user when somebody signs up. But then, 52 00:02:59,450 --> 00:03:01,280 as your application grows and you get more stake 53 00:03:01,280 --> 00:03:04,019 holders and your company's, you know, doubling every two 54 00:03:04,019 --> 00:03:05,989 months, all of a sudden, you've got other things 55 00:03:05,989 --> 00:03:08,439 that you need to add in there, right. You, 56 00:03:08,439 --> 00:03:10,489 maybe you want to send welcome emails, so you, 57 00:03:10,489 --> 00:03:12,930 you end up, you know, getting your action mailer 58 00:03:12,930 --> 00:03:15,530 going there, and cram that into, into your action 59 00:03:15,530 --> 00:03:17,090 when someone signs up. 60 00:03:17,090 --> 00:03:19,469 Oh, and then maybe it's really important that our 61 00:03:19,469 --> 00:03:21,599 business people be able to do analytics. They want 62 00:03:21,599 --> 00:03:23,739 to know about who's signing up and track data, 63 00:03:23,739 --> 00:03:25,319 and there's some other place that we want to 64 00:03:25,319 --> 00:03:29,170 push that data. Oh, and then the sales people, 65 00:03:29,170 --> 00:03:30,749 they really want this to be integrated to their 66 00:03:30,749 --> 00:03:32,810 sales system, and so they want stuff to get 67 00:03:32,810 --> 00:03:36,870 pushed over to their CRM. And maybe, oh, we 68 00:03:36,870 --> 00:03:38,379 want to do some sort of posting out to 69 00:03:38,379 --> 00:03:40,689 the social networks. So we have a background job 70 00:03:40,689 --> 00:03:43,480 that takes care of that. You know, this sort 71 00:03:43,480 --> 00:03:46,340 of growth happens in some of those critical points 72 00:03:46,340 --> 00:03:50,510 in your infrastructure. The spots where interesting things happen 73 00:03:50,510 --> 00:03:52,840 in the domain of your application. 74 00:03:52,840 --> 00:03:56,980 Now, that's kind of, can get to be a 75 00:03:56,980 --> 00:03:59,510 mess, you know. This, over time, I mean this 76 00:03:59,510 --> 00:04:02,230 is a short example and slightly fabricated, but I'm 77 00:04:02,230 --> 00:04:04,060 sure you all have, you know, I'm sure all 78 00:04:04,060 --> 00:04:06,260 of your controllers are, like, twelve lines or less 79 00:04:06,260 --> 00:04:09,939 for an action, right? Nobody has these long methods 80 00:04:09,939 --> 00:04:11,659 that go on and do tons and tons of 81 00:04:11,659 --> 00:04:13,069 things. 82 00:04:13,069 --> 00:04:15,810 You can end up with a massive snarl. You 83 00:04:15,810 --> 00:04:17,660 can end up with controllers that are very difficult 84 00:04:17,660 --> 00:04:20,470 to test, difficult to reason about, and they go 85 00:04:20,470 --> 00:04:23,930 on and on handling all of these different things. 86 00:04:23,930 --> 00:04:26,060 So what we're gonna talk about is a pattern 87 00:04:26,060 --> 00:04:29,330 of using events to handle that and to take 88 00:04:29,330 --> 00:04:33,430 those key parts of your infrastructure and break them 89 00:04:33,430 --> 00:04:35,160 apart into smaller bits. 90 00:04:35,160 --> 00:04:37,830 So, first off, we're gonna talk about what I 91 00:04:37,830 --> 00:04:40,180 actually mean when I say events, the pattern that 92 00:04:40,180 --> 00:04:43,130 we're talking about. We'll talk about how that can 93 00:04:43,130 --> 00:04:46,340 be used in the coupling of your application, both 94 00:04:46,340 --> 00:04:48,690 internally within your app and as it relates to 95 00:04:48,690 --> 00:04:51,160 other libraries that you might be using. 96 00:04:51,160 --> 00:04:53,479 We'll take a look at a couple of mechanisms 97 00:04:53,479 --> 00:04:55,430 that you can use to institute this sort of 98 00:04:55,430 --> 00:04:58,539 system. And then we'll talk about some of the 99 00:04:58,539 --> 00:05:00,740 responsibilities and sort of how you should think about 100 00:05:00,740 --> 00:05:04,620 this type of evented system within your app. And 101 00:05:04,620 --> 00:05:07,440 keep things flexible and performant. 102 00:05:07,440 --> 00:05:12,440 So, first up, the pattern. So, when I say 103 00:05:12,440 --> 00:05:14,190 events, you know, there's lots of different people that 104 00:05:14,190 --> 00:05:17,020 think lots of different things when I say that. 105 00:05:17,020 --> 00:05:19,060 Like, some folks that this was gonna be about 106 00:05:19,060 --> 00:05:22,720 event machine. It's not about event machine. So what, 107 00:05:22,720 --> 00:05:24,229 what sort of things pop to mind when I 108 00:05:24,229 --> 00:05:25,900 say evented programming? 109 00:05:25,900 --> 00:05:27,169 AUDIENCE: Asynchronous. 110 00:05:27,169 --> 00:05:28,440 J.C.: K. 111 00:05:28,440 --> 00:05:30,340 AUDIENCE: ActiveSupport notifications. 112 00:05:30,340 --> 00:05:33,340 J.C.: Visual Basic event handlers? Anybody? 113 00:05:33,340 --> 00:05:34,560 AUDIENCE: Nice! 114 00:05:34,560 --> 00:05:37,090 J.C.: I'm sorry to, no. I shouldn't do that. 115 00:05:37,090 --> 00:05:37,259 No. 116 00:05:37,259 --> 00:05:40,819 A lot of people probably think node. Think asynchronous 117 00:05:40,819 --> 00:05:44,389 sorts of callbacks. But that's not necessarily the core 118 00:05:44,389 --> 00:05:46,180 of the type of event that I'm gonna describe 119 00:05:46,180 --> 00:05:49,919 here today. This, these events are not necessarily asynchronous. 120 00:05:49,919 --> 00:05:53,530 They're not necessarily about IO or about distributing things. 121 00:05:53,530 --> 00:05:56,370 They're just a basic pattern to decoupled pieces of 122 00:05:56,370 --> 00:05:58,240 your application. 123 00:05:58,240 --> 00:05:59,740 So it starts off, the main term that I'll 124 00:05:59,740 --> 00:06:02,699 use. Somebody knows that something interesting happens in your 125 00:06:02,699 --> 00:06:05,599 system, I'm going to refer to it as a 126 00:06:05,599 --> 00:06:08,259 notifier. There's a set of subscribers that also exist. 127 00:06:08,259 --> 00:06:10,400 And those are the pieces of your application that 128 00:06:10,400 --> 00:06:13,740 care about that event that just happened. And then 129 00:06:13,740 --> 00:06:16,169 there's some sort of eventing in the middle. Something 130 00:06:16,169 --> 00:06:20,300 that dispatches those events from the notifier to all 131 00:06:20,300 --> 00:06:21,690 of the subscribers. 132 00:06:21,690 --> 00:06:24,770 Now, this is really pretty basic, and you might 133 00:06:24,770 --> 00:06:29,889 wonder, like, why aren't these just method calls? Well, 134 00:06:29,889 --> 00:06:31,759 it's because of that eventing system that we can 135 00:06:31,759 --> 00:06:34,520 get the decoupling. It allows for the notifier and 136 00:06:34,520 --> 00:06:37,620 the subscriber to not necessarily know directly about each 137 00:06:37,620 --> 00:06:41,449 other. Those classes don't have to interact, directly, without 138 00:06:41,449 --> 00:06:44,789 that intermediary between them. 139 00:06:44,789 --> 00:06:47,009 What's the relationship to the, to callbacks, you might 140 00:06:47,009 --> 00:06:50,520 say as well. There's, you know, at ActiveRecord, we 141 00:06:50,520 --> 00:06:52,979 have before and after hooks and around hooks to 142 00:06:52,979 --> 00:06:55,750 do all sorts of different things. Well, this is 143 00:06:55,750 --> 00:06:57,740 similar, but it's a little different from what we're 144 00:06:57,740 --> 00:07:00,870 gonna describe, because of that line, where we have 145 00:07:00,870 --> 00:07:04,759 to derive from ActiveRecord::Base. That's a really tight coupling. 146 00:07:04,759 --> 00:07:07,639 And what I'm gonna describe doesn't put any requirements 147 00:07:07,639 --> 00:07:11,280 on your class, except that it interacts with the 148 00:07:11,280 --> 00:07:15,280 event dispatcher as a collaborator. 149 00:07:15,280 --> 00:07:17,430 So that's the basics of what I mean by 150 00:07:17,430 --> 00:07:19,990 evented patterns. So let's take a look, now, at 151 00:07:19,990 --> 00:07:23,879 how it can influence coupling. So the first example 152 00:07:23,879 --> 00:07:26,479 that I'm gonna draw is about internal coupling. So 153 00:07:26,479 --> 00:07:28,050 when I say that, I mean, things that are 154 00:07:28,050 --> 00:07:30,430 within the scope of your application, the code that 155 00:07:30,430 --> 00:07:32,979 you own and that you've written. 156 00:07:32,979 --> 00:07:36,490 So, working for New Relic, the gem that I 157 00:07:36,490 --> 00:07:39,740 work on, you install it in your application and 158 00:07:39,740 --> 00:07:43,720 it spins up, starts monitoring performance information, and then 159 00:07:43,720 --> 00:07:46,099 sends it back every minute to New Relic so 160 00:07:46,099 --> 00:07:48,060 we can give you pretty graphs and alerting and 161 00:07:48,060 --> 00:07:50,889 all sorts of insight into what's going on in 162 00:07:50,889 --> 00:07:52,490 your app. 163 00:07:52,490 --> 00:07:55,669 When this gem was originally created, we would load 164 00:07:55,669 --> 00:07:57,490 things up when the app starts and we read 165 00:07:57,490 --> 00:07:59,550 a little config file to say what types of 166 00:07:59,550 --> 00:08:01,479 things we want to be doing. You know, there's 167 00:08:01,479 --> 00:08:03,310 features that you can turn on and turn off 168 00:08:03,310 --> 00:08:06,710 and configure. And we knew the story about what 169 00:08:06,710 --> 00:08:10,419 this configuration was when the application had successfully gotten 170 00:08:10,419 --> 00:08:11,099 run. 171 00:08:11,099 --> 00:08:14,770 Well, later on, we added a feature. And that 172 00:08:14,770 --> 00:08:19,729 feature was server-side configuration. So the application now connects 173 00:08:19,729 --> 00:08:22,860 to our server and gets back some additional set 174 00:08:22,860 --> 00:08:26,939 of configuration values. And what this means is that 175 00:08:26,939 --> 00:08:29,039 the point in time at which we could assume 176 00:08:29,039 --> 00:08:33,260 that the application was actually configured changed. If we 177 00:08:33,260 --> 00:08:35,610 had put a bunch of logic directly into our 178 00:08:35,610 --> 00:08:37,729 app start up, like right there in the initialize 179 00:08:37,729 --> 00:08:40,659 where things start running, we now didn't have the 180 00:08:40,659 --> 00:08:43,700 right answer for what the configuration was. We have 181 00:08:43,700 --> 00:08:46,920 to wait until that connect happens in the background 182 00:08:46,920 --> 00:08:48,890 before we can do that. 183 00:08:48,890 --> 00:08:50,330 So let's take a look at what happened with 184 00:08:50,330 --> 00:08:53,590 that connect method. So we make a call out 185 00:08:53,590 --> 00:08:56,830 to the server and, you know, this is obviously 186 00:08:56,830 --> 00:08:59,090 a little stripped down. There's error handling in real 187 00:08:59,090 --> 00:09:01,160 life. But we get back some sort of configuration 188 00:09:01,160 --> 00:09:03,690 from the server. It tells us what those settings 189 00:09:03,690 --> 00:09:06,160 are supposed to be. We pass that along to 190 00:09:06,160 --> 00:09:10,400 finish set up and then finish set up starts 191 00:09:10,400 --> 00:09:12,670 looking like a little bit of a mess. There's 192 00:09:12,670 --> 00:09:15,160 a whole bunch of different concerns here, right. We've 193 00:09:15,160 --> 00:09:19,970 got something about naming rules. Something about cross-application tracing. 194 00:09:19,970 --> 00:09:23,380 Javascript. Some sort of beacon, like. It's not important 195 00:09:23,380 --> 00:09:25,080 what all of the inner details of all of 196 00:09:25,080 --> 00:09:27,330 these pieces are. But none of them are really 197 00:09:27,330 --> 00:09:29,450 related. The only thing about them is that they 198 00:09:29,450 --> 00:09:32,980 care that the configuration is ready. They're wanting to 199 00:09:32,980 --> 00:09:35,870 respond to that event that happened, that the config 200 00:09:35,870 --> 00:09:37,380 is set. 201 00:09:37,380 --> 00:09:41,560 Now, one of the outgrowths of the code being 202 00:09:41,560 --> 00:09:43,220 laid out like this is that we would like 203 00:09:43,220 --> 00:09:45,660 to be able to write some simple tests. Some 204 00:09:45,660 --> 00:09:49,060 unit tests, like DHH tells us we shouldn't, that 205 00:09:49,060 --> 00:09:50,810 look kind of like this. We run our given 206 00:09:50,810 --> 00:09:52,480 set up against a chosen config and then we 207 00:09:52,480 --> 00:09:54,440 can see the results of what came out of 208 00:09:54,440 --> 00:09:55,010 that. 209 00:09:55,010 --> 00:09:57,490 But, in practice, what we end up having to 210 00:09:57,490 --> 00:09:59,510 do is we end up having to stub out 211 00:09:59,510 --> 00:10:02,050 things. Like those different collaborators that were in there. 212 00:10:02,050 --> 00:10:04,780 The cross application tracing. If we don't care about 213 00:10:04,780 --> 00:10:06,220 it in this test, but we still need to 214 00:10:06,220 --> 00:10:09,900 make sure that that code path can run without 215 00:10:09,900 --> 00:10:12,610 tripping anything up or crashing because things aren't filled 216 00:10:12,610 --> 00:10:16,040 out the way that it needs it to be. 217 00:10:16,040 --> 00:10:18,400 Things can get even worse than this. Now that 218 00:10:18,400 --> 00:10:22,100 beacon line down on the bottom, you know, we're 219 00:10:22,100 --> 00:10:23,910 constructing a brand new object. Who, who knows what 220 00:10:23,910 --> 00:10:26,950 that thing might be doing internally. You know? I 221 00:10:26,950 --> 00:10:29,940 mean, nobody's ever written code like this, right, that 222 00:10:29,940 --> 00:10:32,650 does something bad like that from a constructor for 223 00:10:32,650 --> 00:10:35,710 an object. That doesn't happen. But, you know, we 224 00:10:35,710 --> 00:10:37,870 end up having to do things like stubbing out 225 00:10:37,870 --> 00:10:41,570 new. Make it so that objects don't do interactions 226 00:10:41,570 --> 00:10:43,570 and things that we don't really want. 227 00:10:43,570 --> 00:10:47,310 Well, what if we could take this whole method 228 00:10:47,310 --> 00:10:49,580 and just get rid of it in the form 229 00:10:49,580 --> 00:10:53,290 that it's in and instead we notify that an 230 00:10:53,290 --> 00:10:56,810 event has happened. We tell our event system that 231 00:10:56,810 --> 00:10:59,840 the system is now fully configured. We are ready 232 00:10:59,840 --> 00:11:04,110 to go. Everything's logged. We can head on. 233 00:11:04,110 --> 00:11:07,080 Now this has some really nice side-effects. One of 234 00:11:07,080 --> 00:11:10,860 them is that beacon code. Now, in initialize, you 235 00:11:10,860 --> 00:11:13,430 still see the code where we're making this HTTP 236 00:11:13,430 --> 00:11:16,780 callout. But it's not wrapped in this subscribe block. 237 00:11:16,780 --> 00:11:19,490 So it means that that call is only going 238 00:11:19,490 --> 00:11:22,420 to happen when the event system lets us know 239 00:11:22,420 --> 00:11:25,640 that this configuration event has occurred. That provides a 240 00:11:25,640 --> 00:11:29,110 buffer. You can safely create a beacon now and 241 00:11:29,110 --> 00:11:33,230 it's not going to immediately go hit the network. 242 00:11:33,230 --> 00:11:35,190 The tests surround the finished set up method become 243 00:11:35,190 --> 00:11:38,440 very slim and very straightforward as well. All the 244 00:11:38,440 --> 00:11:41,610 finish set up is responsible for is firing that 245 00:11:41,610 --> 00:11:43,880 event. And we check that that event gets dispatched 246 00:11:43,880 --> 00:11:46,710 correctly and that's all that we need to unit 247 00:11:46,710 --> 00:11:50,160 test at this level. And unit testing for the 248 00:11:50,160 --> 00:11:53,750 individual effects that occur, moves over and gets done 249 00:11:53,750 --> 00:11:56,190 in the place that responds to that event. The 250 00:11:56,190 --> 00:11:59,330 thing that is gonna subscribe to the event now 251 00:11:59,330 --> 00:12:01,370 takes the responsibility for testing that. 252 00:12:01,370 --> 00:12:04,070 Now, this doesn't cover everything. There is a need 253 00:12:04,070 --> 00:12:06,300 for an integration test. You do want something that 254 00:12:06,300 --> 00:12:08,590 sees that we wire up to the right events. 255 00:12:08,590 --> 00:12:10,810 But you probably have tests that are gonna exercise 256 00:12:10,810 --> 00:12:13,730 those things anyways, if this isn't a critical path 257 00:12:13,730 --> 00:12:16,570 of your application. 258 00:12:16,570 --> 00:12:18,990 So events allow us, within our own code, to 259 00:12:18,990 --> 00:12:23,860 have more focused tests around those individual pieces, more 260 00:12:23,860 --> 00:12:27,910 independence between the classes. The configuration in the finished 261 00:12:27,910 --> 00:12:30,980 set up no longer has to know anything about 262 00:12:30,980 --> 00:12:34,850 the Javascript instrumentor, the cross-application tracer, the beacon. All 263 00:12:34,850 --> 00:12:37,770 of that is pried apart. 264 00:12:37,770 --> 00:12:39,970 And we found that this also starts to kind 265 00:12:39,970 --> 00:12:43,020 of create a language within your application. A domain 266 00:12:43,020 --> 00:12:45,530 language, if you will. Because these are the important 267 00:12:45,530 --> 00:12:48,960 events that happen for us. We care, as the 268 00:12:48,960 --> 00:12:51,180 New Relic gem, that we are configured. That is 269 00:12:51,180 --> 00:12:53,180 a critical thing for us. And there's now a 270 00:12:53,180 --> 00:12:55,150 name for that. It's not just a bunch of 271 00:12:55,150 --> 00:12:57,160 stuff that's tacked on to the end of one 272 00:12:57,160 --> 00:12:59,470 of our methods. 273 00:12:59,470 --> 00:13:03,020 It's not all roses, though. There is an issue 274 00:13:03,020 --> 00:13:05,720 if you have some sort of ordering that's required 275 00:13:05,720 --> 00:13:08,420 in the things that respond to those events. And 276 00:13:08,420 --> 00:13:10,340 actually we've had a couple of situations where we've 277 00:13:10,340 --> 00:13:13,050 been refactoring code and trying to pull it into 278 00:13:13,050 --> 00:13:16,460 event handlers and discovered that there were dependencies between 279 00:13:16,460 --> 00:13:20,290 different subscribers that aren't really handled by a really 280 00:13:20,290 --> 00:13:22,830 simple event system like this. 281 00:13:22,830 --> 00:13:24,920 So, that's something that you have to watch out 282 00:13:24,920 --> 00:13:26,370 for. If there's a lot of that sort of 283 00:13:26,370 --> 00:13:29,080 ordering, you're gonna have to deal with that somewhere 284 00:13:29,080 --> 00:13:31,110 in your code. 285 00:13:31,110 --> 00:13:33,770 It can also make debugging and reasoning about things 286 00:13:33,770 --> 00:13:37,080 a little harder. It does spread some of those 287 00:13:37,080 --> 00:13:40,130 responsibilities out. Now you don't see one method that 288 00:13:40,130 --> 00:13:41,760 lists all of the things that we do on 289 00:13:41,760 --> 00:13:43,910 connect. You have to go search for things that 290 00:13:43,910 --> 00:13:46,560 subscribe to those events. But in the right cases 291 00:13:46,560 --> 00:13:48,810 I feel like it can buy you things with 292 00:13:48,810 --> 00:13:51,700 the other benefits it brings along that outweigh that. 293 00:13:51,700 --> 00:13:55,810 Lastly, it is a performance consideration. You know, I 294 00:13:55,810 --> 00:13:58,190 would not use this sort of structure in a 295 00:13:58,190 --> 00:14:00,860 tight loop that's gonna get called a million times 296 00:14:00,860 --> 00:14:03,170 a second. You know. If it's something like we're 297 00:14:03,170 --> 00:14:08,180 responding to a configuration event, like, that we are 298 00:14:08,180 --> 00:14:10,680 now ready to go or somebody just signed up. 299 00:14:10,680 --> 00:14:12,200 I mean, it'd be great if you had a 300 00:14:12,200 --> 00:14:14,930 million people signing up a minute, but reality is 301 00:14:14,930 --> 00:14:19,140 it's not happening as frequently as that. So, being 302 00:14:19,140 --> 00:14:21,440 aware of how this will impact your performance is 303 00:14:21,440 --> 00:14:25,240 really critical. 304 00:14:25,240 --> 00:14:27,300 Internal coupling, like within the code that you write 305 00:14:27,300 --> 00:14:29,570 yourself, though, is not the only place where you 306 00:14:29,570 --> 00:14:33,320 can get bound to different things. So in, in 307 00:14:33,320 --> 00:14:34,940 the New Relic gem, we have a lot of 308 00:14:34,940 --> 00:14:38,700 different functionality that we instrument that work through middleware. 309 00:14:38,700 --> 00:14:42,370 So we do Javascript insertion for doing end user 310 00:14:42,370 --> 00:14:44,640 timings. So as your request is going back out, 311 00:14:44,640 --> 00:14:48,640 we'll modify your html and put things in there. 312 00:14:48,640 --> 00:14:51,120 We have error collection. So if there are unhandled 313 00:14:51,120 --> 00:14:54,870 exceptions that occur during your call, at the rack 314 00:14:54,870 --> 00:14:57,050 level, we will actually gather those up and see 315 00:14:57,050 --> 00:14:59,420 that those happened and report them back. 316 00:14:59,420 --> 00:15:02,440 And we do things with HTTP requests between the 317 00:15:02,440 --> 00:15:04,760 applications if both ends of them are running New 318 00:15:04,760 --> 00:15:07,920 Relic. And we need to modify headers, HTTP headers 319 00:15:07,920 --> 00:15:10,180 that are on those requests. And all of these 320 00:15:10,180 --> 00:15:13,990 separate things fit for us very well within middlewares. 321 00:15:13,990 --> 00:15:16,880 But, that makes kind of an assumption that everything 322 00:15:16,880 --> 00:15:19,780 that we want to apply that functionality to is 323 00:15:19,780 --> 00:15:22,180 built on top of rack. And while that's a 324 00:15:22,180 --> 00:15:23,960 pretty good assumption for a lot of things in 325 00:15:23,960 --> 00:15:26,270 the Ruby space, we do support things that aren't 326 00:15:26,270 --> 00:15:29,210 necessarily configured that way. 327 00:15:29,210 --> 00:15:31,070 We also want to avoid people having to set 328 00:15:31,070 --> 00:15:34,130 things up. There are certain cases where maybe you 329 00:15:34,130 --> 00:15:36,530 have to manually add the things that we've created, 330 00:15:36,530 --> 00:15:38,770 and if we have seven different middlewares that you 331 00:15:38,770 --> 00:15:41,540 need to add for all this different functionality, that's 332 00:15:41,540 --> 00:15:46,350 kind of problematic from a configuration view point. 333 00:15:46,350 --> 00:15:48,510 So our solution to this was that we standardized 334 00:15:48,510 --> 00:15:53,930 on having one middleware that we commonly will install. 335 00:15:53,930 --> 00:15:56,220 And we use events to actually do the dispatch 336 00:15:56,220 --> 00:15:58,430 from there. So you'll see this is just a 337 00:15:58,430 --> 00:16:00,940 very basic middleware. When a request comes in and 338 00:16:00,940 --> 00:16:04,230 hits call, we notify on the before and pass 339 00:16:04,230 --> 00:16:06,700 along the environment that we got. We call through 340 00:16:06,700 --> 00:16:09,450 to the app inside and notify after and then 341 00:16:09,450 --> 00:16:11,270 return the results. 342 00:16:11,270 --> 00:16:13,610 So this allows us to be able to plug 343 00:16:13,610 --> 00:16:16,480 things in that maybe are not shaped like rack. 344 00:16:16,480 --> 00:16:18,870 We could use some of that code, like in 345 00:16:18,870 --> 00:16:21,760 the cross application tracing. If we had some web 346 00:16:21,760 --> 00:16:24,300 server that was not rack-based or some configuration that 347 00:16:24,300 --> 00:16:26,920 was not gonna run through middleware, we could still 348 00:16:26,920 --> 00:16:29,470 have it generate a before call from the right 349 00:16:29,470 --> 00:16:33,410 point and handle that with this same code, without 350 00:16:33,410 --> 00:16:36,940 having to deal with trying to create middlewares or 351 00:16:36,940 --> 00:16:39,610 insert something at a point that doesn't really fit. 352 00:16:39,610 --> 00:16:42,380 Now, just for the middleware case, you know, this 353 00:16:42,380 --> 00:16:44,200 probably could have been solved with some sort of 354 00:16:44,200 --> 00:16:46,970 composition. But, for us, it was actually a really 355 00:16:46,970 --> 00:16:50,570 powerful technique for keeping our code decoupled from the 356 00:16:50,570 --> 00:16:53,490 library that we were building on top of. That 357 00:16:53,490 --> 00:16:56,480 looser coupling depends a lot on what sort of 358 00:16:56,480 --> 00:16:59,010 library and what your interactions with it are, you 359 00:16:59,010 --> 00:17:02,940 know. You're maintaining, basically, kind of a compatibility layer. 360 00:17:02,940 --> 00:17:04,760 And the more code that you have to put 361 00:17:04,760 --> 00:17:07,500 into that layer, the more you should probably think 362 00:17:07,500 --> 00:17:10,299 about whether you're approaching it correctly. Obviously you can't 363 00:17:10,299 --> 00:17:13,220 do something like this with ActiveRecord, it's just not 364 00:17:13,220 --> 00:17:15,539 gonna be plausible. But if you have a small 365 00:17:15,539 --> 00:17:18,819 number of points where you interact with another third-party 366 00:17:18,819 --> 00:17:21,419 library, applying events at those boundaries can be a 367 00:17:21,419 --> 00:17:24,059 way that you can keep some separation between your 368 00:17:24,059 --> 00:17:27,809 code and the library that you're dealing with. 369 00:17:27,809 --> 00:17:30,779 So that's coupling. That's sort of the primary motivator 370 00:17:30,779 --> 00:17:33,590 behind using an evented pattern is to decouple the 371 00:17:33,590 --> 00:17:36,580 pieces of your application and allow for those to 372 00:17:36,580 --> 00:17:39,960 be looser and not as away of what's on 373 00:17:39,960 --> 00:17:42,659 the other end of either firing or responding to 374 00:17:42,659 --> 00:17:44,580 an event. 375 00:17:44,580 --> 00:17:47,840 So, let's talk about what it actually takes to 376 00:17:47,840 --> 00:17:51,620 implement this. What does this look like in practice? 377 00:17:51,620 --> 00:17:53,960 So I have created a small gem. This is 378 00:17:53,960 --> 00:17:56,110 sort of an abstraction from what we do in 379 00:17:56,110 --> 00:17:58,669 the New Relic gem. We don't use it directly 380 00:17:58,669 --> 00:18:01,720 and I am not suggesting this for production use. 381 00:18:01,720 --> 00:18:03,840 But it's a really good example of how simple 382 00:18:03,840 --> 00:18:07,940 it is to implement something like this in Ruby. 383 00:18:07,940 --> 00:18:12,169 So there's one primary class. The SimpleEvents::Notifier. When we 384 00:18:12,169 --> 00:18:14,980 initialize that, it's gonna be the central thing that 385 00:18:14,980 --> 00:18:17,309 keeps track of all the events. And everybody's gonna 386 00:18:17,309 --> 00:18:20,580 talk to this notifier object. So we hold onto 387 00:18:20,580 --> 00:18:23,070 a hash, which is where we're gonna store those 388 00:18:23,070 --> 00:18:28,230 handlers from the people that subscribe to us. 389 00:18:28,230 --> 00:18:31,629 Subscribing gets done. Passing in just a key for 390 00:18:31,629 --> 00:18:34,320 what the event is. We typically use symbols within 391 00:18:34,320 --> 00:18:37,009 our application. Some similar things that we'll see later 392 00:18:37,009 --> 00:18:39,809 use strings. And then hands in a block, which 393 00:18:39,809 --> 00:18:41,980 is the code for it to run at that 394 00:18:41,980 --> 00:18:44,620 point that that event gets fired. 395 00:18:44,620 --> 00:18:46,149 And then it's just a simple matter of keeping 396 00:18:46,149 --> 00:18:48,360 track of that list of handlers. Each event may 397 00:18:48,360 --> 00:18:50,480 have multiple handlers, so we make sure the array 398 00:18:50,480 --> 00:18:53,509 is there and add that handler onto the list. 399 00:18:53,509 --> 00:18:56,029 Now there's one other line here that we're dealing 400 00:18:56,029 --> 00:18:58,980 with and that's checking for runaway subscriptions. 401 00:18:58,980 --> 00:19:00,429 That has to do with the fact that for 402 00:19:00,429 --> 00:19:03,990 our usage, there is a limited number of things 403 00:19:03,990 --> 00:19:06,779 that should be subscribing to events. This is not 404 00:19:06,779 --> 00:19:09,740 something where every single web request that comes through 405 00:19:09,740 --> 00:19:11,879 subscribes and hooks itself in. And we'll talk a 406 00:19:11,879 --> 00:19:14,490 little bit later on about some of the negative 407 00:19:14,490 --> 00:19:16,610 side effects you can have if it's happening. 408 00:19:16,610 --> 00:19:19,269 So, for us, if more than a hundred event 409 00:19:19,269 --> 00:19:22,009 subscribers have subscribed to a given event, we actually 410 00:19:22,009 --> 00:19:24,179 have a bug. And so we check for that 411 00:19:24,179 --> 00:19:27,639 and make sure to warn that that's going on. 412 00:19:27,639 --> 00:19:29,769 Your mileage may vary depending on the structure that 413 00:19:29,769 --> 00:19:32,799 you choose to use. 414 00:19:32,799 --> 00:19:35,000 Notifying is a little more complicated than subscribing, but 415 00:19:35,000 --> 00:19:37,370 not too much more. And we'll step through it 416 00:19:37,370 --> 00:19:40,120 here. So first off, we check whether the events 417 00:19:40,120 --> 00:19:44,620 collection has any handlers for the particular key that 418 00:19:44,620 --> 00:19:46,500 we just passed in. And this is one of 419 00:19:46,500 --> 00:19:50,080 the really nice aspects of taking this simple approach. 420 00:19:50,080 --> 00:19:53,350 There's no central registry. There's nothing to set up. 421 00:19:53,350 --> 00:19:55,870 And event, I can create a handler for an 422 00:19:55,870 --> 00:19:57,830 event that doesn't exist or I can start firing 423 00:19:57,830 --> 00:20:00,360 and event that nobody handles, and it all just 424 00:20:00,360 --> 00:20:03,419 gracefully falls out. It doesn't cause any problems if 425 00:20:03,419 --> 00:20:07,220 there aren't handlers wired up for things. 426 00:20:07,220 --> 00:20:09,870 If we do find that there are event handlers, 427 00:20:09,870 --> 00:20:13,480 we simply iterate across those and call passing along 428 00:20:13,480 --> 00:20:17,480 the arguments that we received on the event. For 429 00:20:17,480 --> 00:20:20,649 our particular use in New Relic, we trap errors 430 00:20:20,649 --> 00:20:24,379 and will log and swallow any exceptions that happen 431 00:20:24,379 --> 00:20:28,100 as a result of our direct event handlers. Now, 432 00:20:28,100 --> 00:20:29,730 this is kind of an artifact of the sort 433 00:20:29,730 --> 00:20:31,230 of gem that we are. We're there in the 434 00:20:31,230 --> 00:20:33,830 background and these events are things for the agent 435 00:20:33,830 --> 00:20:35,929 and for us sending our data back. 436 00:20:35,929 --> 00:20:37,679 And the worst possible thing that we could do 437 00:20:37,679 --> 00:20:40,360 is crash an application. So we trap everything that 438 00:20:40,360 --> 00:20:42,320 goes through. If you were doing this in an 439 00:20:42,320 --> 00:20:44,600 application setting, you may want to log. You may 440 00:20:44,600 --> 00:20:47,409 also want to raise those errors and fail quickly 441 00:20:47,409 --> 00:20:49,149 in the case that one of your notifiers has 442 00:20:49,149 --> 00:20:52,470 something go wrong. But your mileage, you know, you 443 00:20:52,470 --> 00:20:54,340 can choose what the right policy is for how 444 00:20:54,340 --> 00:20:56,509 you're using events and what setting you're putting those 445 00:20:56,509 --> 00:20:58,379 in. 446 00:20:58,379 --> 00:21:01,570 So that's it. Like, that's an entire eventing system 447 00:21:01,570 --> 00:21:04,309 is about fifty lines of Ruby, which allows you 448 00:21:04,309 --> 00:21:07,730 to decouple those different pieces of your application. But 449 00:21:07,730 --> 00:21:09,009 the fact of the matter is that you might 450 00:21:09,009 --> 00:21:12,159 not have to even write that system yourself if 451 00:21:12,159 --> 00:21:16,570 you're using Rails. ActiveSupport::Notifications have been baked in from 452 00:21:16,570 --> 00:21:19,259 I think about the 3.0 version of Rails. And 453 00:21:19,259 --> 00:21:21,210 it's a system that's very much like what we've 454 00:21:21,210 --> 00:21:22,749 described here. 455 00:21:22,749 --> 00:21:27,149 I'll abbreviate in the slides a little because ActiveSupport::Notifications 456 00:21:27,149 --> 00:21:29,749 gets really, really long in the code, so, we'll 457 00:21:29,749 --> 00:21:32,389 scrunch that down a little bit. But all sorts 458 00:21:32,389 --> 00:21:35,009 of things flow through this evented system any time 459 00:21:35,009 --> 00:21:37,679 a Rails request is occurring. So we get things 460 00:21:37,679 --> 00:21:40,389 about the dispatch at the top level. We get 461 00:21:40,389 --> 00:21:42,820 things about the controller and what it's doing. We 462 00:21:42,820 --> 00:21:47,460 get notifications about SQL calls. We get notifications about 463 00:21:47,460 --> 00:21:50,940 view and template rendering. Like, tons and tons of 464 00:21:50,940 --> 00:21:54,830 events are streaming through this ActiveSupport::Notification system all of 465 00:21:54,830 --> 00:21:55,669 the time. 466 00:21:55,669 --> 00:21:58,240 Some common things that you might be familiar with, 467 00:21:58,240 --> 00:22:00,149 like the log, the debug log that you get 468 00:22:00,149 --> 00:22:04,279 of your queries, that's running through ActiveSupport::Notifications that are 469 00:22:04,279 --> 00:22:08,779 fired by ActiveRecord. So what's this look like? 470 00:22:08,779 --> 00:22:11,659 It looks very similar to what we've seen before. 471 00:22:11,659 --> 00:22:14,039 So subscribing to an event, you give it the 472 00:22:14,039 --> 00:22:16,480 name, you give it a block, and then you 473 00:22:16,480 --> 00:22:18,389 can see the form of what one of these 474 00:22:18,389 --> 00:22:20,710 events was that came through. It'll hand it to 475 00:22:20,710 --> 00:22:23,940 us. It's got a name. It's got an identifier. 476 00:22:23,940 --> 00:22:25,440 And then it's got this hash that's sort of 477 00:22:25,440 --> 00:22:30,399 a payload of data that comes along with it. 478 00:22:30,399 --> 00:22:34,259 ActiveSupport also provides a simple wrapper for handling that 479 00:22:34,259 --> 00:22:36,710 payload and handling those events when they're in a 480 00:22:36,710 --> 00:22:39,299 very common form. So most of the things that 481 00:22:39,299 --> 00:22:41,749 Rails sends out, they're gonna have a name. They're 482 00:22:41,749 --> 00:22:44,279 gonna have a duration and a payload in a 483 00:22:44,279 --> 00:22:46,840 standard format. So this class kind of wraps up 484 00:22:46,840 --> 00:22:51,370 that access and makes it a little neater. 485 00:22:51,370 --> 00:22:54,240 On the notifying side, the method that you call 486 00:22:54,240 --> 00:22:57,259 is instrument. So if you want to fire an 487 00:22:57,259 --> 00:22:59,259 event and have that be sent out to the 488 00:22:59,259 --> 00:23:01,789 system, you just give it the string for the 489 00:23:01,789 --> 00:23:04,330 name, give it whatever payload for the data, and 490 00:23:04,330 --> 00:23:07,009 you're off and running. 491 00:23:07,009 --> 00:23:08,450 There's also a nice form of it that it 492 00:23:08,450 --> 00:23:11,690 has that will wrap your code in a block, 493 00:23:11,690 --> 00:23:13,759 so you can do something in there, and what 494 00:23:13,759 --> 00:23:16,259 that'll do is that'll tack a duration on. So 495 00:23:16,259 --> 00:23:18,460 it'll time what's going on. And this is one 496 00:23:18,460 --> 00:23:21,179 of the key things that ActiveSupport::Notifications are used for 497 00:23:21,179 --> 00:23:23,840 within Rails is timing how long those different things 498 00:23:23,840 --> 00:23:25,889 take. Those timings that you see in your debug 499 00:23:25,889 --> 00:23:28,809 output are all coming from things being wrapped by 500 00:23:28,809 --> 00:23:32,509 this sort of instrument call. 501 00:23:32,509 --> 00:23:34,110 As with all things Rails, there's a lot more 502 00:23:34,110 --> 00:23:36,889 richness as well under the surface. You can do 503 00:23:36,889 --> 00:23:42,129 subscriptions by regular expressions. If events are nested, the 504 00:23:42,129 --> 00:23:45,730 ActiveSupport::Notifications system keeps track of that and will take 505 00:23:45,730 --> 00:23:47,909 care of letting you know so you could look 506 00:23:47,909 --> 00:23:50,499 and see whether an event was occurring within another 507 00:23:50,499 --> 00:23:53,919 event, and you can go crazy if that's happening 508 00:23:53,919 --> 00:23:55,289 too much, but. 509 00:23:55,289 --> 00:23:58,669 There are temporary subscriptions and unsubscribe, which is useful 510 00:23:58,669 --> 00:24:00,990 in certain scenarios where, maybe you do want to 511 00:24:00,990 --> 00:24:04,629 have something hook into the ActiveSupport::Notifications for the course 512 00:24:04,629 --> 00:24:06,749 of a request. But you don't want to have 513 00:24:06,749 --> 00:24:09,509 that handler hanging around and responding for the rest 514 00:24:09,509 --> 00:24:12,490 of the lifetime of your application. 515 00:24:12,490 --> 00:24:13,990 And there's some really great examples that you can 516 00:24:13,990 --> 00:24:17,249 find in Rails itself. So the log subscriber class, 517 00:24:17,249 --> 00:24:18,679 which is the thing that spits out a lot 518 00:24:18,679 --> 00:24:20,990 of your development log, is a great example of 519 00:24:20,990 --> 00:24:26,119 how you can hook into that underlying infrastructure. 520 00:24:26,119 --> 00:24:28,090 So that's the mechanism. That's how you can build 521 00:24:28,090 --> 00:24:30,909 events in or use a library that you're probably 522 00:24:30,909 --> 00:24:33,019 already using to get a lot of these things 523 00:24:33,019 --> 00:24:35,309 done. 524 00:24:35,309 --> 00:24:37,789 Let's talk a little bit more in detail about 525 00:24:37,789 --> 00:24:39,749 the different parties that are involved here, and what 526 00:24:39,749 --> 00:24:46,419 they're responsible for and considerations there. So notifiers have 527 00:24:46,419 --> 00:24:48,749 a lot of responsibility. They're, they're kind of the 528 00:24:48,749 --> 00:24:52,720 key points in your application. You should be, in 529 00:24:52,720 --> 00:24:55,159 this scheme, you would be adding events for the 530 00:24:55,159 --> 00:24:56,919 things that matter the most. 531 00:24:56,919 --> 00:24:59,539 And on that, I think that naming is a 532 00:24:59,539 --> 00:25:02,119 really critical thing around this to get the benefit 533 00:25:02,119 --> 00:25:04,850 that you're looking for. So in the example that 534 00:25:04,850 --> 00:25:08,179 I gave up front, you'll, you probably didn't notice, 535 00:25:08,179 --> 00:25:11,710 but I named the event configured, to say, hey, 536 00:25:11,710 --> 00:25:13,460 we are in a state where we are fully 537 00:25:13,460 --> 00:25:13,909 configured. 538 00:25:13,909 --> 00:25:17,179 I didn't name it connect to server or finish 539 00:25:17,179 --> 00:25:19,789 with the set up or, you know, binding it 540 00:25:19,789 --> 00:25:21,899 to the mechanism of what it was. I couched 541 00:25:21,899 --> 00:25:24,840 it in the terms of what mattered to my 542 00:25:24,840 --> 00:25:27,029 application. I think that that's something that's really powerful 543 00:25:27,029 --> 00:25:29,639 if you do this right. If you, it allows 544 00:25:29,639 --> 00:25:32,529 for changes in the location, like in our case, 545 00:25:32,529 --> 00:25:34,899 that change of when we were configured. It moved 546 00:25:34,899 --> 00:25:37,799 from just plain application start up to a point 547 00:25:37,799 --> 00:25:39,789 in time in the future when we may hear 548 00:25:39,789 --> 00:25:42,200 back from a server. And who knows when that 549 00:25:42,200 --> 00:25:45,110 configured point might change in the future? 550 00:25:45,110 --> 00:25:48,379 We're not bound by the event name to some 551 00:25:48,379 --> 00:25:51,529 particular method or point in time. We can change 552 00:25:51,529 --> 00:25:53,440 that and still have it make sense within the 553 00:25:53,440 --> 00:25:57,039 domain of what we've created. 554 00:25:57,039 --> 00:25:59,369 It's also important to consider what your payload is. 555 00:25:59,369 --> 00:26:02,190 What data you're sending along from the notifier. So 556 00:26:02,190 --> 00:26:05,669 Rails follows the convention with ActiveSupport::Notifications that I would 557 00:26:05,669 --> 00:26:09,119 definitely encourage, of sending along primarily a hash of 558 00:26:09,119 --> 00:26:12,429 different values that you can pipe through. I learned 559 00:26:12,429 --> 00:26:14,480 this the hard way the second time that I 560 00:26:14,480 --> 00:26:16,440 needed to add a bit of data onto one 561 00:26:16,440 --> 00:26:19,509 of my events. And the mechanism, as we saw, 562 00:26:19,509 --> 00:26:21,539 just sort of percolates the arguments along that we've 563 00:26:21,539 --> 00:26:22,399 given it. 564 00:26:22,399 --> 00:26:24,570 Well, if you add another argument, all those other 565 00:26:24,570 --> 00:26:28,309 handlers downstream need to get updated. So do it 566 00:26:28,309 --> 00:26:30,570 from the start to make these things flexible. Pass 567 00:26:30,570 --> 00:26:33,049 your payloads along as a hash that you can 568 00:26:33,049 --> 00:26:36,619 then add additional data that old event handlers don't 569 00:26:36,619 --> 00:26:38,619 need to care about and that new things can 570 00:26:38,619 --> 00:26:41,619 pick up along the way. 571 00:26:41,619 --> 00:26:44,549 On that topic of the payload as well, if 572 00:26:44,549 --> 00:26:47,230 you're writing some sort of internal application, you know, 573 00:26:47,230 --> 00:26:50,029 you can put whatever you want into these payloads. 574 00:26:50,029 --> 00:26:51,820 But as a third party, you may want to 575 00:26:51,820 --> 00:26:54,769 be cautious if you're having other people, other gems, 576 00:26:54,769 --> 00:26:57,389 and other codes subscribe to these events to try 577 00:26:57,389 --> 00:27:01,619 to keep your payloads as primitive as you can. 578 00:27:01,619 --> 00:27:03,269 Maybe even all the way down to just base 579 00:27:03,269 --> 00:27:03,909 types. 580 00:27:03,909 --> 00:27:06,429 The advantage here is that you are, if you 581 00:27:06,429 --> 00:27:08,799 put one of your internal classes as something that 582 00:27:08,799 --> 00:27:11,320 you're packing around in this event, and then broadcast 583 00:27:11,320 --> 00:27:13,970 it out to the world for everybody to use, 584 00:27:13,970 --> 00:27:16,340 you now don't know who might be getting access 585 00:27:16,340 --> 00:27:19,799 to those objects and using them. And depending on 586 00:27:19,799 --> 00:27:22,240 what sort of usage you've got with your, your 587 00:27:22,240 --> 00:27:25,869 app, it can be difficult to make changes to 588 00:27:25,869 --> 00:27:28,659 things that maybe you consider to be internal details. 589 00:27:28,659 --> 00:27:31,559 If you turn things into primitives, you know, it, 590 00:27:31,559 --> 00:27:33,970 they're just strings and hashes and numbers, those are 591 00:27:33,970 --> 00:27:37,279 pretty safe, right. You can maintain that mapping from 592 00:27:37,279 --> 00:27:40,309 your internal objects to those primitives and not have 593 00:27:40,309 --> 00:27:43,200 to worry about who might be changed when you 594 00:27:43,200 --> 00:27:46,529 refactor. 595 00:27:46,529 --> 00:27:49,070 So the other end of things is the subscribers. 596 00:27:49,070 --> 00:27:52,590 I think it's really important to consider, carefully, who 597 00:27:52,590 --> 00:27:56,110 the subscribers are for a given event. This pattern 598 00:27:56,110 --> 00:27:58,610 doesn't fit everywhere. This is not something where every 599 00:27:58,610 --> 00:28:00,909 single thing that happens in your application should be 600 00:28:00,909 --> 00:28:04,059 an event. And if you're writing an event, and 601 00:28:04,059 --> 00:28:06,749 there's only one thing that's gonna handle it, you 602 00:28:06,749 --> 00:28:08,960 might be misapplying this pattern. You might not get 603 00:28:08,960 --> 00:28:12,090 the benefit that you need, there. 604 00:28:12,090 --> 00:28:14,289 A lot of times, you'll find that there is 605 00:28:14,289 --> 00:28:17,700 some natural home, some place within your app that 606 00:28:17,700 --> 00:28:20,639 is already there that is the right place to 607 00:28:20,639 --> 00:28:23,389 be subscribing to that event and responding to what's 608 00:28:23,389 --> 00:28:25,950 happening. But if you don't, it's an, there's some 609 00:28:25,950 --> 00:28:28,309 interesting ideas around how you can create what that 610 00:28:28,309 --> 00:28:30,889 location is. So there's this gem that I've run 611 00:28:30,889 --> 00:28:33,950 into, it's called mutations. It's sort of building command 612 00:28:33,950 --> 00:28:37,460 objects that represent different actions that happen in your 613 00:28:37,460 --> 00:28:38,220 system. 614 00:28:38,220 --> 00:28:40,929 Now, you know, you might recognize something very like 615 00:28:40,929 --> 00:28:42,960 this from earlier in the morning, but it can 616 00:28:42,960 --> 00:28:48,110 be an interesting idea if you have key pieces 617 00:28:48,110 --> 00:28:50,950 of your system where a workflow or something that 618 00:28:50,950 --> 00:28:55,190 occurs is really important. You can write something, a 619 00:28:55,190 --> 00:28:58,350 command, that encapsulates what the event is, what that 620 00:28:58,350 --> 00:29:00,549 action is that needs to be taken. And this 621 00:29:00,549 --> 00:29:03,119 can be something that helps in those cases that 622 00:29:03,119 --> 00:29:05,600 I described, where there may be implicit ordering. There 623 00:29:05,600 --> 00:29:08,730 may be ordering between different components. You could create 624 00:29:08,730 --> 00:29:11,320 a command that wraps those up in the right 625 00:29:11,320 --> 00:29:14,129 ordering to be applied and then have that be 626 00:29:14,129 --> 00:29:18,049 what responds to the events. 627 00:29:18,049 --> 00:29:20,320 Probably one of the biggest difficulties that you can 628 00:29:20,320 --> 00:29:23,399 run into with an evented pattern is, if there's 629 00:29:23,399 --> 00:29:26,450 too much nesting, if this gets overused, and events 630 00:29:26,450 --> 00:29:28,889 trigger events and trigger events on all sorts of 631 00:29:28,889 --> 00:29:32,169 different things, it can become very difficult. And the 632 00:29:32,169 --> 00:29:34,769 main advice that I have there is that this, 633 00:29:34,769 --> 00:29:37,190 this technique works best, I think, at the critical 634 00:29:37,190 --> 00:29:39,679 lynch points of your application. The things that you 635 00:29:39,679 --> 00:29:42,899 really care about the most to be providing, that 636 00:29:42,899 --> 00:29:46,840 sort of visibility and language around. 637 00:29:46,840 --> 00:29:48,659 And another thing to be aware of with the 638 00:29:48,659 --> 00:29:50,799 implementation that we've done here. I've had a number 639 00:29:50,799 --> 00:29:53,090 of poeple come up afterwards and point out, they're 640 00:29:53,090 --> 00:29:56,149 like, it's all still synchronous. It's all still just 641 00:29:56,149 --> 00:29:58,919 running. I mean, this is just splitting up where 642 00:29:58,919 --> 00:30:01,929 those things are. And that's totally true. This is 643 00:30:01,929 --> 00:30:05,279 not as described something that will make your application 644 00:30:05,279 --> 00:30:09,059 parallel or asynchronous in how that event handling happens. 645 00:30:09,059 --> 00:30:11,239 But it might give you good points in time 646 00:30:11,239 --> 00:30:13,289 when you could decide to push things off. Things 647 00:30:13,289 --> 00:30:15,129 could go to background jobs or things could get 648 00:30:15,129 --> 00:30:17,149 dispatched to all sorts of other places if you 649 00:30:17,149 --> 00:30:19,279 wanted. 650 00:30:19,279 --> 00:30:21,460 It's also important with subscribers to watch out for 651 00:30:21,460 --> 00:30:25,889 leaks. There is, when you create a block, so 652 00:30:25,889 --> 00:30:27,999 like, if this subscriber was created for every web 653 00:30:27,999 --> 00:30:31,869 request, the fact that we have that block potentially 654 00:30:31,869 --> 00:30:34,509 holds onto a reference to this object and keeps 655 00:30:34,509 --> 00:30:36,850 it alive past a point in time when you 656 00:30:36,850 --> 00:30:38,460 might have thought that it was gonna go away. 657 00:30:38,460 --> 00:30:40,629 I've seen this not just in Ruby but in 658 00:30:40,629 --> 00:30:42,580 a number of different languages with these sorts of 659 00:30:42,580 --> 00:30:46,600 evented patterns with handlers that get subscribed, where they 660 00:30:46,600 --> 00:30:48,730 can hold references to objects that you might not 661 00:30:48,730 --> 00:30:51,110 be expecting them too. And so you gotta watch 662 00:30:51,110 --> 00:30:55,610 out for that to keep things from leaking. 663 00:30:55,610 --> 00:30:58,389 So those are some ideas around the responsibilities that 664 00:30:58,389 --> 00:31:01,590 your subscribers and your notifiers should have. And I 665 00:31:01,590 --> 00:31:03,389 hope that maybe this has opened your eyes a 666 00:31:03,389 --> 00:31:06,110 little bit to some ideas about how you might 667 00:31:06,110 --> 00:31:08,489 be able to partition your app differently. What are 668 00:31:08,489 --> 00:31:12,489 those responsibilities and things that happen during your app 669 00:31:12,489 --> 00:31:14,269 that would be worth having an event or worth 670 00:31:14,269 --> 00:31:16,090 giving that name to. 671 00:31:16,090 --> 00:31:17,399 And as you can see that it's a pretty 672 00:31:17,399 --> 00:31:19,799 simple thing to implement that can give you a 673 00:31:19,799 --> 00:31:22,999 lot of benefit down the road. Thank you.