Skip to content

Instantly share code, notes, and snippets.

@xdite
Created January 12, 2012 19:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save xdite/1602530 to your computer and use it in GitHub Desktop.
Save xdite/1602530 to your computer and use it in GitHub Desktop.
Ruby Rogues 032 Ruby Antipatterns http://asciirogues.com/

Chuck: We already do Ruby AntiPatterns.

James: No, that's a

Chuck: We did? Or we didn't?

Josh: No. We did what' s wrong with Ruby...

Chuck: Oh.

James: I don't really think that's really Ruby AntiPatterns.

Josh: Ruby AntiPatterns should be class variables.

James: Class variables. Yeah!

Chuck: I think my favorite is that you have a constant, which generally implies that it's constant and then you can go in and define constant.

Josh: Constants are, variables don't. Can we do a coherent episode on that without prep for it?

James: Oh, yeah. Any time that you've run into this horrible roomy thing that scared the crap out of you, right?

Chuck: There are lists of pet peeves, then there's James's master list.

Josh: Okay. Then, I'll just sit here and listen to James rant for an hour.

James: And when you do that it makes me so damn mad! And if you do that I will come to your house and take your keyboard away.

Chuck: Hey everybody, and welcome to episode 32 of the Ruby Roads podcast. This week on our panel we have Avdi Grimm.

Avdi: Hello, hello.

Chuck: We have James Edward Grey.

James: Hello everyone.

Chuck: So, I'm back from the dead. I was sick last week. We also have Josh Susser.

Josh: Good morning everyone. I'm almost here.

Chuck: This week we were chatting quite a while about what we wanted to do for a topic, and somebody pointed out this tweet by Jeremy McAnally, basically saying, "What's your least favorite Ruby AntiPattern?" We started talking about it, and we realized that we have a pretty good episode for this. So, we're going to talk about some of the stuff that people do in Ruby that drives us crazy. I think James had the longest list, so why don't we have you go first, James.

James: Does that mean James is the most angry among us? I'm just asking. It's probably worth mentioning that for you who were expecting eloquent Ruby episode this week. We were too, but we screwed up our scheduling. Sorry, Russ. We apologize. We've rescheduled for next week. So, you have one more week on eloquent Ruby if you haven't finished it up yet. Go ahead and do that. We will put the link to the page on our site where we're 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: If you have questions you can also tweet them to @RubyRhodes on Twitter.

James: That's a good point. This week we're going to talk about things in Ruby that drive us crazy, as Chuck said, inspired by Jeremy's tweet. My response to Jeremy's tweet was the rescue nil statement modifier. So, you just had some statement, and you tack a rescue nil onto the end of it, that was my initial reaction. Maybe we should get Avdi to tell us about why that's evil, since he's actually written a book on the topic.

Avdi: So, the reason that 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're doing that because that rescue nil could be all the way at the end of the line. God forbid that line might be 120 characters long. You're giving it a nil back, and really it's an exception being masked that you didn't realize you were masking. For a while I thought that the rescue at the end of a statement was only an AntiPattern, because of this. 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 for rescue at the end of a statement, which is rescue $bang or rescue error info, if you're going to pull in the English library. That's a nice little idiom for converting run time 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 $bang at the end of the statement. Now, you're either going to get the regular return value of that statement or you're going to get as a return statement the exception that it tried to raise.

Chuck: To me, I have this analogy. You've got some guy smoking in the bathroom, and it happens regularly. So you set up this rescue to turn off the fire alarm, because you don't want to evacuate the school because some idiot is smoking in the bathroom. But, when the stage catches fire, you don't want to turn off the fire alarm. You want to 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 the same thing. One of the problems I have with rescue nil, is that when you use 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 and covers a lot of exceptions.

Josh: But, not all of them.

James. Not all of them. Good point from Josh. It's a very broad category. Ideally in your error rescuing, you're rescuing just the errors you care about and generally defaulting through a broad rescue statement is going to be bad. What invariably happens is that you do it because you ran into some error. Later, some code gets changed under there and starts throwing another error, but is masked by the fact that there's a rescue statement returning a harmless or harmful value. In the case of nil, it's probably more harm than good. Rails has been guilty of this in many points of its life cycle, swallowing exceptions and turning them into things that are not helpful at all, and hide the actual problems. I think it's best to avoid it all together.

