Skip to content

Instantly share code, notes, and snippets.

@xdite
Created January 19, 2012 18:53
Show Gist options
  • Save xdite/1641818 to your computer and use it in GitHub Desktop.
Save xdite/1641818 to your computer and use it in GitHub Desktop.
RR-020 RR Object Oriented Programming in Rails with Jim Weirich http://asciirogues.com/

Jim: What I really like is that there are so many Ruby podcasts out there that are newsy. This one dives into technical issues, and I really enjoy that.

Charles: Hey everybody, and welcome back to the Ruby Rhodes podcast. This is your host Charles Max Wood, and this week on our panel we have a special guest rogue. I met him at the Rocky Mountain Ruby Conference in Boulder. He actually suggested this week's topic, so we're going to welcome Jim Weirich to the podcast.

Jim: Thanks for having me. Glad to be here.

Charles: Do you want to introduce yourself really quickly Jim for those one or two people that don't know who you are?

Jim: Sure, absolutely. Jim Weirich. I'm from Cincinnati, Ohio. I've been doing Ruby for over ten years now. I work for EdgeCase. I'm the chief scientist, and I've probably written software that you are using, such as Rake and various mocking frame works and some XML builder stuff, too. You're probably using some of my code somewhere.

Charles: Thanks Jim. We're still waiting for him to write something useful. Also on our panel we have Avdi Grimm.

Avdi: Avdi here and little known fact, I am actually in the eMacs Major mode.

Charles: We also have Josh Susser.

Josh: Good morning from San Francisco, where we're just two days away from the Golden Gate Ruby Conference, which makes me horribly excited. So, if I sound incredibly upbeat on this podcast, that's why.

Charles: Thanks Josh. We also have David Brady.

David: Hey, this is David Brady, I think. Can you hear me?

Charles: We can all hear you.

David: Okay. Good. I've been having mic troubles today. This is David Brady and I run Shiny Systems. I'm in Emacs Minor mode that inherits from Avdi Grimm.

Charles: We also have James Edward Grey.

James: Usually I use worry about being outnumbered on this podcast by people from Utah, but today I'm worried about being outnumbered on this podcast by people who use Emacs.

David: Yes!

Jim: I am a strong Emacs user as well. I'm still tweaking it after 25 years.

David; I got most of my .Emacs file from Jim Weirich. I learned it from watching you, okay? I learned it from you.

Josh: I don't use Emacs, but I do remember when it was written in TECO.

Charles: And I'm Charles Max Wood. I just launched railsrookies.com. It's right now a list of courses that I'm going to be teaching over the next few months. If you're interested in learning or becoming better at Ruby on Rails, go check that out. This week’s topic is suggested by Jim. We were talking and Jim mentioned that a lot of Rails developers don't do much object oriented programming. I thought that was interesting considering that it's in Ruby, which is a heavily object oriented language. So, Jim, why don't you go ahead and explain what you meant by that, and we'll start discussing it.

Josh: Do we need a definition first.

James: Not again.

Charles: We'll waive that.

Jim: That's a good question. What is object oriented programming? And you might think, well we do Ruby and that's an object oriented language, so of course we're doing object oriented programming, but I don't think that's necessarily true. I know that when I was teaching C classes, way back when, I had people who could write FORTRAN code no matter what language they were actually using. I think that's still true today, especially with something like Rails. Rails makes it really easy to massage databases. So, you get a lot of objects that represent stuff from the database and database stuff is all about the data. To me, object oriented code is not so much about the data, but about what the code does, how it does it, what does it do, the behaviors of objects. I think we forget about those behaviors and concentrate on the data a little bit Rails programs.

Josh: I agree Jim. I've seen a lot of Pascal written in Smalltalk myself. The thing that I see a lot, and maybe one of the flaws of Ruby, is that it's too easy to throw together an array or a hash to hold a few values, and not worry about you're doing with that stuff.

James: Wait, wait, wait. Is that a flaw? Are we sure we're comfortable calling that a flaw?

Josh: Anything that leads to bad programs would be a flaw in my opinion.

Jim: Right. But you also have some powerful constructs like arrays and hashes that allow you to do important things inside of your objects to get the job done, right?

Josh: I'm not saying arrays and hashes are bad in and of themselves. It's kind of like a gun without a safety. It's too easy to shoot yourself in the foot. I actually nailed that metaphor. Wow.

Avdi: I have a question that I want to get out there early on. If Ruby or Rails programmers aren't programming in an object oriented way, does it matter, and if so, why does it matter?

Jim: Let me address that a little bit, since I brought the topic up. And I will say that programming in an OO way, just to be programming in an OO way is not the goal. That doesn't make us good programmers just to be doing it that way. There are a lot of programs, and even Rails programs that don't really need OO and a purely data driven approach is perfectly fine, and I have no problem with that. There are times when you want to handle behaviors in your code, and because you're thinking so procedurally, you're forgetting about the OO aspect of the language. I was just looking at some code yesterday where was checking to see if it responds to a particular method before he calls it. He's in the same doggone object, why doesn't call the method, and put the definition up in the base class, and handle it all amorphically. He just wasn't thinking in an OO way in that point and time.

James: That point that Jim just raised, that polymorphism. I think that's the easiest way to the difference between Rails code that is object oriented and Rails code that isn't. When you see polymorphism done well, then you know you're looking at object oriented code, when you don't you know that you're not.

