ERNIE MILLER: Good afternoon everybody. AUDIENCE: Good afternoon. E.M.: How's it going? AUDIENCE: It's going good! Hi Ernie! E.M.: Hi. 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. AUDIENCE: Whoo! [applause] E.M.: If I could ask you all to do me a favor, as it turns out, most of my fellow co-workers that had come out to RailsConf have had to catch a flight to go back home, and so they're missing my talk. And so what I'd like you to do is to Tweet very enthusiastically about the talk, regardless of if it's very good, so that, you know, for at least until it goes on video, they're gonna think they missed the talk of a lifetime. So, RailsConf, huh? Have you guys had a good times? AUDIENCE: Whoo! [applause] E.M.: Yeah? Yeah. I've had a ball, too. I've had a ball, too. So. AUDIENCE: Ah, yeah! E.M.: I am not. AUDIENCE: [indecipherable - 00:01:10] E.M.: 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 fifteen seconds at a time. Then I get booted again. So, so there is that. But, you know, I'm thinking, you know, it's, it's moving up in the world. I'm a member of something core. So, 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. [applause] So, you're not supposed to clap for that. [laughter] 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. [applause] OK. OK. Nope. Nope. That's enough. Nope. No more. We're done celebrating. [laughter] Just that much celebration. Nothing more. [laughter] OK. All right. Stop the part. So. That. That gets me every time. So, that being the case, I, 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, you've gone up against a brick wall. You can't make anymore forward progress and you feel like you've been kind of, you know, so- yeah, OK. So some hands are going up right. And, and, and so it seems to me, like, if there is that much talk about it, you know, it seems like we often get the response that, you know, we just need to run with more passion at the wall. Run faster. And, 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, there's some kind of an issue there, and I wanted to give a few opinions about, you know, why that might be. So, Rails is a convention over configuration advocate, right. That's, that's the big thing that we always talk about, that we would prefer to have convention over configuration. Now, conventions are really what, 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, 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 particular, when we say like, one dot megabyte, right, there's, 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 the sh- 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, we've got that alias to append, so that we can say append. We have object dot in, so we can ask whether an object is in an array include 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, 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, OK. Is the string actually containing the method that you just sent minus the question mark? And so, that's really all its 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 sat 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, these aliases that 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. Nope. You know. They'd 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, 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 like to use a foreign word for something just to sound clever, right? 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 ActiveRecord, 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 ActiveRecord 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 model's 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 ActiveRecord pattern. That's the whole point of it. And if you don't believe me, I'll show you some README 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, 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, once you have determined that there is a greater evil out there, then a lot of lesser evils 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 ActiveRecord::Base end and have magic happen, right. Like, for instance, we infer, and I want to talk a little about, about one thing that we do in that case, right. We infer what the attributes should be on that, 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 want to 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, we'll talk about happy things. So, so you might imagine pretty, 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 kind of 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, cause we don't want to 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, they're, 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, 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 ActiveRecord itself as a class method. So, when we call super, we're actually calling super into ActiveModels. Definition of defining attributes, right. So we're saying, define attributes methods from ActiveModel. We're passing it 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 connections, for starters, to the database to talk, to figure out, you know, what table it's gonna read from. And it also needs to determine table name, right. So now we need to know the table name. So we don't have the table name yet, so we call a reset table name, and most of the time I'm gonna skip past some of the, some of the more convoluted things and just talk about the compute table name, right. So we have to compute the table name. It makes sense, right? So, this is kind of a big method. Hopefully you all can see the, 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 dot 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 conf becomes rails_confs, OK. 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 to find for moose. There is not. There, there, there are some interesting ones, I think. We've got, like, sheep. We do have sheep, so we're at least in the ball park. We have jeans. 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 dot 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, what is magic, really? And, 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, like, there's something going on. It would be pretty horrified, right. We'd be like, I don't be- where have I gone? Like, what is going on here, right? And so there is 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, what I referred to as douche bag magic, which magic that bites you, magic that screws you over in all sorts of wonderful ways. So, let's imagine, for a moment, a world, a world where we do have magic that we can understand. And, so let's just say we have ImaginaryRecord::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? Given an attribute name, tell it's how its to load the attributes. Tell it how to load the attributes. Maybe some other stuff. We don't, we're just, we're imagining here, right. We're, we're just in your imagination. And then let's say that we have a MagicRecord that inherits from the ImaginaryRecord::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'd basically get to the point where we could do something like inherit from MagicRecord 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 to 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. ActiveRecord also does all these other things, I mean, you know, it's got like attribute typecasting and associations and serializations and secure passwords and transactions and macro reflection and nested attributes, time stamps, 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 a important thing in a persistence library. And so, I say yeah. Yeah, exactly. That's. 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, with your library, to cover all of these things. And my answer would be basically that you, you don't. You, you allow this to tell you maybe I've got a crazy idea. So, this is the ancestry chain of, of an ActiveRecord::Base subclass. I just wanted to show it to you real quickly. Now, yeah. Yeah. Three cheers for the, for the ancestry chain of ActieRecord::Base. 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 you're responsibility is to do everything, then you just say, OK, gotta do everything. It's gotta work, right. That's my responsibility. Well, it works. All right. Done. And so awhile back, actually last weekend, I Tweeted some of these statistics about an observation on an, a brand new Rails 4.1 app, what a subclass of ActiveRecord 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 on, 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, you know, 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 trouble shooting with the, with helpers. So, I decided I had a really great idea, and I was gonna 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. 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? 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 are going to make it 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, now I found this after hours of searching, like, because I just somehow missed the memo that we had done that. It was way back in 2.3, like, this has been the way for awhile, right. But, like I just kind of assume, like, 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 to your application dot 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 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, is going to trump everything else. We want convenient usage at expense of anything else. And, you know, so I own a house. And I think to myself often that, you know, when nature calls, I have, like, to get up and like, go to a special room to go do my business, right. [laughter] And I mean that's really inconvenient. So like, why don't I just install a toilet, like, in every room in the house, right? Because then, like, if I'm watching the tube, it doesn't matter you know. Do my thing. It's all good. but the problem with that is, right, that first off, you've got, like, plumbing now to help support this, this aspiration of having a toilet in every room. And plumbers are expensive and, like, 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, like, 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, of, of methods and functions is what you would really like to have, then 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, yeah, doesn't matter. MySQL, sure. Absolutely. I mean, just a thought. So now another, 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 ActiveSupport::Concern. So, ActiveSupport::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 the it's designed to solve is that, in this world, the Ruby world, the one that we live in lots of times, we, we actually would have to include. There's a lot of extension onto a class, right, 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, right. And if you're adding stuff to the singleton, then it's not sufficient for you to go ahead and, and do that in a module that is itself included, right. Because when it gets included in the module, it modifies the module singleton, not the class singleton. With me so far? Right. This is a huge problem. So. So let's solve it. Now, we have this ability to have dependencies that get trapped by ActiveSupport::Concern, so that each singleton knows what, what its dependencies are, and then at the time that you include the, 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. And it's, you know, so what it is is that there was this, this, this problem. There was this problem that we had. And, you know, we decided to bundle a, a, a free razor with every yak. And, I mean, I guess that's one solution, sure. And so, so I've been thinking a lot about this lately. And one of the things that sort of bothers me is that, you know, we're regularly told not to, 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, this kind of module-centric design. Limits the entry points that we can have. So, you know, Yehuda made a really great point, actually, when he talked about that we're kind of on the 400th story, right. And, and I agree. We are, we are like way up here in terms of abstraction. But, like, I've heard rumors that, like, maybe, on most buildings, like, those other floors like have people in them, and like, they do things. And like maybe you can not just be trapped on the 400th floor forever, but maybe you want to like go down, cause like, I heard, like, on floor 350 there's like an ice cream store, and like, I like ice cream. Right. So maybe I want to go down and have some ice cream. But, like, I can't. Because I could only do things with things that are instantiatable, right. 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, here's another Rails opinion. Rails believes that your conventions suck. First example is, now, I know it's gonna 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, and one of the things that they used was JavaScript, right. Now, love or hate JavaScript, it, it, it's here to stay at this point. We, we, we're gonna be writing it. And so, Rails, once upon a time - you guys remember this? You remember this? Like, let's, so. If this was before your time with Rails, we had, 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, there were these methods that if you said page dot whatever, it would generate some JavaScript. And you could go look at the JavaScript and it was, you know, about what you would expect generated JavaScript to be. And then we decided, you know, 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 were at a point where there's this other convention, where like, if you're using jQuery, and many of us are, like, let's say, let's say that I want to render, I have decided I'm gonna be on the straight and narrow, I am going to render my, my, my views in Ruby. I want to render static html that I spit out. But I need some dynamic parts, and so I'm gonna render some, some JavaScript as well that's gonna do some things, right. Use jQuery. This is a pretty standard convention, right. I mean, how many of you have this exact code in your code base somewhere, right. If you're not raising your hand, I'm very shocked. So, we thought, you know, that's, that's great. It's really cool to be able to hook into $(document).ready and do some stuff. And so, so Rails said, that's a horrible idea. You should use Turbolinks. And so now, look, you can yank Turbolinks out of your gemfile and that's true. You can do that, right. But it's my opinion that convention should probably not completely break someone's expectations if they're doing server-side rendering, and this is something that you, you are going to run into if you're just starting out with Rails. You'll be like, well, why isn't this doing? Well, we don't fire. We don't fire the doc. No, there are, there are other gems that will make this seem like that is not the case. But the fact of the matter is, it's gonna bite you. So, so Rails said, you know, we have opinions about how you should write JavaScript. Rails has opinions about how you should maintain data integrity as well. And so in the Rails world, this is a typical, typical way to handle some, 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 :associates and :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, you know, 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, you know, I, I really think that it would be great, like, if there was some sort of a system that we could use. So, like, 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, like, we do. And they are, like, super good at understanding relationships between data. And they are super good at, at validating the data that goes in and out and ensuring that things are atomic, right, and that, that our updates are not gonna 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, those are also able, able to do pretty well at this. Because, Ruby, the Ruby land 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, you know, 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 that stands for Ignorance-Driven Development. It's really blissful. And it's this, this crazy idea that, like, 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, schema is gonna 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, like, migrations are a pain and databases are, ew, yuck. We want to do everything in Ruby, right? And, 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. Like, 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 gonna be able to implement. Like, what is the thing that's gonna be super hairy, that we're just kind of like, afraid to tackle, right. And removing the, like, the analysis paralysis that can set in when you're trying to figure out where your, what your data's gonna look like, while you're just kind of playing around with, 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 it's, 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, 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, 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, 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, OK. I know how to make this monster now. I know how to, how to tackle it, right. And now is a time for you to admit persistence. Right, now you start to think, OK, well, I've gotta persist this stuff somewhere. I have some, some things about this business logic that are gonna require me to save some data to the database. And so you decide, well, what database am I gonna use? Or is it gonna be NoSQL or is it gonna be SQL or is it gonna be, I don't know, something in memory? Right. And then from that point, let's just say you decide, well, now I'm gonna do some ActiveRecord. And so you say, all I do is now inherit from ActiveRecord::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 gonna think. You notice there's no methods here, right. Right. No methods. It's not doing anything yet, except the ActiveRecord stuff. You're gonna think I'm trolling you. But here's what I've started to do. I use modules. Now, the way I see it, you know, in firefighting there's this thing called a back fire, where it's like, OK, so, when they say, like, fight fire with fire, that's actually a thing. And like, I'm like, you know what, Rails, if you really wanna burn the whole place down, that's OK. I got my own little fire going over here. And it's gonna, it's gonna 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 gonna be the solution for everyone. I know that's kind of the hip thing to do is to say, like, 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, right. And so in this case, like, here is the biting module, for instance, right. And it knows how to bite. And let's say this is after we have developed all of our, all of our stuff in plain Ruby, right, this is what we landed on for what bite need to, need to perform, right. And so once we've done that, we can write a class, you know, we can actually just test against the class that limits the API service that our behavior interacts with. This was the goal. Like, this is why I do this at all, is because thinking about how I'm gonna interact with this, like, essentially infinite API that, that a lot of, a lot of Rails provides, particularly ActiveRecord provides in this case, is, is too hard for me. Cause I'm dumb, OK. So, what I need is some help to help me just be able to see into 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 ActiveSupport::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 ActiveSupport::Concern's primary goal is to solve the problem of modules that depend on other modules that modify their base class, right. The intention in this, and that might look like this. Like, let's say now there's like 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 sort of 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 ActiveSupport::Concern. And so, what you actually have here is a canary in the coal mine, a sentinel animal, right. It's, it's something that's telling you, there's this thing that's doing more than one kind of thing that's more complex, right. 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, right, and it might include one or more combatants that select targets and do one of their actions, right. Either bite or scratch. All right. So, to kind of start to sum things up, it, we, we, a lot of us work in the startup world, right. And it's really frustrating and surprising to me that we embrace this idea of a minimal, minimum viable product in the startup world, right. Build the smallest thing that could possibly work and then go from there. I, I kind of feel like in software, the whole goal, really, is to make as few decisions as you possibly can in order to make, get the desired result, right. Every decision you defer till later is going to give you some capability to be able to react to change, right. 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, right. 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 five hundred methods on another class. And in general, just be a considerate software writer. Thanks for your time.