Chuck: One other thing I'd like to 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're getting an error that they want to ignore, they're getting an error they don't understand. It's a code smell because it's indicative of the fact that you really don't understand what the code underneath is doing. You need to be able to understand that and know exactly what you're rescuing from and exactly what you want to do under those circumstances.

James: I don't want to be the only guy to rant, so somebody else say something that bothers you.

Josh: I can do that. I guess we should start with some of the more basic ones. 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. You often see user?user.name:nil. The proper way to do that on Ruby is . . .

James: Is user try right?

Josh: Oh my gosh, I'm going to strangle you. Try is the other thing that I wrote down as the AntiPattern. Try is horrible. The proper way to do that is user.andand.user.name, which is great because you can do user.andand.user.name.andand.user.name.upcase, if you really want to go crazy and chain those things. Just using the boolean combinations like that is so much cleaner in Ruby.

James: Agreed. Definitely.

Josh: That's a cute little one. On the heels on of that, I really hate try, and it's ironic because I actually patched try in Rails to make it better. I think try is sort of on the level of rescue nil, in that it's optimizing the case that you don't want to optimize. You don't want to send your code in the direction of hiding all the information that you need to deal with the exceptional case in your code.

Chuck: On the heels of that, one thing that bothers me is that when you see that over and over and over again. That same guard, whether a.andand.a.name or whatever. If you're doing that all over the place, put it into a method. It doesn't take that long, but then you have that guard everywhere, and just know that it's protected and you'll get nil back if you expect your object to possibly be nil.

Josh: This falls into the Law of Demeter. If you have a . . . we're getting feedback on someone's mic.

David: It's not me!

James: Hi David.

David: So, I hear you guys are still doing this podcast.

Chuck: You should do it with us sometime.

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: I'm doing a half-assed podcast instead of a full-assed podcast.

James: We're discussing Ruby AntiPatterns, which basically means that we get to rant for an hour.

David: Sweet.

Josh: This show was made for you. Can I finish what I was saying about demeter? So, Chuck, I liked what you were saying. The law of demeter is that instead of saying user.name.andand.user.name.upcase, you can have user.upcasename, and that will take care of dealing with the name object for you. The law of demeter says that you only talk to your arguments. Avdi, I'm sorry, your worship, could you articulate the law of demeter for me this morning?

Avdi: For objects you create, I think.

David: 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.

[whistling, cat calls and geeky Star Wars references]

Avdi: You do that way to well. I feel that we may have a nerd in our midst in this programming podcast.

[laughing. Even more geeky Monty Python references]

Avdi: What were we talking about?

James: The Law of Demeter?

Avdi: The Law of Demeter, as expressed by the galactic senate, is basically a way of limiting the number of types. The rule of thumb for limiting the number of types that an individual method interacts with. It basically says that you can play with your own toys that you make yourself, you can play with the toys that other people give you, but you can't take them apart. That limits you to working with the types that are directly passed into you or that you own yourself, but not with the type that you get from calling a method, from calling a method, from calling a method, deep down into some other object's composition hierarchy.

Josh: The thing that I was talking about, which is totally in alignment with the goals of Demeter, although not explicitly expressed. When you don't do that a.b.c chaining of methods then breaking everything out into that chain means that you are making assumptions about the internal structure of other objects. It's better to let those objects handle their own internal structure. Rather than object "a" for object "b" and then asking "ab" for object "c" directly, you say, "object 'a', give me the 'c' object from somewhere deep in your guts. You'll know better than me."

Avdi: Exactly. At the very least, use different methods in you class for dealing with the different levels of object "b," 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 expected to be able to step down through that entire structure.

Chuck: I think the Law of Demeter is something that most programmers roll their eyes at when you bring it up. "But it's just so easy to chain all these methods together!" Then go and you'll have to clean up your code whenever somebody changes one of those things.

David: What I love, is that when you talk about the Law of Demeter, you will get some and I don't know how to say this without being 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 the discussion. You can't even have a discussion about what Demeter means, about what it is. They heard the word law, and they're like, "Screw you. I'm doing it my way."

Avdi: For the people who are pumping their fist into 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, might be the term, that when you couple your code with other object structure in this way, violating Demeter, then various ill effects emerge. When you don't couple it that way, then experience shows that various good effects, other good qualities tend to emerge, just by forcing yourself to follow this guideline. It's a law in the sense that you can observe that gravity works.

Josh: It's intelligent falling.