Charles: So, for our newer listeners, why don't you explain what polymorphism is.

James: There are several concepts of object orientation, attributes that represent object oriented code. The two that probably affect this conversation the most would be encapsulation. Encapsulation is the idea that data inside of objects is private detail of the object, and it's what those objects can do that makes them interesting. Does that make sense?

Charles: Mm-hmm.

James: Polymorphism is the way objects respond to messages. A really good example of it that you see over and over again is a lot of times you'll see a case statement that says, "If it's object xyz do this. If it's object def do this. If it's object ABC do this." Then they handle it three different ways, whereas the right polymorphic way to handle that is to get a method on those different objects and then pass in the object and call that method. No matter what it is, it will do the right thing for that context of that object. Basically, to use the object's behaviors themselves to differentiate what's actually happening to the object. If I call such-n-such method on a xyz object, it should do this. If I call that method on ABC object it should do this, because it knows what it is and it knows how to behave as it should.

Charles: So, how does that help us with Rails? I guess we have one example, do we have any other examples of where people could use this to make their code better?

Avdi: James touched on the case statement. I'd say any piece of code that you look at in a Ruby program that has a case statement that switches on the class of an object is a bad smell. That's not the best object oriented code you could be doing.

David: One of the tricks that I use with polymorphisms, specifically with case statements is when you write that case statement, look at the top of the condition. The case foo, and as yourself according to the law of demeter, am I allowed to know this? Ask yourself, "Am I looking at somebody else's implementation? Am I looking at the guts of something?" You can often find, that yeah, if I wrap this up into an object, I can put the implementation of that case foo, I can put that into three different classes and now all three classes can have the same behavior and I can say, "Just handle this." They can implement it differently, but the behavior is the same. That's the trick that I use. I just ask myself, "Am I allowed to know this?" I hardly ever write case statements anymore because I'm usually not.

Avdi: Let me play devil's advocate here for a second.

David: I would just point out, sir, that your client is the devil.

Avdi: Let me point out a common objection. You have a case statement that might have three different cases for three different types of object. For each type of business object, it writes out different HTML. The immediate polymorphic response to that seems like it would be, you stick a .to_html method on each of those objects, and then you just call .to_html Now, those business objects are also responsible for displaying themselves, which seems like a pretty big violation of the single responsibility principle. I'm curious how people respond to that.

Charles: Aren't you just trading one problem for another?

Avdi: I'm curious how Jim addresses that. I know how I address it. I certainly would not put a .to_html on one of my objects, but I'm curious how other people address it.

David: Rails does encourage you to make that tradeoff by the way. That's bad. This is the whole point of our topic.

James: Actually I'd like to touch on what David just said briefly. David did just say that Rails encourages a lot of this. I think that is true and that we need to think about that. Rails in its design, for example how it moves instance variables down from the controller to the views, that's a violation of encapsulation. Yet, is that a bad thing? I don't really know that it is. Let's imagine that that didn't exist, and you wanted to get data down to the views. You'd have to call some method and say something like render(whatever) and pass some value down, whereas the way Rails handles it is through the simple assignment of the variable. I think that is interesting that Rails does encourage us in some places. Helpers are another great example. Let's go back to Avdi's question. What about throwing .to_html, or to give a Rails example, .to_xml and .to_json on everything.

Jim: That's part of the problem. In the business logic, exactly how things are going to be displayed, whether it's going to be XML, HTML or JSON, so putting display responsibilities in that object is part of the problem. We just move that into a different object. Let the polymorphism work there. Let the business object decide what information he wants to display and then go through some presentation layer you need to get that done. It's a fairly easy thing to solve, but you have to think about it a little bit and not just put that method where it's convenient and just drop it wherever you want to.

David: So what you're saying is that you would have a user object that managers users and does the users stuff. It has the user job, and you have another one that's the user presenter that presents the information for the user in whatever means that you want to put it in.

Jim: Yes. The key is, you ask yourself when you design and object, "What does this object do for you?" and you use it based upon what it does not necessarily on what data it has. That's the difference between a data driven design and an object oriented design. Here's an example. I mentioned the XML builder library earlier. That is a simple library that builds up XML based upon calls that you make. You can extract that a little. It's pretty much tied to XML at this point, but you could extract the builder object, where you would pump in the data, and it would format the data in whatever format you wanted it to be in.

James: You're talking a lot about presenters and things like that. Did you see Steve Klondike's recent blog post about object oriented programming in Rails. He had a follow-up post about Ruby presenters. Did you happen to read those posts?

Jim: I did read those posts. Well, I scanned them quickly to be honest.

James: And what did you think of those?

Jim: I thought his points were really good for the most part.

Charles: For the benefit of the listeners, I did not see those posts. Can someone summarize?

James: Sure. Basically Steve said in his first post, his primary point was that Rails helpers are evil. His reasoning behind that was that they encourage you to do individual functions for presentation stuff, whereas using something like a presenter object like Jim's been discussing is generally superior. Steve kind of said always superior, and I don't think I agree with that. I think there are cases where a simple one off function is just fine. If you look at Rails helpers, to make Steve's point a little bit, look at something like the number helper. Because we have all these different ways to do numbers, like currency or with delimiters, you end up with all these one off functions that aren't really related to each other in every single view. It's kind of a mess. It might be more useful to treat something as a number and then have all kinds of conversion methods on it.

