RR Debugging in Ruby
- Debuggers and Tools
- Formatting Debug Output
- Outputting debug information
- Other debugging tricks
- abort_on_exception = true
- The Ruby executable's -d switch and the $DEBUG constant
- Using a logger to output data from a specific piece of code
- The debug method in Rails helpers and views
- Using Object#freeze on to find what is modifying the object
- Passing a dummy object that uses method_missing to output method calls and arguments
- Do not debug alone
- Spike the debugging, git stash the changes, write the test, unstash the changes and verify the result
CHUCK: Hey everybody and welcome back to the Ruby Rogues Podcast. This is Charles Max Wood and this week on our panel, we have James Edward Gray from Gray Productions. He's been a long time member of the community and we’re happy to have him here just about every week.
JAMES: Me too.
CHUCK: I almost forgot to mention that it’s his birthday. He's an old man.
JAMES: It’s my birthday today, that’s right.
GREGORY: What are you like 75 years old, James?
JAMES: That’s pretty close, yeah. Just 75.
CHUCK: [Chuckles] That’s all, just 75. That was Gregory Brown chiming in. Greg is the master over at Ruby Mendicant University. He's also the author and maintainer of Prawn PDF library, and does a whole bunch of other stuff for the community, including jumping in the middle of the Ruby Gems debate. Welcome, Greg. I have to apologize though I'm running a little slow. I got back from vacation yesterday and my brain isn’t working at full speed. Also, we have Mike Moore. Mike is a Rubyist here that I actually had lunch with him the other day and he's the organizer of the Mountain West Ruby Conference, the Ruby Web Conference and is the host at the Ruby Verse Podcast. Welcome, Mike.
CHUCK: And the last but not least, we also have Peter Cooper who runs Ruby Inside and… I'm drawing a blank. What else do you do? [Chuckles]
JAMES: He's your weekly news guy.
CHUCK: That’s right. And I'm Charles Max Wood from teachmetocode.com. And we'll go ahead and jump in and get started.
JAMES: So can I ask a question off the intros?
CHUCK: Go ahead.
JAMES: I've never listened to the Ruby Verse. Mike, what it’s about?
MIKE: Ruby verse is an excuse for me to talk to people, and they talk about different subjects and then I edit it so they sound extra smart and that’s about it. So it’s kind of a no frill, information-only podcast.
JAMES: So interviews mainly, is that what you do?
MIKE: Interviews mainly, yeah. Only, actually.
JAMES: Okay, cool.
CHUCK: He's interviewed some really cool people. It’s definitely worth checking out RubyVerse.com
JAMES: Yeah, I´ll check that up.
CHUCK: All right. This week we are going to be talking about debugging, and I think we are going to get into debuggers a little bit too. It was interesting when we were talking about it before we got started, a lot of people were saying, “I don’t know a whole lot about debuggers.” And it sounds like people do most of their debugging in ways other than using an explicit debugger. So I'm a little curious, and I´ll just let whoever wants to jump in, but what do you use when you have a bug that you have to track down in your code?
PETER: That answers it really, doesn't it?
MIKE: I use put as.
CHUCK: Put as.
MIKE: Yeah, [03:25] basically.
CHUCK: You know, I think a lot of us at various stages in our careers and even yeah, where we are at now, where some of us are pretty advanced in our careers, mostly you more than I, if you think of something that you can find pretty easily or quickly up, put as is a really quick and easy way to do it.
PETER: No, just use p.
JAMES: That's right, p! Yay, Peter!
MIKE: Actually, what I use instead of doing puts or in combination with it, is I will actually use raise quite a bit which is a message because then it halts the execution. JAMES: [Chuckles] That’s awesome.
CHUCK: [Chuckles] That’s interesting.
JAMES: That is by the way my favorite way to debug Rails; when I'm in the middle of something and it’s down some action and I wanna see what an object is, I just raise and whatever the object is, I can call .inspect on it so it turns it into a string for the error message. There's reload the page and it pops right up at the top of the page.
CHUCK: So I have a little bit of an issue with that method and that is just that, you kind of have to run things over and over again to get different bits of information. So, if you don’t pull up the object and see the issue right there, then if you call another raise or put as, I mean you have to change it and then run it again. I mean isn’t that a little bit slow or inefficient?
JAMES: Yeah, you are right that it is. So let me ask you this, Chuck. What do you do in the middle of a Rails stack when you wanna look something up, what do you do?
CHUCK: I usually actually use the Ruby debug library. You just require it and then you put debugger in there and it effectively opens up an interactive prompt kind of like IRB, where you can then query the state of your stack at that point.
JAMES: So in my experience, I've noticed that there's two kinds of people on the world. Two kinds of programmers, that I seem to come across and it’s half the world does their debugging in a debugger and that’s just how they do it. And whenever they run into a bug, they immediately fire up the debugger and that’s what they tend to do. The other half of the world is like what most of us have mentioned, just a little bit of application of puts and we tend to track things down that way. And it’s always been interesting to me because I've used the debugger in the past. I can use a debugger and I know how it works. I've actually tried to hook myself on them a couple of times, and I've actually tried to get into the habit of using them regularly and I cannot do it. And I think the reason for me, I've been trying to figure that out and I believe it’s that it is a context shift; it’s when I'm sitting there and I'm working on the code and I have it all on my head, then I'm working on the code and I have it in my head, so it makes sense for me to just say, there's probably something going wrong somewhere right around here, so let me just see what it is printing right around here and then print that out and then stay in the same context. But when I have to stop, and then fire up the debugger and set a break point and get it to step through to the right point and all that, I had to stop thinking about the problem for a while and that context shift bothers me.
MIKE: That’s a really good point. That’s why I actually find using raise is not really inefficient, especially because when I do my debugging, I try to think through the path somewhat. I'm not just sort of putting in a put statement or a raise in a random place and seeing what happens, but trying to think through the path. And then what it does is it allows me to focus on just one thing at a time, because when I drop into a debugger, the explorative nature of being able to interactively interact with objects and things like that gets me distracted. And I find that like what normally happens is I´ll do raise statements and I´ll run it, and then based on the outcome of that, I really know where the very next place that I might put it would be and it just helps me focus on one thing at a time.
CHUCK: That makes sense. I have to say that I don’t really see a huge difference between using a debugger like Ruby debug or Ruby debug 1.9, depending on which version of Ruby you are running versus using put statements, because effectively, you just put the debugger the breakpoint in where you would put your put statement. And then from there, you can step through your code to the next place you would put it if you are not seeing an apparent problem there. But effectively, what you are doing is you are running a whole bunch of put statements; it’s just that you’ve kind of frozen the context, you don’t have to run it over and over.
GREGORY: But I think that’s actually a disadvantage because you basically need to come up with an execution plan ahead of time, for where you are going to put those break points. Where if you stopped the world and then what you can do is you can make the decision at that time where the next place to go would be. So I don’t really think that there's a whole lot of value looking in five predetermined places when the first answer is going to tell you yes or no, yes or no, yes or no, sort of thing.
CHUCK: Right, but I guess what I'm trying to say is that, you get the first, “No, this isn’t the problem,” and you’ve already got the contact set up so that you can immediately move on to the next place, unless it’s previous in the execution. Because you can always step forward, you just can't step backward. So you move on to the next spot if it’s further down the execution chain and you get another…
GREGORY: You can step sideways when you realize that your first idea was wrong. I mean, normally when you are looking at a debugging problem, you want to divide up the space rather than going deep. You wanna try to figure out whether your initial idea was right or wrong. If your initial idea was right, but you didn’t get enough contacts there, the debugger is nice because you can step down to the next step moving forward. But if your whole idea was wrong, then you have to start over and set up a whole nother context.
CHUCK: Yeah, that’s true.
GREGORY: And I don’t know Chuck, where are you finding a situation where debugging something is taking all that much time to run it.
CHUCK: I'm just going to answer Greg's question real quick. The places that I found this the most effective really is in code that I didn’t write and I don’t completely understand anyway. So under that context, it’s nice because then I can stop the world and I can say what is everything doing. Then I get a feel for the context where it’s at, and then I could move through it.
GREGORY: That’s where debugger and pry probably overlap in their value. A couple of weeks ago I was saying that I like using pry, basically from exact purpose that you said because if you are trying to figure out where to go, then having an interactive prompt is very, very useful. So if that is a use case, I definitely agree with that in terms of the general value of it.
CHUCK: Yeah. In general, I don’t go directly to the debugger either; I usually actually do start with put statements. But if the solution, it doesn’t become apparent in try or to, then I would plug the debugger in so that I can actually walk through it step by step and see where I'm going wrong.
JAMES: I think that’s actually a really good point. As far as debugging, I do actually just prefer puts or as Peter pointed out in Ruby, we have p, which is even better. But I have used a debugger in the past to understand an algorithm. Like it’s a tight loop and it’s using a couple of variables, and it’s one of those that’s complicated enough that I can't work it out in my head what's in which variable each time through the loop and I just wanna walk through a few phases of it, I do like a debugger for that because I can walk through the phases loop, examine each variable and then do it again and again.
GREGORY: So basically, the longer the life cycle of the problem, the more useful a debugger gets to be, especially if you don’t understand the code that you are working on, because you can sort of look at it at the intermediate points. And so there's a long set of intermediate steps then yeah, that makes sense. I think like when we first talked about debugging where we are more thinking, “Oh, something broke,” and if you can isolate that and then that’s where you don’t necessarily need the debugger.
JAMES: I think Greg is actually on to something there too in that I don’t spend a lot of time just randomly bug hunting these days. And I think that’s because I'm so good about testing, and always doing that, and so my cycle is really short from the time on the amount of code I write before it’s actually being run somewhere and I see a problem. And when you only have three lines to look in, you generally know right where the problem is. So I think I've gotten to a point where I just don’t spend much time debugging more. And when I am kind of planning something out or trying to see how pieces work together, I tend to fire up IRB and play with objects a little bit until I've got it in my head pretty good. So then I go back in and write some tests around it and build it. So I think that’s part of the point is the reason the debugger is not that valuable to me is I've managed to really shorten that cycle between when years ago I would write 6000 lines of code and then try to run it -- and that’s horrible. And at that point, debugger is very helpful.
GREGORY: Totally agree.
CHUCK: Right. So James is just so good that… yeah… he's just so good.
GREGORY: James doesn’t write buggy code. Period.
JAMES: That’s right. If you just don’t make mistakes, you don’t need a debugger at all. That’s the way to go.
PETER: He's right though.
CHUCK: It is true. And we talk about tests as kind of a way of avoiding bugs, but there's another means or methodology of finding bugs that I was taught that I haven’t used a lot, and that is that you write a test that basically exposes the bug. Do you guys do debugging in that way at all, where you know there's a problem so you write a test that basically should pass when you the fix bug.
GREGORY: I've had to do that extensively, especially because in open source projects that become so important. But in just I worked on a lot of things that has very high complexity and you will have regressions if you don’t actually automate the test for finding the problems. So, I mean, what the process normally is for example like the best example is Prawn. PDF generation is crazy hard and when things break, it’s possible that later on they will break again in not obvious ways. So what normally would happen is people would basically say, “I try to do this and then my PDF blew up.” And we do combination of messing around in IRB and put statements. And I didn’t use pry at the time, but I definitely would have if I had it available to me. That’s a place for a debugger. So you do this sort of exploration process until you feel like you know where the problem is, and then I will typically try to build a minimal example, but reproduces the problem. And then once you got that, if you have just the simple example that really only touches the things that really matter at the core that reproduces the problem, it’s so easy to turn that into a test, that even if you are not doing TDD day to day, it would be like… it would just be irresponsible not to turn it into a test because…
PETER: Dude. You know that's cold. Its bug driven development.
GREGORY: I guess what I'm just saying is like the more complex something is, the more people who have to use it and work on it, the more that your test should cover every regression. Because by the time you have a bug fixed, it should be so easy to produce that. But I don’t know that I would start there as my first step. A lot of times, we will fix the bug in a spike, and then back that out and then write the test, get failure and then make it pass.
JAMES: So Bug Driven Development, that’s BDD?
GREGORY: That’s right.
JAMES: Sorry, just checking.
GREGORY: Actually, that was the original idea behind TDD. The original concept before the concept of the driven development was that test were regression suites. So the whole point of BDD was to tell people, look it’s not more than that, but it still includes that as a core component. The regressions suites are really, really valuable.
JAMES: I got to agree with Greg. To me, in any bug hunt, step one is find the bug and you have to get to the point where it’s repeatable. That’s the whole point; once its repeatable, then its super easy to fix, right? So if I'm going to do that, I would much rather do that by being just writing the test that narrows it down. But even if it was a non-tested code for whatever reason, the first thing I would do is I would try to come up with the exact series of steps that lead me to the bug every time. And I would probably try to automate that so I could sit there and try something run it again, try something, run it again.
CHUCK: Have any of you guys actually worked in QA?
GREGORY: I've trained QA people before.
CHUCK: Okay. So I'm the only one here with actual QA experience. And that's exactly what the process is for QA; both in validating new releases and in finding bugs is you break it down into an exact process to replicate the bug. Or in the case of acceptance testing, you present an exact case that should produce an exact outcome, and then you verify that the outcome matches. And it’s not very different from what we do in our unit and integration tests but that’s exactly it; you break it down into step by step by step that a kindergartener could follow to break your code or to verify that it actually works.
JAMES: But that’s so helpful. I mean as a programmer, once I have those steps, I can always figure it out. As soon as I've isolated it to the point where it fails every time, it’s a few seconds from that.
GREGORY: And I think that’s part of that you were saying before even though you were joking about it just not having to debug all that often, I think that using regression suites actually reduces the amount of time that you are hunting down old bugs or reintroducing. Because once you make a test for something, then if you got that wrong, if you found out that you didn’t get all the problem, it will eventually fail when you change something, or it will fail another way and you have another test. So overtime, your more stable parts of your code gets better and better guarded against these bugs. And so once you basically squashed them forever with tests, if they ever reproduce, you just get a really quick feedback look and you know that the regression is related to the change that you’ve just made right then and there and not one that might have been made six months ago.
CHUCK: Yeah, and I think honestly that when we think about kind of the hairiest or the most painful debugging experiences we have, it’s usually not the ones where we ran the test suite and it said, “Oh by the way it is broken.” It’s usually the other way around where it wasn’t covered by the test suite. And by putting those tests in, you protect against that kind of behavior in the future. I have another question that I want to get into, and this is kind of related to debugging but it kind of grows out of something that Greg said he was talking about and he was riffing off of what James said about complicated loops and things that you can't hold it all on your head, or figure out exactly what it’s doing over the course of its execution. And so I'm wondering if the need for a debugger indicate some sort of deficiency on your code cleanliness or clarity.
GREGORY: That’s an interesting question. So I'm trying to think about when I've needed that and it’s been in situations where if I simply printed out the intermediate results of some complicated process, it would be overwhelming, or not especially meaningful to look at that output. So what I've wanted to do is grab a hold of that object and interrogate it with some interactive calls and play around with it and that sort of stuff. But that sort of means that there's some amorphous blob siting in the middle of a complicated process and it could be an indication that there's a lot of dependencies that are tied up with one another, or that the flow has an intermediate steps knowing way more about the process than it should have to, and sort of thing. And I find that like for example, if you go into that, then you break down the problem more and you say take something that used to be class with 200 methods and make it compose some other objects that like the more that you can do to isolate things, then the easier it gets to be to have a low ceremony debugging process. So I think that’s interesting to think is that a metric that there is a sign of a problem, is it a code smell, so to speak. I think maybe so.
CHUCK: Uh-huh. Well it also makes it easier to test. So I mean, there are both sides of that coin and they may be related as well, where you have the, “I have to use the debugger because this is so complicated that I can't keep track of it on my own with simple put as statements.” But at the same time, testing long or complicated methods can be kind of hairy as well; where if you’ve tested all the underlying pieces, then testing the overarching functionality isn’t necessarily as tricky.
JAMES: I think that situation can kind of arise naturally too even if you are doing pretty good composition of breaking things apart. And that like if you have two or three processes for example that are interacting with each other, it can get pretty complicated pretty fast. And I've run into scenarios there where it’s very difficult using just some print statements to figure out what is going on. Unfortunately, it really is a bunch of processes , then something like Ruby debug generally isn’t all that much more helpful to me anyway. It doesn't easily allow me to grab all three and peek inside at the same time with that exact same thing.
GREGORY: Yeah, definitely you need sort of need that integration testing harness that will deal with looking at it from the whole picture.
CHUCK: Yeah, that would be interesting. I'm a little curious as to what that would look like.
JAMES: Yeah. At that point, I tend to use a shared log file and have everybody start writing to the log so that you can see with each process identifying it’s process id and things. So there again, I'm just using a more elaborate form of a put statement, in that I'm throwing them in a log just so I can see what each one is thinking at the same time.
CHUCK: All right. I have one more question that I wanna jump in on, and then maybe we can change tactics a little bit. Have any of you guys used the debuggers that are built in to the IDEs? And do you find them more of a useful tool or more of a distraction?
GREGORY: I've never used an IDE for Ruby ever.
PETER: Don’t bother.
JAMES: Don’t bother [chuckles]. I think they are a lot more popular in languages like Java and stuff, where the language is so static that the IDE can make a ridiculous amount of assumptions, and thus do a lot of things for you. You can say all the refactoring and stuff like that that languages like that have because they are very static and you can always count on them. In Ruby, where everything is so dynamic, that it is basically impossible for the IDEs to know exactly what they are looking at, I think that lowers the appeal. And I don’t know, then again, it seems like there's kind of two levels of programmers; there's the level where they wanna have as much as possible done for them, and then the ones where they really want to just be in control of everything. So I guess this is me saying I'm an ego maniac and I just really need that level of control. So yeah for me, it’s just a text editor.
CHUCK: [Chuckles] Happy birthday, ego maniac.
JAMES: [Chuckles] Right. Exactly.
MIKE: I used to be a .NET developer, and I used to spend an awful lot of time in Visual Studio and we used the debug a lot in that environment. I think the difference between Ruby and an environment like Java or like the .NET world is like the amount of complexity in the environment and in that culture. And the debugger is useful because that’s really the only way to discover, not really what the problem is that you are having but just how system works, right? Because you can't go and just look at the source code. You can’t gem open and go through your different libraries. Eventually got to place a break point and inspect all the different actors that are going on in your system at runtime, to try and get an idea about what the system is actually trying to do or how the system is trying to accomplish the task at hand. And so, I agree it’s probably a philosophical approach to the how you code and how you organize all of your different concerns and solidify it to instructions that are getting saved into a file somewhere. But I also think that there are just some things to be said about these big giant companies trying to push out a solution that's going to solve everybody’s needs, and the overwhelming complexities it comes with that.
PETER: Have you tried Ruby Instil?
MIKE: I've played with it a little bit.
PETER: The debugger in that, I mean I have to try all these things just for the fact that I end up writing about them. So I need to play with them a bit, but yeah, it’s just like a Visual Studio; it’s hugely visual studio. Its IDE for Ruby on Windows. It’s like one guy working on it and he had done a crazy job on it. But the debugger in it I think was like written from scratch, so it’s not using any of the existing stuff and it has like in Visual Studio, you get like conditional break points; so you can like put in condition that you want to be true like x==10, at literally any point in the program where there's a local variable called x==10, it will stop. You can chance variables on the fly in your break points and everything. It’s just really crazy. But I'm not using Windows and I'm not using Visual Studio, but if I were, it’s just a really slick implementation. And I imagine it’s a lot like what is on Visual Studio for .NET developers, but I've never done any .NET developing, so I'm imagining it’s a similar situation in that area, though.
MIKE: We never really used the debugger in Visual Studio to debug our code; not nearly as much as we did just trying to figure out what the hell system.windows.forms is doing. It’s so opaque; you just can't see through it.
JAMES: Right. When is this chunk of code being called, when does this change to this, kind of thing.
MIKE: Yeah, I mean and after like the 300th page of MSDN documentation, you just start to not remember what you are reading anymore, and just going straight to the sources or straight to the behavior within the debugger is a lot easier way to learn.
JAMES: So I got a couple of things out of there. Mike mentioned gem open, which actually my particular technique is gem unpack. I'm not sure if that is similar. Where just throws the source code into a folder that I can crack open and go look at exactly what Ruby is doing -- and I really love that. That kind of made me think, maybe we can go around the horn. Anybody have any other great tips for debugging? Because I have a couple I think I could give that may be helpful.
PETER: Why don’t you start first?
JAMES: Okay. So in Ruby, especially if you have threads going and a thread dies with an exception, the default behavior is to just carry on. And it’s not until you do something like join that thread where you'll get the exception, and I've seen multiple people just totally mystified by this behavior because their program actually had some problem way back when, but then they find out about it later. And on Ruby’s thread class, there's a method called “abort on exception =” and if you and if you call abort on exception = and pass true, then the minute any thread has an exception, the entire Ruby interpreter will just die with your stack trace. And that’s like super helpful for debugging thread exceptions. Then other things that are cool to know about, Ruby has a debug flag, its -d that you pass in the interpreter. And it sets a global variable, $DEBUG to true whenever you use that flag. And this causes Ruby to have lot more error spitting behavior which is great; you get a lot more feedback from things that happen. But you can also use it yourself. So you can just write statements in Ruby and say like puts such and such if $DEBUG. And then that way, when you want to trigger those statements, you can just start Ruby with the –d. When you don’t wanna throw those statements, you cannot start Ruby with the –d. So I kind of like that mechanism for debugging prints when I wanna put some in, I'm working with something. Sometimes it doesn’t work well, if you're using a lot of other libraries or stuff because they tend to be so chatty in their behavior that drowns out the other stuff. But if it’s just a simple program yourself you are using, it’s pretty good technique. Some other things we've already mentioned puts and of course p, which is ruby’s debugging print that prints more like Ruby sees the object. Other things that are nice if you have yaml loaded, yaml makes a y method. It’s literally just the letter y and that will print out as a yaml document basically. Which is sometimes helpful for more complex objects with a bunch of fields, so you can use that as another form of debugging print. And I know that there's libraries out now that do really cool stuff like awesome print and stuff. I don’t tend to use those. I actually had somebody ask me the other day, we were looking at an IRB session and he said, “Do you have you can just turn that on and it would show us the names of these objects.” And I said, “Sure.” And I did .map&:name, so I could see the names of the objects. And I think there again, it’s back to the context shifting. I prefer to use my programming to show me what I wanna see. But if you do like those automatic shows you more information, you might look at something like awesome print. And then one other tip that I thought of at the time are are having this conversation in Rails, there's a method in the views that help our method called debug and you can pass it an object and this time it’s little “debug”, but you can pass it an object an it basically turns it into yaml, sticks it into pre tags and then drops in to the page right there. So that can be useful for seeing what's going on inside of Rails. It will ---- your page really bad, but you'll be able to see what's going on. So those are just some of the many debugging tips I can think of that I´ve used before.
CHUCK: Wow. That was awesome.
JAMES: I was saving them up.
GREGORY: So I've got a couple; and this I don’t use very often at all, but I found that’s useful or at least interesting when I do use it, is that pretty much object freeze is useless for pretty much everything, except that if you freeze an object that you expect not to change, and then pass it through a path where it’s not supposed to change and then something tries to change it, it will blow up on you. So if you’ve got like some object that’s been passed around that’s been modified when it’s not supposed to be, like maybe there is an array that has a dangling reference somewhere that’s being changed or something like that, if you freeze the object, then it will get you to the exact line where the modification was attempted.
CHUCK: Oh, that’s interesting.
JAMES: That’s a really good trick and it made me think of one more that I've seen if you are using a API like rexml some kind go xml parsers, pull API where it reads and then calls methods as events happen or something like that, basically any evented API, sometimes if you wanna figure out what exactly is going on, you can pass just an object with method missing defined, that just puts whenever called and shows what arguments it got and stuff like that. So you can see are being called with which arguments and that shows you exactly the interface that you need to implement. But yeah, Greg's trick you are using freeze is very helpful in those scenarios too.
GREGORY: So another one that I don’t use often but is still interesting I think is that if you require yaml, you are actually, you got a y method and y pretty much works like p, but it makes the output in yaml. And then again that’s not especially useful, like I wouldn’t use it as a replacement for like pp or something like that. But what it does do which is interesting is because of the way that yaml works, is it will make references to the same object look very explicit. So if you think that you are dealing with a bunch of copies of objects but you're actually dealing with references to the same object, it’s sometimes a lot clearer to look at it through the yaml output than it is through any other inspect format that I've seen.
CHUCK: Yeah, that sounds useful too. I think James mentioned that. I'm taking notes, but I didn’t write who said what. One other trick that I think James kind of mentioned in reverse, that I would bring up is that you can create a logger. And I've don’t this before where I've just needed specific output from a specific process, and so what I would do is instead of doing a whole bunch of put as in there, I would just put a logger. And so I’d create a logger, I’d have it logged to its own file and then I would just have it dump a whole bunch of information out to it and then dig through it that way. And James also mentioned pulling in where you have everything logging to the same place and that's also useful in a lot of cases, where you have multiple threads or process working in the same way or working on the same data.
GREGORY: So James, when you use that approach, do you do something to make sure that the logs indicate which process is which?
JAMES: Yeah, I try to pretty much always do that. In fact, that’s the one thing that bugs me about Rails logger is that it doesn’t, by default, include the process id and I always will do that; if I set up the log, I will make sure that is part of the information at the beginning of the line that the process id is in there so I can tell exactly which program did what.
CHUCK: Oh yeah, that's a good idea. I haven’t really thought about it but it makes sense.
JAMES: It’s really helpful. I got one other tip for debugging because I've only learned this one recently and it’s like a whole new world for me. So this is my best recommendation. And I actually saw it tweeted this is ironic because I saw it tweeted just the other day and I made sure to retweet it, but seriously do not debug alone. You don’t have to, and you will not believe what a difference that makes. I've recently been working on a project where there's another developer available to me and I can't believe how when I run into a problem, if I go get that other developer and ask for help, I think it’s hard because by default it kind of make us look bad like, “Oh, can I bug you for a second?” But it’s like whenever I try to debug it on my own, it’s like 45 minutes or whatever, I'm sitting there doing it and whenever I ask for that help, I swear within 10 minutes we both have it And it’s just the fact that two minds really are better than one. Its whatever you miss, the other guy will see. Whatever you didn’t think, he will. And man, it makes all the difference in the world. So open invitation if you are stuck and you are fighting a bug, call me on Skype I´ll be your wing man.
CHUCK: Sounds good.
GREGORY: That’s a really good point James. I think part of it is that whenever a bug happens, it’s basically impossible at least for me, not to already have a path in mind that I wanna go down. So I might miss some obvious things on the surface that weren’t on that path that someone else just looking at the screen you could see.
CHUCK: Yeah, one other thing that I want to add to that is that a lot of times if I've written the code, then I have some certain expectations of certain parts already worked and if I have somebody else come in, then they don’t have those same assumptions and a lot of times, they’ll take you in a different direction.
JAMES: Exactly. A lot of times you are like, “I just know it’s over here.” But the other guy, he doesn’t have those. And he's like, no its probably that other method you wrote that’s crap. And he'll say that and he'll force you to prove it. And maybe it’s not true; maybe that’s not really the thing, but it’s the fact that he forces you prove do that, that he doesn’t have those preconceived notions. And I've got to stress that whenever I can debug with someone else, every time I'm amazed that how quickly we go straight to the heart of the problem. So stop debugging alone. That’s my advice.
GREGORY: So this is a bit of a tangent, but just because you mentioned the word “prove”, I actually used little informal proofs all the time when I think that some assumption of mine about a system should be true but I know that if I just assume it, that it could cause problem for me. So a lot of times, I´ll right up the little examples or mess around an IRB to test the concept rather than just trusting my intuition, because if it works out the way that expected to, it’s good because I can sort of assume it’s going to be true which reduces the solution space. If it’s wrong, then I have to completely rethink things. So sometimes, I´ll attack a bug by checking my assumptions without even necessarily directly working on the bug itself.
CHUCK: Yeah, and I think a lot of those proofs that you are talking about make really good tests.
GREGORY: Right. They certainly sometimes so it depends on whether they test anything of value, because sometimes what they are are just exploratory sort of things. But in the end, for the most part, if there are some behavior that you are trying to verify and you don’t have a test for it, the structure of that naturally translates to the test -- without a doubt. There's just a question of sometimes those are like not really describing a behavior, they are just exploring some part of the process. And that doesn’t necessarily need to become a part of your test suite.
CHUCK: Yeah, that makes sense. Now I wanna ask a question, and I know that this is pretty specific to the problems that you might run into or the the bug that you may find, but what is your process once you found a bug for actually fixing it or solving the problem? I mean at that point, do you write the test first and then solve it? Or do you just go in and change it and see if that makes the difference?
GREGORY: For me, I normally will try to and see if can make a difference, make it fix and then I rerun through the manual test process. And then once I've confirmed that, I´ll normally stash my changes at a test, and then reinstate them to see if the test passes.
JAMES: Cool use of stash. I like it.
CHUCK: Anyone else? Is that how everyone else does it?
JAMES: Yeah, I think finding a bug for me is usually building the tests, so at that point I already have it and then I feel free to go in there and just start hammering a way of fixing it because if I break something else, then hopefully my test will show me that, right?
GREGORY: So James, let me ask you this, do you find sometimes that you are writing tests… the reason why I don’t normally start with tests is because a lot of times I´ll write a test but it’s at too high of a level and then I write another test and then I write another test. So I get a reproduction but it is not really the minimal reproduction. And then I get a test that is valuable as a validation, but doesn’t necessarily describe a behavior and it doesn’t describe the bug at low enough level to be a sufficient fix. And so you find yourself sometimes running too many tests that way?
JAMES: That’s a good point. I do tend to guess what level it’s at and you are totally right that I guess wrong fairly often. Oh, that’s got to be in the a controller and you go write a test around that controller and you find it, but then you did and you are like, oh no, actually it was down on this model method. And when that happens to me, I actually… this isn’t the most efficient way so I am not offering a great solution, but when that happens to me, I just go rip the test out of my controller and I rewrite it as I model test when I've moved it down. So I've kind of honed in on it, but you are right, I'm kind of wasting some effort there.
GREGORY: That was what I was curious about because I mean, if you are guessing reasonably well, it might not be terribly inefficient to do it that way. But the test leftover, the ones that weren’t at the right level, I've actually found those… because I used to just leave them in when I try to do testing that way. And then I found that those would make for brittle test because they'll be testing something that like exposes the problem, but isn’t quite at the right level so they don’t fully solve the problem. And they also, if you get a failure from one of those tests, it’s not necessarily a sign of the problem later moving on. So it’s good to hear that you remove them because that's always the thing that I wrestled with and caused me to avoid writing them.
JAMES: I think that’s actually kind of an interesting point because then I think people have taboos about removing tests, but if a test is useless for any reason because things have changed or my understanding has changed or whatever, I don’t have any problem removing a test. I would rather have the right amount of test, covering what I wanna cover, then some ability to brag that, “ooh, look I wrote ten times the amount of test I did as normal code.”
PETER: But it’s my baby!
JAMES: It’s my baby, right. It’s not important to me. I'm a baby killer.
PETER: Nooo! You heard it here first.
CHUCK: [Chuckles] All right. Well, I'm going to go head and make the call. We’re going to move on to the picks so that we can honor that time contract that I always bring up when I end the conversation. If you are new to the podcast, the picks are basically just the things that we find that we like. Usually, most of them are code related that make our jobs or lives easier, but you know, we do bring in other things as well just whatever we are into at the time. So I'm going to go ahead and we'll let the birthday boy go first. James, I know one of your picks is birthday cake, right?
JAMES: Yeah, who doesn’t love birthday cake. So the pick I'm going to make today for my birthday, my wife took me on to the game store and let me basically just pick up whatever I want. Actually, the Ruby community has been kind of getting in to games. I've noticed if you go to the conferences and stuff there’s usually some kind of fight events going on with gaming and I totally encourage that you get into that if you haven’t yet tried a few out. But for those of you who don’t know, there's this massive world of games out there, board games we are talking about here, card games that kind of thing that does not mean Monopoly and Scrabble. So if that's your idea of a board game, you have no idea what you are talking about and you are really missing this cool world that is out there. Lots of Euro games; the best ones tend to come from Europe. So I'm going to recommend everybody who is not yet checked out all the cool games that are out there. If you just want something great to play with your wife or friend, then try something like Lost Cities or Jambo. If you want a great group game that you will have a total blast, it’s a lot of fun, try Pandemic, which is actually a cooperative game, so you are all on the same side against the board which is trying to destroy you. It’s a very fun game, everybody loves it. And then if you just wanna go crazy, then you can try games like Agricola or Race For The Galaxy and things like that. But all great games. So if you haven’t checked out the world of gaming lately, you need to try that. You are missing something.
CHUCK: Wow. I haven’t heard of any of those. Now I feel ashamed.
JAMES: [Chuckles] See? I gave you a great pick.
CHUCK: Yeah, well my wife and I were into the board games and we've played several of the ones that come out of Europe; just none of these.
JAMES: So what ones do you play, Chuck?
CHUCK: We really got into Catan a while ago. We also got into Ticket To Ride… I'm trying to think. You put me on the spot and I don’t remember.
JAMES: Ticket To Ride is very good as well. Those are both good and a little bit casual, and a little bit gateway, so you can go farther, keep going. You are getting there.
CHUCK: Oh, you are going to ruin my life. All right Peter, go ahead.
PETER: Okay. First I'm going to tell James the cake is a lie.
JAMES: [Chuckles] Oh no!
PETER: That’s important to know. I´ll just do a very quick antipick, which is that Scrabble is an amazing game. It’s a very good game and it’s probably the only board game that I actually like and will consistently play. So just different strokes, to different folks, I guess. I'm just a big, big, Scrabble fan. So to hear it being dismissed, so callously just wrangles my… yeah I´ll stop picking on those cool words.
JAMES: Actually, that’s hilarious because the one normal board game that everybody plays that I do still play all the time is Scrabble is so I was unfair in dismissing it.
PETER: So, yay for Scrabble. So I used to play normally, but my wife is quite good at it and she is very relentless; she's a different person when she plays it and she will like take me to the cleaners. So I've kind of got off Monopoly since marrying here. So, moving on to slightly technical things though, this is kind of like attack James day, I kind of wanna stand up for Michael Dvorkin and Awesome Print because awesome print really is awesome. I really do love it and there's lots of cool stuff in there like you can do just ap and it let you use an active record class and bam, it will show you all the attributes. And you know it will kind of just use magic in a lot of cases to work out what you see about something and not necessarily what you are technically trying to represent. So it’s just lots of cool stuff in there. Worth checking out, Awesome Print. And along similar lines because we are talking about Rails a little bit, there's something called Rails foot notes and I've not used this, but I've seen so many people raving about it on twitter so that I thought I should mention it. It puts like a bar on your browser and you can define what stuff you want to appear in there, and that can include debug information and session information, stuff like that. So that could be useful if you are doing sort of more light higher level debugging in a Rails app so people just keep recommending it to me and I've just been too lazy to try it, but I might as well pass that on. And last but not least, I've been just kind of like casually keeping an eye on the Go programming language over the last year or so. I think it came like two years ago now, and I just sort of have a casual on it. And there was an article out recently called, The Go Programming Language, or: Why all C-like languages except one suck. And basically, it’s quite a long kind of introduction why Go is cool compared to say C, C++, C# and what it brings to the table. And it just sums up Go so well and why you should perhaps give it a go. And Go is a cool language. I think we are going to see a lot of systems programing being done in it over the next 5 to 10 years’ timeframe. It’s still a baby. I´ll be sending the link across so you can put that in the show notes. So that’s me.
CHUCK: Awesome. Sounds interesting to me too. All right, I´ll go ahead and go next. While I was traveling to Disney land with my kids, there were a couple of things that really paid off for me; one was the android appstore had an app that gave us all the wait times and fast pass times for Disneyland while we were there. So I literally will just pull out my phone, turn it on and unlock it, and I could see what the wait times were and I could take my kids to the lines wouldn’t kill them off because they are 4 and 5 to wait in. It was really, really, super nice. So I´ll put a link to that in the show notes if I can find one. Otherwise I´ll just put the name of the App because I don’t remember what it is. One other pick that I have is my sister turned me on to a book called Elantris by Brando Sanderson. The copy she had had been my brother’s before she got her hands on it and it was pretty well abused and worn out. So I started reading it. I actually bought it on the Kindle store on my iPad app, and it’s a really fun book, I'm really enjoying it. So I guess my pick are just a game and android app. That’s what I did the last week.
JAMES: At least you didn’t say, “Everything James said is bad.”
CHUCK: Well, I didn’t have to. Peter already said that.
JAMES: Thanks. I'm not showing up for another podcast on my next birthday.
CHUCK: [Chuckles] All right, by then hopefully your count of episodes and my count of episodes will be the same again because you’ve been on more than I have now.
CHUCK: All right, Gregory Brown, what do you have to pick this week?
GREGORY: Well, the first thing is my wife and I decided we wanted to stop being couch potatoes and get some exercise. And this is something that I've already seen a lot of Ruby programmers do, but we've been doing the couch to 5k program. And basically, the idea is that like in a period of 9 weeks, you can go from a completely sedentary lifestyle to being able to run a 5K. I don’t know that that is realistic, but we've been doing it for three weeks now. And it sure works because it starts off by just incrementally trading walking and running. So you get more running and less walking, overtime. And for someone who is very, very bad about being consistent or determined about exercise, the program has worked for me and it’s actually fun. And there's also stuff you can get apps for it for android or iPhone or whatever we've been using. You can also get mp3s that are set to music that do the timings for you, which are nice. So I would recommend the couch to 5k program for anyone who wants to get into exercise in a really gradual way. I'm in hideous shape in terms of my physical fitness, and it’s really helped a lot in just a couple weeks. So the other thing and I swear that Peter hasn’t given me a check for this -- at least not yet -- is I’d like to recommend Ruby Flow, which is a site that Peter runs where basically… I don’t know how to describe it except for that it’s like meant to serve some of the same purposes of what you would use, Reddit Ruby or Hacker News for. But it’s a totally different thing, because there is not voting associated with it. You basically get just a little blob of HTML, where you can put a paragraph in a link and then that gets put there like with everybody else’s stuff in that day. And I found that during the whole Ruby gems fiasco that I've been trying to get information out to people about that, and I did this stuff on my personal blog which now has a reasonable audience, but didn’t before and that was a way to reach people. And it was also a way just to sort of get information out there without it being yet another point for conversation. So I think that it did drive people over to the blog. I mean there's a comment system on the Ruby Flow, But it seems more like it used for posts than it is for comments. And it’s a cool site. In fact, I like it so much that we are stealing his idea, and were going to have something like that a more curated list for the students at RMU. We're building a system inspired by Ruby Flow, so the students at RMU can show what they are interested in. But just the mechanics of it are neat and I wish it was more used than it is even though it has surprisingly good traffic. He didn’t pay me for that endorsement, but maybe he should.
PETER: Yeah, you get $5 off the show.
CHUCK: [Chuckles] Yeah, I have to agree with you on that one, Greg. When I was getting started with blogging and things, it was a great way to build traffic to my site and as well to look and see what was going on and figure out what people wanted to hear about. It is definitely a great way to get your message out there, as well to interact with other rubyists who are out there sharing what they have to share as well. So last but not least, we got mike Moore. Mike, what picks do you have for us?
MIKE: So I wanna give another plug for the open gem. Open Gem is a plugin for Ruby gems and so you install it with gem install open_gem and you can call gem open open_gem and it will open the gem in your editor. And it’s not going to make a copy like unpack will, it’s actually going to give you all the files that are on your file system that Ruby is using to run that library, so that you can actually edit it right then and there. So if you need to debug an external dependency, you just open up a gem as it’s set in your system and edit it. It’s a really great little tool. CHUCK: Sounds good. Sounds pretty handy.
JAMES: So when I'm doing that and I don’t wanna edit a gem on the system because I'm like scared of that…
MIKE: Then don't save.
JAMES: Then don’t save, yeah that’s a good point. But then you have to run it, right? So you have to save to run it, right?
JAMES: When I'm doing that, I just use Ruby’s monkey patching; so I just like grab a method and I copy it out of the gem that I unpacked and just drop it in whatever file I'm messing with right there and I edit the hell out of it and when I'm all done, I just delete it.
MIKE: I like Open Gem because it’s a little bit easier for me to read different source code in my editor than it is to use something like GitHub file viewer and stuff like that. So I'm just more comfortable reading code in my own environment instead of on a webpage. I just like it. So since I've found it, I end up reading a lot more source code. So it’s part of that whole issue that folks are talking about a year or so ago but just reading source code. And I found the open gem plugin to be a really handy little tool for doing that.
JAMES: It is a cool idea, it seemed lots of people do it.
CHUCK: Yeah, I've heard about it too. Was there anything else, Mike?
MIKE: No, that’s it.
JAMES: Mike was the quiet member of the show, but entire time at the back channel, he was telling us what to talk about. So this episode is brought to you by Mike Moore.
MIKE: That’s actually what I do in my Ruby podcast, so.
CHUCK: Well that’s what makes a good interview. All right, we are going to wrap this up then. I wanna thanks in no particular order, Mike Moore, James Edward Gray, Gregory Brown, Peter COOPER and I'm Charles Max Wood. Thanks you guys for coming on the podcast.
MIKE: Thank you.
JAMES: Thank you.
CHUCK: There are a couple for things I wanna point out; first off, if you go to rubyrogues.com you can get the show notes. Also there's a new link at the top that says “request a topic.” We're using user voice or that. I'm not completely fond of the interface, but you can vote for existing topics that other people have suggested or you can suggest your own. I appreciate both of those, and that gives us an idea of what you wanna hear about so that we can talk about stuff that’s relevant to you. The other thing is go ahead is to leave comments on the post, so that we can see if there's anything to add. I think this particular discussion, I think there are probably other tricks that we don’t know about or have missed, and so if you have other debugging tips, go ahead and leave those in the comments. And finally, leave us a review in iTunes. We really appreciate the feedback that we get there on iTunes. You can rate it, you can write a review. Writing a review helps us out a little bit more and it only takes a couple of minutes. So by all means, do that and we will catch you next week.