James: Nice. If anyone is doubtful that the theory of gravity is accurate, please throw yourself off the roof, and if your wife send a picture to the Ruby Rhodes and we will retract the statement.

Chuck: Screw Ruby Rhodes. Send it to James Randi, he'll send you a million bucks.

James: That's right.

Avdi: And if you manage to throw yourself off the roof and miss, then you just figured out how to fly.

David: On the Law of Demeter, and by the way, my response is to, "It's not a law," is yes it is. One of my favorite AntiPatterns, and this one requires that you already be in the law of sin, because you're 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 object, it will get the city for 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 method's job. I also hate sending a symbol to do a class's job. If you're going to break the Law of Demeter, get reg//.andand. gen and stop using the try in Rails. The reason is that you can type user.andand. ,because you can't overload the ampersand operator. user.andand.city.

If user is null, that will return a null object that is a wrapper that you can call the city method on, and it will return nil, and down the road you go. Because I wouldn't be me if I didn't take everything to a perverse extreme. I actually built the gem a few years ago. It's gone from the gem index mercifully. Maybe I should put it back. I wrote a gem called turtles. What turtles lets you do is have nil all the way down. If you violate the Law of Demeter, and there's violating the Law of Demeter, and then there's gang raping the Law of Demeter. Turtles lets you do the second one.

If you turn on turtles, it turns every single call into, basically it wraps no 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 longer as you did it in a turtles block, it's turtles all the way down. It works just great. That's one of my favorite AntiPatterns because I wrote it to be an AntiPattern. I'll post a link to that where you can get that from gethub. It's horrible. It's got good specs on it, by the way. I'm astonished by how many people have written back to me in horror at the turtles code because they believe I was serious when I wrote it. That boggles my mind.

Chuck: Break the law, or break the line in style.

Avdi: You don't get people writing back saying, "Oh my god. This gem is so awesome. Thank you for writing. I'm using it in all my projects."

Chuck: I'll just write an autoresponder that writes back and says, "God help you."

Josh: David, you just admitted giving in to the dark side.

David: I don't give in, I jump in with both feet.

James: David likes to wade in the dark side pool.

Avdi: I worked on a project once that had something like that. It was called IgnoreNil. It was a block just like that. All it did was suppress NoMethodError. It didn't care what the NoMethodError came from. It just suppressed NoMethodError. This was all throughout the project, so you would have huge sections of the code that were covered by IgnoreNil. So, no misspelled methods would ever signal with that.

Dave: That's actually a brilliant refactoring. I've got all this duplication. Every single line of code with ends with Rescue nil. That's duplication, I should get rid of that.

James: We have not heard an AntiPattern from Avdi or Chuck.

Chuck: I'll wait Avdi out.

Avdi: My favorite is unless...else. Unless is great. Unless is the inversive if, and it can be quite readable sometimes. So you take an unless, and then you violate it by tacking and else on the end of it. If you can read and unless...else and it makes perfect sense to you, then you're a Cylon. You are not a human being.

James: Wow. That's Star Wars, BSG, Hitchhiker's Guide to the Galaxy . . .

David: And a damned useful test.

Avdi: This is some kind of Cyborg detector. It's a replicant detector.

David: I just watched Blade Runner two nights ago.

Avdi: That's one of the replicant tests. They flash a unless...else in front of their eyes and if he doesn't recoil in horror, then he's clearly a robot.

David: If you're not a robot then you might not being a human. Just unless it's not painfully clear.

James: If you are doing unless...else, you can just switch it to if...else and reverse the two clauses.

David: So it's else, and then else...else.

Chuck: I confess that I have written code that clearly read to me as if not some condition, do this, else do this other condition. The reason I did this was because if...not failed, and so I wanted the positive case, the happy path, to be in the top block. I didn't write unless there.

Avdi: There's nothing wrong with that. There's no need to be afraid of the not operator. Sure, if you string a ton of them together, that's going to be confusing. Nobody likes multiple negatives, but if it's between using unless...else and just tacking a not on the first the condition, use the not.

Chuck: Ain't nobody doesn't like multiple negatives.

James: Basically, anybody who uses unless...else needs to be forced to use it in a sentence.

