RR Ruby Antipatterns
- Published on:
- rescue nil
- Exceptional Ruby
- terniary operator as a guard clause
- Law of Demeter
- mixin modules
- "Never use a symbol to do a method's job!"
- inheritance from Core classes
- inherit from Struct.new(...)
- terniary operators that cause side effect methods rather than simply returning values
- test ? true : false
- !! for boolean
- Don't override #nil?
AVDI: We already do Ruby antipatterns.
AVDI: We did? Or we didn’t?
JAMES: We did, ‘What's Wrong with Ruby.’
JAMES: Yeah, but I don’t think that’s really Ruby Antipatterns.
JOSH: Yeah, Ruby Antipatterns would be like, “Class variables.”
JAMES: [Chuckles] Class variables. Yay!
JAMES: Rescue nil.
CHUCK: I think my favorite is you have a constant -- which generally implies that it's constant -- and then you can go in and define constant.
JOSH: Yeah, constants aren’t variables. Don't. Can we do a coherent episode on that without prep for it?
JAMES: Oh, hell yeah. I mean…
Anytime you've run in to this horrible Ruby thing that scares the crap out of you, you know? Right?
CHUCK: There are lists of pet peeves, and then there's Jame’s master list.
JOSH: Well I´ll just sit here and listen to James rant for an hour.
CHUCK: “Hey why do you do this? It makes me so damn mad!”
JAMES: And if you do that, we'll come to your house, and take your keyboard away.
CHUCK: Hey everybody and welcome to episode 32 of the Ruby Rogues podcast. This week on our panel, we have Avdi Grimm.
AVDI: Hello, hello.
CHUCK: We have James Edward gray.
JAMES: Hello everyone.
CHUCK: So, I'm back from the dead. I was sick last week. We also have Josh Susser.
JOSH: Hey, good morning everyone. I'm almost here.
CHUCK: [Chuckles] All right, so this week we were chatting for quite a while about what we wanted to do for topic, and somebody pointed out that this tweet by Jeremy, basically saying, “What’s your least favorite Ruby antipattern?” And so we started talking about it and we realize that we have a pretty good episode for this, so we are going to talk about some of the stuff that people do in Ruby, that drive us crazy. So, I think James had the longest list, so why don’t we have you go first, James?
JAMES: [Chuckles] Does that mean James is the most angry among us? I'm thinking. It's probably worth mentioning for those of you who are expecting the Eloquent Ruby episode this week; we were too, but we screwed up our scheduling, sorry. We apologize. So we've rescheduled for next week. So we have one more week on Eloquent Ruby; if you haven’t finished it up yet, go ahead and do that. We'll put the link to the page on our site, where we are collecting questions, so feel free to give us questions you'd like us to ask Russ. And we'll talk about Eloquent Ruby next week.
CHUCK: Yeah, if you have questions, you can also tweet them to @rubyrogues on Twitter.
JAMES: That’s a good point. But this week, we are going to talk about things in Ruby that drive us crazy -- as Chuck said, inspired by Jeremy’s tweet. So my respond to Jeremy’s tweet was the rescue nil statement modifier. You just have some statement, and you tack a resque nil on to the end of it – that was my initial reaction. Maybe we should get Avdi to tell us why that’s evil, since he’s actually written a book on the topic.
AVDI: So the reason that's evil is because you can hide a lot of things with it; you can accidentally mask exceptions that you did not expect to mask. And it may not be obvious to the reader that you are doing that, because that rescue nil can be all the way at the end of the line -- god forbid that line might be 120 characters long or something. And you are getting a nil back, and really, it's an exception being masked but you did not realized you were masking.
Now for a while, I thought that rescue at the end of a statement was just an antipattern, period because of this. Because it’s pretty much the only thing that people use it for. But I realized that there’s actually at least one kind of cool use of rescue at the end of a statement, which is rescue $! Or rescue error info, if you are going to pull in the English library, which that’s a nice little idiom for converting runtime errors, into return values.
So if you want to get the error info back, but you just want to inspect it rather than raising it up the call chain, you can stick a rescue $! at the end of your statement. And now, you are either going to get the regular return value of that statement, or you are going to get as return value, the exception that it would have raised, or that it tried to raise.
CHUCK: Right. To me, I kind of have this analogy, where you've got some guys smoking in the bathroom, and that happens regularly. So, you set up this rescue; you just go turn off the fire alarm, because you don’t wanna evacuate the school because some idiot is smoking in the bathroom. But when the stage catches fire, you don’t wanna turn off the fire alarm; you wanna know what's going on, so you know you have to evacuate the school -- or kill the program.
AVDI: That is the perfect analogy.
JOSH: Chuck, it sounds like your high school years were more interesting than mine.
JAMES: I was thinking of the same thing.
JAMES: But one of the problems I have with rescue nil, is with the statement modifier version of rescue, you are not allowed to specify the kind of exception you want to rescue. Rescue just defaults to standard error -- which is a very broad category, covering a lot of exceptions.
JOSH: But not all of them.
JAMES: But not all of them, right. Good point from Josh, there.
JAMES: But it's a very broad category. And ideally, in your error rescuing, you're rescuing just the errors you care about. And so, generally, defaulting to a broad rescue statement is going to be bad. And what invariably happens is you do it because you ran in to some error, and then later, some code gets changed under there, and starts throwing another error, but it's masked by the fact that there's rescue statement returning a harmless value there -- or maybe harmful value -- in the case of nil, actually is probably more harm than good. But Rails has been guilty of this at many points in its life cycle; swallowing exceptions and turning them into things that are not helpful at all, and hide the actual problems. So I think it's just best to avoid altogether.
CHUCK: Yeah, one other thing I wanna point out is that to me, this is kind of a code smell, because effectively, most of the time when you see something like this, it isn’t because they are getting error they want to ignore, they are getting error they don’t understand. And so it's a code smell because it's an indicative of the fact that you really don’t understand what the code underneath is doing. And you need to be able to understand that and know exactly what you're rescuing from, and exactly what you wanna under those circumstances.
JAMES: All right, I don’t wanna be the only guy to rant, so somebody else say something that bothers you.
JOSH: Oh, I can do that. I guess we should start with some of the more basic ones. So I think that the proper idiomatic way to do a guard for a nil value before you try and access it, is not using the ternary operator. So you often see like, user? user.name:nil. And the proper way to do that in Ruby is…
JAMES: Just use ‘try’, right?
JOSH: Oh my god, I'm going to strangle you! [Laughs]
JOSH: Try is other thing that I wrote down here as the anti-pattern. Try is horrible. The proper way to do that is user&&user.name, which is great, because you can do user&&user.name&&user.name.upcase, if you really wanna do chain these things. But no, just using the Boolean combinations like that is so much cleaner in Ruby.
JAMES: Agreed. Definitely.
JOSH: That’s a cute little one. But on the heels of that, I really hate try, and it's ironic, because I actually patched Try in Rails to make it better. But no, I think Try is sort of on the level of rescue nil, in that it's optimizing the case that you don’t wanna optimize. You don’t wanna set your code to in the direction of hiding all the information that you need to deal with the exceptional case in your code.
CHUCK: Yeah, and on the heels of that, I kind of want to… one thing that bothers me is when you see that over, and over, and over again, that same guard, whether that’s a&&a.name or whatever, if you are doing that all over the place, put it into a method. I mean, you know, it doesn’t take that long. But then you have that everywhere, and then you can do a.name whatever you wanna call it, and just know that it's protected, and then you'll get nil back if you don’t expect… or if you expect your object to possibly be nil.
JOSH: Well then this just falls right in to the law of Demeter, where if you have…
Uh-oh, we are getting some feedback from someone’s mic.
DAVID: It’s not me. Oh, by the way, hi guys!
JOSH: Hi, David.
DAVID: So I hear you guys are still doing this podcast.
JOSH: You know, you should do it with us sometimes.
DAVID: I thought today I’d show up fashionably late, instead of fashionably not at all.
CHUCK: So our guest Rogue this week is David Brady.
DAVID: Woohoo! I'm doing a half ass podcast, instead of a full ass podcast.
JAMES: So David, we are discussing Ruby antipatterns, which basically means we get to rant for an hour.
DAVID: Oh, sweet!
JOSH: [Chuckles] This show was made for you.
DAVID: Oh, yes.
JOSH: Can I finish what I was saying about Demeter?
JOSH: Okay Chuck, I like what you were saying, and that’s actually right along with the law of Demeter is that instead of saying like user.name&&user.name.upcase, you can have like user.upcasename, and that will take care of dealing with the name object for you. The law of Demeter just says you only talk to your arguments or… Avdi, your worship, could you articulate the law of Demeter for me this morning?
CHUCK: Hand that man a scepter.
AVDI: And a pair of Harris nails. I am actually wearing my golden bikini this morning. It's funny you should bring that up.
AVDI: [Laughs] Do that way too well.
AVDI: I feel that we may have a nerd in our midst in this programming podcast
DAVID: Find the witch! Find the witch!
AVDI: [Chuckles] What were we talking about?
JAMES: The Law of Demeter.
AVDI: All right, the Law of Demeter, as expressed by the galactic senate is that…
It's basically a way of limiting the number of types that a specific… it’s a guideline… sort of rule of thumb for limiting the number of types that an individual method interacts with. So it basically says you can play with your own toys, the toys that you make yourself; you can play with toys that other people give you, but you can't take them apart. And that kind of limits you to working with the types that are directly passed into or that you own yourself, but not with the type that you get from calling a method from calling it a method, and from calling it a method deep down into some other objects composition hierarchy.
JOSH: Right. And the thing that I was talking about, which is totally in alignment with the goals of Demeter -- although not explicitly expressed -- is that, when you don’t do that a.b.c.whatever chaining of methods, then… I mean, breaking everything out into that chain, means that you are making assumptions about the internal structure, effectively, of other objects. And it's better to let those objects handle their own internal structure. So, rather than asking object A for object B, and asking object B for object C directly, you say, “Object A, give me the C object from somewhere deep in your guts, and you'll know better than me.”
AVDI: Right, exactly. At the very least, use different methods in your class for dealing with the different levels of object, so that when that structure changes, you don’t have to rewrite every single method in your class, because every single method in your class expect it to be able to sort of step down through that entire structure.
JOSH: Yeah, I think the law of Demeter is the thing that most programmers roll their eyes at when you bring it up, and they are like, “But it's just so easy to chain all these methods together.” And well, then yeah sure, then you clean up your code whenever somebody changes one of those things.
DAVID: What I love is when you talk about the Law of Demeter, you will get some… I don’t know how to say this without getting political, but basically, you get some complete anarchist nut job on your team who says, “It's not a law!” And that’s the end of discussion, right?
DAVID: You can even have a discussion about what Demeter means, about what it is; they heard the word “law” and they are like, “Screw you! I'm doing it my way!”
AVDI: So for the people that are like punching their fist in the air listening to that right now; just to make it clear, the ‘law’ terminology in the law of Demeter refers to the fact that it is quantitatively observable -- I guess might be the term -- that when you couple your code to other object structure in this way, violating Demeter, then various ill effects emerge. And when you don’t couple it that way, then experience shows that various sort of good effects… other good OO qualities tend to just sort of emerge just by forcing yourself to follow this guideline. So it's a law in the sense that you can observe that gravity works.
JOSH: It's intelligent falling. [Chuckles]
DAVID: I like it.
JAMES: If anyone is doubtful that the theory of gravity is accurate, please throw yourself off your roof and if you survive, have your wife send a picture to the Ruby Rogues, and we'll remember to retract this statement.
DAVID: Screw Ruby Rogues; send it to James Randy, he'll give you a million bucks.
JAMES: That’s right.
CHUCK: And if you amamnge to throw yourself off and miss, well you just figured out how to fly.
DAVID: How to fly, yeah. So on the Law of Demeter…. And by the way, my response, it's not a law, “Yes it is!” But anyway, one of my favorite antipatterns -- and this anti pattern that you already be in a state of sin, because you are breaking the law of Demeter -- is that in Rails, we have the try method, so you can say user. try: city. And if user is nil, then this will return nil; but if user is a real user object, then get the city from this person. This is actually a corner case of this… the general case of this antipattern is I hate sending a symbol to do a methods job. I also hate sending a symbol to do a classes job.
DAVID: Yeah. But if you are going to break the law of Demeter, get the ‘andand’ gem, and stop using the try method in Rails. And the reason why is because you can type user.andand… because you can't overload the && operator… user.andand.city, and if user is null, that will return a basically a null object that is a wrapper that you can call a city method on, and it will return nil -- and down the road you go.
And because I would be mean if I didn’t take everything to a perverse extreme, I actually built a gem a few years ago. It's gone from the gem index mercifully, maybe I´ll put it back. But I wrote a gem called turtles! And what turtles lets you do, is it lets you have nil all the way down. So if you violate the law of Demeter… there's violating the law of Demeter, and then there's gang raping the law of Demeter. And turtles lets you do the second one.
If you turn on turtles, it turns every single call into… basically it wraps more method error on nil, so that you can literally call user.city.mayor.children.first.lastname and if any of those objects Is null, as long as you did it in a with turtles block, it turtles all the way down. It just works just great.
And so, that’s one of my favorite anti patterns, because I deliberately wrote it to be an anti-pattern. I´ll post a link to that, where you can get that from GitHub. It's horrible. It's got good specs on it by the way. And I am astonished how so many people have written back to me in horror at the turtle’s code, because they believe I was serious when I wrote it. And that boggles my mind.
CHUCK: Break the law or break the line style, huh?
AVDI: Do you get people writing back saying, “Oh my god, this gem is so awesome! Thank you for writing it and I'm using it in all of my projects.”
DAVID: Yeah. [Chuckles] I´ll just write an auto responder that writes back and says, “Can I help you?” [Chuckles]
JOSH: So David, you just admitted giving into the dark side.
DAVID: Oh, I don’t give in. I jump in with both feet.
JAMES: David likes to wait in the dark side.
DAVID: Oh yeah.
AVDI: I worked on a project once, that ahead that had something like that, it was called ignore nil, and it was a block just like that. And all it did was suppress no method error. It didn’t care where the no method error came from, it just suppressed no method error.
JAMES: Oh my god.
AVDI: And this was all throughout the project. You would have huge, like sections of a code, that were covered by ignore nil… no misspelled methods would ever signal with that.
DAVID: [Laughs] So with ignore nill. That’s actually a brilliant refactoring. I've got all these duplication. Every single line of code ends with rescue nil. That’s duplication. I should get rid of that. [Chuckles]
JAMES: All right, so we have not heard an anti-pattern from Avdi or Chuck.
CHUCK: I´ll just wait Avdi out.
AVDI: [Laughs] All right, so my favorite is unless… else… I mean, unless is great. Unless is the inverse of if, and I think it can be quite readable sometimes. But then you take an unless, and then you violate it by tacking an else at the end of it. Now if you can read an unless else, and it just makes perfect sense to you, then you are a Cylon. You are not a human being.
JAMES: [Chuckles] Wow, that’s Star Wars, BSG, Hitchhiker’s Guide to The Galaxy.
AVDI: It's some kind if cyborg detector. It's a replicate detector.
DAVID: I just watched Blade Runner two nights ago.
AVDI: That’s one of the replicate test; they flash an ‘unless else’ to the person’s eyes, and if he doesn’t recoil in horror, then he’s clearly a robot. So yeah, don’t do that. Just don’t.
CHUCK: If you are not a robot, then you might not be a human.
JAMES: Just in case it's not painfully clear: if you are doing unless… else, you can just switch it to if…else, and reverse the two classes.
JOSH: [Chuckles] Okay.
CHUCK: So there’s else, and then else else, right?
DAVID: I confess, I have written code that most clearly read to me as, “If not (some condition) do this, else… do this other condition” And the reason I did it that way, is because the if not condition… if not failed, and so I wanted the positive case, the happy path to be at the top, in the top block, but yeah, I didn’t write unless there…
AVDI: There's nothing wrong with that. You should be… there's no need to be afraid of the not operator at all. I mean, yeah, if you string a ton of them together, that’s going to get confusing -- nobody likes multiple negatives. But if it's between using unless else, and just tacking a not on the first condition, use the not.
DAVID: Ain’t nobody doesn’t like multiple negatives.
JAMES: [Chuckles] Yeah, basically I think anybody who writes unless else… needs to be forced to use it in a sentence.
CHUCK: Unless not else, not. Anyway, so for that one, think my biggest pet peeve is when people misuse method missing. This is something we discussed when we were discussing some of the antipatterns. The big thing for me, I mean for one, I think we were talking about it when we were saying that if you have a list of like defined messages that you want your object to respond to, then you should be able to just loop through them with define method.
But I've actually found people effectively defining methods and method missing, where they actually know the signature of the method that they need to define, rather than define method. They can actually just go in and def this… do this other thing. And it blows my mind how many people just, that they use it, when really, you want that method to show up in the objects method signature. You don’t wanna hid it down the method missing, where who knows what it's going to do.
AVDI: Closely aligned with that, defining method missing without defining respond to.
JAMES: Although I just learned from an exchange you have on Twitter yesterday Avdi, I did not know this before yesterday, we have a ‘respond to missing.’ And so if it goes up the respond to stack, and doesn’t find anything, it will call respond to missing, so you can override respond to missing as you do method missing, which is kind of weird because I guess that exists for parity, which is kind of cool.
But you know, the thinking there would be that you could probably get a way without doing super, but then Avdi came back and said, “Well, not really because all good method missing implementations need to call super anyway, so that you pick up any other included modules or anything like that defined their own,” so same thing with respond to missing.
AVDI: Well, that was a special case. So that was in the context of the hack I posted today, which was actually yesterday… which was a trick for defining method missing in respond to, at the same time using a macro. And because of the way that works to behave well, it needs to call super in respond to missing. I do like the fact like if you are just doing an ordinary class that needs to do some kind of proxying or something, and so you have a simple method missing, it makes sense to define respond to missing and you can avoid the super if you know you are not doing anything super fancy in that class. My thing had to do with having lots of modules -- all of which define respond to missing -- all included in the same class.
CHUCK: So what you guys were talking about reminds me of another pet peeve that I have, and that is people that don’t call super when they monkey patch or inherit or whatever. It drives me crazy. And the reason that it reminded me is because sometimes people don’t call method missing, or they don't call super or method missing, and then you don’t get the no method error return, when it doesn’t respond to the message being sent to the object. But ultimately, you need to be calling super, because usually there's stuff that needs to happen, maybe a level or two up that you didn't define. And especially when you are mixing in modules. I mean, then you are just asking for trouble, if you don't.
AVDI: And it's not just for monkey patching. I mean, just in general, it's a good idea if you are going to be sub classing something, or including modules, it's a good idea to get into the habit of calling super -- specially in your initialize method -- but often in other methods as well. And if you are in a method where you are concerned, that you are not going to be able to call that super… super is going to explode because there is no super, you are not sure that there is a super, because you are in a module or something, you can use the define, the define operator with super to ask Ruby if there is a super for this methods. You can say define ? super… and or if define ? super then, super.
JAMES: That’s an awesome trick. I didn’t know about that one until recently. But define its keyword, so if you are expecting it to be one of the normal methods in Ruby, it will surprise you, it has very specialized behavior. And if you pass super to it, it will basically answer the question, “Do I have a super method to hand off to?”
DAVID: I almost have to wonder if respond to missing isn’t an attempt to optimize the speed of method missing, because if respond to missing works by just going up, we checked the class, we checked the super class, we check the super, super class, and then we call respond to missing. Where like the 1.8.7 implementation, we checked the child class and then we ask method missing. No? Then we get to the method class, and then we check it for method missing and then we go to the grand parent class, and then we check it for method missing. I guess that would work anyway. You'd still have to do that anyway.
AVDI: It's still doing that. It's a programmer optimization for not having to remember to always call super in your respond to.
DAVID: I see, okay. That also gives you an advantage that your respond to missing is going to be as late as possible in the method missing chain.
JAMES: So we have several more we wanna go over, but David did have a really good one earlier that I would like to hear him elaborate on. So David, tell us what you mean by, ‘ never use a symbol to do a method’s job.’
DAVID: Okay, you are only saying that because I whined about it in the back channel. Thank you. Now know that whining in the back channel works. But no, just really, really quickly, like the ‘andand’ gem, I love because you can call like x.&&.foo and pass it whatever arguments. And I hate the try method where you call x.try, and you pass it the symbol foo. And the reason I hate… I call it ‘don’t send a symbol to do the methods job’, the reason I hate this is because you know that the foo method exists, you know it's a real method, you know it's a real thing, go ahead and call it, keep treating it like a method.
And if you want to see this in action, use the try method, to assign a value to a hash, that might be nil. Because you have to call like hash.try:[close]=,some value… and trying to access the value of it, same problem. whereas with &&, you say hash.&&[… and you type in your value and then close bracket… equals key close bracket equals value. And Curtis talked about this on Twitter recently. He ran to the similar problem, where never say render:my renderer, when you've got the my renderer class right there in the name space. Just actually type the name of the class; MY Render pass the class name in that place.
Now if this is in a YAML file, or this is in something that serialize where that class doesn’t exist, sure. Go ahead, knock yourself out. Go ahead and use symbols, because that’s what a symbol is for. It's meant to symbolize something. But if you are in the Ruby namespace, and those objects exists, use the objects. Don’t put names on them, than you then later have to decode, especially in case of methods, where the decoding and encoding has a different syntax; it actually looks and behaves differently than the way that the actual method call looks like. They are equivalent but they are not identical with…
JOSH: So Ruby is not exactly Lisp. And it's not IO, actually Steve Dekorte's language IO… the representation of executable code, and the talking about code at the meta level, they look the same. So it's kind of crazy, you almost don’t need blocks. Anyway.
So I have a rant – I'm sorry -- an anti-pattern. And that’s inheriting from array or hash, or just other core data types in general. There are definitely cases where you wanna do these kind of stuff, when you get expert level. Like I've inherited from module, to create specialized kinds of modules that have extra behavior. Once you know what you are doing, sure why not. But in general, you don’t wanna inherit from an array; you wanna take an array and put it in an instance variable on object, and then delegate those particular array type behavior that you care about exposing.
DAVID: But Josh, I have all the methods on enumerable that I have to implement now.
JOSH: Yeah, screw you.
DAVID: [Laughs] Good answer.
JAMES: Josh is right, and there are some severe gotchas for doing so. Ruby takes some shortcuts in the system, mainly make things go faster, and so, there are cases where you can, for example, say you inherit from string, and you put some code in the initialize to setup some instance variables for something you are going to try. The problem is there's ways to get strings in Ruby without the initialize method ever being called.
For example, if you do gsub on an existing string, then you get another string back, but gsub is not… initialize is not called on the string return. And there's other behaviors like this, where Ruby cut certain corners for the sake of speed or whatever, so if you are relying on those core classes to behave exactly like your classes would, you are going to be surprised.
JOSH: Yeah, and actually in some of the 1.9 work, they have been changing how things work on array, and when you get like, when it creates a new version of the array, and when you get back the old array side affected or what have you.
AVDI: Yeah, you have confusing stuff like, usually as simple as add two arrays together, use plus to add two arrays together. And suddenly, you don’t have your special array anymore, because it created an original flavor array, rather than your special array for the concatenation.
CHUCK: Yeah, I wanna point out that the code retreat, I actually sub classed array for Conway’s game of life, which…
CHUCK: Yeah… [Chuckles]
DAVID: Chuck, what happens at code retreats, stays at code retreats.
JAMES: That’s right, yay!
CHUCK: Yeah, the thing is yeah, even then, it made me uncomfortable, because I didn’t completely understand everything that goes on with array, and delegations seem like a better way of going. But anyway, the guy I was coding with, his thing was finally just… and I got tired of arguing with him, but basically, it was, what we are going to throw away in 45 minutes. And you know, we just wanna get this done fast, so that we can move on to other parts. But you know, if there is any chance you are going to keep that code, I'm with you guys on this.
DAVID: If you got to code retreat, you have 45 minutes to write a piece of code, the whole reason you are there that day is to learn better ways to do code. And to walk in to a coding exercise and say, “I'm in a hurry, let’s do this like crap.” I don’t know if you are fired, but maybe you should leave the code retreat.
AVDI: I'm actually going to go out on a limb a little bit here, and say that in Ruby… you know, inheritance itself, can kind of be an antipattern. I mean, it's one of those things that you really think twice about. Other languages, you just have to inherit if you want to get things done, but I've seen so many cases in Ruby of code that really, there was no reason to have that base class there. It can easily have been a base module, and it's actually very rare that inheritance makes sense.
JAMES: I was just going to agree with that, but I think we rely on inheritance a bit too much in Ruby. It's funny how a lot of the things you need inheritance for in other languages, just don’t apply in Ruby, because of duck typing and stuff like that. So you just don’t need it that much. However, that said, there are cases where inheritance just makes a heck of a lot of sense, and it is exactly what you want. And some Ruby programmers actually get to the habit of avoiding it so much, that they do some kind of crazy things to avoid inheritance.
In fact, since we are going to talk about Eloquent Ruby next week, there’s just a couple examples in Eloquent Ruby I don't like. And there's one in a delegation chapter later on, where he inherits from a simple delegator, and then passes that to a class, so class less than super delegator and inherits from something. And does all this. This is the most complicated way I've ever seen to reproduce inheritance. And it has no benefit that I can recognize. And so in that case, just inherit. You know. If you need to inherit, then you inherit. But yeah.
JOSH: So the flip side of that is another pet peeve of mine, and that’s explicitly checking the type of an object – usually an argument. Yeah, it's like, don’t ask the object what it's class is, you know. Do a respond to for a particular method, that you would expect that class to implement, or don’t. [Chuckles] Yeah, because there's a lot of different ways to deal with it.
Sometimes, I will invent my own notion of types, and just throw some predicates on particular classes, So monkey patch special ? in the object, and have it return false, and then I´ll put special ? into a couple classes that I wanna note, is being the kind that I care about. Avdi’s trick with mixing in modules of type tags, is something that you can do, if you are not on a cranky version of Ruby that makes that really slow.
DAVID: So we are talking about duck typing right? I actually to drill home that point of, “Don’t check the type, don’t check the type,” I have rephrased a lot of duck typing as this, “If it quacks like a duck, and it walks like a duck, you are not allowed to give a crap what it is.”
JOSH: [Chuckles] Right. Okay.
JAMES: The one you just did Josh were… oh, checking the type of the class, I always think of that one as space balls when he has little fit about, “You are always preparing. Just go!”
JOSH: [Chuckles] Yeah.
JAMES: Stop preparing. Just go! Just call the method. Just do it.
JOSH: So James, do you wanna do the inherit from Struct.new(…) or should i?
JAMES: No, I´ll definitely do it. This is definitely one of my pet peeves.
JOSH: Okay, go for it.
JAMES: Struct.new(…), when people are making structs all the time… this is similar to my simple validator example. They do class less than and then they define struct new right there on the super class -- don’t do that. It's stupid for a lot of reasons: one, it causes all kinds of problems with all the crazy reloading code we have everywhere, because every time your class gets reloaded, then you get a new super class, and so you get a super class mismatch error.
The main reason not to do it, struct was built for sub classing in mind, and it takes a block. Struct.new(…) takes a block. And it just runs it to the context of that class, so you can just do struct new, and put a block right there and define methods directly in it. So there's the reason to do that, and you get the class you want. And then you can assign it to a constant, and there you could use or equal if you need to, and then you handle the reload in case as well. So anyways, don’t use struct as a super class on supervised lines, just give it a block, and define your methods in there.
CHUCK: In my code, they need a de-struct.
JAMES: We got to do the ternary operator real quick before we do picks. We have lots of things to say about it.
CHUCK: Oh, okay.
JAMES: I didn’t mean me.
AVDI: [Chuckles] Yeah, so this is kind of a pet peeve of mine, that I just find out that apparently, everybody here shares it. So if I see a ternary operator, a ternary operator being the operator that takes three arguments with the question mark and the colon – works like an if then else. If I see that, I expect it to be a truly functional expression, that is an expression that just returns a value, and doesn’t have any side effects. And if you put some kind of side effect expression in there, so you use it as a switch for control flow, I get confused and annoyed. And I really prefer to see that, if it's going to be control flow like that, I prefer to see that as an actual ‘if then else.’ So that’s just a peeve of mine.
JOSH: Totally agree.
JAMES: Yeah, I mainly only use the ternary operator when I'm assigning a variable, right? So it's just to return some value that I can shove to a variable.
AVDI: And it's one of those things. it’s not like Ruby is going to bite you for using the ternary for that, it's just one of those programming convention things where certain constructs tell you something about what the programmer had in mind. And generally, when I see a ternary, I expect that to be just a logical expression.
DAVID: Yeah, and we all agree that you should not nest your ternary operators more than five levels deep, right?
CHUCK: Just five?
DAVID: You got to draw the line somewhere.
CHUCK: As my five year old would say. “Aww!”
JAMES: Another thing on the ternary operator -- I see this all the time -- where you have some test ? true : false. Don’t do that please. Don’t do that, okay?
CHUCK: Yeah, it's better than true : nil.
JAMES: [Chuckles] Yeah. if you find yourself doing that. First, slap yourself on the hand with a ruler, then just select from the question mark on, and push the delete key, okay? You can just get rid of it all together, if you absolutely have to have a Boolean, which I almost never do, but if you think for some reason you really need a true or false, stick a !! in front of a test, and that will switch it to a Boolean.
DAVID: I have worked with an API where you had to return a Boolean. We were talking to a java server, and so yeah, we have that !! uservalid ?... and because for whatever reason, valid didn’t return true false, it returned, these objects or return nill. And !! turned it into true or false.
JOSH: Yeah, it's like define. That doesn’t return true or false.
JAMES: That's right. Define returns a lot of interesting information, like types of variables and stuff like that. It's pretty cool to play around with.
JOSH: Mh-hm. So okay, I have something that I actually run into in somebody’s code, that I was dealing with that was completely mystifying. So along these lines, nil is a false type value. So you always do stuff like, if user blah, blah, blah, and so you don’t have to say like… you wouldn’t say ‘unless user.nil ?’ or ‘nil p’ as we used to say -- I'm not explaining that, by the way. So you wouldn’t say like unless user.nil, you'll say ‘if user.’ But there's this pattern in object in programming called the null object pattern, where instead of sprinkling your code in say the user class with all of these or even worse, your controller class that’s using these requests, that instead of sprinkling all these conditionals through that code, you take all those conditionals, and you bind them together in a null user class. And you have now embodied the user who isn’t logged in. And that cleans up all the rest of your code. It's a really nice pattern, that’s been talked about in a lot of other places. When you are doing one of these classes in Ruby, never ever, ever override the nil ? method. Because while you can make nil ? return what you might expect there, you say, “Oh, this is a null user, so nil should return true, because this isn’t a user,” that would be incredibly stupid to do that.
JAMES: Like crossing the streams.
JOSH: [Chuckles] Yeah. So now you can't say like if user, because it's not actually nil; it's not the nil value. And that’s the only special nil value that Ruby language knows about. You can't Ruby into thinking it's nil.
DAVID: And the whole point of defining a null user… a nil user, is so that you can say, “if user” haven’t returned true, haven’t returned the nil user, then you can continue operating on it. Yeah, it defeats the entire purpose.
JOSH: Yeah, you actually want to send messages to it. It's not nil. So just don’t do that. James will come to your house, and take away your keyboard.
JAMES: [Chuckles] Right. Yeah. if you violate any of these rules, you will see the Ruby Rogues on your doorstep. By the way, the nil object pattern, that one seems to throw people a lot. And it is a really cool pattern. And actually, if you've ever programmed Rails, you've most likely already used it. When you see the typical definitions in Rails, of the seven actions we usually put in controllers or whatever they are, the new action usually assigns just like @user=user.new, that’s the use of the nil object pattern. Basically, you are putting a dummy user in there, for the case where user hasn’t yet filled out the form, so you can call the methods like name and stuff like that, but those fields would be blank. So that’s a perfect example of the nil object.
AVDI: I would not call that a nil object.
JAMES: Really? Okay.
JOSH: Fight! Fight! Fight!
JAMES: Because why?
AVDI: Because it has logic. I mean, I've definitely had controllers where the logic in the blank user was used. And it has storage as well; I mean, you can assign attributes to it and actually carries them around. It doesn’t just ignore them.
JAMES: Yeah, I realize that it's not a special object -- which I think is what you are saying -- but the usage I believe is actually the nil object pattern usage, because what’s happening is you haven’t pulled out the form yet, so what you want is you want to be able to give the form some user and say, “What's your first name? What's your last name? What's your favorite color?” But you haven’t done those things yet, so you give it a user that has those things. They just all happen to be blank. But you know, it allows you to use the same user interface. So I believe the usage is the same, but I do see what you are saying in that, typically, a null object is specialized object you choose to return, to give a consistent interface, but it doesn’t generally have any kind of storage or anything like that. I definitely see that.
AVDI: Like I would expect… if I have a null user, I would definitely expect save to do nothing. Like I would expect it to prompt to save, but it would do nothing.
DAVID: A null object is supposed to be chemically inert. It will not react with any of your code. Most importantly, it will not react spectacularly exothermically with your code. Where if you supposed to fill out things and save it on it, that seems to me to be a very different thing than a null object. At least that’s my understanding. If you ask the system, “Who is the current user?” You might get like a null user, because there's nobody logged in. But you need to fill out the user form or the user login form, then go ahead and call user new because we are going to create this user… but the nil object is not part of the objects of a real object’s life cycle.
JOSH: I think nil objects are considered to be immutable.
CHUCK: Your mom’s immutable.
CHUCK: Okay, picks. We'll have David go first.
DAVID: Pretty JSON plugin for the Chrome browser. When you are looking at JSON, it colorizes it, breaks it out. It looks like you've run some awesome print in Ruby, dumps out all the JSON in a nice nested hashes of hashes of hashes of arrays, etcetera. It makes it look really readable. People that use it say they have one complaint with it, and that is that you can't copy and paste the json once it's been formatted that way. And the workaround for that is you just hit command option new, or control shift new or whatever to view source. And the Pretty JSON goes away, and you get back the source JSON that you can then paste to a string, and then throw it on a Ruby console and parse it and manipulate it.
DAVID: And that’s my pick. I like it. it's pretty. It's useful.
CHUCK: All right, Josh.
JOSH: So I have a very useful pick, which is the simpleform gem. So if you are doing a form helpers in Rails, form for whatever, simpleform is a much nicer way of doing that. So for a while, I was using formtastic -- which was pretty good -- but I discovered that I didn’t like how opinionated the markup was, and it made it difficult to do some things. Simpleform though, is sort of a much better formtastic in my opinion. It replaces the form for helper with simple form for, and then it has a lot of really smart helpers, to create the inputs into form.
And the new 2.0 release, which will be up has been using the master or edge or head or whatever you wanna call these days. I've been using the pre-release version and it's great; it has integration with Twitter bootstrap, which I mentioned as my pick last week, which is really nice. And has a lot of flexibility about you generate the markup, so I've been really happy working with simpleform and I recommend it a lot. And then I have a seasonal pick. And so we are coming up on cold and flu season, so I am… my pick is the neti pot…
DAVID: [Laughs] Yeah!
JOSH: [Chuckles] So there's a yoga practice…
CHUCK: I kind of grew on the neti pot…
JOSH: [Chuckles] Thank you. This is the other San Francisco practice. This is yoga. So there's a yoga practice called neti, which means cleansing I think. So it is cleansing your sinuses. So you can go to the drug store and find these like squeeze bulbs to clean out your sinuses. The more traditional, the other way of doing that is they have these things that look like little teapots and you fill them up with warm salt waters, and you wash out your sinuses. And I write this all the way to work in San Francisco and it's very like a petri dish full of people’s germs. So if I just brush my teeth, do my neti pot, I don’t get sick the way that everybody else gets sick. So you know, usually, If I let it go for a few days, and I feel like myself coming down with the cold, I´ll do neti pot, so I won't get the cold. So it’s a little uncomfortable until you get used to it. It's like brushing your teeth. You just got to do it. But it's so worth not being sick in bed for a week.
CHUCK: Been there, done that.
DAVID: Michelle Silverstein wrote a poem called, "There's a snail in my nose." And the first time you use neti pot, you'll meet the snail.
JOSH: Okay, I'm done.
CHUCK: [Chuckles] Avdi.
AVDI: I have got nothing this week. I have been wracking my brain, and I don’t know, I'm just not interesting this week.
CHUCK: Okay, James.
JAMES: I'll make up for Avdi's lack this week. I'm going with linksplotion. We'll see how this goes. I was reminded twice in November of a book I read a long time ago that I'd forgotten how much I absolutely love. It's called "Pragmatic Thinking and Learning". It's basically a book about how our brain works, and if you know that, you can use that knowledge to your advantage. It's tilted a little bit toward programmers. That makes it even more great and how you can use it to be more productive. I wanted to focus on one specific tip that it has. That's to get an exocortex, is how Andy Hunt, the author, describes it.
An exocortex is the idea that you need someplace where you can write all your ideas and thoughts down. Put them somewhere, so you can get them out of your head. If you're familiar with other productivity systems, that's a very common thing; getting things done has you keep these lists of things, to get them out of your brain, because they keep popping up into your brain and bothering you, and bogging you down.
Also, if you like Pomodoro technique, it has a similar thing, where you handle interruptions by writing them down and then getting back to what you're doing. If you are into Pomodoro, then Prags have a great book on that too, called "Pomodoro Technique Illustrated".
So, You need some kind of exocortex, your brain outside of your brain. A lot of people use Moleskine notebooks for that. That's great for them. I'm glad if that works for them. That doesn't work for me, I actually have to have it in the computer. A lot of people like not having it in the computer, but that doesn’t work for me. Although, I will say that if you are going to get into Moleskine notebooks, there are Star Wars Moleskine notebooks, which your worship would definitely approve of. That's an argument in their favor.
Anyways, what I'm currently using for my exocortex is Evernote, which is kind of a note taking program. It has a lot of features; I've actually heard that someone leveled a complaint against it, but it's got a lot of features. It's true that I don't use all of them. For example, you can put files and stuff in it. Not storing files in a file system is kind of weird to me, so I don't go quite that far. It can do things like audio and video notes. I don't do that, but it does have some features that I really love, as far as keeping track of things.
For example, it gives you an email address that you can fire things to, and then have those end up in your various note groupings. The reason I love that is that if a client sends me an email and says, "Can you take care of this, this, and this?", I just forward it to that special email address, and I can change the subject to be whatever I want, which ends up being the note title. It also gives you a way to embed some things in the subject to tag it with certain tags, or make sure it ends up in a certain notebook, and things like that. So I send that message over to Evernote.
Also, when I'm editing it in Evernote, Evernote will let you just basically put check boxes anywhere. Almost like you were typing it. Any old letter on your keyboard, you can type a check box, basically. So, then I go through the client's note, and type check boxes everywhere. They were like, "Can you do this and this and this?" Then I can check those boxes off, as I accomplish those things. I also have a safe search that will bring up any notes with check boxes that aren’t checked, which is basically my to do list.
I find it easy for keeping track of things I need to do. It also has some sharing features, so if you work with other Evernote users, you can share those ideas with other people, and kind of work together using those collaboration systems. For me, I like that about it. I would encourage people to look around though. I've definitely tried a ton of things, from using plain text files on my computer, to running a wiki. I found that was a little too much process for me. You should try and find what works for you.
Bare Bones has similar Evernote product called Yojimbo, so it may be that you would like that one. It's pretty centered on getting lots of different kinds of information into it, so it's very feature full. And for me, it just doesn't work for me as well as Evernote. So check it out.
JOSH: James, Yojimbo isn't hosted is it? It runs locally?
JAMES: That’s true. That’s the difference. Evernote is hosted service, so anything you save in Evernote is pushed up to the cloud by default. You can check that off if you want for certain things, but it's pushed up to the cloud. Then if you have your iPhone or your iPad, you can learn Evernote on hem and you basically looking at the same notes everywhere, whereas Yojimbo is not hosted, so it's all going to be on your computer.
JOSH: James, there is a podcast called Mac Power Users, and they did like whole hour-long episode about Evernote in October.
JAMES: Oh, sweet.
JOSH: And literally, the guy who wrote the book on Evernote was their guest, so they have like an hour of Power User tricks about using Evernote. If you are getting into Evernote, just listen to it. It's awesome.
JAMES: Sweet. So that’s a great source for people looking at it. Like I said, I have heard some people complain that Evernote is too heavy. And I saw kind of a conversation on Twitter yesterday, or the day before about some options, if you feel that way. There's a simple note app, which is kind of like Evernote minus a bunch of features. So if you do feel it's a little heavy, that might be one way to go.
Another app I've seen mentioned a lot recently, if you are really an outlining kind of person, Workflowy. And it's a big outliner, but they'll let you focus on specific parts of the outline and kind of treat those as individual notes.
So anyways, these are all various options that make for good exocortex kind of software. And I´ll put links to all those in the show notes. But I encourage you to look around and find one that works for you, because it's a massive difference. Okay that’s it, I'm really done.
CHUCK: So I guess I'm last. Nobody should be able to find my picks after James. Anyway, the things that I wanted to point out, I just got a new finder replacement because the regular Mac finder is awesome, but I don't know, sometimes do more stuff, and the one I've been using lately actually just bought it because I really love it, it's called Total Finder. And what it is, is it has a whole lot of features, but the ones that I've been using the most is does tabs in your window, so you get your finder window, and then if you open up a new folder or something, it will just open it up in a new tab, in your finder window, which is really cool.
And then the other really handy thing that it does is if you have two tabs open, you can actually merge the tabs, and what it does is it puts one tab on the left, and one tab on the right, and then you can drag and drop files between them and stuff. And it's just super handy. And so, if I have to move stuff around, I have to move stuff into my Dropbox, for my sub-contractors or for my podcast, for my virtual assistant to handle, I literally can just take them from where I've got them, usually on a digital audio recorder or something, and I can just drag them straight across, and then I can process from there and things like that.
So it's really handy. The place I learned about total finder, is a podcast called Business Tech Weekly, and you can get there at businesstechweekly.com. And that’s done by a couple of really cool guys, Cliff Ravenscraft and Andy Traub. And I've kind of been following them for a while, and I've gotten into a few other podcasts about running your own business, or going out on your own and things like that. And how to succeed, how to build products and stuff like that.
And so a couple of others that were kind of done by the same people, or by people who are related to them, that I just wanna mention are the 48 Days Podcast. That’s by Dan Miller; he wrote 48 Days to the Work You Love. So it's really just, if you hate your job, he helps you figure out what you want to do, helps you figure out how to find the job that will allow you to do that, put you through a whole bunch of steps, that don't involve going to job boards and things, which is really kind of an interesting approach, but it's kind of finding that job market that isn’t being actively advertised, and maybe getting your dream job because there are only a handful of applicants for that job.
And then the other two that I wanna mention are Free Agent Underground By Dan Son and Kevin Miller. And it's kind of a different flavor; they actually have a membership site where you can go and hook up with people. And they kind of walk you through a whole process of figuring out what your about, figuring out what business will work for you. Help you figure out the business model, and the marketing and all that stuff. And kind of runs you through that, so Free Agent Underground.
And then the other one is the No More Monday show, and that’s done by Andy Traub, who's on Business Tech Weekly. And Justin Savage, who used to be my business coach. So, just great podcast there and some great stuff you are looking at going at it on your own, either freelancing or building a product, and just some ideas on how to be a solopreneur or good small business entrepreneur. So, that's my stuff that Total Finder totally rocks.
So with that, we will wrap up. Again, on our panel we have in no particular order, James Edward Gray,
JAMES: Bye, everybody! Don't forget Eloquent Ruby next week.
CHUCK: Josh Susser.
JOSH: That’s all, folks!
CHUCK: Avdi Grimm.
AVDI: In conclusion, I pick, Obi-Wan Kenobi, because he's my only hope.
CHUCK: [Chuckles] David Brady.
DAVID: Just remember kids: I've missed you so much.
CHUCK: And I'm Charles max wood from teachmetocode.com. You can pick up the podcast in iTunes, you can also listen to it on your Android device, or whatever you listen to podcast on. And we really appreciate people leaving reviews in iTunes. If you have some feedback for us, you can also get us on Twitter @rubyrogues, or you can just email me firstname.lastname@example.org, and we are always happy to get your feedback and answer concerns, and take great suggestions. So that’s it. we'll catch you next week, with Eloquent Ruby.