RR When to Use Modules
- Published on:
- Articles mentioned by James:
- Destroy All Software
- Cheating Multiple Inheritance
- Code Organization
- DRY Principle
- ActiveRecord's create and create! methods
- Code's primary purpose is the conversation it has with the reader
- Put methods in a place where we can look at related methods together
- Module included hook
- delegation and forwardable libraries
- delgate objects
- When to use modules
- shared functionality
- managing delegation
- grouping like functionality
- only including a module when you need the functionality
- limit my black magic
- replace a method
- breaking down into more granular business objects
- Destroy All Software
- There is a performance tradeoff when you include a module (it flushes the method cache)
AVDI: I just read that GTK apps, like the next version of GTK, you know the toolkit that a lot of Linux desktop apps are built on, the whole GNOME desktop is built on, it can render itself to a Webkit browser.
JAMES: It seems like an incredibly bad idea to try to…
AVDI: Yeah, I know right?
JAMES: …move a GUI app inside a web page, so I'm all for it.
AVDI: Yeah, we keep doing it. [Laughs]
JAMES: I know.
CHUCK: Hey everybody, and welcome to Episode 22 of the Ruby Rogues podcast. I'm your host, Charles Max Wood. And this week we have on our panel, Avdi Grimm…
CHUCK: [Chuckles] We also have James Edward Gray.
JAMES: Eew, coffee.
CHUCK: [Chuckles] And we have Josh Susser.
JOSH: Let’s see.. so, I'm in San Francisco; I should be drinking latte.
CHUCK: And I'm Charles Max Wood. The only coffee I use is CoffeeScript. All right, we are going to be talking this week on When to Use Modules. And I understand that Ryan Bates was involved in suggesting this topic, and James has a little more information on that, so I´ll let him explain.
JAMES: Okay, so the conversation that we decided to talk about this week is basically, are modules overused? And it kind of came out of a little bit from a Twitter discussion that Ryan Bates started about how Rails, when it takes a class, and then breaks it out to into 50 different modules; for example ActiveRecord::Base include modules for things like validation and associations, and stuff like that. When it breaks it all out like that, well then you have 50 files you have to go through instead of the one, to figure out where things are. And he also discussed it a little bit with Steve Klabnik, and they kind of had a back and forth of a refactoring example that Steve showed. We'll put all these links in the show notes if you wanna read up. But it basically kind of talking about what should this be broken into a module? Should it be in a class, things like that. So today, we are basically talking about when should we use modules. So who has opinions about that?
CHUCK: Well, one place I use modules, and it's related to an example that we used when we were talking about Exceptional Ruby, is just to kind of contain something or namespace it, so that I don’t have to worry about collisions. But I don’t think that’s exactly what we are talking about here.
JAMES: Yeah, that’s kind of a good point probably that there are uses of modules, that probably don’t really fall under this particular discussion that we are having. What you just said is a great one like Avdi’s example from Exceptional Ruby where he is tagging exceptions. And he's really just doing that to put a label on them or create a type out of them. So I don’t think that is the particular complaint that’s being raised here.
If we use modules as mixins, obviously that’s pretty much a requirement since, that's the only way to get a mix in. And sometimes, they get used to kind of cheat single inheritance; kind of make a multiple inheritance thing. Those kind of things probably aren’t really what we are talking about here. We are talking about more when people chose to break things out into modules, when is that a good idea, when is that not a good idea, and that kind of thing.
AVDI: Modules are [inaudible] in Ruby, and they serve a lot of different roles, so. I mean, you have to be pretty specific about what we are talking about, because they do a lot of different things.
JAMES: That’s kind of a good point. They are kind of really overloaded in Ruby. Like, you know, you have the kind of a name space right for methods and constants. The mixin thing that we've already talked about, and then Rails does kind of use them as a code organization thing, I would say in some ways. So yeah, certainly a lot of different roles there.
CHUCK: So one thing that comes to mind here too… I guess what we are really talking about is about is what are the tradeoffs? I mean what are the tradeoffs between breaking something out into its own module, versus just keeping everything in the class. And I think one example of this is when you want code to be DRY. So if there's something that I'm going to be using across multiple models in Rails or across multiple classes in my Ruby program, then I definitely wanna be breaking it out.
JAMES: Yeah, so this is kind of interesting, because when Ryan Bates first brought up this discussion, I actually found myself agreeing with it. And I was saying, yeah, it really bothers me that there's things in ten different files and I have to go look through the ten different files to find the method that I'm interested in right now, you know?
Just to give one example, like so if you look for… if you have a model, define an ActiveRecord and you look for the .create method, that models have on the class level to create an instance of that object, that's an ActiveRecord::Base, I believe. But if you look for create!, that’s in the validations module that gets mixed into Active Record base. And so these two methods that are really similar to each other ,in what they do or in two different places. So depending on which one you are looking for is what you have to do there. And that’s kind of confusing.
AVDI: I'm actually completely okay with that.
JAMES: Oh, yeah? Why do you say that?
AVDI: Well, I mean with the active model stuff, the ActiveRecord and the active model stuff, a lot of stuff has been [inaudible], so that they can include bits. And as such, I think it makes a ton of sense, as separate module because it enables you to do it; it enables you to pick and choose which bits you wanna include in your class. And also, some of it is just kind of all about sort of modules overloading other modules, and having a chain of methods where they can call super and rely on the sub class, or not the sub class, but sort of the proceeding module functionalities, so it kind of makes sense for that use case.
JOSH: So yes. And theoretically, I agree with that statement. I think what I've seen in the Rails code at least is that, the organization of code in the modules seems like some of it was… some of the modules were extracted from previously existing class functionality, and others were probably thought up by somebody as a good idea as a way to organize the code. And sometimes you can really tell which is which because there's more friction involved with trying to work with those modules.
AVDI: I think that if you’re [inaudible] modules to just break up… these class is too long, and so I'm going to find some [inaudible] methods and [inaudible] module because the class is too long, that’s just sweeping the [inaudible] under the bed; that doesn’t actually accomplish anything. Now you have two problems.
CHUCK: Yeah, that's how I always clean my room.
JOSH: And you didn’t even have to use regular expressions.
CHUCK: That’s right. [Chuckles]
JAMES: Okay, so I actually wanna go back to what Avdi said, because what I was saying was I actually agreed with Ryan Bates when he first brought it up. But somebody has me reading this cool book, called Smalltalk Best Practice Patterns, and it's actually changing the way I think about a lot of these stuff. And as I was reading it, I was thinking about this problem we are discussing today, and it kind of changed my mind. And I actually went back just yesterday, and kind of reread a large portion of Rails current active model stuff and like Avdi, I now like it; the way it's divided up, but for different reasons. And one of the things Avdi mentioned that he liked, I don’t like.
So what I do like is that Smalltalk Best Practice Patterns… this is kind of a spoiler for the upcoming episode, but it really talks about code’s primary purpose and the conversation that it has with the reader -- which I really love. And that basically a lot of sacrifices are made to make the code read correctly, and make it easy to walk through and understand. To one of those ends, he talks about putting methods in a place where we can look at related methods together. And that’s really important, I mean we all understand probably as our single responsibility principle, where each things should only be doing one thing. And that’s part of that; so that we wanna see all that related functionality together. But I was thinking about it, and basically that example I gave earlier is kind of a little bit of a red herring; the whole create being the same as create!, well they actually not because create! involves validations, whereas create does not.
So that’s why those methods are different and the validation version as in the validations module. So that’s the part I do like, is the related methods are grouped together in a module. But then what Avdi talked about being a string, being able to use super and stuff, I recognize all that, but I think that actually turns out to be the problem, because you read something like ActiveRecord::Base, and you see a save method and you think like, “Oh, this is save.” But actually, that’s not the save that usually gets called when you call that save. Because the one that usually gets called is the overridden version around ActiveRecord validation, right? It's hard to know which method holds at any given time.
JOSH: So some of that I think is a peculiarity of how Rails manages its code. There's a fair amount of complexity in dealing with a framework that large. And one of the ways Rails does that is how it loads code and breaks it up into pieces. There's this concept called a concern in active support, that is somewhat higher level abstractions on top of the modules, that lets them do the loading of things in a somewhat more intelligent way. And so, you don’t have explicit includes in files like ActiveRecord::Base… there's some higher level metaprogram machinery that mixes on in the module all in the right way. So it makes it harder to see what's going on, unless you know the right place to look.
I think that this is where you start to see not having an IDE for a language, impact your development process. But I think that some of the things like PRY, and some of the other stuff that you can in the console to examine what are all the methods that you have on your class at runtime, you can just drop them into a console or PRY, and start poking around and seeing what methods are where, and where they are implemented, that can be really helpful in understanding that kind of program structure.
CHUCK: Yeah, and you can definitely pull some of the other information just off of the class itself, I mean there are other reflection methods that you can use like, like .ancestors and stuff. So I mean, even if you don’t have a convenient way to say, this version of save is implemented in ActiveRecord::Base, or in the validation’s mixins or something else, you can at least look at the ancestors, see where it's looking first and where it's looking next, and then you can kind of look at your way up and look through the code that way.
AVDI: I feel like there's a command or a tool I saw somewhere once, like a plugin for IRB that would actually let you say… if I call save right here on this object, what methods is that actually going to be calling. I'm going to have to look that up, because that would be… I think that would maybe help alleviate this problem.
JAMES: Yeah, that one should be pretty possible. I mean, it should be pretty possible to find something like that, because you could walk up the ancestor tree. The only gotcha there is if it gets the method missing, then it's going to have to throw up a… because it's not going to be sure which one, you know?
JOSH: I actually just saw something like that released last week. It's called, ‘method locator’. And it does just that. I haven’t had the chance to play around with it, but it's not the first thing I've seen that does that kind of thing, but certainly the most recent. [Chuckles]
CHUCK: So I have a question that's sort of related to this. And we're talking about Rails, and that’s an example that we can use. What's the difference between having it say, inherit from ActiveRecord::Base versus having some mixin module that gives it the same functionality? Or having some mixin module that gives it the same functionality or is there really a difference?
JAMES: So that’s a good question. You mean, why doesn't… and I believe there are actually ORMs that work just by mixing something. And I think there's one for MongoDB.
AVDI: Data mapper.
JAMES: Data mapper, yeah that’s right.
CHUCK: Yeah, so what's the tradeoff between doing it, say Data Mapper versus the ActiveRecord way? Or is there?
AVDI: There isn’t. Data Mapper is right.
JOSH: I’m glad we got that cleared up.
JAMES: Oh wow, geez. Job done. See you guys next week.
AVDI: No, I mean I literally have never seen anything… any reason to prefer the inheritance version. And since the module version by definition is more flexible, you are not saying, “I'm going to be your one and only parent. You can't define a parent of your own.” I would prefer the module inclusion version.
CHUCK: Okay, I guess my question is, is there functionally any difference? I mean, is doing inheritance, does it do more than just add it to a list of ancestors?
JAMES: So to answer your question directly, not the way we typically use modules. Like usually, I mean if you were saying all you were doing is sub classing or including a module or the way Ruby defines including module, then yes, there is a difference. If you inherited, you gain the whole class structure, so the a class is a parent of your class, which basically means class methods will also inherit, as opposed to just the instance methods is what you get out of the box with Ruby.
However, Ruby hate that so much, that we almost always override include, include it and use a hack in there to mix in another module into the class, which gives you the class level inheritance methods and stuff. So in that case, I don’t really think it's very much of a difference. And like Avdi says, “You only get one parent.” So if you take a parent, that’s a big deal; you only have one of those, the module does tend to be more flexible. But I like the idea of persistence being in a module. That does seem to feel right to me. Like this thing is whatever it is, it just happens to also be persistable, because I throw this persistence module in there.
AVDI: Quick note: I believe it's Ara T. Howard has a gem called Using, which if you don't like the mocking about with like having a module and then as a class method module, which it extends on inclusion, Using will basically let you define a module as if… just define your class methods and your instance methods, the normal way that you would in a class definition, and then you say using that module. And it will just bring them them all in. It just works. It does the right thing. It does what you expect.
JOSH: That’s very similar to active support concern, which does a lot of the same stuff.
JAMES: Right, that’s how Rails accomplishes that trick, basically.
JOSH: So, I wanna take that opportunity to speak to a point of, we are talking about how to use modules, maybe we are talking about when to modules. But that pattern of having a module that you care about both the instance methods and then class methods, there was some early gems or plugins that use modules in a particular way. And the author of one of these things decide, “Oh well, I'm going to..” Okay so, as James said, in the included method of a module, you can do stuff like basics and class methods. That is something that you see very common to the class methods mixed in to the class.
But somebody decided it would be a good idea to have another module within the main module called instance methods. And on including the main module, you include the instance methods module, and I think somebody probably thought they were doing something clever by organizing their methods within the module better, but it just leads to module soup when you do things like that. So I've seen a fair amount of… I guess the term is “cargo culting” around that pattern. And I don’t see that there's any use at all in having this instance methods module within your main module, that you include as part of including the main module. It seems rather nutty to me, so I wanted to just advice people to understand what you are doing, not just necessarily copy pasting this stuff.
JAMES: Right. And as Avdi took his stance on the modular versus inheritance, I'm just going to go ahead and say the guy that did the instance message method module thing was wrong.
JOSH: I´ll back you up on that.
JAMES: Actually, if you look at Rails code base, I believe you know in the 2 series, they still had that and then in the 3 series I believe they went to remove all that.
JOSH: Yehuda just went through and took an axe to that.
AVDI: I just wanna make a quick statement here, because just sort of a community oriented statement. When I say that such and such is wrong, what I'm not saying is that the person that implemented that, the person that implemented ActiveRecord::Base as a base class or whatever was an idiot, I'm not saying that they are sort of maliciously stupid or anything like that. My operating assumption is everybody is doing the best they can with the resources at their disposal, and with the knowledge at their disposal. And I just wanna put that in there because I do make strong statements like that sometimes, and sometimes it can be misconstrued as sort of combative. And I really do have the utmost respect for anyone who has put their code out there in the open source space for other people to use.
CHUCK: I think we all kind of feel that way, where basically, the idea is wrong means in my experience it doesn’t usually work out as well as something else.
JAMES: That having been said, if you have heard Avdi say it’s wrong and you do it, he will come to your house and take your keyboard away.
CHUCK: I'm going to have to lock mine out.
JOSH: I think Avdi’s point is a good one. Well said, Avdi. There is a difference between criticizing some code someone has written and criticizing the person.
JAMES: So is it possible we could come up with a set of rules of when it is a good idea to use modules? Is that possible?
CHUCK: Whenever you want.
JOSH: [Chuckles] Tuesdays.
JOSH: So James, I think that's a good goal. Can we take a slight side trip into the conversation of when is it a good idea to use inheritance?
JAMES: Yeah, that's a great question. And actually, you lead to something I wanted to mention on this episode; I want a Ruby Best Practice Patterns. Reading Smalltalk Best Practice Patterns, I read it and I think, “Wow, this is great. And I'm really enjoying this.” But in other ways, it solves some problems and I think, “Oh, you are just wanting Ruby so bad.”
JAMES: You know, just to give one example, he solves the problem of giving an accessor that exposes the collection. And he says, ”You don’t wanna give them the whole collection, because then they'll start adding and removing and all kinds of stuff like that.” And one thing you can do is just give them an iterator. And he goes through and builds that one iterator method just to give them each, basically. And I'm thinking or in Ruby 1.9, you could do .toenum and get access it every single iterator in a read-only fashion. So, I really think that a lot of these patterns can be… in Ruby and get better. One thing Ruby doesn’t have.... Ruby’s modules are pretty different from a lot of other languages. I realize some of them have something close to them, but I really think that there aren’t patterns around modules and when to use them and stuff. And it would be great to know those.
JOSH: Well, maybe it's time for the Rogues to write a book.
JAMES: That would be awesome, yeah.
JOSH: [Chuckles] So back to the question of when should you use inheritance. And the canonical alternative to inheritance is composition. I've seen some cases where people have been mixing in modules and doing multiple inheritance type things, where composition will work just well. You just add an object to some instance variable in your class and then delegate some behavior to it.
JAMES: And Ruby makes delegation so easy; method missing just catch things and pass them on, but that’s all even wrapped up in the delegation and Forwardable libraries and standard libraries. So that kind of thing is really easy to do. And you are right; inheritance is one of those things I think when object orientation was first getting big, it was like, “Oh, inheritance, inheritance, inheritance. And then the further we went, we learned yeah, that’s not a great idea. And we tried to avoid it in most cases, unless it really is exactly like that object, which is one small difference. But a lot of times, you can accomplish better with wrapping.
Also, there's a lot of gotchas to inheritance in Ruby. Because Ruby’s classes are implemented the way they are, sometimes they take short cuts for the sake of speed. So to give an example, if you inherit from string and then defined an initialize method, and then you take some string and call gsub on it, that gsub returns a new string, but the initialize method never gets called because the way Ruby builds that object. So you can't always count on perfect behavior, especially if your sub classing a Ruby core class or something.
JOSH: Okay, so enough about that side bar then. [Chuckles]
JAMES: So then the question is, can we come up with rules of when to use modules. So maybe we can just go around and throw out rules. I´ll throw one that I see all the time. In fact, I'm pretty sure I can point to the documentation of almost any project and see it. People will use classes when like for example, Rails will say something like, “If you wanna customize how this route works, pass in an object that has a something method on it.” And what they'll do is they will define a class, and they'll do defself.something. And then that’s it. That’s the whole class. So there’s this class, and it has one class method on it. That’s not a class; that’s a module, right?
JOSH: No, that’s an object.
JAMES: [Chuckles] Yeah, right.
CHUCK: I object!
JAMES: Exactly, it is an object because classes are objects.
JOSH: No, but you'll never use it to generate another instance of anything. It's just a singleton object is just what you are talking about.
JAMES: Exactly, that was my point. So I was going to say, my rule is a class is state plus behavior; if you only want the behavior, use a module because that’s what a module is.
AVDI: Well in cases like that, I wouldn’t even use a module, and I wouldn’t require module.
JAMES: So what would you do? Like object new and then define a singleton method on it?
AVDI: Well, if I had to, I would. Now you see that pattern… actually I was just reading there's a name for this pattern in Smalltalk Best Practice Patterns. It's the one where basically, a class exists to have a single callable method on it. And I can't find the name right now, method object that’s the term they used. When I have a situation like that, and also I really have a good reason not to, I just make that method be called, “call”. Ad if that method is called Call, then if somebody wants to, they can just throw in a quick proc; they can throw in a lambda. And it's very, very simple for them to use, but then if they want to, they can create a module that has a .call on it, or they can create a class that has a call method, and instantiate it and pass that in. So that’s kind of the universal callable thing convention in Ruby is .call.
JAMES: I like that even better. And I have actually in the past created a lambda and then because I was passing it to something that wanted some other method, I just alias the call method and then pass it.
CHUCK: [Chuckles] Nice.
JOSH: So without stealing too much thunder from the Book Club episode in a couple of weeks.
CHUCK: It’s next week?
JOSH: Yeah. So that method object pattern is actually one of the richer patterns in the book. It’s not just having a class with one method. That’s the starting point for it.
JAMES: I agree. It was one of my favorites and I took a bunch of notes on them.
AVDI: It's more than that. So don’t just think that way.
JOSH: [Chuckles] Okay, so where were we?
JAMES: We were defining rules with the module… and oh, I just wanna say one more thing since it's my soapbox I'm on here; whenever you see documentation like that that says, class and then it just defines one method, and they just pass in the class object, you can totally ignore that documentation, and just build the module and do it the right way and pass that in. Because they never check to see if it's a class or a module, so you can just pass it in and it will just work.
CHUCK: Just do a pull request on the documentation.
JOSH: Avdi, didn’t you talk about that in the Exceptional Ruby, like the exception method on exception classes?
AVDI: Yeah, I mean… wait, in what context?
JOSH: The context of this is a class and the only requirement we have on this thing that we expect to be a class is that it has the exception method.
AVDI: Oh right, yeah, exactly. It has the exception method. And as a matter of fact, in the context of exceptions, it's explicitly opening things up for you to have that on just random objects because one of the things Ruby does when you reraise an exception is it takes the exception that you give it, or it takes the currently active exception and it just calls .exception on it. So yeah, it’s an example of that pattern.
JAMES: So what other rules can we come up with?
AVDI: Shared behavior.
JAMES: Right. That's the whole mixin case, right? Probably the best example being enumerable, right?
AVDI: Yeah. if you have two classes that are legitimately two separate classes, but they also legitimately share some behavior, I think in Ruby your first choice should be to look at factoring them out into a module, rather than into some kind of base class, and then using that module as a mixin. But conversely, if you don’t have a reason to share that behavior yet, you shouldn’t necessarily be pulling it out into a module. And eventually, you may want to pull that into some kind of delegate object rather than a module. But a module is a nice first step.
JOSH: I have a counter to that, and that’s that so everybody reading Smalltalk Best Practice Patterns and you keep… James, I would bet that the first time you saw Kent writing about protocols, you were scratching your head.
JAMES: Yes, I had to look it up.
JOSH: Yeah so on Smalltalk, a protocol is a collection of methods within a class that are related by functionality. So in active record, you would have a protocol for persistence an a protocol for validations and a protocol for life cycle, maybe a protocol for associations.
CHUCK: That’s starting to sound like active model.
JOSH: Yeah, somewhat. But the point is that you are building the Smalltalk IDE, people realize, “Oh, we need some more abstractions from being able to organize code.” And partly that was because they didn’t have multiple inheritance and couldn’t use other tools to do it. But in Ruby, there's multiple inheritance A lot of what I see in the use of modules is especially in active record, is that you have related pieces of functionality pulled out into a module. Not only does that make it reusable to some extent, but even in some cases where it's not reusable, you have related features all in one file; it’s all in one organizational unit.
JAMES: So yeah, I think Josh just hit on another rule there, which I would basically say as, if you can't say all of these methods are about reporting, and they stand alone, and they are just the reporting methods, I think it is correct to pull those out into a module and put them in a separate file, because you only need to go into that file, if you are interested in reporting, right?
And I think there's even other advantages that can be gained for that. And this is again what I'm kind of getting about is how this pattern and design relates to Ruby itself. If you do that, if you separate it into a module that’s only about reporting, and lets think about it, right? When we are doing queries in like web application, what's the number one rule? It's going to happen in a microsecond or two, because we need to get this request done and get it back out. But if you are doing reporting, you don’t care if the queries are a little slow because some Cron jobs are going to kick in, you run them at 2am in the morning and just send an email when it's done. And the traffic on that side of time won't be too bad. So you usually don’t care if your reporting methods are a little slow, right?
So if you do this, if you follow the practice and you separate that out, you could choose when to make stop module in and when not to mix that module in. So for example, when you are doing your normal, just web stuff, don’t mix the reporting module in, and then there's no danger that these slow modules are accidentally being used inside of your web app. But then when the Cron job kicks in, and you are doing the task, you go ahead and mix that module in right then because now it's okay because we know we are doing this stuff and it's okay.
CHUCK: Well, one thing I wanna jump in and point out, and this is something Avdi mentioned was that the delegate object, and we've talked a little bit about it, but I think we wanna be careful because sometimes you want to pull it out and put it in the module, and sometimes you wanna pull it out and put it in its own objects because it actually has state, and it has certain responsibilities that have to occur that aren’t part of the responsibility of the class that you are pulling it out of.
AVDI: Exactly, so you may want a reporter type object that actually might make more sense.
CHUCK: Yes, exactly. And what you may wind up doing is actually pulling out a module that’s reportable that basically hooks in to the reporter object to do its job.
CHUCK: So then what it is is it's really just a module that manages the delegation to the other object.
AVDI: And what we have there is we are getting close to the idea of DCI, which I've just started hearing about lately, which I'm sure I'm very late to that party. But the core concept of it is kind of having different hats that objects can wear, so you have sort of roles that are assignable at runtime and you divide up your functionality between roles and you say, “Okay, this object is wearing the reportable hat right now, so it has this functionality.”
CHUCK: Yeah, I also got really excited when James was talking about mixin in the module only when you need it. I thought that was kind of cool.
JOSH: So Avdi, the delegate object and mixin that you described, I like that approach. It's reminiscent of having a remote web service, and then a Ruby library that’s an API to that thing.
AVDI: Exactly, yeah. that’s a good analogy for it. So I draw a pretty hard line with this division of functionalities between using it for libraries, and using it for business objects. I do agree that it makes sense a lot of times to sort of break these different responsibilities up in libraries, into different modules. But what I've been starting to see lately, is people taking their business objects, like their user class or something in a Rails app and starting to break that out into module, saying okay this module has as the validations, and this module has the methods, and this modules has like the associations.
JAMES: See I think that’s an example of a bad way to...
AVDI: Yeah. And I think it's in pursuit of smaller classes. I think it's a lot of times how it's justified. But like I said, I think they are just sweeping the problem under the rug, instead of addressing the problem head on, which is you need to break down into more granular business objects. And the problem is then you have two problems because now all these things, these validations, associations, that’s all part of your business logic. You can't say that, “Oh, this is my business logic. These methods are my business logic. And then these validations are not my business logic.” Because it's all related and they all have interactions. And to break those across different modules, you are just giving yourself a bigger headache trying to keep track of the interactions, because now that stuff is in different files.
JAMES: Plus also it fails the conversation with the reader test. And the reason with that is you’re going to try to use that module, then the first thing you need to know is like, okay, I'm going to try to instantiate one of these guys and… sorry, the model, not the module. I'm going to try and instantiate one of these guys in IRB, so I need to know what things I have to pass in that will make it pass the validations. And then I wanna call some methods on it, those are in a different place, so it fails the conversation with the reader test, in my opinion.
JOSH: And, we can go back to having the delegate object as a better way to organize the code in that case. Rails 3 you can do that, you can create a validator class, and reuse the functionality of those validations in many different module objects. So you don’t have to pull that out into a module; you can create another class, delegate behavior to it.
CHUCK: I just like to point out that in a lot of cases, we're talking about things that are symptom; so for example, shorter classes, or some of the other things that are deemed code smells that we are trying to solve. And if you are trying to break this out, either into delegate objects or into modules simply for the sake of needing that metric, then you are definitely missing the point. What these code smells usually are, are they are indications of other larger problems. And if you are not addressing the larger problems, and it's the point that James bringing up, where you are talking about communicative code, if your code doesn’t reflect what it does, if you can't look at it and figure out what it's doing, shortening the class just for the sake of having a shorter file doesn’t help you.
And so if you seeing a long class, then definitely go back and look at it, and that’s fine because it can be an indication of another problem. But then trying to figure out, “Okay, is this just shared behavior?” “Are these methods things that I can put in to a module, kind of put over off to the side that all have shared functionality that might be somewhere else?” Or is this something that I actually need to create a delegate object for, and make sure that your solving the problem in the right way that communicates what the code is supposed to do.
AVDI: It's all about responsibilities; a long class indicates an object with too many responsibilities.
CHUCK: Right. There are exceptions to every rule, and that’s the point.
JAMES: I'm glad Chuck said that though, that there's exceptions to every rule. I think that’s right. I've been watching the Destroy all Software which Steve Klabnik recommended, when he was on the show and I have been watching those videos, and they are really good by the way. But there's one in there where Gary goes through and shows… he basically, I think it's called, conflicting principles. And he basically makes an argument saying, if you followed every single rule we've come up with for object-oriented development, you basically have to take your hands off the keyboard because there's nothing you can do.
And he goes through and shows examples where rules began to conflict with each other and you know, you have to pick sides; sometimes you decide, well, what is the more important principle here? And kind of decide which way you are going to go. And it's very interesting, so I think that’s a good point. And I think its the same way in chess. I'm a big chess player and you learn lots of rules, strategies and stuff that you have to do in chess. And if you followed all the rules all the time, you'd have to just never move any of the pieces because at some point, you are trading off something for something else, right? And it's the same way when you program; you are trading off… I'm trying to make this code communicate better with the reader. I may slow it down in the process, but that’s okay.
CHUCK: All right, I'm going to try and do something a little bit different getting ready for the picks. I'm going to give us a few more minutes to talk, and then we'll go into picks. So if you have anything else you wanted to add, that you have been dying to say, now is the time.
JOSH: Oh great. So I have a [inaudible] about how to create modules that are going to be used as an API or as an extension of something. One of the things we saw in Rails a lot, for a long time is the access whatever pattern. So somebody created a plugin to do something, and it would inject some behavior into ActiveRecord::Base in some way. But the way that you would activate that is you'd call a method access version. And then that would decorate your class somehow with some new features.
CHUCK: It's pretty.
JOSH: It's pretty. And as far as I can tell, there's only one thing that that does for you, that you can't get just by including the module. Because the module, you can put some code in the self.include module method and have it do whatever you want in there. But the one thing you can't do with that is you can't pass customization parameters.
CHUCK: Right. Device does that.
JAMES: Yeah, that’s one of the Avdi actually mentioned on Twitter recently about Perl’s use, and I can't remember what other example you gave was, Avdi but the Perl use is like Ruby’s require; only it can take options. [Chuckles] which is kind of awesome really when you think about it, and I've often find myself wanting that, where I could require a library and pass in a few things, which is kind of what Josh was talking about right there when you call that method, you can also configure how it does what it does.
AVDI: So that’s actually a great little heuristics though, because when you are making the decision, I wanna factor out some functionality, does it makes sense as a module, as another object that I can use composition with, or as like some kind of wrapper, a decorator object. One of the ways to decide whether it's going to be a module is to ask, “Does it have any state?” And at least this is a rule that I like to use, you know. If the answer is, “it has no state, it's just behavior,” then it makes more sense as a module. If the answer is, “it has state; it needs to be initialized with some state,” then it might make more sense as an object that you compose in or as an object that you wrap around. And the fact that include doesn’t take any parameters, is kind of ringing that bell, reminding you of that heuristic.
JAMES: So I did wanna say one more thing, since Chuck is going to cut us off. We were talking about our rules to use modules, and I wanted to give two more, and I believe you should do it. And one is I use modules to limit my black magic. So like if I'm going to do something like use class new, which is like one of my favorite methods to start randomly generating a bunch of classes or whatever, I shove that in a module always just to keep scope on how crazy my magic gets, you know? At least if I do it in one module, then only that one module gets bad, and I can still not worry about polluting the main name space or something like that. Or you know, similar tricks with method missing. If you are going to do some kind of really dynamic programming, I think you should shove it in a module just to kind of scope your magic, basically. It's one of the we give for when to use the module.
JOSH: That sounds right. I also wanna add a little bit to that and that’s if you are building your own application code, namespacing isn’t quite as important, but if you are building code that’s meant to be used in other people’s application, whether it's library or utility of some sort, namespace all of your classes and modules and constants. There was that one wonderful problem with Mongo years ago about it having some fairly common word as class name, and it wasn’t name spaced, and it just caused people a lot of grief trying to work with that. So it's one example. There's been a lot of people that did that kind of thing. We haven’t really talked about this side of modules as much, but yeah, if you are building a gem, namespace everything.
CHUCK: Yeah, and it's not just to make it hard for somebody to accidentally call what you are trying to mess with, but it actually makes the blame a little easier, which makes debugging easier. So it's a good way to go.
JAMES: That’s a great rule Josh just said another one there. Modules should be used to name space the stuff that belongs to you. That’s true. But the other one I wanted to use, and this is my favorite use of modules. So a module is a in my opinion, the correct way to replace a method. It's not to go into the class and monkey patch it or undef it or replace it or alias it into an old one, and then write a new one that calls the old one. That’s the so wrong way to do it. The right way to do it is to insert a module in Ruby’s method lookup or whatever, so that it would be called before. Usually the easiest way to do this is to just extend the instance with your module, because it's going to put it into a singleton class, which means it's going to be in front of the method, and then you redefine the method in the module and then call super if you need the old behavior.
JOSH: That’s awesome. So I like that a lot, and I've done things that way. That’s a much cleaner way of doing that. But I wanna put in a little performance advisory, which is something that we missed when we were doing the Exceptional Ruby episode. When you do things like that; when you include a module or extend a module on to a class, that will flush the caches that the Ruby runtime, the virtual machine uses to make performance happen. It's a dynamically bound language, it takes a lot of work for Ruby to figure out which method you mean, when you send the message to an object, using Smalltalk terminology there. So it's saves the resolved of doing all that work by caching it somewhere. And when you do something like include a module or extend a module on an instance like that, it will… mri, it pretty much carpet bombs the method cache.
AVDI: Well, 1.8.
JOSH: Yeah, 1.8. 1.9 is somewhat better about that. Rubinius and JRuby are much better about that in various ways. Rubinius, I think the cache and validation is only limited to the names of the selectors that are found within module. And if it's an empty module, then it has no effect. JRuby is even more specific. I think its only particular objects that it cares about. But MRI, yeah it can really mess up your application performance if you do that a lot at runtime.
CHUCK: So when it flushes the cache, it starts building it again afterward, right?
JOSH: Right, but if you are doing that in like an interloop or something, that will be incredibly bad.
AVDI: Standard disclaimer though, for any performance optimization advise; profile before you use this advice, either to go that route or to avoid that route, always profile.
JOSH: Absolutely. But I thought it was worth raising a red flag.
JAMES: Yeah, I think it's important to know it does it, but at the same time, it's still the right way to override a method like 100% sure of that. And so like I would definitely take that into account, but at the same time, I would always override my methods that way, and I would not change unless it was causing me performance problems that I couldn’t get around.
CHUCK: All right, I think we are going to cut it off there. So I just wanna… I learned a ton from you guys. [chuckles] so thanks a lot for that and we'll get in to the picks. Let’s go ahead and start with Josh this time.
JOSH: I have a couple of picks this week. Speakerdeck.com. We all love conferences, we go to a lot of Ruby conferences. And even if we don’t, we like working at the slides for the speaker’s presentation online. And there have been a couple of fairly high profile sites that have been used for this in the past. Some of them can be kind of cluttered; you have to login and create an account before you can download slide in PDF and things like that. There's a new player now, it's called speakerdeck.com, and I'm really liking it. I like the visual design of it, I like the interactive features, I like that there's not much clutter, you don’t have to create an account or login to be able to download PDF’s. So it's nice. And we have the first event up on there for GoGaRuCo, and I´ll put a link to that on the show notes. But it's nice, it's a good application. And they just launched Monday of this week, that would be yesterday, so congratulations to them and I hope things go well for them.
The other one is greplin.com. And this is really cool; they've been around in beta and such for, I don’t know, months now, and they finally are open to the public. And it's web search for your accounts, that Google can't get to the index, is the way that I think of it. So if you have your Twitter account, or your Facebook or even your Gmail, you can hook all these things up to your greplin account and you go under greplin and you type in a search, and it will find you that tweet that you tweeted three months ago that have that in it.
AVDI: That is awesome.
CHUCK: Yeah, that sounds really handy.
AVDI: I had a service like that a couple of years ago, and they basically just decided to get out of that business.
JOSH: Yeah, so Greplin is awesome for that. Because the Twitter search only searches… it used to be that it only search stuff in the cache, so if it was more than a couple of days old, you just could never find it; you'd have to manually page back through things and remember who’s tweet stream it was in, etcetera. So Greplin is just awesome for that. That one feature alone makes it worth it for me.
JAMES: The Twitter search blows. Let’s face it.
CHUCK: Yeah, no kidding.
JOSH: [Chuckles] And then I'm going to sneak in a quick third pick here, just because it's so awesome. And so I read… I'm a big fan of Vernor Vinge. And he has this great novel years ago called The Fire Upon the Deep. And then had a prequel to it called Deepness in the Sky, but there is now a sequel called Children of the Sky, that is now available for pre order on Amazon. And it's coming out next month. So, I'm very excited.
AVDI: Oh my god, oh my god, oh my god!
JOSH: [Chuckles] I've been waiting over ten years for this book.
AVDI: [Chuckles] I know, right?
JOSH: [Chuckles] So it's going to be available soon.
CHUCK: What genre is that?
JOSH: It's science fiction, space opera, galactic whatever. [Chuckles] It's great.
CHUCK: You had me at space opera. All right, James?
JAMES: Okay, my pick this week is Peter Cooper’s new Ruby 1.9 walkthrough video. He sent me a copy of this just to kind of check out and get feedback on. I sat down to watch it and it really is good stuff. I'm going to recommend that people check it out. So basically, what Peter did, is just went through and collected all of the changes between current Ruby 1.8.7 and 1.9.2, and then a little bit on 1.9.3 what's coming down the pipe. And he also sometimes will even show a change that technically got back ported into 1.9.7, but it's just important that you need to know it's different. And this is an epic video. Like I mean, epic in scale; it's three hours running time. I don’t know about you, but I started having like palpitations when I look in to something that big.
And it is; it's not…. I wouldn’t say it's a light, fluffy, easy watch you go through. And pretty much the whole time, its dumping data into your brain. So it did take me some time to work through it and it's definitely a commitment. But I will say, there is some some massive amount of information in it. I'm going to do it, knowing Ruby 1.9 really well. Like I've studied parts of it probably to an unhealthy degree like in codings and stuff. And I was surprised by somehow I still picked up from Peter’s video. Things I didn’t even know were in Ruby. So I seriously doubt you can watch this and not learn something about Ruby 1.9. So if you are interested in getting up to speed on the future of Ruby, this is probably one stop shop and the easiest way to do it.
CHUCK: Even the deep intelligence of James Edward Gray was not enough. [Chuckles]
JAMES: I was challenged. So yeah, I definitely recommend watching it. It's a good stuff.
CHUCK: All right, Avdi go ahead.
AVDI: My picks this week are going going be Linux stuff for the ten people that Linux and Emacs stuff ten people that are using one of those platform. And yes, Emacs is a platform, not an editor.
CHUCK: [Chuckles] So true.
AVDI: All right, so my picks this week are going to be obscure Linux stuff, for like the ten people that are… Linux and Emacs stuff… the ten people that are using one of those platforms. And yes, Emacs is a platform; not an editor. Its an operating system. So one pick is KdenLive, which is of all the buggy and underpowered video editors on the Linux platform, it is the least buggy and underpowered one that I've been able to find. And I've been able to more or less able it to hammer it into submission at this point. And I even made my first video with transitions and zooming last night, so I'm kind of happy about that. And once you get the hang of it, it's actually not that horrible, except when it crashes.
Now, this one is even more obscure but it made me so happy that I had to pick. Some people know I do like all of my book writing and talk writing and stuff like that in Emacs org mode, which is like kind of like an outliner on crack. And the one hold in this chain recently has been I really didn’t have a good solution for writing for my blog. And I did a lot of hacky stuff, but mostly I just wound up writing it into the wordpress composition window, which isn’t that great of an experience when you are used to working in a decent editor.
So there's a package somebody put together called Org2Blog, which just lets me post Org files straight to WordPress. And its amazingly well done because it lets me adjust texts into categories and the post date. And even this bit amaze me; and even if you have images attached to your org files, it actually uploads them in the background and translates the links into the live links on the website. And so, I basically have achieved blogging nirvana at this point, because I never have to leave Emacs. So I'm super, super happy about that. And for the one person listening that is using Emacs and org mode and wordpress, hopefully, this will make your day.
CHUCK: I think David will be happy, because I know he uses those.
CHUCK: All right, it did sounds handy to me. Now, when are they are going to port that to Vim?
CHUCK: Yeah, that’s about what I expected. All right, my picks this week, I've been teaching my Rails Rails basic course and I found some software that I wanted to bring up, that has really been handy. Now, I have to disclaim that I actually know a lot of the guys over at this company that has built the software, it’s called Instructure. They are located here in Salt Lake City. I worked with most of those guys when I was working at Mozy. Ad their CEO is actually the old CEO of Mozy. But anyway, they have a product called Canvas and they actually have open sourced it. It’s built on Rails 2.3.8, I wanna say. And its web-based learning software. I mean, they make their money from going the big universities and stuff and selling to thousands of students, and making the universities pay them lots and lots of money.
But one way that they are trying to get customers is by open sourcing the software and so, small businesses like mine can actually set it up on a web server and just use it. And so I've been using it and its been amazing. It has a discussion. It’s kind of a discussion forum. It’s got assignments, discussions, grades, you can look and see who is in the course, you could set up… they have kind of a little wiki that you can put course material into, you can edit the syllabus, you can organize things into modules -- all kinds of stuff. And it’s really super easy to use. So if you've ever used blackboard and you know what a nightmare that is, this is like coming to heaven for your education stuff.
And I've been embedding all of my videos -- this is my other pick -- through Vimeo. You can set it up so your videos are pretty much private, and can only be embedded on sites that you want it to be, unlike YouTube. I haven’t been able to lock it down like that. You have to pay for it, but their player is a lot nice I think than YouTube’s. And it will convert to html5 if you are hitting it from mobile device or something like that. So it’s really, really handy that way.
And I'm also doing weekly webinars as part of the course, and I'm going to be using… for that. I've only ever been an attendee in go to meetings, so I´ll let you all know how that went next week. But those are the products that I am using for this. And so far it’s been like flawless, so I just through I’d share some of the things that I am using there. And if you are looking to setup a course like this and you wanna use Canvas, I'm happy to help you out with it.
So anyway, those are my picks. And that’s pretty much it for this week. So next week, we are going to be talking to Kent Beck about Smalltalk Best Practice Patterns, and we'll talk about all the stuff that we didn’t talk about in this episode. [Chuckles] Because we did that a lot. And I wanna thank our panel for coming. In no particular order, we have Avdi Grimm…
AVDI: Happy hacking!
CHUCK: James Edward Gray.
JAMES: Hey everybody, see you next week!
CHUCK: Josh Susser.
JOSH: That’s all folks!
CHUCK: And I'm Charles Max Wood. If you have any suggestions for us, go ahead and go to rubyrogues.com and click on choose a topic. We've had some request to add episode numbers to the podcast, so we've done that. The picks are all on their own page. I think we are missing last week’s and this week’s, so we'll get those in there as well.
JAMES: And by the way, this is Episode 22.
CHUCK: Yeah. And anyway, if you have suggestions like that, you can also reach out to us on Twitter. I have been running the Ruby Rogues Twitter account, so you can link suggestions there, but I know that some of the other panelists also receives suggestions, and they let me know or whoever know what needs to be done there. So again, if you have any feedback, go ahead and do that, and leave us a review in iTunes. And that’s all. We'll catch you in a week. Thanks!