Recognizing Parameter Creep0:00
One thing I've learned to watch out for in my own codebases is functions that accept four or more arguments. So here's an example. Maybe we have some kind of function called compress that will compress a file or an asset or something. It doesn't matter. Now, initially, you only had to feed it the files that you were compressing, and everything was great. But then, later, you realized, well, you need to configure the output. So the compiled file or something like that. Okay, well, you add another argument output, or maybe let's call that destination. Okay, so yeah, everything's fine. But then a little more time goes by, and you realize that maybe it's necessary to pass in the type of file that you're working with. And maybe you use that to branch off and do different logic depending upon that type. This is all stuff that just kind of happens as you work on code. So you keep adding to it.
Four Args Signals Class2:11
Okay, so there's your guideline. One more time, when a function or a method accepts four arguments or more, that might be an indication that there's a missing class. Okay, so let's play with that. Maybe here, yeah, like I was saying, you check the file type, and you see, well, if maybe we're compressing assets or something, if the file type is CSS, then we will compress the CSS using some formula. If the file type equals JavaScript, then we're going to take it in another direction. And we're going to have to use a different compiler for that, maybe Uglify. And then further, you'd have checks like, well, if they gave us a custom compressor, then that's what we would need to use in this example. You get the idea, right? So we see four arguments, we see a lot of conditions, so a lot of different branches for a method. And as we know, we sort of want to keep our methods as small as we can. A lot of people have rules about a method can be no longer than two lines,
Refactor Using Strategy3:00
so a lot of different branches for a method. And as we know, we sort of want to keep our methods as small as we can. A lot of people have rules about a method can be no longer than two lines, or three lines, or four lines, or five. Everyone sort of has a different metric. Again, these are not hardcore rules that you have to follow. They're general guidelines to keep you in check, so to speak. So when we have all of these conditions that branch us off into different logic, it's more difficult to read the code, it increases the line length, it introduces a variety of little imperfections. Okay, so if I said the alternative is introduce a class, maybe instead, when we call this compress function or method, we can pass in a specific compression strategy. For example, maybe we would send through the JavaScript compression strategy, or whatever you want to name it. And that would accept the files and the destination. Why don't we just get rid of this,
Connecting Patterns to SOLID4:41
and just say strategy, and maybe a handle or a fire method. So notice, this is kind of once again the strategy pattern that we learned about earlier in the series. And this is, I may have talked about this before, but this is one thing you'll learn as you review design patterns, and SOLID principles, and basic object-oriented design. They all circle around the same basic ideas. So if you can learn some basics, like polymorphism, and contracts, and stuff like that, you're going to see those ideas illustrated through so much of what you learn in all of these books and screencasts. So now, yeah, your strategy object, that will contain the files, the destination, and internally it will know which plugin to use to compress the files. So for example, if we had, how about JavaScript, I don't know, maybe we'll call these drivers, or something like that. Okay, well that will implement an interface CompressionStrategy. Let's create that. And if you hate interfaces,
Implement Drivers with Interface5:34
I don't know, maybe we'll call these drivers, or something like that. Okay, well that will implement an interface compression strategy. Let's create that. And if you hate interfaces, we'll talk about that in just a minute. But this will get us started. Anyway, so that's going to need a method called fire, and that should really be it for our contract. So now our JavaScriptDriver implements that contract, it adds a fire method, and this is where, well actually on this note, let's go ahead and accept the files, as well as the destination, if we want to put that stuff here. Yeah, so now this will handle the process of compressing JavaScript-specific source files. Then you would create another one for your CSSDriver, and that too would have a fire method, but it would use a CSS-specific compressor, rather than maybe like JavaScript would use, maybe Uglify or something like that. Then when you call your main compress function,
Apply Guideline Pragmatically7:54
just basic duck typing 101. Now, number two, the very last thing I want to cover here. Don't immediately find every function with four arguments and think, I got to fix this, I got to change it. No. Only change it if it's causing you a problem here. And that's why I said, yeah, four arguments is, it's an indicator to you that, hmm, something might be off here, and especially if you find yourself adding yet another argument, you're probably missing something. So the solution may be create a couple more methods so you can divide this stuff up, or, like I said, figure out if there's a missing class in this parameter list. And if there is, extract your classes, your different concrete classes, have them adhere to a common interface, in this case a fire method, and then pass in an instance of that class into your main compress function instead. And that should help you a good bit.
and then pass in an instance of that class into your main compress function instead. And that should help you a good bit.