His second post goes into that in more detail as far as what are presenter objects and how do they work. What I thought was interesting, both about Steve's post and what Jim's been saying, is that in object oriented programming, you're always allowed to introduce new objects, and I think people feel a resistance to that. In Rails we think we're only supposed to make the models that inherit from active record and controllers that Rails will make for us. Those kinds of things. I think some people forget that it's okay to make your own object that handles another part of the system that isn't necessarily tied to the database or insider controller or something like that. I think that's kind of the resistance.

Jim: I think that's absolutely true, that people forget that you don't have to make active record objects. You can make any kind of plain old Ruby objects to do what you need the system to do. A little bit of thought about what behaviors you want your objects to have goes a long way.

Charles: I think by popular demand we need to ask Josh Susser for a definition of plain old Ruby objects.

Josh: They're the unseasoned Ruby objects. If you grill them in a little light oil and add some salt, they're great. Plain old Ruby objects are objects without of all the active record stuff added in them. I think a good way to think about them is that they're objects that are not directly backed by database records. Ruby objects are amazingly functional. Maybe that's the wrong adjective. They have a lot of functionality in them, and you can do a lot with them. I think that pulling out pieces of business logic into separate classes that have a single responsibility is a great way to improve Rails programs.

I built a little gem to help do that. I call it informal, and this is an example of taking a plain old Ruby object and enhancing it with a little bit of the active record API, so that you can use it in your form in your view, and also in your controller and object validation and re-display life cycle. It's just a tiny bit of code. I pulled in some of the ActiveModel functionality. It's slightly tricky to do that. That's the only reason I built informal, because ActiveModel wasn't quite built to do this itself. I extracted this from an application, where I said, "I've got to do this."

It's so easy in Rails with the way the view stuff works to build these data structures, things like arrays and hashes that hold all of the data from the view, but don't do anything with it. We had a log in form that we didn't have backed with an ActiveRecord object. It was too difficult to work with as arrays and hashes of data, so we build a little class. Suddenly, we should be plugging this thing directly into the form. That made that whole part of the program so much easier to deal with. We could build a very simple [restful] controller. We didn't have to know about the structure of things as much. That's very classic object oriented programming. It's not rocket science. It was very simple to do. It's something that all Rails programmers should know how to do.

David: I think it's interesting too, that in a lot of cases we find that people don't completely understand things like this, so they just assume it's hard. Then, you find that something like that is really, really simple. It's a really simple and elegant fix for whatever issue you have, whether you're violating the single responsibility principle or whether you're doing some of the other things that we've talked about.

Avdi: To be fair, some of this stuff used to be harder than it is now. It used to be kind of a pain to come up with a regular old Ruby class that would play nicely with routing helpers and form helpers. A lot of times, you'd just hit a point where, "This is too much work. I'm just going to inherit form ActiveRecord." In ActiveRecord 3, they really have done a nice job of splitting things out into ActiveModel and making it a lot easier. It's a lot better documented, exactly what interfaces your object needs to support in order to make the helpers happy.

Talking about this split between ActiveRecord based objects and plain old Ruby objects, which is a term I hate, but I'll leave it aside for now. As there's been a little bit of a Renaissance about thinking about object oriented principles in Rails lately, I've noticed that a lot of people are looking at an approach of having thin ActiveRecord objects which just have associations and validations and scopes in them and no business logic. They're basically treated as data access objects. Then you have business objects which are just pure Ruby with no ActiveRecord base. The business objects have an internal reference to their data access object. I'm curious about opinions on this approach.

James: I actually have opinions on that. I think it can be a good thing. I think the reason a move like that comes out to be positive, is that a lot of times we have business logic applied to multiple pieces of our database. For example, this particular piece of business logic I'm managing may affect users and their subscriptions. In that case, splitting it out into a separate object seems to make more sense there because where does that functionality belong? On use or on subscription or whatever? I may be manipulating more than one thing at a time and am working cross purposes like that where I have to reference everything I'm going to work with is more natural. I think you can take it too far too. There is a user object, and that is the user. And, there are things that just apply to the user, like resetting their password. I don't see any problem attaching that functionality to the user object. In fact, I think it's good object oriented design to do so because it is the behaviors that operate on that data.

Josh: There is a little bit of a danger as well. Maybe Avdi's being deceptive deliberately here. Avdi, you've read Object Thinking, haven't you?

Avdi: I have not.

Josh: So, maybe this is unintentional. In the great philosophical war between software composition, where you start at the bottom and build up, and software decomposition, where you start at the top and build down, there's this thing called the impedance mismatch problem. We've heard this stated a lot in different ways. Specifically, with object oriented programming. The database is the last bastion of the barbarians when it comes to object oriented thinking. ActiveRecord has completely surrendered to this, unfortunately. You do not interact with ActiveRecord in an object oriented fashion typically. You get something out of the database, and now you have passive data at rest. You can operate on it. You can query it. You can change it. And then you can tell it to save itself back to the database. It's very state machine. It's very passive data. It's very database data-based programming.