Chuck: How about a must not...else. Not. If we're done with that one, I think my favorite pet peeve is when people misuse MethodMissing. This is something we discussed when we were discussing some of the AntiPatterns. For one, I think we were talking about it and saying that if you have a list of defined messages that you want your object to respond to, then you should be able to loop through them with DefineMethod. But, I've actually found people defining methods in MethodMissing where they actually know the signature of the method they need to define. Rather DefineMethod, they could actually def this, do this other thing. It blows my mind how many people use it when really you want that method to show up in the object's method signature. You don't' want it hidden in MethodMissing where who knows what it's going to do.

Avdi: I closely aligned with that, defining MethodMissing without defining RespondTo.

James: I just learned from an exchange you had on Twitter yesterday, Avdi. I did not know this before yesterday. We have a RespondToMissing. If it goes up the RespondTo stack and doesn't find anything, it will call RespondToMissing, so you can overwrite RespondToMissing as you do MethodMissing. It's kind of weird. I guess that exists for parity, which is kind of cool, but the thinking there would be that you could probably get away without doing super. But, Avdi said, "Not really, because all good MethodMissing implementations need to call super anyway, so that you pick up any other included methods or anything like that, who define their own, so same to RespondToMissing."

Avdi: That was a special case. That was in the context of the hack I posted yesterday, which is a trick for defining MethodMissing and RespondTo at the same time using a macro. Because of the way that works, to behave well, it needs to call super in respond to Missing. If you're just doing an ordinary class that needs to do some kind of proxy'ing, so you have a simple MethodMissing. It makes sense to define RespondToMissing and you can avoid the super if you know you're not doing anything super fancy in that class. My thing had to do with having lots of modules all of which define RespondToMissing, all included in the same class.

David: So, while you guys were talking about reminds me of another pet peeve that I have, and that is people who don't call super when they MonkeyPatch or Inherit. It drives me crazy. The reason it reminded me is that sometimes they don't call super in MethodMissing and then you don't get the NoMethodError returned when it doesn't respond to the message being sent to the object. Ultimately you need to be calling super, because usually there's stuff that needs to happen a level or two or up that you didn't define. Especially when you're mixing in modules, then you're asking for trouble if you don't.

Avdi: It's not just for MonkeyPatch. In general, it's a good idea. If you're going to be subclassing something or including modules, it's a good idea to get into the habit of calling super, especially in your initialize method. Often in other methods as well. If your in a method that you're concerned that you're not going to be able to call super, that super is going to explode because there is no super and your not sure that there is a super, because you're in a module. You can use the define operator with super to ask Ruby if there is a super for this method, such as define?super or if define?super then super.

James: That's an awesome trick. I didn't know about that one until recently. Define is a key word. If you're expecting it to be one of the normal methods in Ruby, it will surprise me. 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.

David: I almost have to wonder if RespondToMissing isn't an attempt to optimize the speed of MethodMissing. If RespondToMissing works by going up - we check the class, we check the super class, we check the super super class - and then we call RespondToMissing, like the 1.8.7 implementation. We check the child class, and then we ask MethodMissing. no? then we go to the parent class and we check it for MethodMissing, and then we to the grandparent class. I guess that wouldn't work anyway. You'd still have to do that anyway.

Avdi: It's still doing that. It's a programmer optimization to not always have to call super in your RespondTo.

David: I see.

Avdi: And it also gives the advantage that your RespondToMissing is going to be as late as possible in the MethodMissing chain.

James: We have several more we want go over, but David didn't have a really good one that I would like to hear him elaborate on. Tell us what you mean by never use a symbol to do a method's job.

David: Okay. You're only saying that because I whined about it in the back channel. Thank you. Now I know that whining in the back channel works. The andand gem I love, because you can call x.andand.foo and pass it whatever arguments. I hate the try method where you call x.try and you pass it the symbol foo. I call it, don't send a symbol to do a method's 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 hash.try:{}=some value close thing. Trying to access the value the of a hash, you have the same problem. However, with andand, you say hash.andand{your value} = value. And, [Curtis Rembolt Green] talked about this on Twitter recently. He ran into a similar problem where, never say Render: and then :MyRenderer when you've got the MyRenderer right there in the name space, just type the name of the class, MyRenderer. Pass the class name in that place.

If this is an yaml file or if this is in something that's serialized where that class doesn't exist, then go head and knock yourself out. Go ahead and use symbols, because that's what symbols are for. It's meant to symbolize something, but if you're in the Ruby name space, and those objects exist, use the objects. Don't put names on them that you later have to decode, especially in the case of methods where the decoding and encoding has a different syntax. It actually looks and behaves differently from the actual way that the method call looks like. They are equivalent, but they are not identical.

