 Okay, so let's go ahead and get this thing started. My name is Michael Kelly. I'm a senior Rails Dev, been doing this for, doing Rails for about five years. I've been a Dev for on and off maybe 15 total. And as you can tell from the slide in your program, we're going to talk about Rails controllers today. So before we get started, I know this is in the junior track. Let me see a show of hands. Who here is actually a junior developer? Somebody newer to the technologies? Okay, good, good. How many people here are senior developers who are here to judge me on my presentation? Oh, good. Okay, so I only have to impress a few of you. All right, good deal, good deal. So I'm going to start off, like I said, we're talking about controllers. You've all seen them. You've all dealt with them in some way or the other. And a lot of times what you see, especially for new developers, coming out of Boot Camp or maybe some, you know, a run on tutorials online and the slides went away. So that's me. I apologize for that. Okay, so we've all seen them. We've seen index actions. We've seen show actions. You've all seen the standard crud. But what I'm kind of here to talk about is what actually happens out in the wild. Controllers you're going to see when you step onto a new job or, you know, pick up a new product, something like that. And actually the first slide I have is one such controller. No, you're not supposed to read that. We're not going to go through that line by line, nothing like that. That's atrocious. That's over 350 lines of a single controller with over 18 different actions and 100 lines of just boilerplate code. That's wrong. If anybody's wondering, that's wrong. What I want to talk about a little bit is how we get this nastiness out of what is essentially our standard controller, the one we've all seen. And it actually happens a lot easier than you think it does. So what we have here is the standard. You have your index show, new create, all the standard actions. But a lot of the times what you'll hear people say is that they blame controller bloat on things like rapidly changing requirements, uncontrolled feature growth, maybe changes in your team, or even in the worst case, where factors elsewhere in the app make you add things to your controller. That's all wrong. Every bit of it. Every time you read something like that, it's incorrect, because that's not what happens. These are all controllable things. They exist in every business, every software product. These things happen, all right? There's a way to maintain a good controller. So what actually causes this? How do we end up with 300 lines of garbage? Well, main thing is, is it's a misunderstanding about what your actions are actually doing, what resources they're actually working on. So I want to walk us through a small example. It's a little bit closer to real world, but I've glossed over a few things for time here. So we're going to take, for example, and this is actually something I've done a few times. Let's say you're working somewhere and your company is in charge of running ads for its clients on Facebook, Twitter, any of these social platforms, okay? So the fairly standard requirements that you'll see, you need a way to kind of browse, edit, and deal with the ads, create them, edit them, things of that nature. We also have to have a way to control those ads, pause them, activate them, basic on-off style features. And the last, users have to be able to see the performance of their ads, see how many people are seeing them, see who clicks them, how many times they've been clicked, what the impressions are. So in this example, I'm not going to build a whole app. I'm only going to deal with one controller. Call this the ads controller. So first thing we do, we come in, okay, we have an ad object somewhere, and we want to be able to do the standard CRUD operations, or you'll see there, I actually prefer the term bread because it includes the index, that's browse, read, edit, add, and delete. That's just a nomenclature thing, and I'm weird that way. So you saw this before. This is just re-implemented in this context as an ads controller. Pretty straightforward. I don't even have any features in there like paging or search or anything like that. Just straightforward actions. So we've implemented this. We've pushed it to production, and everything's fine. But the next thing, well, I'm sorry, so we have a total of seven actions out of the game. Every controller has these, or most do. So we're already talking about something that has seven different contexts that you have to keep mentally. But like I said before, we have to control these ads, and we want to be able to do that in a nifty kind of way, maybe some JavaScript button on the front end. We click it, and it makes some Ajax called our app and pauses an ad. So we come in, and this is something you'll see a lot of times. I won't say naive, but eager developers will take these actions and go, okay, well, they're Ajax actions. Let's just stick them in the ads controller. That's what we're dealing with, right? All right. So this is that same controller with those actions added. Don't worry if you can't read the code that's on the screen there. I actually want you to keep, just kind of keep a mental model of how that controller is shaped and how much information is there, okay? We're not looking at specific implementation today. But you see there, our action count has ballooned up to 10. All right. So that's now 10 different contexts, in different ways this controller can be used. Now that's great. We have these three new actions that maybe kick off a background job that talks to Facebook or Twitter, something like that. Then one of your Ajax walks in, and this is a phrase I've literally heard multiple times. So we want more of a responsive UI. We want some way that our page can load and then load individual visuals for our ads asynchronously. So we come back over here to our trusty ads controller. And maybe we need a pain to preview the ad so the user can see what it will look like on Facebook. Maybe there's, we want some little widget that will show them generic stats in a, like a list of their ads, something of that nature. So we come in, we add two more actions. Now these actions, I don't know if you can see it there, but all they do is render out a partial, something for Ajax to process and insert into the page. Again our action counts back up to 12. So the controller doesn't look so bad. Now I'll let you know each one of those actions is as minimally implemented as possible. The rendering of partials is a single line. The background jobs are a single line. So any logic added here is only going to complicate the matter. Oh wait, now we have to be able to deal with our stats, our statistics about these ads. So once again we come back. Let's say we want a page that will show our, the audience, the people who have clicked our ads. These are people who have interacted with our ad and we want to maintain a list of those. We want a dashboard to kind of see how I as a user am performing in general. So we come back and we add a few more actions. And these, these actually deal with maybe some helper objects to do some calculation. Maybe there's some aggregation or processing that goes on in this data. Here we are, now we're up to 14. Now I don't know if, I don't remember if I mentioned it, but that original controller I showed you only had 17 actions. So we're not that far off. And you can see how again if any kind of logic gets inserted into these actions, if you add any if-else blocks, if you add any escape statements, anything, anything directly in these actions, all you're going to do is turn it back into that. So we're not that far off. It's actually pretty easy and it, it happens without you thinking about it. You know, you're thinking about that one feature, adding a preview or adding a statistics page. Not your controller as a whole. So the answer to this to keep yourself from getting out of control like that is to break it up, break your controllers up into pieces. Now I've, I've talked to a couple of junior developers before about this topic directly and a lot of times people will have trouble breaking the context. You know, in every one of those actions we were dealing with ads. So it makes sense mentally to stick in the ads controller. But what I, what I argue is we're not actually dealing with ads in all those actions. So to, to kind of help you out a little bit, these are some different ways you can think about what kinds of controllers you're going to, to build. So in that, in that example, we had actions that dealt with static or view layer data. This is processing a partial or dealing with maybe a static page. It's a landing page, things of that nature. We had actions that, excuse me, dealt with things that are composite concepts, concepts that aren't mirrored directly by like an active record model or something of that nature. And then finally there, we have aggregate actions, things that collect a bunch of data together and pipe it down to the front end. So let's take that example, we're actually going to break it up along these lines. So excuse me, looking at your static control, your, your static and view style actions, these are those same actions from that previous controller. You can actually read those now. That's a font you can read again. These are the preview and stats actions. I've separated them out and I've stuck them in a different controller because what you're dealing with here is a view of an ad, not an ad itself, okay? That's a different resource, a different quote model that you're dealing with. You see the same thing over here with your composite controllers. Now these are things you'll see a lot of times, device is actually a good example of this. If any of you have used device for authentication or authorization, anything like that, there's all sorts of session controllers that you can override and add your own functionality. Anything that I know of has ever built a session model in a Rails app. Or like in this example, jobs. So those, those AJAX actions that would pause and activate your ads. Actually what we're doing is we're starting a job on the back end, starting something that's going to call out to Facebook, tell it to pause a specific ad. So I've broken those up as well into this ads jobs controller or ad jobs controller. Because that's what we're dealing with is jobs, not ads. The same thing goes for aggregate data, our audiences. That's something that's pulled from every ad we have, the dashboard. That pulls in information about every ad we have. So it's an aggregate resource. It's not a single model. And then of course, we have our standard CRUD controller with the index show, create, add, delete, blah, blah, blah. So what we've done is separate all these pieces out into different controllers. And it's not immediately obvious what the benefits to doing something like this are. But one, it's easier to debug your controllers. It's easier to navigate them mentally because if you have a problem with say the previews that we talked about a minute ago, maybe we need to render them differently or something about that is breaking, well we know right where to go and there's two actions in that controller. So we can make those edits without having to build the entire mental context of that ads controller that we talked about earlier. The other is, and you'll see this a lot when you step out into the real world, learning and onboarding. This is one of the toughest things the developer does, and that's step into a new application. So when you're learning a new app, do you think it's easier to take 350 lines and dig out maybe two lines you need to deal with or two lines you need to learn how a specific action works? It's a lot harder when you have to dig through that big giant mess we saw a minute ago. The other is you localize your changes and this is something that a lot of people talk about encapsulation, separation of concerns and what not. But ultimately, like I said before, if you're dealing with, say, stats, you need to calculate something differently, your changes are going to occur in that controller, not in one big giant mess. So if you go and you add, say, a before action, you now want to, I don't know, authenticate this call or do some object setup before the action comes in. If you've got 20 different actions in that controller, you now have to explicitly control which actions that filter is called on, you know, do a before action except all these others are only these two. So now when you make a change, it only affects the pieces of functionality that you want it to. And the last here, this is one that I haven't seen talked about quite a lot. And that's that it's actually easier to coordinate working on a larger team. If you've got multiple people working on this code base, maybe you're working on improving statistics, adding more information and data there and you over here you're working on making the previews look slicker, look cooler. Maybe you over there, you're working on, you know, improving, maybe there's some business logic we need to add to creating an ad, some kind of check we need to include. We can do that now. Not all making changes to a single file that then conflicts when you go to merge it in. So I kind of blasted through that a little bit faster than I expected but the main things I want you to take away from this talk are that you need to actually look at actually what your actions are dealing with, okay? You're not, they're not all dealing with an ad resource or a product resource or a user resource. These are different conceptual ideas that it's dealing with. And your controllers, I want to see a lot of controllers, okay? I don't want to see big, giant ones. I don't want to see 300 lines with 20 different actions. In fact, I actually challenge you that controller we saw in the beginning, the standard CRUD controller. Make that the most complicated controller you have. The one you see in the tutorials, the one you see online in the perfect examples. Make that the most complicated controller you have. It's challenging, it can be. But ultimately, that was the most complicated one I showed you outside of the trashy controller. So the main point here, like I said, and you'll see I actually had a couple people ask me how this relates to restful design, which is a fun buzzword in our world. And I make the argument that this is restful. To create a rest resource, an object that can be created, that can be destroyed, that can be changed. You have to actually define what that object is. And it's not, I promise you, it's not the same as all your other actions. Dig in and take a look at that. So I've gone way under time here, but I think I overcaffeinated, but does anybody have any questions? I would love to go back through and talk about it in more detail. The question was if I have any examples of where it's permissible or okay to add some actions on top of those standard CRUD actions. And in some cases, it can be. I mean, as developers, we kind of play a balancing act between the right way and the achievable way. If you have a feature going out or it needs to be in production in 20 minutes or a fix that needs to be in production very quickly, it can be very hard to do a refactor into three different controllers and test all of those controllers and push them up, get them reviewed, the whole nine yards. And so what you'll see is a lot of times, earlier on in a project, it's very convenient to add small actions like that, like possibly the Ajax actions or maybe the Vue actions. And it's all right early on, if you have a total of maybe three controllers and you want to attack some small functionality on there, that's fine. Get it in there and get it pushed out. Not a big deal. The main thing, though, is understanding when you introduce a new concept. So for instance, the previews that I mentioned, if that was a very small feature early on, yeah, we'll stick that in the ads control, not a big deal. But if this is a concept that you are approaching in the app a lot, you're going to come back to it with previews and maybe some stats widget or further widgets along those lines. If this is something that's going to keep happening, separate it out. Don't just tack it on there extra because it will grow uncontrollably. Actually build like an API namespace. And that's, I'm sorry, the question was, so with the, like the ads previews where you're rendering out partials, after you've created a few of those, it starts to appear like a kind of a private API. You know, your front end app or your front end page is making these private calls to get these partials. And at what point do you look to refactor that to, say, like a slash API namespace? And again, just like everything else, it's a lot of judgment calls. But it tends to, a decision like that tends to matter more when you foresee. It's a little bit about looking to the future. So if you're writing your first couple that render a partial and then a few more are coming along, maybe you're even dealing with some JSON elements, you know, serializing your objects in a certain way. Really, it comes down to when an abstraction like that, excuse me, when the elements you're adding justify the work necessary for the abstraction. And you'll see a lot of times it's an interesting balancing act because I'll jump into an app like that and I've done that so many times, creating this internal API that I can crank that out in a few minutes. So the level of difficulty is different based on the developer who's picking it up. If you've ever dealt with agile development, you've estimated that way. So it kind of depends on the velocity moving forward, where you're headed. And to kind of further your question a little bit, at what point does that stop being an API embedded in your app and a dedicated API launched at a different URL? Those levels of abstraction in the app itself really kind of depend on where you see the app going from a design perspective, from an architecture perspective. And that's something that I, to this day, still get into arguments with my own team about, I'm like, hey, let's go ahead and abstract this thing up there. And so I'm like, oh, it's not worth it. It's not worth it right now. And you make the debate back and forth. And ultimately, when you can go to your team and say, hey, I'm gonna create this API and they go, hey, okay. When you all kind of come to that same decision, it's time. It does, it does. And did everybody hear that question? So his question was, in a lot of the designs that he's dealing with, the designers don't follow RESTful. They view the design of an app and how users are gonna interact with it. And that's actually the crux of my point here, is that designers don't deal with controllers. Designers will never deal with a controller. The controller is your side of that. So in that situation, I would make the effort to maintain the separation. A customer's controller, a questions controller, a student's controller, and then leverage your front end to combine that data if necessary, whether that's through AJAX or something of that nature. Now, if it's extremely heavy, so you have lots and lots of places that these two objects are rendered or serialized together, then you start to look at it more like a composite resource, kind of like I mentioned earlier. So if you're always rendering those together, then create a controller that encapsulates that concept. This is a, I'm not sure what your context is, but call this a student questions controller and it renders them out as a grouping of that data. The decision to go one way or the other on that tends to matter more how much you're doing it, how closely tied they are consistently throughout the app. But I tend to, designers don't like me because I tend to force my code into a good design and it'll add a little bit of work to kind of converge it on the front end. But in my mind, the benefits of ease of development and localized changes really outweigh that. Because a lot of times, if those two things are rendered together at the same time, a lot of the changes you want to say the logic associated to creating a student or viewing them will apply to the student itself, regardless of if it's rendered together or separately, in which case you want that separated into its own controller. So a lot of times it can be hard, especially in a meeting room, but your code is your code. The designer's design is their design and there has to be a line of separation there. What I'm gonna implement will achieve that design but I'm gonna do it in my way so that my code is still understandable, still maintainable. Otherwise, you're gonna get into fights with them later on when you can't change something to the way they want it because you've kind of locked into this marriage of the two resources. Favorite Zen philosopher. Well, considering I stole the title from Robert Persig and his Zen and the Art of Motorcycle maintenance, I'd have to say him. It's a lot of the same concept though. It's about looking at what's in front of you and kind of seeing it from both the functional and the aesthetic perspective. And that's one of the reasons why I said don't try and read the code, just look at the file as a whole. You'd be surprised how much an eye for aesthetics on your code will actually do for it functionally and vice versa, as long as you kind of apply a much more whole mindset to it. All right, well I am now out of time. I managed to kill the rest of that. Thank you guys very much. I really appreciate it.