This can bleed up into the rest of your program, because it's very easy to do this. The easiest way to turn this object into something we can use on the form is to put a .to_html on it and now we have passive HTML data that we can query, and pull out. Avdi, your question about should we have a separate business logic layer and James' answer of maybe yes, many now, sometimes yes, sometimes no. There's churn here. The reason there is churn is because you've got the database, which is running at one speed, and it's trying to mesh gears with object oriented code and another. The reason why there feels like there's an impedance mismatch here is because there is an impedance mismatch here. I'm curious to know if anybody else has had this problem that I have specific problem about presenters that happens with this. I'll stop talking for a minute and let other people have a chance.

Jim: I have definitely seen the impedance mismatch. In fact, one job that I as on, I was working with another developer. He had a very data oriented way of approaching problems. I had a very object oriented way of approaching projects. We would butt heads all the time. We couldn't agree on how to approach problems at all. It was very interesting, because one of project I was working on was some kind of authentication library that we were using. We had to authenticate users against roles against particular privileges against particular jobs that people needed to do. I came up with an object oriented design very early that specified how the system would behave. Because I captured the behavior of the system, that tended to be pretty stable throughout the life of this project. We coded up the objects and were able to work with that.

The database side of the house had entirely different issues. They couldn't decide if they wanted to go with a fully relational database or maybe an LDAP system would be good. I think we were making schema changes and fiddling with it down to the last week before the thing went live. The behavioral description of the system, implemented by the OO piece of it was steady and constant. All we had to do was change the mapping on how it was stored. I think that's generally true, particularly within an application. Behavior tends to be the constant there. What you want to do with the program tends to be the same, so you program with that with an OO.

However, the very interesting thing, where the OO-DB mismatch comes in, is that when you start talking about larger applications spread across different user bases, the emphasis switches from the behavior aspect of that to the data aspect of it. Data tends to be the thing that's more constant. That's why we have humongous Enterprise oriented databases that lots of different groups are using and pulling different pieces out of it. That tends to be what comes out of the big Enterprise level stuff, whereas at an application level, it's the behaviors that remain constant.

James: Looking at the idea of having a separate business logically or from the data layer itself. It seems that that would make it easier to do things like switch from a relational database to a document database or things like that. Another point where it might be a win is where you have several applications sharing the same business logic. Their data wouldn't necessarily have to be exactly the same, so the lower level could be a little different, but the business logic on top of it, if it was written correctly, could work in those scenarios.

David: So, what do you call that business layer? Are they models or super models?

Avdi: They're models. They're objects. If they mode a concept in your business domain, then I think it's correct to call them models.

Charles: Yes, and that's a trap that Ruby programmers fall into. They think that app/models is the directory for their ORM layer, but there must be a one to one mapping between classes there and tables in the database. That is not true.

Avdi: A very brief rant here. I'm going to get up on a soapbox for just a second. If you have an object that represents a concept in your business domain, it belongs in app/models. It does not belong in lib.

James: What? Not in lib?

David: It belongs in vendor/plugins

Jim: If this is Rails 3, it belongs in engines and a jump.

David: I keep everything in my .bundle directory. I don't know about you guys.

Avdi: Before we get too far afield, I think there are a couple other topics to look at in the ways Rails can encourage people to do poor object oriented programming or discourage good object oriented programming. Object oriented programming. Typically I think of it as encapsulation polymorphism and inheritance. We haven't talked about inheritance very much here, but I think that's the number one pitfall for people trying to do object oriented programming. They think that inheritance is so key to object oriented programming that if they're not inheriting from something, then they're doing something wrong. Usually it's the other way around. Being able to delegate stuff to take care of something on your behalf, that's usually a better way to do that.

Jim: I was going to point out anyway, that inheritance is the only way I'm ever going to get any money.

David: Waiting for your parent objects to die. That's a whole topic. I'm going to write a gem called vulture.

Jim: ActiveRecord::Base. Experienced object oriented programmers will complain about ActiveRecord::Base. Other Rubyists will look at that and go, "What's the big deal?" Part of it is what Avdi has been talking about here, about the way to incorporate the persistence into your business model. In Rails, that's done by inheriting from ActiveRecord::Base. That's the standard way that everybody does that. That has all sorts of weirdness to things. For instance, you have to talk to the database when you're doing your tests. You can't just test your business domain logic, you're also testing all of your active record queries. So, if the persistence layer was included in your models through an API that was meant be used through composition, then that would simplify that a lot and people wouldn't have to be re-inventing this stuff all for themselves.

Josh: But, do we really have that though? Isn't that exactly what the database adapter does? You compose with that and the save and create methods just delegate down to that?

Jim: If there were a clean membrane between those two layers, I would agree, but there's too much SQL that leaks. It's a leak abstraction. You get all of the SQL stuff that you have to deal with within ActiveRecord. That pops up even in the API all over the place. If you're doing joins or includes within your ActiveRecord queries, those things become very obvious.

David: We don't have to go back in Rails very far to remember a time when there were bugs in the ActiveRecord mySQL adapter or the postgres adapter. Remember that? It was always lagging the mySQL adapter. In theory, we don't have to test the database or database connection. I think that's great. We can now be cavalier about it and say, "Let's not test the database connection. We can stub and mock that." We don't have to go back very many years, 2009 or 2008, when you did not to have too many joins before you needed an acceptance test that exercised the full stack.