Josh: So Ruby is not exactly Lisp, and it's not Io. Actually Steve Dekorte's language, Io, the representation of executable code and talking about code at a meta level, they look the same, so it's kind of crazy. It's almost like you don't need blocks, although you do. So, I have a rant, I'm sorry an AntiPattern. That's inheriting from an array or hash or other core data types in general. Strings. There are definitely cases where you want to do this kind of stuff when you get expert level. I've inherited from module to create specialized modules that have extra behavior. Once you know what you're doing, go nuts. But in general, you don't want to inherit from an array. You take an array and put it in an instance variable of your own object and then delegate this particular array type behavior that you care about exposing.

James: But Josh, I have all the methods on enumerable that I have to implement now.

Josh: Yes, screw you.

James: Good answer. The end. Josh is right, and there are some sever gotchas for doing so. Ruby takes some shortcuts in the system, mainly to make things go faster. There are pieces, for example, you inherit from string and you put in some code to set up for instance variables you're going to track. The problem is there are ways to get strings without the deinitialize method ever being called. For example, if you do a gsub on an existing string, then you get another string back, but initialized but not called on the string returned. There are other cases like this where Ruby cuts certain corners for speed or whatever. If you're relying on those core classes to behave exactly like your classes would, you're going to be surprised.

Josh: Actually in some of the 1.9 they've been changing how things work on array and when you get, when it creates a new version of the array and when you get back the old array side-effected.

Avdi: You have confusing stuff. You can 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 instead of your special array for the concatenation.

Chuck: I want to point out that the coder tree, I actually subclassed and array for [Conway Cm of life 35:00].

Josh: Leave this show.

David: What happens at code retreat stays at code retreat.

Chuck: Even then it may be uncomfortable because I didn't completely understand everything that goes on with array, and delegation seems like a better way of going. Anyway, the guy I was coding with . . . I got tired of arguing with him, but basically it was, "Well, we're going to throw it away in 45 minutes." We just want to get this done fast so we can move on to other parts. If there's any chance you're going to keep that code, I'm with you guys on this.

David: You go to code retreat. You have 45 minutes to write a piece of code. The whole reason you're there that day is to learn better ways to do code. To walk into an exercise and say . . .

Chuck: I'm in a hurry, let's do this like crap.

David: I don't know if you're fired, but I think you should leave the code retreat.

Avdi: I'm actually going to go out on a limb here and say that in Ruby, inheritance can kind of be an AntiPattern. It's one of those things to think twice about. In other languages, you have to inherit if you want to get things done, but I've seen so many cases in Ruby where there was no reason to have that base class there. It could easily have been a base model. It's actually very rare that inheritance makes sense.

James: I was just going to agree with that we rely inheritance too much Ruby. It's funny how many of the things you need inheritance for in other languages don't apply in Ruby, because of duck typing and stuff like that. You just don't need it that much. However, that said, there are cases where inheritance makes a heck of a lot sense and is exactly what you want. Some Ruby programmers get into the habit of avoiding it so much that they do some kind of crazy things to avoid inheritance. In fact, since we're going to talk about eloquent Ruby next week, there are a couple of examples in eloquent Ruby I don't like. There's one in a delegation chapter later one, where he inherits from simple delegator and then passes that to a class, so class less than simple delegator inherits from something. He does all this. This is the most complicated way I have ever seen to reproduce inheritance, and it has no benefit that I can recognize. In that case, just inherit. If you need to inherit, then inherit.

Josh: The flip side of that is another pet peeve of mine, and that's explicitly checking the type of an object, usually an argument. Don't ask the object what its class is. Do a RespondTo for a particular method that you would expect that class to implement, or don't. There are 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 class. So, MonkeyPatchSpecial?intoObject, and have it return false, and then put special? into a couple of classes that I want to note as the kind I care about. Avdi's trick of mixing in modules as type tags is something that you can do if you're note on a cranky version of Ruby that makes that really slow.

Chuck: We thought about duck typing. To drill home that point of, don't check the type, 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're not allowed to give a crap what it is.

James: The one you did Josh, where you're checking the type of the class. I always think of that as Space Balls, when he has the little fit about, "You're always preparing, just go!" Just call the method. Just do it.

Chuck: James do you want to do the inherit from struct.new, or should I.

