- Dan Kubb (twitter github bio)
- Avdi Grimm (twitter github blog book)
- Charles Max Wood (twitter github Teach Me To Code Rails Summer Camp)
- James Edward Gray (blog twitter github)
- Josh Susser (twitter github blog)
- Staying away from magic
- DataMapper is a variant of ActiveRecord
- Coding Disciplines
- Coding is an experiment
- Try something new and see how it affects your code. If you like it, keep it.
- Mutation testing
- Code Review
- Pure command query separation
- All code is experimental
- There’s no such thing as a good design
- Try something that people are saying isn’t a good idea to understand why
- Dan’s style guide
- boring stories: No story is uninteresting
- test coverage
- discipline vs creativity
- Adam Keys’ blog (James)
- Breaking Bad (James)
- DavidBradyPickMachine.com (David)
- webhamster.com (David)
- Michael Feathers: Tell Above, Ask Below (Avdi)
- Objects on Rails Google Group (Avdi)
- Github Ruby Style Guide (Josh)
- Larry Niven (Josh)
- Known Space (Larry Niven) (Josh)
- John Carter (Josh)
- Things (Chuck)
- F*ck You, Pay Me (Chuck)
- Mutant (Dan)
CHUCK: So, I have a question for you, James. I’m going to be ordering this horrific hat [laughs] that I’ll be wearing in a month. Can I ship it to your house and have you drive it to the Rails Conf for me? [Chuckles]
JAMES: So Chuck, you’re shipping your porn to my house again?
JAMES: Seriously? Yeah, go ahead. It’s fine.
CHUCK: Alright. I’ll need an address. You can just put it in the chat or Email it or something.
JOSH: What is this about hats?
[This podcast is sponsored by New Relic. To track and optimize your application performance, go to RubyRogues.com/NewRelic.]
CHUCK: Hey everybody, and welcome to Episode 47 of the Ruby Rogues podcast. This week on our panel, we have Avdi Grimm.
AVDI: Hello, hello!
CHUCK: We also have David Brady.
DAVID: Hey everybody! Dave Brady, Chief Metaphor Officer at Sliderule Labs.
CHUCK: We also have James Edward Gray.
JAMES: You guys don’t realize what I go through to be in this show. I just sat through 20 minutes of emotionally scarring material.
CHUCK: [Chuckles] That’s so true. We also have Josh Susser.
JOSH: Hey, good morning from San Francisco.
CHUCK: And I’m Charles Max Wood from Teach Me to Code. We also have a guest rogue, and that is Dan Kubb.
DAN: Hey everyone.
CHUCK: Do you want to introduce your self for those who don’t know who you are?
DAN: Yeah, I’m Dan Kubb. I’m working mostly on the DataMapper project. And in 2009, I won the Ruby Hero Award for that. And I do a lot of other open source stuff in Rails and random small projects. And right now, I’m working on mostly DataMapper 2. So, that’s pretty much it.
DAVID: So, I got to lead with one question, Dan. DataMapper, is that thing still around?
DAN: Yes, it is. [Chuckles] I mean, we’re obviously competing with Active Records. So, that’s pretty tough. But we still have a pretty active user base. It’s not quite as busy as back in the Merb days. But the DataMapper project was much stabler now than it was back in 2008, 2007 when the bulk of the Ruby community tried it. But yeah, and DataMapper 2, we have some great plans for that. We’ve been blogging about it here and there. And if you want to talk about it, I will.
DAVID: So, we actually have a different topic for the show today. But DataMapper — so, I’m a big fan of magic. I love some magic. I love to get as much active support monkey patching up my business as I can handle. But DataMapper, have you guys stayed true to the philosophy of ‘No magic, everything should be explicit if you want it. It should be out where you can see it’?
DAN: Yeah. There are a few things that we do differently. For one, all the attributes are declared inside the model so you could see what’s happening. We do try to stay away from magic when we have multiple different ways of doing things. We try to do the simplest thing that will work. And obviously, there are things depending on your level of experience, that might be considered magic. But I mean, we definitely try not to do things that are not overly clever.
DAVID: I think it’s brilliant. I think it’s good to have two competing models coming from opposite ends of that spectrum so that people can try both and use which one is going to be the best fit.
DAN: Yeah. I mean, one of the things with DataMapper is that, it’s actually, given the name, you would think it’s an actual data mapper, but it’s actually a variant of an Active Record, at least, Version 1 is. But what we are working on with DataMapper 2 is like a real mapper so that you actually write normal Ruby objects and then you write a mapper that will map them to the persistence engine. So that you can test things in isolation rather than having everything coupled into single object.
JAMES: Holy cow! I have not heard about this and that was very exciting.
AVDI: There have been some talks and some blog posts going on about this.
DAN: Yeah. It’s something that we haven’t promoted yet because we are still in development. So, it’s not like we are going everywhere to talk about it. But yeah, if you actually look at the trend, a lot of people are doing crazy things with their Active Records to make them more easily testable. Maybe that’s a sign that the model itself needs changing. So, that’s what we’re trying to do.
CHUCK: Yeah, that’s really interesting.
JAMES: Sweet! Looking forward to checking that out.
CHUCK: Yeah. I just think that the whole idea of being able to go ahead and like, well, for one, to test it out in isolation. But the other thing is like if you have some obscure database that you want to use, you could just write your own adapter, persistence layer for it and just kind of go with it that way.
DAN: We’ve allowed that to some degree with DataMapper 1. I mean, people don’t know this but there’s about 40 adapters, backend adapters for DataMapper 1, for everything. There’s the normal database ones you’d expect, but there’s stuff for, I don’t know. I can’t even think off the top of my head. Oh, Salesforce. There’s one for Salesforce and there’s one for all sorts of web services. But yeah, what we’re going to do with DataMapper 2 is make that even easier and make that easier for people to map to their crazy back ends, legacy back ends or even back ends that were created with Active Records.
CHUCK: They have an adapter for Salesforce? Did they write that in pure pain?
DAN: I have no idea.
AVDI: I did a talk for Red Dirt Ruby last year where I showed how to write, in 20 minutes, I showed how to write an adapter to Google spreadsheets. I’ll confess I didn’t actually write the original code in 20 minutes but it was very quick. The wonderful thing about writing DataMapper adapter is, one of the reasons I love it so much is if you want to write an adapter, there are four methods that you must implement. Create, read, update, and delete.
DAVID: Once you actually have the vials of orphan’s tears, the four methods are easy.
AVDI: Okay. So, this is actually a pretty good lead in to…
CHUCK: To orphan’s tears?
JAMES: Wait! This isn’t what we are talking about this week.
AVDI: So, it was kind of my idea to have Dan on the show and this got a good lead in to why I wanted to have him. I’ve been using DataMapper. Anybody that watches me tweet or something knows that I really love DataMapper. I’ve been using it for years ever since my Devver days. And so, as a result of using that, Dan has been one of my coding heroes for a long time because one of the things that I love about that project is that the codes, at least the parts that Dan has been able to renovate, is just beautifully written, very easy to follow. One of the first major things I did with DataMapper was implement an adapter or actually help update an adapter for Amazon, I think SimpleDB. And it was just so easy to follow the code that was in the project. He’s been kind of a hero of mine because he writes really, really clean code. Every time I read his code, I feel bad about my messy code.
And then more recently, I’ve had the privilege of actually working with Dan in Code Benders. And so, I get a better window into his working process. And I realize that a lot of his, a lot of the cleanliness and beauty of his code comes from the fact that he practices a lot of careful coding disciplines. And he talks a lot about just trying different coding disciplines to discover what effect they have on his code.
Dan, can you expand on that a little bit and talk about like why you try coding disciplines and what that does for you?
DAN: Yeah, sure.
JOSH: Can you start with a definition?
AVDI: Isn’t that your job, Josh?
JOSH: No, it’s my job to ask for it.
AVDI: Oh, okay.
DAN: Is that for me?
JOSH: Yeah, sure. What’s a coding discipline?
CHUCK: Object dot put in corner Josh.
DAN: No, the way I see it every time you write code, you’re experimenting. You don’t know the solution upfront. It’s very rare that you would know exactly how to solve a problem. So, I might take a small project or even a branch in an existing project and try something out. Usually, I’ll make a specific kind of constraint for myself and usually, there’s lots of them. But you know, I might say, for example, I did some tests with some early DataMapper 2 code, this was like two years ago where I said, “I want to experiment with mutation testing.” So, I’m like, “Well, how will that shape my code?” So, I will actually try my best to go through and write it using that constraint and many others and see how it shapes my code. And if I like it, I might roll that into the main project or I might just throw it out and tell a bunch of people, “Maybe this didn’t work for this reason.”
What I try to do is go in with constraints and one thing that Avdi and I were talking about before that I think might have sparked this talk is that I told him that the longer I code, the more constraints I have for myself. And I don’t think it makes me slower. I think it makes me faster because when I come into a new project, I can apply the constraint that I know that work. And I keep experimenting with new ones. I might try metric-fu or some of these other things and see how they change my code.
No, I don’t necessarily believe in taking tools and following them precisely without thought. But when they flag something, I like to look at it and try to understand where the author was coming from so I can decide, is what they designed for in their tool applicable to what I’m doing? And I think it’s good especially when you’re doing lots of coding by yourself like I do on open source projects that I have that feedback because with the Code Benders team, you can pass things through for code review. But I don’t always get that in my open source stuff. That’s pretty much it.
AVDI: You mentioned mutation testing. For those who don’t know, can you explain what that is and what it does for, like what is the result that using that has on your code?
DAN: Mutation testing is something that I started doing a while back with a tool called Heckle. And what it does is it will take a method and change something, like it’ll flip a bullion from like true to false or it’ll replace a string with some random string. And then, it will run the tests and then it will see if the test passed with that mutation in, then that means that there is some state that the program can be in that isn’t tested.
So, I started using Heckle and it was really great on small projects. But on larger projects, it couldn’t work. Because what happens is you mutate the one method which means just flipping one thing and then you run all the tests. And if the tests take ten to 15 seconds which actually is pretty fast for like a Rails project, it would take extremely long time to mutate every method in, and every variant inside each method, because you’re running the entire test every time. So, I kind of gave up on Heckle at that time.
But more recently, let’s say in the last three years, I started doing something a little bit differently where I would mutate a method and I would just run the test specific to that method or specific to that class and it cut down my times down to a manageable time. So, I can actually heckle my code. So, it allowed me to have a lot more confidence in my test, that my tests were actually testing things. At the same time too, I wouldn’t recommend it for every project because it’s a lot of overhead to make sure you’re proto-heckable or mutation testing safe. So, I use it in parts of DataMapper that are foundational that have to be solid. I don’t know if I’ve used it in every project. But it’s been quite interesting to see how it shapes, how I write tests, and how I think about the different states a method can be in. That’s just one example of some constraint that I had.
CHUCK: Well, I’m just curious as to what other disciplines or practices you’ve put in place, that you’ve kept that you now find more or less essential?
DAN: On a team code review, a good code review process is absolutely essential. In the case of Code Benders with Avdi and I and Peter and Matt, everything that we actually push to the master branch or integration branch is we go through and we — it’s almost like a game. When you write the code, you’re like, “Okay. I know that Avdi is going to see this. So, I want to make sure that it’s clean. And I don’t just get lazy or whatever.” And then, I pass it to him and it’s a good way for us to kind of spread the knowledge that we might have in specific things.
JAMES: Oh, we play that game differently when I think about who’s going to see it. That just means I include a crude comment with it.
CHUCK: Or firefly quotes.
JAMES: That too. I’ve done that. Yup.
DAVID: Somebody tweeted last night that they are starting to use Apple slogans as their commit messages. So, it’s like ‘Everything is different…again’.
JAMES: That’s awesome.
CHUCK: It’s awesome in comments. I don’t know if it’s useful in commit messages.
JOSH: Commit messages, you just swear a lot, right?
CHUCK: [Chuckles] Yeah. I fixed the blankety-blank because it was blankety-blanking.
JOSH: I have a quick really important question for you and that’s, where in the Avatar cycle Code Benders fall? Are they like after Water Benders or after Air Benders?
JAMES: Oh! Took me way to long to get that joke.
CHUCK: I didn’t get it until he explained.
DAN: I didn’t know what that is and I’m not going to reserve any permanent neurons for that data.
JOSH: Okay. I withdraw the joke.
CHUCK: When he said Avatar and I was thinking blue men.
JAMES: Yeah, that’s where I went too. I’m like, “Wait, what?”
DAVID: I was thinking Twitter Avatars. I’m like, “What?”
CHUCK: Yeah. Those blue men are from the other part of Canada.
DAVID: I was thinking like the Avatar Cycle is first you put the green dot on it for Iraq or Iran. And then you black it out for SOPA.
AVDI: Alright. So Dan, another constraint that you mentioned to me once was doing a project with pure command query separation. Can you explain what that’s about?
DAN: Okay, yes. Command query separation means that when you’re writing a method, you decide, is this a command or is this a query. And the difference is a query can return some value but it can’t change the state of the object. So, you can call it as many times as you want and it won’t change anything. A command, you never really return any — well, you can return whatever you want but I usually return self from those. But the purpose of it is to sort of change the state of the object.
And one of the things I did in one of the core pieces of DataMapper which we’re now code naming ‘Veritas’ is I used strict command query separation. And I found it really nice for testing because I knew exactly, from my query methods, I knew that I wouldn’t change any state. And it was really useful to have the separation rather than methods that change state and return values. It’s hard to reason how those things will work when you do them. I think it’s sort of the trend but there are lots of common methods that do that in other libraries like for example, Active Records, valid method, it returns the state true or false whether or not the object is valid, but it also sets the errors. So, just in the simple fact that you are asking the object for some state, it actually changes the object or changes something inside.
JAMES: That’s kind of interesting. I wasn’t familiar with that idea. So, talk to me about how a method like array delete, does that qualify because it changes the state but it returns the object if it was able to delete or nil, if not, is that a violation or not?
DAN: Well, I think that there are definitely exceptions like that. There are some cases where when you are removing something, you return the state. But in general, I usually try stick to command query separation because I like how the code looks. I find it much easier to test things when you’re doing one or the other, not both. But definitely, in parts of Ruby standard lib and core, there are places that don’t follow it. And I’m not really sure how you would do that without it, you know, the array delete. Would you set some state…
JAMES: Yeah, you’d almost have to have a last deleted thing, right?
DAN: Yeah. That would be almost just clumsy. So, I think definitely it’s one of those things if you — I try to follow it. But there are definitely places where you can’t follow it or it would make your code clunky if you tried to.
DAVID: So, do you have a way of enforcing command query or at least a notation that helps you know, I’m in command mode or I’m in query mode?
DAN: Usually in my specs, I’ll have a shared spec that will include it must behave like a command method. And then, it does some tests to make sure that I didn’t mutate the object, and same thing with query. I do try to do it but it’s one of those things that I don’t know if you can enforce with a tool specifically. One other thing that I do a lot is I use YARD Documentation. I think Avdi, I probably drive Avdi crazy with this. But I like to, when I write a method, I like to document what it does. I like to think about, what does it return? What does it accept? And at that point, I usually am thinking, “Is it a command or a query?” And usually, like I said, if it’s a command, I usually return self because then I can get nice chaining, a nice fluid interface with the chaining. Some people like to return nil or whatever, but it’s a personal process. I think the main thing when you’re doing it is not to return something that means something.
AVDI: You’ve definitely jogged my thinking with the whole ubiquitous documentation thing because I think Rubinious in general erred more towards the side of, “Let the code speak for itself.” And honestly, if anyone’s code speaks for itself, I’d say Dan’s does.
DAVID: But he’s documenting the hell out of his code. [Chuckles]
AVDI: Yeah. I mean, if you look at his code, any code that he touches, he writes full documentation for each method, explaining what it does and what the inputs and outputs are. At this point, I still have kind of mixed feelings about that. But I have to admit, on many occasions, I’ve gone in and it’s been very helpful. What got you started on that anyway?
DAN: Actually, that habit probably got started when I was writing the DataMapper stuff because people were asking, “How do I use this? How do I use this method?” So, I started using YARD Documentation on everything. And I couldn’t, you know, sometimes when I sit down at the end of the day to do some open source work, I would look at DataMapper and I’m like, “I don’t know where to begin.”
So, I actually wrote a tool called Yardstick that measures the coverage of my code and it will tell me what methods have no documentation. So, I would use that just as tool to identify what areas of the code have no API docs, and I would go in and add them. And I, too, am kind of questioning whether or not you want to document everything. But like I said, everything is — I view like almost all coding as experimental. So, what I know now, I might change my mind. And I’m okay with that. I’m okay with being wrong.
DAN: For now, I think it’s, if you look at our code, obviously, we can’t share with anyone. But I think that it feels like stopping to think about what each method does, it results in something a little bit nicer than what was there before.
DAVID: Dan, I’d like to ask you to go back and revisit a sentence you just said.
JAMES: Me too, I think you’re going to go after the same one. Go for it.
DAVID: “I like to view all code as experimental.”
JAMES: That’s exactly what I was going to say.
DAVID: A flower has bloomed in my heart when you said that.
DAVID: Could you perhaps elaborate?
DAN: Yeah. I think as coders, we’re all trying to write really good code. And to some degree, all of us have perfectionist tendencies. And I think that you have to sort of reconcile that with the fact that you can never be 100% right. Give it a long enough time. I think I said this in Campfire yesterday, give it a long enough timeline. Almost every decision you make is probably going to be wrong. So, you have to be comfortable with being wrong. I view almost all code as experimentation. That doesn’t mean that I go off and write crazy code. But also, I write it, given what I know right now, this is the best I can do. It might not be right in six months but that’s why we right tests and that’s why we write clean code and document it so we can go in and make the changes later.
JOSH: A friend of mine, the way he would say that is, “There’s no such thing as a good design.”
JAMES: That’s a great idea. It’s a good design given whatever information you have now and then you run into something six months later and like, “Ah, that’s why that was a really bad idea.”
JOSH: Every solution is like an ad hoc response to some situation and situations change, requirements change.
JAMES: That’s really good. I really like what Dan keeps saying here about, “I’m okay with being wrong.” I think as programmers, we have a real problem with that. I mean, almost what we do — and I think it’s that. It’s that what we do kind of requires a little bit of ego. You know what I mean? I mean, we run up against problems that are very large and very hard to tackle. I’m just going to design this complete system out of my head and make it all up as I go and things like that. So, we tend to have an ego problem. And then, when the day it comes around, it’s the good programmer who can admit, “Oh, yeah. I totally screwed that up.”
CHUCK: I just wanted to point out that I don’t have an ego problem. I actually am always right.
DAVID: I have a problem with Chuck’s ego.
CHUCK: It’s crowding you out two miles away, sorry.
DAVID: Completely, in all sincerity, knowing that it’s hypocritical but I am very proud of my intellectual humility. And it’s one of the things that I value about myself. I’m sincere when I say I’m proud of it which is I recognize it’s messed up. But Angela Harms came and spoke at Mount West Ruby Conf and she talks about problems with pair programming and she talks about, “Do you ever zone out?” And I’m like, “I zone all the time. That’s why I take 60 milligrams of Ritalin every day.” Well, 40.
DAVID: But anyway, the thing is that I figured it’s an ADD thing. And she says, “No. If you’re zoning out, it’s because you’re lost and you’re afraid to admit that you’re lost.” And I took a huge ego hit when she said that because I realized that it was absolutely true. I get lost. When I zone out, it’s because I’m lost and I don’t want to tell my partner that I’m lost.
This all started with Dan saying, “I tend to consider all code as experimental.” And the best freaking programmer — and we’re interviewing Dan because he writes beautiful, wonderful code here. And if you’re listening out there, everybody, be willing to be humble about your code and continuously improve. And that’s how you become as awesome as Dan. That’s what I have to say about that.
AVDI: I think it’s absolutely true. Dan’s probably not going to say this for himself. So, I’ll say it for him. He’s absolutely one of the humblest programmers I know and he inspires me. Not just in his code, but in his attitude, he inspires me every day to kill my ego a little bit more and be a little bit more open about all the things that I’m probably wrong about.
CHUCK: Right. So, two things here. First off, we should do a dramatic reading of Dan’s code and then angels can sing.
JOSH: [Singing] Hosanna! Hosanna!
CHUCK: The second thing is I’m a little curious about where you come up with new things to try. There are always new things to try out there. But it seems like sometimes, I see things and I’m like, “Ah, that just doesn’t make sense for me.” And other times, it’s like, “Well, I’d really like to try that, but I don’t feel like I have time,” or whatever. And so, I’m trying to figure out how do I find things that I feel like are important enough to give a shot to? And how do I get over the issues where I don’t think it’s a good idea and maybe it really is?
DAN: I actually don’t know exactly where a lot of these ideas come from. Sometimes what will make me a little bit curious is when everyone is saying, “Don’t do that.” I kind of want to know why. So, I will try to try it anyway, just to see, “Why is everyone saying this? Why is everyone universally against this idea?” I kind of want to know for my self, like if you hear a lot of people will talk about code coverage, for example, everyone will say 100% code coverage is a waste of time. And I’m curious, why do they actually say that? Have they actually done it or are they just repeating what someone else has said? So, I’ll try it and I’ll find out if there’s some good things in this and definitely some bad things about it. And if I feel like it makes an improvement in what I’m doing, I’ll keep doing it. Otherwise, just don’t be afraid to throw it away and try something else.
I may try lots of different things too. And each project that I come into, I try to take what I’ve done before and maybe introduce a few more constraints and just see how it shapes, how it changes the code and the tests to see if it makes an improvement. The code reprocess, I think, is really important too because when I am, say reviewing Avdi’s code and I see something that I think could be improved, I actually have to put it in words rather than just thinking, “Oh, I don’t like that.” I have to explain to him why I think that it could be done differently or better. And it sort of helps me solidify my own style. And I think that’s something that’s missing from a lot of dev shops that I’ve worked at before where their people don’t spend enough time reviewing other people’s code and actually explain possibly better ways to do things.
And then too, sometimes, I’ll come up with something and say, “Hey, here’s a better way.” And Avdi will come back and say, “Actually, this is what was going through my head,” which will make me think that you have an exception or your way is much better than mine. And that helps shape my style and the constraints that I use from that point on.
JAMES: That’s a really good point. You talked about how a lot of us don’t do code reviews and I think that’s very true. Can you describe maybe the process you guys use at Code Benders?
DAN: So, when we work on stories. And each story is programmed with a task. And when we finish all of the tasks that we have for development, we usually have another one that’s for QA. In general, you don’t QA your own stuff. So, I would pick someone else on the team that maybe has a little bit of free time after my project finishes and then I will send the code over to them. I’ll create a pull request and they’ll go into Github and look at the diff and actually add comments in line.
And usually, what I do when I’m code reviewing is I’ll do like a first pass, looking for really syntactical things. I’m just looking for cosmetic changes. If I see someone doing something like, “If not, value blank,” or something. And I’ll ask, “Why don’t you use value present?” That kind of thing. So, I’ll just do a simple pass over trying to get my way around the code. And I might do a couple more passes before I go deeper and deeper until I get to the point where I’m actually looking at the design of maybe how the classes are in rack and some of the naming between them. I will admit too, sometimes you can’t get down to the same level as the person that wrote it because you can’t. Just by reading the code, you can’t always understand exactly to the degree that they did. But I think you can get fairly close. And then too, adding comments like ‘how about this, how about that’ gets the discussion going so that you can actually get a little bit deeper into what was going through their head when they wrote that code.
JAMES: That’s really awesome.
JOSH: Dan, I’m curious what kind of coding standards, or what level of coding standards you work with like style guides or do this but don’t do that?
DAN: Actually, I have my own style guide on Github. I forked one a few years ago. If you actually go into Github.com/DKubb and I think it’s Ruby Style or something? Basically ,what I did is I took someone else’s coding style guide and I changed it and added my own. And every few months, I go back to it and kind of add what I’ve learned. It’s DKubb/StyleGuide. And it helps put it in words, it looks like it’s been six months since I’ve changed it. So, I guess I haven’t done anything recently. But it just helps me get kind of — this is basically the first level, the first pass that I do for a code review. This is the kind of stuff that I would look for. I don’t know if I necessarily could go to a much deeper level than this. But to be honest, a lot of code reviews, if you just said to someone, “Before you pass it to me for a code review, can you please just check it against this? Because this is the stuff I’ll be flagging for sure.” Starts the discussion too where people will say, “Oh, I actually disagree with this point.” And then, you can talk about why and figure out maybe there’s a better way or not.
JOSH: So, there’s style guide at the level of like curly braces versus do/end. But then there’s also things like, using a numerable inject, which some teams have things they say about using inject versus other forms of numeration.
JAMES: Those teams are wrong.
CHUCK: Hey, as long as the needle’s clean.
DAVID: Chuck is using inject to do hash.
DAVID: Thank you. I’m here all week.
CHUCK: There’s a certain key to that.
JOSH: Okay. My point is that there’s different levels of abstraction where you can worry about style guides or standards. And some of them are even higher level like modules versus class inheritance. So, I’m curious if you have things that are codified around the higher level abstractions for team style guides?
DAN: Actually, I don’t have anything specific about that. Usually when I come into a team, I’m looking at very simple, very cosmetic things. And then, we’ll get down and start talking. After we get past all that and we sort of have an agreement on how we’re going to approach things, then we might get into that level. But usually it’s — using inject, for example. I actually have a rule about inject. I don’t use it unless I’m mutating, unless I’m returning a different object every single time through the block. I’ll usually use each with object because in the case where it’s through the loop. For me, that’s just more precise because I’m actually not changing the object every single time.
JAMES: I actually want to dwell on this for a minute because it’s one of my pet peeves. The reason everybody hates inject is because we all do — in Ruby, it used to be that people used it with hash all the time and they’d pass a hash into it. And then, they’d set some key in there and they do semicolon and put the hash after it because you have to return the return value.
DAVID: That’s the only thing you can do with inject, isn’t it?
JAMES: Yes. So see, David Brady writes code like this.
CHUCK: It’s true. David Brady is doing it wrong.
JAMES: Is doing it wrong. That’s right.
DAVID: That should be our new slogan.
JAMES: In Ruby 1.9, there’s a new iterator called ‘each with object’ which is actually meant to serve that purpose. And it’s when you want to iterate with some object along with the iteration. So like the hash, you pass the hash in and every time that object carries forward, no matter what happens in the block. So, you can use ‘each with object’ and stuff like that.
Inject wasn’t meant for stuff like that. Inject is meant where you are over time building up some results and you’re doing that — the great example is if you have an array of numbers in your [inaudible] memory which Rails has its own method. But when you’re adding on to each other, that is the correct usage for inject.
CHUCK: Right. So, it’s value accumulation like the top of my desk. I need to clean it off.
DAVID: Is there really — and maybe this is too much of a side thing, but is there a real difference between inject and reduce?
JAMES: No, they’re aliases. They are the same method.
AVDI: Easy answer.
CHUCK: I’m going to have to go write Dan Kubb Lint off of his style guide now.
DAVID: Dan, I may be jumping way ahead to the end of the call. But seriously, will you go out with me? I mean, will you pair programming with me?
DAN: Sure, yeah. I’ll pair program with you.
DAVID: Woohoo! In before the rest of you guys, suckers!
JOSH: And Dan, when he zones out, you know what that means.
JAMES: It means he doesn’t give a shit.
DAVID: About you or your code!
AVDI: Dan, you said something recently in a Campfire chat that stuck with me. We were discussing, or Peter and I were discussing tickets, user stories that just aren’t interesting. The ones that you want to leave until the end because they’re just boring, dumb stories from a coding point of view. And you basically said that no story is uninteresting.
DAVID: I love this guy!
AVDI: [Laughs] For a specific reason, if you remember that conversation, could you just restate yourself rather than me try to restate what you said?
DAN: I think I said something like there’s always something that you can find interesting in a story. And sometimes, you have to make it interesting by introducing some constraints or using it as a learning experience. I think, I don’t remember the specific case. But I believe it has something to do with the story wasn’t particularly interesting. And I was like, “Well, maybe this is an opportunity to try something new.” We do this pretty religiously. But say, if you weren’t doing strict, red green refactor steps, to actually say, “I’m going to actually do this in this story.” And use it as a time to experiment with something that might be unfamiliar to you. That’s going to vary for every person. Every person is going to have different things that they want to try.
But I think, in general, you can make almost every story interesting unless it’s just data entry or something. But then, again with data entry, you can maybe automate some of it, build yourself a little Sinatra app that allows you to enter the stuff and it does, you know. So, I mean, I think that in general, you can find everything interesting. Was this the specific time where you were bugging me about being like Mary Poppins?
AVDI: That is the time when I decided I was going to start calling you Mary Poppins because it reminded me of Mary Poppins saying, “Every task can become a game. You just have to find a way to add a bit of fun to it.”
DAVID: I mentioned to Uncle Bob a year ago or more that programmers just want to work on cool stuff. And his reply was, “It’s all cool stuff.” And I’ve done data entry, raiding an Oracle database to import it into an Informix database. And yeah, it’s once you get down to like — there are some weird mapping algorithm stuff going on down here. I think this is boring stuff that let’s government comptrollers count the number of beans being dispensed by bean dispensers somewhere. Who gives a crap? “Man, there’s this really cool data structure that you have to move over.” “Oh, yeah.” That’s all.
DAVID: Apparently, I had no point.
CHUCK: No, the government came and took all my beans away.
DAVID: Yeah. Just 48%.
CHUCK: Oh, is that all?
JAMES: I’m over here reading the style guide that Dan directed us to. It’s a pretty neat exercise. I actually don’t agree with some of the things in it. But everybody should read through it because you can get some neat ideas like, using a blank line before the return value just like to set the return value apart. It’s kind of a neat idea.
DAVID: I’m actually going to take Dan completely at face value, spiritually as well. I’m going to read through this. And the ones that I don’t agree with, I’m going to try them.
DAVID: The difference between me and James is that James has probably already tried them and that’s why he disagrees, whereas I’m just an idiot.
JAMES: I like the idea of trying the ones you don’t agree with.
DAN: Yeah. You want to kind of find out why they don’t work.
CHUCK: My problem is I need to try some of the ones I do agree with.
DAVID: Yeah. If I’d only known then what I know now, I’d be happy if I could just do now what I know now, right?
CHUCK: Some days, I tell you, some days and some projects, you just don’t want to. And I think that’s part of what we’re discussing here too is that, we all know generally the right kinds of things to be doing. And it’s hard sometimes to really have that kind of discipline and sit down and say, “Look, I’m going to write this code the right way, the best I can from start to finish.” And I mean, most of the time, I’m in a mode where I’m willing to do that. But every once in a while, I really have to fight to get it done.
JAMES: There’s a good question. Dan, do you find yourself cowboy coding sometimes? Do you say, “Today, I’m going without the rules.”
DAN: Oh, yeah. I mean, I don’t think that you can maintain 100% discipline all the time. You have to give yourself a break. I might have open source projects where it’s just me experimenting off in the corner. And in those cases, I might cowboy code. I might just bite something out with no tests and just see how it works. So, I think that there’s room for everything. I don’t think that you should be slavishly using these guides and never — diverging from them is also not good. You have to stop and think about what you’re doing and sort of match what you’re going to do to how you’re feeling because I don’t think that you can maintain 100% discipline all the time. You’ll burn out really fast that way, I think.
JOSH: Dan, are there sort of false disciplines that you’ve encountered over time?
DAVID: Oh, yeah. Tell us what didn’t work?
DAN: Oh, what didn’t work. Because we were talking about mutation testing earlier, I’ll tell you some of the things that I don’t like about that. With mutation testing, if you have a code base that actually passes all mutation testing, it means that every line of code can be changed and it will cause a spec failure. And not just every line, every statement inside each line. So, if you have a condition that can be over multiple states, it will mutate to each one. And what you end up with, if you actually go through this exercise, is you end up with code that just by default will pass like [inaudible], it will be 100% covered in [inaudible].
To get to that point, I had to do some crazy stuff like specking my hash methods. So, if you’re not familiar, a hash method is something that hash, the object actually uses internally to keep track of where an object is inside the hash table. And the two objects that have the same hash value are stored in the same place. And then, when you do a look up, it will find that place and then see if it’s actually stored there. At least, I think I’m probably simplifying. James might be able to give a little more insight into exactly what it’s doing.
So I had to spec these hash methods. And these hash methods, all they do is call hash on instance variables inside the object and then XOR them together. It seemed like such a waste of time when I was doing it. Although I will mention that I did actually find a bug in, I think it was Rubinious or JRuby because of this. It wasn’t all a waste of time. But I definitely found cases where methods that were otherwise obvious when you look at what they were doing, I had to spec them so that they would pass through Heckle.
I think that if I was to do that exercise again, I might make an exception for certain methods like that and say, “This doesn’t have to be mutated,” because I’m pretty sure, by looking at the one line of XOR instance variables, that it’s going to pass.
JOSH: So, you now fall down firmly in the camp that 100% test coverage is not worth it?
DAN: Yeah. I think that you have to use your brain and decide what level is necessary for your code. I do have some foundational libraries in DataMapper that I like to be pretty high. I released DataMapper 2 that I like to be pretty high. I like them to pass through limitation testing but I don’t necessarily believe that 100% code coverage is a good goal. Although, I will say you have to try for yourself and make your own decision.
JAMES: So, one of the interesting points in the style guide links to an Erlang thing where it talks about, “Do not program defensively.” That was really interesting. It talks about how you basically should check your inputs when they come in. But then, the rest of your code should assume you have good input which is a great idea, I think.
DAN: I was just going to say if you’ve ever seen code that doesn’t do that, it will have checks at every single method for every argument. I believe that when data enters the system, that’s the place that you have to verify and validate it. And then, once it’s inside the system, I think that you have to trust it. Otherwise, you’re going to end up with assertions in every single method and I don’t necessarily know that that’s a good — at least in my experiments, it hasn’t resulted in good code.
AVDI: And that can even introduce new bugs. If you check the same thing over and over and over again, eventually you’re going to get it wrong or you’re going to over check somewhere.
CHUCK: Not if you copy and paste.
CHUCK: I had to go there.
JOSH: I’ve seen languages that bathe this stuff in where they describe the invariance at the beginning of the function or the method. Didn’t Eiffel do something like that?
JOSH: Yeah, I agree. You should put that stuff out front, make sure it’s all cool and then you can play around with it and within the rest of the code.
CHUCK: So, do you just stack up card clauses or what?
JOSH: That’s one way to do it.
DAVID: I’ve been bitten by this, by having a guardian at the border of the class and something gets through. And it just runs amuck because nobody else inside the class is checking their inputs. They’re just assuming. I thought that was a defect. And so, we should just go through and program defensively and put guards on everything. But that’s a violation of the DRY principle. The guardian was supposed to guard that. And go ahead and write unit tests. And yeah, if you’re three levels into this class and you have bad input somehow, the correct behavior is to just blow your code’s brains out and that is the appropriate response at this point.
JOSH: Alan Kay, object oriented programming, he always equated it to objects are like cells. And there were things like independent lifetimes and had their own internal workings. One of the things that he liked to say about cells is that they spend a huge percentage of their energy making sure that the outside stays out and the inside stays in.
JOSH: The cell membrane, or the cell wall even, it’s a huge amount of the cells metabolic energy keeping the right stuff out and the right stuff in. That’s the way he thought about objects as well. And the appropriate place to be checking those invariants and making sure things are correct is at the point where data is flowing into the object.
JAMES: Right. That’s important for a lot of reasons because if you are guarding everywhere, all you’re doing is you’re adding to every single method. And the whole point is to keep those methods small, tight, understandable, things like that. It also applies to many cases, like for example, if you’re going to deal with encodings, if you’re going to handle multiple encodings, transcode the UTF-8 on the way in, work with UTF-8 everywhere and then transcode back to whatever you need on the way out.
DAN: Boundaries exist for a reason. If you put guards everywhere, you’ve just given your code cystic fibrosis.
AVDI: This is also another argument for, like at the library levels, this is another argument for having few entry points into the library. A warning flag for me is code where the actual right way to use a library is to do a lot of calls of foo, colon, colon, bar, colon, colon, bas dot new. Where you’re instantiating some object that’s way down in the bowels of the library. When you have tons of entry points into a library, then you’re really not able to have areas where you say, “Okay. At this point, I check the inputs.”
CHUCK: Alright. Well, I’m going to cut us off. We’re going to get to the picks. Unless somebody has one last thing they have to get in.
JOSH: I have a philosophical question for Dan.
JOSH: And that’s, doing hardcore XP development, discipline is a big part of it. So, I’m a big fan of the disciplines you’ve been talking about here and adhering to some sort of discipline. But the flip side of that is creativity. I’ve written about discipline versus creativity, a lot of people have. I’m curious to hear your thinking on ‘constraints are freeing’ or ‘constraints are constraining’. What do you see the effect is on your code and your level of creativity for problem solving if you are following these very strict disciplines?
DAN: I think that constraints actually liberate you a little bit. I do believe that you have to go back and obviously question the constraints that you have. But sometimes, if you’re running some code and there’s multiple ways of doing it, you’re constraints will sort of lead you down a path. And you always have to question whether that’s still the right thing, that you’re not just following something that you decided ten years ago because someone told you so. So, I find them liberating. I find that I can focus on things that are a little bit higher level than, do I use curly braces or do I use do/end here, that kind of stuff. I’m not focusing on that low level stuff. I’m able to focus on something higher and sort of how everything fits together. Are my classes right? Am I using the right naming here?
I never feel that the constraints that I use limit my creativity. Although, I think that if some do, I think it’s time to question, is that a good idea or not? I would use that as a test, as my creativity getting stifled here because of something that I learned ten years ago that might not apply anymore.
JOSH: That’s a great way to think about that. Cool.
CHUCK: Yup. Interesting.
JAMES: I think it’s kind of also, if you adopt some constraint, like I am not going to write a method over four lines, period. And then, you write that method that totally makes sense as five lines. That’s the way you naturally write it. But then, you have to go back and figure out, “Okay, how am I going to shrink this down to four lines?” And sure, you’ll do bad things. I mean, if the method really should be five, it should be five. But you’ll do bad things in order to make that happen. But at the same time, it will make you creative. “How am I going to shrink this by one line?” Maybe not a good kind of creativity, but you can often learn things from that.
CHUCK: Yep. Alright. Well, let’s get to the picks. James, why don’t you go ahead and share with us first?
JAMES: Okay. So, I have an on-topic pick and an off-topic pick this time. Or not necessarily on-topic, more like work related and not work related. I’ve kind of been in and out of blogs lately. I haven’t been able to find a blog I really enjoyed reading lately until recently. And that’s Adam Keys’s blog in my opinion has been really good lately. Just incredibly practical posts, in my opinion, like he did one just the other day about data based shape problems. And it was just a very practical look at, does database fit the problem or the problem fit the database and stuff like that. He has one where he just has a video of how he uses splits and vim and it’s kind of sloppy, like his process and stuff. But it’s very real because of that and I kind of like that. So anyway, if you’re looking for a blog that I’m finding regularly interesting, The Real Adam is what the blog is called and it’s quite good.
Okay. So then, off-topic or not work related, I’ve been watching the TV show Breaking Bad. And if you haven’t watched Breaking Bad, you’ve got to try it out. It’s definitely what a train wreck in progress looks like. Almost every single episode is another amazing crisis that you wonder how he’s going to get out of. Really cool episode about a Science teacher, or a show about a Science teacher who finds out he has terminal cancer and what he decides to do with his life at that point. So, you should check it out. It’s very enjoyable. Those are my picks.
CHUCK: Alright. David, what are your picks?
DAVID: I just have one today but it’s absolutely freaking incredible. I’m a little embarrassed about this but I’m going to go ahead and have this be my pick. My pick today is DavidBradyPickMachine.com.
DAVID: This is a fan submission from Aaron Cruz. He’s @mraaroncruz on Twitter. He’s got a big thing at the bottom that says, “Not affiliated with David Brady or The Ruby Rogues.” But it does have a gigantic picture of my head on it that spins around.
JOSH: David, any picture of your head will have to be gigantic.
DAVID: This is true. This is true, even with a wide angle lens. But this is a really, really cool. This is an example of somebody scratching their own itch and then saying, “Hey, can you use this?” So what this is, Aaron was frustrated that he kept wondering, we would pick five things or 15 things at the end of every episode. Well, we’ve done 42, 43 episodes now.
CHUCK: Forty six.
DAVID: Forty six episodes. And so, there’s like 200 different picks out there. So, he wrote this thing that takes each of our picks at the end of each show and he goes out and he scrapes the page that we linked to. And he takes all of the keywords on that page and basically there’s a little postgress, full text engine search. So, you can go to this thing and you can basically say, “I want to search for blog.” And it brings up Avdi’s Org to blog, it brings up Stevey’s Drunken Blog Rants. Anybody that made a pick that had the page that it linked to, had the word blog in it shows up in this search. So, you can come here very quickly and find who mentioned what and what they searched for. Like I said, I think it’s a little hilarious, a little funny that he decided to name it after me. I think maybe it needs a better name because I don’t want to be the next Hamster Dance of the Internet.
DAVID: Actually, maybe I kind of do.
AVDI: Yes, you do.
DAVID: Yes, okay. It’s fair, I do want to be the next Hamster Dance.
JOSH: Search your feelings.
DAVID: [sound] Yep, that’s me. So anyway, DavidBradyPickMachine.com, it might need a better name down the line seeing it’s for all of the Ruby Rogues. But hey, it’s got a gigantic spinning head of me. So, there you go.
JAMES: With fans like that, who needs enemies?
DAVID: Yes, yes. Thank you, Aaron Cruz. That’s freaking awesome.
CHUCK: Alright. Avdi, what are your picks?
AVDI: Well, James actually reminded me that I read a really good blog post yesterday. Michael Feathers wrote ‘Tell Above, Ask Below – Hybridizing OO and Functional Design’. And it’s well-written and it’s thought provoking and it pretty much is in alignment with the way I think of how OO and functional programming can work together. Talking about how OO can be kind of a higher level design discipline and functional works really well inside of methods.
JOSH: I liked that too. We should have him on the show and talk about it.
AVDI: Oh, absolutely. I would love to get him on the show.
JOSH: Michael, if you’re listening, make room in your calendar.
AVDI: [Chuckles] Another pick I have is a community and this is tooting my own horn a tiny bit because, I guess, I kicked off the community but it was almost accidental. And I can’t really take any responsibility for the quality of the discussions that have gone on. When I was writing Objects on Rails, I wanted some feedback. And I didn’t realize at the time but one of the smartest things I did writing that was I created an open to the public mailing list for anyone that wanted to come in and discuss the drafts of the book that I was putting out. It’s got well over 400 members now. And there have been just some great discussions of object-oriented programming in Rails there. It’s not just like stuff about the book but it’s just general questions like, what are the best ways to separate my storage from my business logic and stuff like that. I’ve really been enjoying some of the discussions there.
DAVID: Avdi, I know you’re too humble to shill yourself on the show, but where can I go to buy your book?
AVDI: You can also go there to read it for free.
DAVID: Sweet! It’s the Internet! Why should I pay for anything?
CHUCK: Because it’s awesome. Alright. Josh, what are your picks?
JOSH: Okay. I actually have an amazingly on-topic pick, although a little redundant now. This is the Github Ruby Coding Style Guide. It looks like it has a common ancestor to Dan’s Style Guide which is why it’s a little redundant. But it’s super well-presented. It’s amazingly well-formatted. And I agree with almost everything in it. And after David Brady’s comment, I’m going to try some of the things I don’t agree with, but there are very few. And this is very much the way that I write my Ruby code. So, I would recommend everybody take a look at this and try and either think real hard about why you wouldn’t want to do things this way or just do it. That’s on Github.com, of course, Style Guide Ruby. And they use that for their internal coding but, of course, they make it available for everyone else. That’s my useful pick.
My other pick is, when I was in College, I read a lot of science fiction by an author named Larry Niven. And he hasn’t been writing very much lately but he wrote a ton of stuff in the 70’s and the 80’s that really appealed to science nerds and to programmers. I don’t know who on the show is a big fan of Larry Niven but yeah. He’s so good at making hard science fiction fun. It’s like the old Arthur C. Clarke or the Isaac Asimov stories that were basically puzzles to figure out as they… So, the Larry Niven Known Space stories are just great and that’s the universe where ring world is set and there’s just a lot of really awesome stuff going on in there. So, I would recommend, if you’re looking for some good classic science fiction to read, Larry Niven.
DAVID: Do the Man-Kzin Wars take place in Known Space?
JOSH: Oh, yeah.
JOSH: And in fact, some of that stuff going on with Known Space — one of my other picks a couple of months ago was the Star Trek animated series. And one of Larry Niven’s short stories got turned into one of those episodes.
DAVID: That’s cool.
JOSH: Yeah. Anyway, it’s awesome and a lot of what he’s done has percolated out through the rest of science fiction. So, he definitely set some tropes that have been repeated elsewhere.
AVDI: I particularly liked his collaborations with Jerry Pournelle.
JOSH: Yeah. Those aren’t in the Known Space but absolutely, I thought that Lucifer’s Hammer was one of the most amazing things that I read in 80’s.
AVDI: Yes, very good.
JOSH: Although Footfall was much weaker in comparison. But are you talking about The Mote in God’s Eye?
JOSH: Yeah. The Mote in God’s Eye, it’s not Known Space. It actually takes place in Pournelle’s universe. But yeah, that’s a really good story too.
AVDI: They’re a good writing team.
JOSH: Yeah. And then just as a little final note, I saw John Carter over the weekend. Awesome movie!
CHUCK: Oh really?
AVDI: I’ve been hearing really good things about it.
JOSH: The reviews have been a bit mixed but it’s just amazing everything for two hours.
AVDI: Just to geek out for a second. For those who don’t know, John Carter is based on a series of science fiction stories that basically, along with a few others, created science fiction as we know it.
JOSH: Yeah. This was written by Edgar Rice Burroughs, the guy who wrote Tarzan 100 years ago.
AVDI: Yeah, and the whole Princess of Mars series of books.
JOSH: Yeah. It’s really incredible how many — talk about, I mentioned Larry Niven had some tropes. The John Carter stories, so many tropes that you see everywhere now.
CHUCK: Wasn’t that put together by Disney?
JOSH: Amazingly enough, yeah, did a great job.
CHUCK: I’ll have to go see it. I’ll go ahead and go next. So, my first pick is Things. Yeah, I’m picking Things. Things is a to-do application. You can get it in the app store, the Mac app store. You can also get it for the iPad and then it will sync over wireless with your computer. It’s really helped me get organized whenever I have something new that I have to get done. I just throw it up into Things and then, I’m able to remember that I need to get it done. The more I use it, the more I love it. [Chuckles]
The other thing is that it has something that no other to-do task list that I’ve ever tried to use has ever had. And that is that I can actually set it up with tasks that need to recur. So, things that I need to do every day or every week, I can say, “Look, I want this to be in my today’s tasks each day,” and make sure that I do it. So, it’s really nice. I can schedule out my tasks and make it work.
The other pick that I have and this comes from a conversation that David was privy to and I think I posted something on Twitter about it. But I was pretty frustrated because I had a client that I couldn’t get to pay me.
DAVID: I knew you were going to use this pick. Yes! Yes!
CHUCK: Anyway, and at risk of losing our clean rating, I’m actually going to tell you what it’s called. There’s this video on Vimeo and it’s called ‘Fuck You, Pay Me’. He goes over a lot of things that you really need to know, just to make sure that you can collect. It turns out that I did just about everything right, luckily enough. I didn’t really know that I had but my contract is pretty solid. He really just goes into, “Look, you need to do these kinds of things and you need to do these kinds of things. Don’t do these kinds of things.” I think my favorite part or the part that kind of made me laugh was, he goes up and he says, “You know, you go to Cora and that’s like the font of all knowledge and you want to get a super good answer. So, that’s where you put it.” And he shows a question where somebody says, “I can’t get this guy to pay me.” And the first answer is, “Well…” I think it was like appeal to their emotions or write emotionally charged letter.
DAVID: You could write a heart wrenching letter.
CHUCK: That’s what it was! And I was just sitting there going, “That doesn’t sound right to me.” And then he goes, “Don’t do this.” [Chuckles] Anyway, he really just talks you through, how to go through and make sure that you’re getting paid. He also talks about a lot of situations that freelancers or service providers will run into and just makes some stellar recommendations. “Here’s how we handle this.” And most of the time, it’s, “We quit and we collect our kill fee.” It all makes sense. And so, I’m actually going to be looking into adding a kill fee to my contract.
But anyway, just really, really interesting and really enlightening, really made me understand, “Okay, this is how you have to look at this stuff because if you don’t, you’re setting your self up.” So anyway, Dan, what are your picks?
DAN: I only have one today. Since we were talking about mutation testing earlier, the one that most people know about when it came out about three years ago, actually I think it’s more like five years ago now, it’s called Heckle. And Heckle is an awesome tool but the only thing is that it only works with Ruby 1.8. So, if you’re doing 1.9 or other, you want to write for Ruby 2.0 in the future, there’s nothing that works with it. So, there’s a new mutation tester called Mutant, it’s by Joseph Bach and Justin Ko. It’s at Github.com/txus/mutant. And it uses Rubinious to parse the code into an AST and then it mutates the AST, recompiles it to Ruby and then, executes the specs. It’s still in early development but it looks like it will probably surpass Heckle in terms of how many mutations that it has. It also looks like it’s a lot more extensible. And it also mutates 1.9 syntax code. So, that’s definitely something to look at if you want to get into mutation testing. So, that’s it.
CHUCK: Alright. Let’s go ahead and wrap this up. Next week, we’re talking to Jose about crafting Rails applications, right?
CHUCK: I just couldn’t remember what today was.
JOSH: Jose Valim.
CHUCK: Yeah. So, I’m really excited about that. I can’t put the book down. It’s just so good. So, I’m really excited to dig into this with him.
I’m sorry, my brain just turned off.
We’re also in iTunes. So, if you want to get the podcast there, you can just look us up, Ruby Rogues. Leave us a review while you’re in there and let us know what you think. And if you need to get it on another device, there is an RSS link on the main website. So, you can pick that up.
Finally, I just want to remind you to go check out our sponsor, New Relic. You can just click on the link on the website, or we have that little thing that plays at the beginning of the episode that tells you how to get there.
Anyway, that’s it. Thanks again for coming, Dan.
DAN: Thanks for having me.
DAVID: Yes, absolutely.
CHUCK: And we will catch you all next week.