 Good afternoon, everybody. How's it going? My name's Ernie Miller. I work for a company called Appriss in Louisville, Kentucky. Please ask me about them later so that I can justify expensing the trip. If I could ask you all to do me a favor, as it turns out, most of my fellow coworkers that had come out to RailsConf have had to catch a flight to go back home. And so they're missing my talk. So what I'd like you to do is to tweet very enthusiastically about the talk, regardless of if it's any good, so that for at least until it goes on video, they're going to think they missed the talk of a lifetime. So RailsConf, huh? Have you guys had a good time? Yeah? I've had a ball, too. I've had a ball, too. So I am not. Yes, yes it was. So I am not a member of Ruby Core. I am not a member of Rails Core. However, last month, this game came out, and I'm an avid gamer. And I'd like to happily report that I am very frequently a member of Damage Core at this point. Unfortunately, membership only lasts for about 15 seconds at a time, then I get booted again. So there's that. But I'm thinking it's moving up in the world. I'm a member of something core. So it's come to my attention recently that I have been giving a fair number of talks that usually involve me ranting about something, and I think I'm becoming a bit of a curmudgeon. So you're not supposed to clap for that. OK. So one of the things that I want to start off by doing is saying that I recognize that most of us would not be in this room if it weren't for Rails, and that we really owe a lot of our opportunity to get paid for doing Ruby. I know I do anyway, to Rails's existence. So first off, I'd like to get a hand for Rails and how awesome it is and how it enables us to do everything. OK. No, no, that's enough. That's enough. Nope, no more. We're done celebrating. Just that much celebration, nothing more. OK. All right. Stop the party. So that gets me every time. So that being the case, I have to say, a lot of us have been hitting brick walls. How many of you have been building something relatively complex with Rails? And you sort of feel like you've gone up against a brick wall. You can't make any more forward progress. And you feel like you've been kind of, you know, OK, so some hands are going up, right? And so it seems to me, if there is that much talk about it, it seems like we often get the response that we just need to run with more passion at the wall, run faster, and if we just fully commit that we'll burst through and we'll be in this sort of magical land where everything works the way that it's supposed to, and just don't fight so much, right? I have to think that if so many of us have kind of run into these sort of problems that maybe there's something there, maybe there's some kind of an issue there. And I wanted to give a few opinions about why that might be. So Rails is a convention over configuration advocate, right? That's the big thing that we always talk about, that we would prefer to have convention over configuration. Now, conventions are really what opinions want to be when they grow up, right? So most conventions have stemmed from an opinion. We hopefully share the opinion. But I want to be clear that when I talk about the opinions that Rails has today, I am not talking specifically about any members of the core team. I'm not talking about the people, though the software may in fact reflect opinions of people. What I want to talk about is what does the software tell us, right? Because we know that Rails is opinionated software. So with that out of the way, let's go with the first opinion that Rails has, that I believe Rails has anyway, which is that code should read like English. And we see this pretty frequently in comparisons between straight up Ruby versus Rails kind of code, right? So here's something that a lot of us actually like. Like I know this is one of the things that hooked me on Rails right off the bat was like, oh, I can say like five dot days ago or, you know, because I'm writing something in old English. I can say one dot fortnight from now. That's very useful, right? So there's nothing particularly when we say like one dot megabyte, right? There's nothing megabyte-y about the number, right? It just does some multiplication. Similarly, we have some, oh yeah, fortnight, yeah. Similarly, we have some differences where we have something that Array already has, for instance, on it, like I just found out it's called the shovel operator. I always just said less than, less than, but whatever it is, right? So we have like Array less than, less than object, right? And we've got that alias to append so that we can say append. We have object.in so we can ask whether an object's in an Array instead of ask an Array whether it has an object. Things like that. We have string methods that have been, you know, kind of patched in for, for instance, the string inquirer, that's one of my favorite ones. Right in the middle there, we have a check on the left. In Ruby, you simply ask if the environment string equals production. But in Rails, there's a thing called a string inquirer which simply patches method missing so that you can actually say, okay, is the string actually containing the method that you just sent minus the question mark? And so that's really all it's doing, the thing on the left. Here's another one. So in time, we can say beginning of day, we can say midnight, we can say at midnight, we can say at beginning of day, we can say midday, noon, at midday, at noon, at middle of day, right? They're all the same thing. And yet, there's this really clean API that's exposed this whole change thing, right? It's fairly discoverable. Like, I could make a reasonable guess that if I said change minute to something or if I said change any piece of the time to something, it would be able to do exactly what I ask it to do just then. But instead, we have these aliases to allow us to write code that's like English. Now, when I go into a coffee shop and I want something that's got a high caffeine content, I may order one of these. You all know what this is, right? This is coffee brewed by forcing a small amount of nearly boiling water under pressure through finely ground coffee beans. And that's what I go up to the counter and ask for, right? Now, you know, they probably go, you mean an espresso, right? Because espresso is what we call a loan word. We borrowed that word from Italian because it was concise. It was a good way to say what it was that we wanted to say without all of those words, right? Ruby is a language in and of itself. It borrows from English where it makes sense. But it is my opinion anyway that if there is a concise way to say something in Ruby, we don't necessarily need to borrow a loan word in English. You know how you sit across the table from that guy who always likes to use a foreign word for something just to sound clever, right? That's what we're doing, right? Like, it doesn't make a lot of sense. Now, here's one you may initially disagree with. I believe that Rails believes that models descend from active record, or at the very least an ORM. Now, if you disagree with me, I have three words for you. Rails generate model. What do you get? You get an active record subclass, right? Now, you might say, well, that's silly, right? But this is the first exposure that Rails developers are likely to have to what goes in a models directory. And I have talked to extremely smart developers who have told me that they went a number of years before they realized they could stick plain old Ruby classes in app models because they just thought that, that's not what models are, right? And so, rightfully so then, Rails believes that the data is the domain, right? That's the active record pattern. That's the whole point of it. And if you don't believe me, I'll show you some read me information, right? The prime directive is that we're minimizing the code needed to build a real world domain model. Lots of reflection and runtime extension is the understatement of the year. And magic is not inherently a bad word. Now, what this really comes down to is Rails was very much a reaction to very configuration heavy frameworks in Java, XML files and the like, big reaction to that, right? So what we had determined at that point was that configuration is the devil, right? And once you have determined that there is a greater evil out there, then a lot of lesser evil start to seem pretty great by comparison, right? So you can rationalize yourself into a really tricky spot. And so, our goal is to be able to write class post inherits from active record base and have magic happen, right? Like, for instance, we infer, and I wanna talk a little about one thing that we do in that case, right? We infer what the attributes should be on that model without writing a single line of code. Now, there's a problem with that, namely that in order to infer the attribute names, you must first invent the universe. So I wanna walk us through what that looks like. We're gonna do one deep dive into some Rails internals and then I promise we'll come back up for air and we'll talk about happy things. So you might imagine pretty early on that we're gonna go ahead and initialize a module and we're gonna actually have a module to store our attribute methods in. That's actually something I kinda like, right? Because as a Rubyist, I expect to be able to call super if I define my own method on the class. So that makes a lot of sense, right? So if we look at what happens when we generate the module, we have a new anonymous module that extends mutex because we don't wanna be modifying the module from two different threads. And then in method missing, we have this handy little hook that defines the attribute methods, right? And so in method missing, we call this every single time, right? And the idea being that once we've defined the methods, there we're not gonna hit method missing, at least for those methods anymore. And so we bail out if in fact we've already generated them. And we call super with column names, right? Now where do we get column names from? Well, it's not there. In fact, method missing was the only thing that actually sits on the instance level. The rest of the stuff that we're gonna be looking at sits on the singleton. It sits on the subclass of active record itself as a class method. So when we call super, we're actually calling super into active models, definition of defining attributes, right? So we're saying define attribute methods from active model. Passing at the column names. So here's column names. Well, column names is again a singleton method. It knows that it needs columns, right? And below here we have columns. Well, columns needs the connection for starters to the database to figure out what table it's gonna read from. And it also needs to determine the table name, right? So now we need to know the table name. So we don't have the table name yet. So we call reset table name. And most of the time I'm gonna skip past some of the more convoluted things and just talk about the compute table name, right? So we have to compute the table name. Makes sense, right? So this is kind of a big method. Hopefully y'all can see the part that matters, which is we call undecorated table name with the, again, we're sitting on the class. So name refers to class.name, right? The string name of the class, the full module name. And undecorated table name basically does exactly what you see here. Let's say we have a namespace model. Conferences RailsConf becomes RailsConf becomes Rails underscore cont becomes RailsConfs, okay? Which is great. And then, of course, if we have animals moose, it becomes moose, it becomes moose, it becomes mooses, which makes lots of sense, right? Well, that means we need to handle irregular pluralization. So we check and we see whether or not there's a default pluralization defined for moose. There is not, there are some interesting ones, I think. We've got sheep. We do have sheep, so we're at least in the ballpark. We have genes, we have fish, but we don't have moose. So we go into an initializer, and we set inflect uncountable moose, and then it works, right? But configuration. Or we can say self.table name equal moose, and then bypass all of that altogether, right? But again, configuration. Now, if configuration is the devil and magic is the goal, then we have to think to ourselves, what is magic really? And an enjoyable magic trick is basically willful suspension of disbelief, right? So that is, if this magician came up and said I'm going to saw my assistant in half, and you didn't think there's a trick here, like it's based in the rules of reality, but like there's something going on, it would be pretty horrific, right? It would be like, I don't, where have I gone? Like what is going on here, right? And so there's this level where we would do better to consider how can we root this kind of magic in some reality that the average person is going to be able to understand, and then kind of build on that knowledge, sort of scaffold if you will. And otherwise you end up with what I referred to last year as douchebag magic, which is magic that bites you, magic that screws you over in all sorts of wonderful ways. So let's imagine for a moment a world where we do have magic that we can understand. And let's just say we have imaginary record, record, that always asks us to configure a table name, that always asks us to define the attributes in a very mapper style, data mapper style, right? Give it an attribute name, tell it how it's to load the attributes, maybe some other stuff, we're just imagining here, right? We're just in your imagination. And then let's say that we have a magic record that inherits from the imaginary record, record, and does all the same stuff that we did before, except it calls these methods on the class in order to set the table name programmatically, in order to set the attributes programmatically, right? Well, that would be pretty cool. We would have to make some trade-offs, but we would basically get to the point where we could do something like inherit from magic record and get the exact same behavior as we wanted. But as a freebie, now we have the ability to drop down another layer if we want and actually define this stuff with less magic. And you say, well, that's great, so that's attributes. We kind of understand that, that's pretty simple, right? Big whoop. Active record also does all these other things. I mean, you know, it's got like attribute typecasting and associations and serialization and secure passwords and transactions and macro reflection and nested attributes, timestamps, lifecycle callbacks, validations, dirty tracking, mass assignment, sanitation, to name some, and oh, by the way, we have querying and persisting, right? That's kind of an important thing in our persistence library. And so I say, yeah, yeah, exactly. That's an interesting problem that we have, right? Because they're all kind of living in one place and how do you expose this kind of interface, this kind of way of interacting with your library to cover all of these things? And my answer would be basically that you don't. You allow this to tell you maybe I've got a crazy idea. So this is the ancestry chain of an active record-based subclass. Just wanted to show it to you real quickly. Now, yeah, yeah. Three cheers for the ancestry chain of active record-based. So, somebody's clapping, oh no. Right, so in Rails we call this clarity. You may have heard that earlier. Because API surface area is irrelevant. We don't care about that. In other words, the single responsibility principle is super simple for sufficiently large values of responsibility. Like, if your responsibility is to do everything, then you just say, okay, gotta do everything. It's gotta work, right? That's my responsibility. Oh, it works. All right, done. And so a while back, actually last weekend, I tweeted some of these statistics about an observation on a brand new Rails 401 app, what a subclass of active record has, what the view has, and what the controller has in terms of ancestors, public protected class methods, public protected instance methods, and same for private methods, right? Now look, it may very well be that this is exactly the API size that we need. I'm not gonna argue that one way or the other right now. But what I will say is that there are other ways to get there, just because we want these methods does not mean they all actually have to be implemented in modules that are included onto the class. And so what I'm getting at is that it's very, very hard to keep track of just what you're doing. I've been writing Rails for over seven years. I'm not exactly sure how long at this point, but I know that since I've been doing it, I still have to have documentation open most of the time when I'm doing anything serious. Like, maybe I'm just dumb, possible, I don't know, but I need documentation. It's a really big namespace to try to keep in your head all at one point. So this is online at GitHub, and you are free to do science to verify my empirical observations and see whether or not they are accurate. And I would love to see PRs to this repo, actually, with different versions of Rails to see how things have changed complexity-wise. Now it's not enough, really, for ActiveRecord to just do this on its own. It actually encourages us to do this, right? Rails has this whole helper thing, right? And let me give you an example of something I actually encountered, and I'm embarrassed to say, spent, like, half a day troubleshooting with helpers. So I decided I had a really great idea, and I was going to use something that I heard that OO developers like to do, which is polymorphism, and use it at the view layer, right? And I'm like, I can have something that is summarizable, and so I might have a helper for posts that's summary, and I might have a helper for reviews that's summary. And I can share a partial that prints that summary in an appropriate way for that particular thing, right? That seemed pretty cool, right? So this is how it would look in a partial. And in development, it worked wonderfully. It worked exactly the way I expected, and then I deployed to production. Now, how many of you think it worked? All right. How many of you think it didn't work? Well, it's kind of a trick question, because honestly, you can't really tell me, because you don't have enough information right now, because there's this thing, right? OK, so seven years ago, there was a commit to Rails that said we're going to make it a default assumption. You want all helpers all the time. No comment. And for a long period of time, I'd like to imagine it was some kind of a dark age in Rails. There was really no way to opt out of this, per se, until a patch came in that added include all helpers as a configuration option. So I thought, this is great. I found this after hours of searching, because I just somehow missed the memo that we had done that. And it was way back in 2.3. This has been the way for a while, right? But I just kind of assumed it's named post helper. It should help posts, not like other things. But that's not how it works. So there's this kind of big namespace, right? And so I would recommend that nearly all of you consider adding this to your application.rb. You will be much more sane for it. If you're going to use helpers, at the very least, having a namespace that you can kind of control. If you want it to be available to all controllers, then throw it in application helper or have a module. You can still use modules. I hear it works. Now we did all this in the name of convenience, right? Convenience is going to trump everything else. We want convenient usage at expense of anything else. And so I own a house. And I think to myself often that when nature calls, I have to get up and go to a special room to go do my business, right? And I mean, that's really inconvenient. So why don't I just install a toilet in every room in the house, right? Because then, if I'm watching the tube, it doesn't matter. You don't do my thing. It's all good. But the problem with that is that first off, you've got plumbing now to help support this aspiration of having a toilet in every room. And plumbers are expensive. And stuff breaks. And then it's like, I've got a leak. And I've got damage and stuff. And then the other problem is every room is a toilet, right? So I would encourage you to consider that if this is kind of what you're looking for, if a giant namespace of methods and functions is what you would really like to have, I got the language for you. It is super convenient. Like everything is at arm's length. What's that? You want to do something with a string and an array? It doesn't matter. My SQL? Sure, absolutely. I mean, just a thought. So now another Rails opinion is who needs classes when we've got modules? And I say this primarily because of one interesting piece of code, which is active support concern. So active support concern, you may think, is mainly for having a convention around having a class methods module inside your module and instance methods and so forth. But it's not. The problem that is designed to solve is that in this world, the Ruby world, the one that we live in lots of times, we actually would have to include. There's a lot of extension onto a class when you include a module in the Rails world. Like a lot of the modules that Rails is built on go and do metaprogramming and add methods to the singleton or whatever onto the class itself. And if you're adding stuff to the singleton, then it's not sufficient for you to go ahead and do that in a module that is itself included. Because when it gets included in the module, it modifies the module singleton, not the class singleton. With me so far, this is a huge problem. So let's solve it. Now we have this ability to have dependencies that get tracked by active support concern so that each singleton knows what its dependencies are. And then at the time that you include the dependency that you're really looking for, it can also go back and include into your module all the other ones that it needed. And so then that way they can do their metaprogramming magic on your singleton instead of their singleton. It's great. So what it is is that there was this problem that we had. And we decided to bundle a free razor with every yak. And I guess that's one solution? Sure. So I've been thinking a lot about this lately. And one of the things that sort of bothers me is that we're regularly told not to fight the framework, right? But our framework pretty actively fights the language. There are things that the language is saying, hey, this might be crazy. Maybe you don't want to do this. And we're like, I won't do what you tell me. I will do exactly what I want to do. And it encourages this kind of module-centric design limits the entry points that we can have. So Yehuda made a really great point, actually, when he talked about that we were kind of on the 400th story. And I agree. We are way up here in terms of abstraction. But I've heard rumors that maybe on most buildings, like those other floors have people in them. And they do things. And maybe you can not just be trapped on the 400th floor forever, but maybe you want to go down. Because I heard on floor 350, there's an ice cream store. And I like ice cream. So maybe I want to go down and have some ice cream. But I can't, because I can only do things with things that are instantiatable. And if everything is a module, I'm not instantiating that. I guess I could write my own class and include half of what's going on. But that seems like I'm just perpetuating the problem. So here's another Rails opinion. Rails believes that your conventions suck. First example is, now, I know it's going to be hard for you to believe, but there were conventions for building applications before Rails came out. Like, people were actually building. I know. It's a little weird. They were building web applications. And one of the things that they used was JavaScript, right? Now, love or hate JavaScript, it's here to stay at this point. We're going to be writing it. And so Rails, once upon a time, you guys remember this? You remember this? Like, so if this was before your time with Rails, we had this great idea, right? Which is, JavaScript's a pain to write. And let's write Ruby that writes JavaScript instead. And so we called that RJS. And you could write these. And there were these methods that if you said page.whatever, it would generate some JavaScript. And you could go look at the JavaScript, and it was about like you would expect generated JavaScript to be. And then we decided, OK, maybe that was crazy. But we're still not happy with the whole state that we have to write JavaScript. So we decided to use JavaScript that looks like Ruby, right? OK, great. All right, fine. I can see that. And then at that point now, we're at a point where there's this other convention where if you're using jQuery and many of us are, let's say that I want to render. I have decided I'm going to be on a straight and narrow. I'm going to render my views in Ruby. I want to render static HTML that I spit out. But I need some dynamic parts. And so I'm going to render some JavaScript as well that's going to do some things. Use jQuery. This is a pretty standard convention, right? I mean, how many of you have this exact code in your code base somewhere? If you're not raising your hand, I'm very shocked. So we thought, that's great. It's really cool to be able to hook into document ready and do some stuff. So Rayl said, that's a horrible idea. You should use turbo links. And so now, look, you can yank turbo links out of your gem file. And that's true. You can do that, right? But it's in my opinion that conventions should probably not completely break someone's expectations of their doing server-side rendering. And this is something that you are going to run into if you're just starting out with Rayl. You're like, well, why isn't this doing? Well, we don't fire the doc. Now, there are other gems that will make this seem like that is not the case. But the fact of the matter is, it's going to bite you. So Rayl said, we have opinions about how you should write JavaScript. Rayl has opinions about how you should maintain data integrity as well. And so in the Rails world, this is a typical way to handle some validation of data integrity, right? Maybe you make sure that you have a customer and you need a unique reference number and you have a typo there. Validates associates. Validates associated on line items, right? And you won't save an order unless its line items are valid. And that's really interesting to me, because objects, unfortunately, they don't really understand their relations to other things very well because those live somewhere else. They're in the data store separate, right? And I really think that it would be great if there were some sort of a system that we could use. So I don't know, it would be like a system for managing, I don't know, relational data, maybe? I don't know. It would be great if we had one of those. And it turns out that we do. And they are super good at understanding relationships between data. And they are super good at validating the data that goes in and out and ensuring that things are atomic, right? And that our updates are not going to run into race conditions and the like, right? I mean, and I'm talking about even the, let's say, less than civilized versions of databases, those are also able to do pretty well at this. Because Rubyland has to cross a process boundary to know any of this stuff. And that's pretty lossy, really. So I don't think it would be fair. I've griped a lot at this point about a few of the opinions that I think Rails has. And I feel like you came here hoping that I would offer you some solutions, right? I want to show you some solutions that I've found. These are my solutions. They look pretty nice, I think. Science. No, so I've been doing this thing lately. And I'm calling it IDD. And it stands for Ignorance Driven Development. It's really blissful. And it's this crazy idea that maybe starting with Rails G model, like starting out thinking about your persistence, is maybe not the way to go. If you're thinking about your persistence for, I mean, I can tell you, all right, raise your hand if you have stopped to consider what your database scheme, scheme I was going to look like after you've typed Rails G model, and you're just kind of frozen there like, crap. Analysis paralysis sets in, right? Because migrations are a pain, and databases are, oh, yeah. We want to do everything in Ruby, right? And so that's a problem, right? Because I don't necessarily know what the best way to store my data is off the top of my head, right? I may find that out as I go. So here's a crazy idea. Start with Ruby and ignore persistence off the bat. Probably that is not your domain. Your domain is not to be a crud app. Most of us here, anyway, our domain is not to just be a crud app, right? We have some business logic. And after you start with Ruby, then you start to identify the scary things, right? And this is like the part of our domain that we're really scared we're not going to be able to implement. Like, what is the thing that's going to be super hairy that we're just kind of like afraid to tackle, right? And removing the analysis paralysis that can set in when you're trying to figure out what your data is going to look like, while you're just kind of playing around with an algorithm, is great because it gives you this sort of power to attack the scary things. You can do, I know it's crazy to say, some TDD and attack these scary things. And the cost of experimentation is a lot lower when you're not messing around, running migrations. You're just running super fast tests. Everything is really nice. And you validate that the business logic that you're trying to write is going to be sane before you go any further. And so what that might look like, for instance, is let's say I have a monster class, right? I simply give it some teeth and some claws, right? And it can bite and it can scratch. And I write my test. And let's just assume that biting and scratching is a very, very difficult thing for a monster to do, right? And so it starts out that way. And you gradually iterate on the things that you want your monster to do, right? And then what you find out is that, eventually, after having iterated through maybe many, many iterations on what this class looks like, what its collaborators might look like, you get to a point where you're like, okay, I know how to make this monster now. I know how to tackle it, right? And now is a time for you to admit persistence, right? Now you start to think, okay, well, I've got to persist this stuff somewhere. I have some things about this business logic that are going to require me to save some data to the database. And so you decide, well, what database am I going to use? Or is it going to be NoSQL? Or is it going to be SQL? Or is it going to be, I don't know, something in memory, right? And then from that point, let's just say you decide, well, now I'm going to do some active record. And so you say, all I do is now inherit from active record base. The teeth and claws are no longer supplied via injection, but instead they come from relationships in some way. And we maybe have determined that we require that we have teeth and claws. And then, you guys are going to think, you notice there's no methods here, right? No methods. It's not doing anything yet, except the active record stuff. You're going to think I'm trolling you. But here's what I've started to do. I use modules. Now, the way I see it in firefighting, there's this thing called a backfire, where it's like, OK. So when they say fight fire with fire, that's actually a thing. And I'm like, you know what? Rails, if you want, I'm going to burn the whole place down. That's OK. I've got my own little fire going over here. And it's going to allow me to have some semblance of order. And let me show you what that looks like. And before you think that it won't work, I can only just say that it has worked for me. Give it a try. Strangely, I'm not going to prescribe that it's going to be the solution for everyone. I know that's kind of the hip thing to do, is to say my solution will work for you. But it worked for me. And what it would look like is this. So I now have behaviors that I expose in modules, right? These behaviors are specifically intended to provide one isolated thing, one isolated capability to the persisted record. And so in this case, here is the biting module, for instance. And it knows how to bite. And let's say this is after we had developed all of our stuff in plain Ruby. This is what we landed on for what bite need to perform. And so once we've done that, we can write a class. We can actually just test against a class that limits the API service that our behavior interacts with. This was the goal. This is why I do this at all. It's because thinking about how I'm going to interact with this essentially infinite API that a lot of Rails provides, particularly Active Record provides in this case, is too hard for me. Because I'm dumb. So what I needed some help to help me just be able to see in the test, this is the part of the API I care about. And you may be concerned about this. You may say, this looks a lot like Active Support Concern. I can understand why you would say that. Let me show you why that's not the case. So earlier, we talked about how Active Support Concern's primary goal is to solve the problem of modules that depend on other modules that modify their base class. The intention in this, and that might look like this, like let's say now there is a whole fighting behavior that might bite and might scratch. We don't know yet. There may be some probability associated with it that against a particular target, or maybe more than one target, or whatever. And so it has this dependency not just on the API that the class that it's being included into has, but also the stuff that's getting included into that class already. So it expects bite and scratch, which are provided by other two behaviors. So that kind of thing becomes actually painful. That actually becomes painful when you're not using Active Support Concern. And so what you actually have here is a canary in the coal mine, a sentinel animal. It's something that's telling you there's this thing that's doing more than one kind of thing that's more complex. And it really isn't fully encapsulated in the stuff that I've got so far. And it leads you to understand that maybe there's another thing, like maybe there's an encounter. And it might include one or more combatants that select targets and do one of their actions, bite or scratch. So to start to sum things up, a lot of us work in the startup world. And it's really frustrating and surprising to me that we embrace this idea of a minimum viable product in the startup world, build the smallest thing that can possibly work and then go from there. I kind of feel like in software, the whole goal really is to make as few decisions as you possibly can in order to get the desired result. Every decision you defer till later is going to give you some capability to be able to react to change. So I would like to see us, both in Rails and in the software that we write, start off with fewer opinions, start off with fewer assumptions. Make sure that the floors that we build have a purpose. One great way to do that is to make sure that you can instantiate a lot of the things. If you can instantiate a lot of the things, then they must have a purpose that we can reason about, we can think about, as opposed to, well, they might modify 500 methods on another class. And in general, just be a considerate software writer. Thanks for your time.