James: I'll definitely do it, since it's definitely do it since it's one of my pet peeves. When people of are making structs all the time, this is similar to my simple delegator example, they do class less than, and then they define struct.net right there as a super class. Don't do that. It's stupid for a lot of reasons. One, it calls all kinds of problems with the crazy reloading code we add everywhere. Every time your class gets reloaded, you get a new super class and so you get a super class mismatch error. The main reason not to do it is that struct was built for subclassing in mind, and it takes up blocks. Struct.new takes a block, and it runs it in the context of that class, so you can just do struct.new and print a block right there and define methods directly in it. There's no reason to do that, and you get the class you want and you can assign it to a constant. There, you can use or equal if you need to, and you handle the reloading case as well. Don't use struct as a super class on the super class line, just give it a block and define your methods in there.

Avdi: In my code they need a destruct.

James: We get a got to do the ternary operator real quick before we do picks. We have lots of things to say about it.

Chuck: Okay.

James: I didn't mean me.

Josh: This is kind of a pet peeve of mine, but I just found that everybody here apparently shares it. If I see a ternary operator, that being the operator that takes three arguments with the question mark and the colon. It works like an if...then...else. If I see that, I expect it to be a purely functional expression, that is an expression that returns a value and doesn't have any side effects. If you put some kind of side effect expression in there. If you use it as a switch for control flow, I get confused and annoyed. I really prefer to control, if it's going to be control flow, I prefer to see that as an actual if...then...else. That's just a peeve of mine.

James: I mainly only use the ternary operator when I'm assigning a variable. It's just to return some value.

Avdi: And this is one of those things. It's not like Ruby is going to bite you for using a ternary for that. It's just one of those programming conventions where certain constructs tell you something about what the programmer had in mind. Generally, when I see a ternary, I expect that to be a logical expression.

David: And we're all agreed that you should not nest your ternary operators more than five levels deep, right?

James: You're tying my hands.

David: You have to draw the line somewhere.

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. If you find yourself doing that, first slap yourself on the hand with a ruler, then select from the question mark on and then press the delete key. That way you can get rid of it all together. If you absolutely have to have a brand, and you almost never do, but if you think for some reason you do, stick a bang bang in front of the test and that will switch it to a boolean.

Avdi: I have worked with an API where you had to return a boolean. We were talking to a Java server. So we had bang bang uservalid?, because for whatever reason, valid didn't return true/false. It returned the user object or it returned nil. Bang bang turned it into true or false.

Josh: 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: So, I have something that I ran into in somebody's code that I was dealing with that was completely mystifying. So, along these lines, you know how nil is a false type value, a false C value, so you always do stuff like, if user . . . You wouldn't say unless user.nil? or nil p, as we used to say. I'm not explaining that, by the way. You wouldn't say, unless user.nil, you'd say if user, but there's this pattern in objective programming called the null object pattern, where instead of sprinkling of your code in the user class or controller class that's using the user class, you'd take all the conditionals and you bind them together in a null user class, and you've now embodied the user who isn't logged in. That cleans up all the rest of your code. It's a really nice pattern that's been talked about a lot of other places. When you're 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 might think, "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: That would be like crossing the streams.

Josh: Now you can't say, if user, because it's not actually nil. It's not the nil value, and that's the only special nil value that Ruby knows about. You can't trick Ruby into thinking it's nil. It just doesn't work.

Chuck: And the whole point of defining a nil user is so that you can say, if user, have it return true, have it return the nil user and you can continue operating on it. It defeats the entire purpose.

Josh: Right. You actually want to send messages to it. It's not nil. Don't do that. James will come to your house and take away your keyboard.

James: If you violate any of these rules, you will see the Ruby Rugs on your doorstep. By the way, the null object pattern seems to throw people a lot. 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, the seven actions we usually put in controllers, the new action usually assigns @user=user.new. That's a use of the null object pattern. Basically you're putting a dummy user in there for the case where the user hasn't yet filled out the form. You can call all the methods like name, but those fields will be blank. That's a perfect example of null object.

Josh: I would not call that a null object.

James: Really? Okay.

David: Fight! Fight!

James: Because why.

Josh: Because it has logic. I've definitely had controllers where the logic in the blank user was used. And it has storage as well. You can assign those attributes to it and it carries them around. It doesn't just ignore them.

James: I realize that it's not a special object, which I think is what you're saying, but the usage, I believe, is the null object pattern usage. What's happening is that you haven't filled out the form yet, and so you want to be able to get 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. It allows you to use the same user interface. I believe the usage is the same, but I do see what your saying in that typically a null object is a specialized object you choose to return to keep a consistent interface, but it generally does have any kind of storage. I definitely see that.