James: That's an interesting point. Josh talks about having a layer separate. The interesting part about that is wouldn't that create more of the problem you worry about, Josh, where people are throwing together arrays and hashes of data and running through those to do things?

Josh: Perhaps, but that is an easier problem to mitigate than the problem we have right now. That can be solved with a little bit of good design. The problem of the persistence layer leaking into the business domain logic layer isn't something that's easy to deal with in Rails right now. In fact, it's very difficult.

James: I'd like to go back to the question Avdi asked a long time ago, almost back in the beginning. He said, "Why do all this? Why does it matter?" Can't we just build a procedural Rails app, and doesn't that work? Why do this? Why do we have to?

Jim: Well, apparently it does work. People are doing it, right?

Charles: It works up to about 20,000 lines of code.

Josh: Or based on a client that I've looked at in the past two weeks, up to 70,000 lines of code. In a Rails project, that's too freaking big.

Jim: Right. But what I think we're about isn't necessarily does it . . .

Josh: What I'm saying is that it doesn't scale. The complexity doesn't scale beyond a certain point. Eventually, if you have passive data, you have to have universal adapters. This is like my comment about the database adapter. It has to be universal in order for everybody to interface it in every possible way. If you write procedurally, you've got passive data, you must protect this data from any kind of weird sidewards access. That can work up to 5,000, 10,000 of code, 20,000 or 30,000 if you're really bloody minded. Eventually, the technical debt starts to go exponential on you. Where, like Jim said, if you say, "Here's the behavior." at the very beginning, and they you discover that the behavior didn't change. It stayed very stable throughout. They refactored and changed implementations, but the behavior stayed very stable the entire time.

Jim: So, what we're talking about here is not whether or not you can build a Rails app that works. What we're talking about is maintenance costs down the line.

Josh: Should you build a Rails app that works. No. Wait. That wasn't what I was trying to say.

Jim: Capturing that behavior and having it be constant, that's the benefit of going with the OO approach.

David: Actually, the better question is, it's not can you build a Rails app that works in procedural, because the answer's absolutely yes. The question is can you build a Rails app that can be maintained.

James: That's a great question, I think.

David: The answer is maybe.

Jim: The answer is, given enough resources, yes.

Avdi: The answer in my experience is as long as you are willing to accept a very, very slow evolution of features and a fair amount of "Oops. It's broken. We have to roll back."

Charles: I want to raise my hand and ask a question. I'm really good at writing good procedural Rails code. What approaches are there to make my life and my code easier to deal with?

Avdi: I was just thinking about a similar question. What is the one thing you do to approach your Rails code in a more object oriented way? I don't think I have time to list several things, but I'll say one. Don't use generators. Generators push you in the direction of thinking about the data first, because you generate a resource with all of your data attributes listed out, and they also push you in the direction of thinking in terms of a one to one to one relationship, table, model, helper, controller, view. Start writing that object just as a plain old Ruby object representing your domain, and add things in as you need them.

Josh: You said very succinctly and very well the answer that I was going to suggest. I recently did this on a small project, and it was absolutely brilliant. I used this trick from Smalltalk. In Smalltalk, when you start designing your objects, you build everything together, but, you're in this image. Everything is in memory in this virtual machine inside the image. So, you can put off serializing to the database. You can leave it alone forever, because you can turn off Smalltalk, and the image goes away. You bring it back up, and all the objects that were in memory are still in memory.

Why not go ahead and translate that into your next Rails app. Just for fun, write your next Rails app, by starting off by defining the objects and the interactions and don't inherit from ActiveRecord::Base, don't save them anywhere. Just leave them in memory. Let the server hang on to them. You're going to need a class level hash on each class. This is crazy and it's starting to get into the stupid side of crazy, but work out those behaviors and those interactions. I was going to go right to the white board and draw my entity relationship diagram for the database. We sat down and started figuring out, this object talks to this object, but it turns out that this object really has more of this data.

Just by leaving the data in the sever, when you reboot the server you lose all your data, because it's in memory. But, this is just a scratch server, a dev server. If you just leave these things out there, work out the interactions between them and then figure out how to serialize, you push the impedance mismatch problem all the way to the end, the database layer. Then the database gives you grief because it is angry because you dissed it like that. It's extremely enlightening. I highly encourage anybody to try that on a project once. You will be astonished at how your object model changes.

Jim: That's a good idea. I'd also make the suggestion that whenever you want to get data out of an object and do something with it, stop and think if you can do the reverse. Instead of asking for data, see if there's an object that you can tell to go do something. The idiom is, "Tell. Don't ask." If you start asking that question, it helps as well.

James: I was basically going to say the same thing. I learned the most when I started trying to push more than I pull. When you call the method to pass in all the parameters needed to figure it out, and stuff like that, that's kind of where ActiveRecord gets a little backward. It forces us to pull everything. You pull that record from the table. It has all those attributes in them that you pull out to figure out what you're doing. Most of the time it's much better than pulling this attribute and chaining it to something else. It would be much better to call a method that has the correct behavior to affect the desired change.

Josh: I have three small things for people to watch out for that are easy to avoid if you think about it. One is case statements, especially case statements that switch on the class of the object. If you see a lot of case statements, especially case statements with object classes in them, that's an opportunity to move to a more polymorphic system and have better object oriented design. Another thing that I've already mentioned is simple data structures, like arrays or hashes or arrays of hashes of arrays, like we see in ActiveRecord a lot. That could also be modeled better as a class.