Josh: If I had a null user, I would expect save to do nothing. I would expect it to respond to save, but actually do nothing.

Chuck: 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're supposed to fill out things and save it, then that seems to me to be a very different thing from a null object. At least that's my understanding. If you ask the system, "Who is the current user?", you might get back a null user, because there's nobody logged in. If you need to fill out the user form or the user login form, go ahead and call user.new, because we're going to create this user. The null object is not part of a real object's life cycle, to my understanding.

Josh: I think null objects are considered to be immutable.

David: You're mom's immutable.

Chuck: Picks. We'll have David go first.

David: Pretty JSON plug in for the Chrome browser. It makes it so that when you're looking at JSON, it pretty prints it, colorizes it, breaks it out. It looks like you've run awesome print in Ruby. It dumps out all of the JSON in a nice nested hashes of hashes of hashes of arrays of etc. It makes it look really pretty and really readable. People who 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. The work around for that you hit the command-option-U or control-shift-u or whatever it is on Windows, to view source, and the pretty JSON goes away and you get back the source JSON that you can then paste into a string and throw into a Ruby console, and parse, and manipulate it. That's my pick. I like it. It's pretty. It's useful.

Josh: I have a very useful pick which is the simple form gem. If you're doing form helpers in Rails, the form for whatever, simple forms is a much nicer way of doing that. 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. Simple form, though is a much better formtastic, in my opinion. It replaces the form for helper with simple form for, and it has a lot of really smart helpers to help create the inputs for the form. The new 2.0 release will be out any day now. I've been using the master or edge or head or whatever you want to call it. I've been using the pre-release version of 2.0. It's great. It has integration with Twitter bootstrapped, which I mentioned in my pick last week. It has a lot of flexibility about how you generate the markup. I've been really happy working with simple form, and I recommend it a lot. And then I have a seasonal pick. We're coming up on cold and flu season, my pick is the neti pot. There's a yoga practice . . .

James: I thought it grew on the neti plant.

Josh: This is the other San Francisco practice. There's this yoga practice called neti, which means cleansing, I think. You can go to the drugstore and find squeeze bulbs to clean out your sinuses. The more traditional way is with these things that look like little tea pots. You fill them up with warm salt water and wash out your sinuses. I ride the subway to go to work in San Francisco, and it's like a petri dish, full of people's germs. If I just brush my teeth and do my neti pot, I don't get sick the way that everybody else gets sick. If I let it go for a few days and I feel myself coming down with a cold, I do neti pot, and I won't get a cold. It's a little uncomfortable until you get used to it. It's like brushing your teeth. You've just got to do it. It's worth not being sick in bed for a week.

David: Michelle Silversteen wrote a poem, called, "There's a snail in my nose." The first time you use neti pot, you'll meet the snail.

Josh: Okay, I'm done.

Avdi: I have got nothing this week. I have been wracking my brain, and I'm just not interesting this week.

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 want 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 your ideas and thoughts down. Put them somewhere so you can get them out of your head. If you're familiar with productivity systems, that's a very common theme, getting things done as you keep these lists of things, to get them out of your brain because they keep popping up into your brain and bogging you down.

Also, if you like Pomodoro it has a similar thing, where you handle interruptions by writing them down and them down and then getting back to what you're doing. If you are into Pomodoro, then Prags has a great book on that too, called "Pomodoro Technique Illustrated". You need some kind of exocortex, your brain outside of your brain. A lot of people use moleskin notebooks for that. That's great for them if that works for them. That doesn't work for me, I have to have it in the computer.

I will say that if you are going to get into moleskin notebooks, there are Star Wars moleskin notebooks which your worship would definitely approve of. That's an argument in their favor. What I'm currently using for my exocortex is Evernote, which is 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 that far. It can audio and video notes. I don't do that. It does have some features that I really love, like keeping track of things.

For example, it gives you an email address that you can fire things to and then have those adapting 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 forward it to that special email address, and I can change the subject to be whatever I want, which is the note title. It also gives you a way to embed some things in the subject and tag it with certain tags, or make sure it ends up in a certain notebook.