David: Primitive obsession. Avoid it.

Josh: And one thing I'll say that you should never ever do is inherit from an array or hash, unless you're building another fundamental data structure class like the hash with different access. Just don't do it. If you have a class that has a bunch of thing of it, have an array instance variable and put the things in there. Don't inherit from array.

Charles: So compose from an array, but don't inherit.

Avdi: The forwardable library is your friend.

James: Absolutely. Josh gave a couple of circumstances where it's okay to inherit from array and hash. Ignore those. Don't even do it. Ruby takes implementation shortcuts with those classes and every now and then it can come back and bite you because it doesn't follow the proper rules. An example I can think of right off the top of my head, is that people inherit from string, and then when Ruby does a [Regexp] replacement sometimes it skips string initialization, so you may end up with a string, but your initialize method never got called. Just don't do it. There are so many dragons down that road, you're going to get bit.

Charles: Also in Ruby 1.9, haven't they broken most of that stuff out now, so that if you really want a hash like object, you can just mix an innumerable, and a couple other modules and build enough data to support those, and down the road you go.

James: Basically what Avdi said is in the standard library there's a delegate library and the forwardable library. You would be better in those cases to use those so that there's a real object there.

Avdi: If you mix an innumerable, your object will now present the API of an array or a hash externally.

James: Absolutely:

Jim: Rake actually does that. It provides an array like object called a filelist. The original version had that inherit from array, and I found that it was much easier to more closely emulate the real behavior of array if I didn't inherit from it, but delegated to it. Conversion issues came up, and that made that true.

David: That's really interesting. One other thing I was going to ask, and I was going to ask this earlier. We talked about the presenter pattern a little bit with Steve Klabnik's article. We've talked a lot about models and ActiveRecord. Does this apply in cases with the controller at all or is this more focused toward handling things well for the view and handling things well for the model?

James: You know, the controller is an interesting beast, because I think everybody's always trying to find a way to make it go away. Really, that seems like the ultimate best thing the controller could do, is go away. Ideally, all of our controllers should be almost identical. We're told that RESTful controllers with the second actions that are predefined. In the ideal scenario, that would be every controller. In a way, what the controller does, the job of the controller is to get some data and prepare for the view to trigger the process that will show that data to the user. Ideally that would be handled in some uniform way that wouldn't require us to write code at all. It's not really the way it works. I think as far as how I handle the controller, is I try to keep as little as anything going on in there as possible. I want to call a few queries to get some data back, and then hand off to presenter objects or whatever that are actually going to make sure that the view is rendered as needed.

Avdi: It's probably worth noting that the MVC pattern was originally built up with desktop event driven GUI's in mind. I think [FAT] controllers probably make more sense in that context than the do on the web. Just a thought.

Josh: My devil's advocate there, is that when I see a bible thumping REST advocate, a real REST evangelist, nine times out of ten, and I'm not trying to incriminate them character wise, but what I find is that someone who's really religious about REST, all they're really trying to do is pull the impedance mismatch up from the database, up through ActiveRecord, up into the API so that now you have data at REST, in the controller level. I tend to be the one guy on the team who advocates RESTless controllers, and you should hit a controller and it should make the system behave a certain way rather than necessarily give you back a list of data. The controller should not just be an API into your SQL database to allow you to list objects and iterate on them. You should have some real behaviors there.

Jim: I think it's just a different focus. The point of REST is about applications interacting with each other, and the URL's become the API. There's another level of impedance mismatch problem there. It depends on where your focus is. I think that REST is a really good solution to the problem of applications and servers interacting with each other, but it's not going to give you the best design center for how your application operates internally. We have see that it reduces the code that you write in your application, because a lot of the coding has been pushed into the framework and you can reuse that. That is an advantage.

Avdi: The common Rails idea of what is RESTful, isn't terribly restful anyways. That is definitely a topic for another show.

David: We should do a whole show on splitting things out like that because a lot of the SOA guys that I'm talking about having REST as a basic fallback, but also having very complex controllers just to reduce the number of trips you have to make between services. I need to stop talking about that because it needs to be for another show.

Charles: This sounds like a good breaking point, and we're definitely going to go over this time. We'll get into the picks. If you're new to the show and you don't know what the picks are, basically we just talk about one or a few things that we've been using over the last week or last little while that we like or that make our lives better. They can be code related. They can be non-code related. We've had office toys and different toys. It can be whatever. We'll go ahead and start out with Josh.

Josh: My first pick is the RailsBridge Workshops. Any of you guys heard of that? RailsBridge has been around for a couple of years. It's a group of people who are supporting increased diversity in the Rails development community by providing free Rails training workshops for women and their friends. It's a yucky analogy, but it's kind of like ladies night at a bar. You can get free if you're a woman, or if you're in the company of a woman.

David: Rails is the new meat market. I love it.

Josh: I've volunteered and taught at a couple of these workshops. They typically do a Friday night, set up your laptop so you can be all ready to go for the all day training on Saturday. They've been doing these in a couple of cities. There have been a bunch of them here in San Francisco. They do them in New York. They often do them before a Ruby conference in whatever city you happen to be in. They work with the organizers. They're great. You do all day training and test driven learning of how to program. A lot of the women who've been doing these workshops, I see them get hired at Pivotal Labs or Blazing Cloud or various other Rails consultancies here in San Francisco. It's a great way to expand the Rails development community. We all know how hard it is to hire Rails developers these days. It's also a great way to enhance our diversity, which is a topic for another show. There's definitely a lot we can be doing there, and I think it's great that they're doing this. RailsBridge. If you have a friend who's not happy with her job as a php coder, bring her to one of these workshops and get her going on Rails.

Charles: James, what was your wife doing when she brought home that awesome Regexp problem and then she became the goddess of Regexp?

James: She was working for a food company at the time and they had to process massive amounts of ugly data and she kept coming home frustrated with it. She asked me to show her something better, so I sat down and taught her regular expressions one evening. She used that to process through massive amounts of data.

Charles: You said that, and what came to my mind was sorting food by Regexp.

James: It's kind of like that.

Josh: That's enough from me this week.

Charles: Sounds terrific. By the way, you did mention and we've heard a few times, this is a topic for another time. If you want to hear about those topics, go to rubyrogues.com. Click on request a topic and either vote them if they're already in there or type them in. The diversity topic is an interesting one. James, go ahead.

James: I have the absolute best pick this week. Sorry, you guys all lose. A long time ago there was a great blog post by Ryan Tomayko called, "I like Unicorn." because it's Unix. That went around and was very popular, because it went through the Unicorn server, which is my favorite Rail server because it uses all these UNIX idioms to do what it does. If you like that kind of thing, or if you think you would like to know about that kind of thing, the author of Unicorn has started his own mailing list called "Unix system programming with Ruby." There's this mailing list, and he's going through and basically teaching you the Unix model, what it is, how to use it in your code, etc. It's really great so far.

The articles start at the very beginning. You do not have to have a very deep knowledge in this topic. He actually gives the requirements. You need to know Ruby, a little bit knowledge of bash is helpful but not required. You do not need to know C. The fourth thing you need to know is that in Ruby, multiple variables can point to the same object. So, you can do a = substring, then b = a, and both those variables point to the same object. If you change one, you're going to change both in effect. If you know those four things, you can get on this list and follow along.

It's very basic and there are a lot of great people on there. I've watched some people talking. I have some pretty high hopes for this list that it might become a replacement for the Ruby [talkable]. If you find this kind of stuff remotely interesting or you've always wanted to learn about Unix and it's intimidating to you, then this list is the perfect place for you. I recommend it.

Charles: That sounds really interesting. I used to be a sys admin, and I don't completely understand that stuff. Sounds good. David. Go ahead.

David: Two real quick. The first one is the Awesome Print gem. We are always playing with different ways to present data better in IRB or at the Rails console. I think I've used them all. I've used [Werbel] and [Herb] and Boson, which is great. I've used [LookSee], which was really interesting, but I didn't quite get into it. I was pairing with Giles Bowkett last week and he showed me Awesome Print, which is awesome. It colorizes and clarifies things out really nicely.

The other one, and this is going to sound a little bit traitorous, but I'm going to recommend vimcasts.org. I'm definitely a fan of Emacs, but I believe that whatever editor you use, you should know it. You should know more than just than copy paste and insert. Vimcasts.org is the single best screencast I've seen in the past two years in terms of production value and quality. They're very well put together. They're very cleanly edited. They're five minutes long each. There are 35 episodes.

You can sit down and watch them all in whatever 35 times 5 minutes is. Except that you can't do that because your brain will explode after the third one because he really gets into some great details on that. If you're a Vim user, you need to be watching the vimcasts. I really, really, really wish somebody would start Emacs casts and put the same level of quality and excellent production value out there.

Charles: Alright. Thanks Dave. Avdi, go ahead.

Avdi: If you're listening to this, chances are you are using Git for version control, and chances are that 99% of the interactions that you do with Git are dealing with Github hosted repositories. Lately I've been using a Git wrapper called hub, which is available in Github. It is a wrapper that adds a lot of sugar around interactions with the Github repositories, so you don't ever have to specify the whole repo. You can just specify for a project, just username/project name. Lots of extra stuff like that. It's really easy.

If you've got a project local, you can very quickly create a repo on Github to push it to. That's been making my life a little bit easier. Non programming pick. I am also a big coffee nerd. I try to collect every coffee making implement under the sun. I've got press pots and a vacuum pot and various other contraptions. Recently I acquired an AeroPress. I've been drinking AeroPress coffee lately, and I think it's some of the best coffee I've ever had. The AeroPress. It's made by a Frisbee company, but it makes great coffee.

Jim: I have to say that the coffee nerds are right up there with the Emacs fanatics in terms of how much they tweet and post about this stuff.

Charles: Thanks Avdi. That was great. I'm going to go next, and then we'll hear some wisdom from Jim. My first pick is a mailing list that's being put together by Amy Hoy. It's called the Institute of Awesome. If you're a freelancer, this is something you probably ought to go check out. Every day I get an email in my inbox. Basically, it introduces some kind of topic and then links to a PDF that has a ton of information in it about, here's something you should think about doing with your freelance business. It's really awesome.

I can see it as a marketing tool for her other product, which is Let's Freckle. I have to say, I've read a handful of them. I haven't had time to get through all of them, but just the ones I've gone through, they talk about building a process that you go through for user stories. Building a process that you go through for interviewing clients. Basically, you can spare your executive function for the more important things, because this stuff is already pretty much lined up. It's just awesome. So, that's one that I want to point out.

The other one that I've been doing stuff with, is a game I've been playing on my iPad. I've actually had it for a while on my computer. It is World of Goo. This is something that several people have recommended to me. It's a really fun game. Kind of a physics based game where you build towers and structures to get stuff. You're basically trying to get your goo balls into this pipe, and if you get enough of them, you get an OCD rating on each level if you get enough goo balls in. That's a fun one.

The last one is also a game that I've been playing online. This is one that David introduced to me last year at Ruby Web Conference. It's Bloons Tower Defense. It's somewhat addictive, and I play it every few months. I'll play it when I'm taking a break from my coding. It's a fun game. It's a tower defense game. You build a bunch of towers and try to pop all the balloons before they get through. That's it. Just remember that the monkeys are right handed and you'll do alright. Jim, go ahead.

Jim: I have a couple of picks that I'd like to share. The first one is a programming book, but it's an older programming book. About ten years ago or a little more, I stumbled across this book, and believe it or not it's from Microsoft. But before you freak out, it's from Microsoft Press. They put out a book called, "Writing Solid Code," which was one of the early books that really changed how I was doing development. It really affected the way I was coding. This was before the Agile movement. This was before Ruby. This was before all of that. It's one of the managers for Excel, how he inherited the project and turned it around from a buggy program into a really good product.

He talked about a lot of the techniques that they used there to turn it around. He talks about stuff like developers need to own the bugs that they write. They can't just pass it off to QA. He says that there are no free features, so don't allow needless flexibility. That's the whole, "You ain't gonna need it." motto from Agile. It's sort of a precursor to Agile. I've been really enjoying re-reading this, and I'm hoping to do a talk on this at Ruby Conf in a couple of weeks. I've got to re-apply these old ideas and recycle them around for that.

The other pick I have is more of a general pick. A couple of years ago I picked up a ukelele fairly cheap. If you are ever interested in learning a stringed instrument and you want to pick up something that's easy, that's fairly inexpensive, that's just doggone fun to play, go to a store and find yourself a good ukelele that you can play. I really recommend that. We've got three ukelele players in the office now, and we declared Friday to be the day we all bring them in. We jam a little bit at the end of the day.

Charles: That's awesome. Is there a good place to learn to play the ukelele?

Jim: Look around. There is a ukelele club here in Cincinnati. It's totally for beginners. We come and go through some of the music. If you're a guitar player, ukeleles are easy to pick up, because it's essentially the top four strings of the guitar. It's easy to move from guitar to ukelele. Since it's only four strings, even a non-guitar player can pick it up pretty easily.

Charles: Jim, I have a quick question for you, and it's a confession. I am physically incapable of taking ukeleles seriously. Is there something I can do to fix that or is that the correct response towards ukeleles? Are they meant to be lighthearted and fun?

Jim: That reminds me that I actually have a secondary pick related to this. Go and look up on YouTube, Jake Shimabukuro. I will type his name into Skype. I think I said his name right. Google some videos of him. The first video I saw, he was playing, My Guitar Gently Weeps, on a ukelele, and all of a sudden I realized that ukeleles are not toy instruments. They are real serious instruments that serious musicians play. Google for Jake and you will be blown away.

David: Shimabukuro, I'll bet he also plays the shamisen, which is the Japanese banjo.

Charles: Well, I guess that's it. We're going to go ahead and wrap this up.

James: Before we do, one thing. I'm usually the book club guy, but this week Josh is taking over. So, Josh do you want to give us an update?

Josh: David, you weren't on the show last week, but because you always talk about Smalltalk Best Practice Patterns, we decided to use that as our book for our book club next week. Because he's a thoroughly awesome guy, Kent Beck has agreed to come be on the show with us.

David: Sweet.

Josh: So, I wanted to let the listeners know that so that they can be reading the book. We're also going to set up something on the site for people to submit questions so that we can have a little more listener interaction and get them involved in the book club more. We'll put something up on the website to give people a way to submit questions.

David: I will try very hard to keep my fanboyism in check.

Josh: We'll just have a very long pre-show for you to get it all out of your system.

David: Just run around the desk, Dave. Just run around the desk.

Charles: If you're not familiar with Ken Beck, he is not just the Smalltalk guy. He was involved with Extreme Programming, if I remember correctly, and I think he was also involved in that original group that drew up the Agile Manifesto. He's been around for a while and he's made a lot of contributions to computer science. It's really exciting to have him come on and share his experience with us. Now I'm going to wrap this up.

If you want more information about the show, you can go to rubyrogues.com. If you have a topic that you want to suggest to us, go to the website and click "Request a topic." You can get us in iTunes, and if you have any other podcast aggregators that you want to find us in, then email me at [email protected] and let me know. We'll see if we can get them added to those as well. If you want to leave a review in iTunes, that really helps us out as well. Good reviews or bad reviews, but preferably good reviews. We'll take what we can get. Beyond that we will catch you next week.

James: Thanks everybody. Thanks Jim.

Jim: Thanks for having me.

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