Also, when I'm editing it in Evernote, Evernote will let you put check boxes anywhere. Almost like you were typing it. Any old letter on your keyboard, you can type a check box. So, I go through the client's note and type check boxes everywhere there's a "Can you do this and this and this?" Then I can check those boxes off as I accomplish those things. I also have this safe search that will bring up any notes with check boxes that are 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 users, you can share ideas with other people and 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 kind of information into it, so it's very feature full. It doesn't work for me as well as Evernote.

Josh: Yojimbo isn't hosted is it? It runs locally?

James: Yes, that's true. That's a difference. Evernote is a hosted service, so anything you save in Evernote is pushed up to the cloud by default. You can turn that off for certain things if you want, that's for certain. It's pushed up to the cloud, and then if you have your iPhone or iPad, you can run Evernote on them, and then you're looking at the same Notes everywhere. Jimbo is not hosted, so it's all going to be on your computer.

Josh: There is a podcast called Mac Power Users, and they did a whole hour long episode on Evernote in October. And, literally, the guy who wrote the book on Evernote was their guest, and they have an hour of power user tricks about using Evernote. If you're getting into Evernote, listen to it. It's awesome.

James: Sweet. That's a great source for people looking at it. I have heard some people complain that Evernote is too heavy. I saw a conversation on Twitter either yesterday or the day before. If you feel that way, there is a SimpleNote app, which is like Evernote minus a bunch of features. If you do feel that it's a little heavy, that might be one way to go. Another app I've seen mentioned recently, if you're an outline kind of person, is WorkFlowy. It's a big outliner, but it will let you focus in on specific parts of the outline and individual notes. These are all various options that make for great exocortex kind of software. I'll put links to all of those in the show notes today. I encourage you to find one that works for you, because it makes a massive difference. Okay. That's it. I'm really done.

Chuck: So, I guess I'm last. Nobody's going to be able to find my picks after James. So, the things that I wanted to point out, I just found a new finder replacement, because the regular Mac finder is awesome, but I sometimes wish it would do more stuff. The one that I've been using lately I actually just because I really love it. It's called TotalFinder. It has a lot of features. The ones that I use is that it does tabs in your window, so you get your finder window and then if you open up a new folder, it will open it up in a new tab in your finder window, which is really cool.

The other really handy thing that it does, is that if you have two tabs open, you can actually merge the tabs, and it puts one tab on the left, and one tab on the right, and you can drag and drop files between them. It's just super handy. If I have to move stuff around or into my drop box for my subcontractors, my podcasts or for my assistant to handle, I can literally take them from where I've got them, usually on the digital audio recorder, and I can drag them straight across.

Then I can process them from there. It's really handy. The place I learned about TotalFinder is on a podcast, called Business Tech Weekly. You can find them at businesstechweekly.com. It's done by a couple of really cool guys, Cliff Ravenscraft and Andy Traub. I have been following them for a while and have gotten into a few other podcasts on running your own business and going out on your own, how to succeed, how to build a product. Some of the others are done by the same people or who are related to them.

I want to mention the 48 Days podcast by Dan Miller. He wrote, "48 Days to the Work You Love." If you hate your job, he helps you figure out what you want to do. He helps you figure out where to find a job that will allow you to do that. He puts you through a whole bunch of steps in finding a job that don't involve going to job boards, which is an interesting approach. It's finding that job market that isn't being actively advertised, and finding your dream job, because there are only a handful of people for that job.

The other two I want to mention are Free Agent Underground By Dan Son and Kevin Miller. It's kind of a different flavor. They have a membership site where you can hook up with people. They help you walk through the process of figuring out what you're about, finding a business that works for you, helping you figure out the business model and runs you through that. That's Free Agent Underground. The other one is the No More Mondays Show. That's done by Andy Traub, who's on Business Tech Weekly.

And Justin Lucas Savage who used to by my business coach. Those are some great podcasts and some great stuff if you're looking to go out on your own, either freelancing or building a product. Just some ideas on how to be a solopreneur or a small business entrepreneur. TotalFinder totally rocks. With that we will wrap up. Again on 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: 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 in your Android device or whatever you listen to podcasts on. We really appreciate people leaving your reviews on iTunes. If you have some feedback for us, you can also get us on Twitter at Ruby Rhodes, or you can email me, Chuck, at teachmetocode.com. We're always happy to get your feedback and concerns and take great suggestions. That's it. We'll catch you next week with eloquent Ruby.

@xdite
Copy link
Author

xdite commented Jan 12, 2012

I will put more transcriptss on http://asciirogues.com/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment