CHUCK: I’m so trying not to go all fan boy on this one. [Chuckles]
[This episode is sponsored by Hired.com. Every week on Hired, they run an auction where over a thousand tech companies in San Francisco, New York, and L.A. bid on Ruby developers, providing them with salary and equity upfront. The average Ruby developer gets an average of 5 to 15 introductory offers and an average salary offer of $130,000 a year. Users can either accept an offer and go right into interviewing with the company or deny them without any continuing obligations. It’s totally free for users. And when you’re hired, they also give you a $2,000 signing bonus as a thank you for using them. But if you use the Ruby Rogues link, you’ll get a $4,000 bonus instead. Finally, if you’re not looking for a job and know someone who is, you can refer them to Hired and get a $1,337 bonus if they accept a job. Go sign up at Hired.com/RubyRoguesPodcast.]
[This episode is sponsored by Codeship.io. Don’t you wish you could simply deploy your code every time your tests pass? Wouldn’t it be nice if it were tied into a nice continuous integration system? That’s Codeship. They run your code. If all your tests pass, they deploy your code automatically. For fuss-free continuous delivery, check them out at Codeship.io, continuous delivery made simple.]
[This episode is sponsored by Rackspace. Are you looking for a place to host your latest creation? Want terrific support, high performance all backed by the largest open source cloud? What if you could try it for free? Try out Rackspace at RubyRogues.com/Rackspace and get a $300 credit over six months. That’s $50 per month at RubyRogues.com/Rackspace.]
[Snap is a hosted CI and continuous delivery that is simple and intuitive. Snap’s deployment pipelines deliver fast feedback and can push healthy builds to multiple environments automatically or on demand. Snap integrates deeply with GitHub and has great support for different languages, data stores, and testing frameworks. Snap deploys your application to cloud services like Heroku, Digital Ocean, AWS, and many more. Try Snap for free. Sign up at SnapCI.com/RubyRogues.]
CHUCK: Hey everybody and welcome to episode 182 of the Ruby Rogues Podcast. This week on our panel, we have Jessica Kerr.
JESSICA: Good morning.
CHUCK: Avdi Grimm.
AVDI: Good morning.
CHUCK: David Brady.
DAVID: I would like to read a prepared statement. Last week I said that four out of five dentists recommend me. The American Dental Association’s legal counsel has since advised me and I would like to retract that original statement. In the interest of complete transparency, one out of one dentists recommend me but I had to poll 23 dentists before I found that one. And I concluded the study once I had my data point. Thank you.
And yeah, we also have a special guest this week and that is Michel Martens.
MICHEL: Hello, everyone.
CHUCK: So, do you want to introduce yourself really quickly?
MICHEL: Yeah, I’m a programmer from Argentina. I’m currently living in the outskirts of Paris. I’ve been programming in Ruby and other languages. But I discovered Ruby in 2003. And I like to build very small and simple tools. That’s what I try to teach others too.
CHUCK: Yeah, I could tell you that I’ve actually played with some of them, some of them at the behest of Federico Iachetti and some of them just on my own. The ones that I’ve used that I really like are Ohm which is an ORM for Redis, which is really handy. I’m actually using that on the JSRemoteConf site. And then the other one that I’ve played with is Cuba.
CHUCK: Which I don’t know if you can compare it to Sinatra but it has a lot of features that I really like that make building web applications really simple.
MICHEL: Yeah, it’s actually like the core idea of Cuba, which is a routing library, the core idea is not mine. It’s from, I hope I will pronounce the name correctly, but it’s Christian Neukirchen, a Ruby dev, creator of Rack. And at some point, he released a very small library called Rum which was this router. And it had some very small bugs and it wasn’t a gem. So, what I did with Cuba was to just make it a gem and just fill the gaps. And over the years, it was reworked many times. But actually, all the credit for this idea of using the blocks, these nested blocks, goes to him.
CHUCK: Oh, cool. So, one thing that I noticed working with your libraries, and you’ve talked about it some here and there, is that you get the minimum thing that can work and then you push people to find other little things that plug into it if they need more functionality. And I’m curious. What do you think the payoffs are for that?
MICHEL: I think that yes, that the basic driving idea is that when you write code to solve a problem you are actually creating some complexity because all the code is complex to some degree. And ideally, the problem you are creating should be easier to deal with than the problem you are solving. Otherwise, there is no reason to solve the problem with such a bad tool. And that’s why I think the focus should be on simplicity of the tool and to solve the problem in the most elegant way. And here, I’m talking about elegance in terms of simplicity, to solve it with the minimum force or the minimum number of parts. And that’s why I think it’s better to build two different tools if you have two different problems, rather than just modifying an existing tool to cope with the new use case you have in mind.
JESSICA: Michel, when you talk about simplicity of a tool, are you talking about its external API or its internals?
MICHEL: I’m talking about both because actually, programmers have to deal with both. And sometimes you have some very simple API and a lot of complexities hidden. And you can get away with that for some time. But at some point you may run into that internal complexity when you have to debug or when the program is doing something that you are not expecting it to do. So, I think it should be simple in both aspects, the outside and the inside. I think that you have to reduce all the future worry you would have to do. So, if you keep it simple both inside and outside, you remove the need to do a lot of maintenance and a lot of work afterwards, like debugging, all that stuff.
JESSICA: If you get a tool just right, is it ever finished? That’s one thing that I feel like is hard to achieve these days with software.
MICHEL: No, it’s… I think it’s maybe easier than ever. We use tools that are feature complete like when you want to explore a directory and type ls. It’s a tool that, it’s been feature complete for years; or when you type cat to see the content of a file. So, those are small tools that have been around for years. Nobody knows who the author is or when was the last version, when it was released. But we use them anyway. And right now we have languages that are very powerful that allow you to create very simple tools. Ruby’s an example of such a language. Ruby is in itself, is very big and provides a lot of context for creating meaning with just a couple of lines of code. So, it’s maybe easier than ever to write very small feature complete tools.
But I think in a way, programs grow to tackle many different use cases because that’s easier when you’re approaching the problem. Sometimes you just need to add some, a couple of lines of code to modify a tool to tackle this new use case. But in the end, this growth in complexity and at some point, the collaborators and as the program solves many different use cases, a lot of users start reporting issues and new use cases. And the program grows and grows. And I think that’s what usually happens.
And we have in our industry; the popularity of a tool is a very good metric for adoption. I don’t recommend popularity as a metric for adoption. But that’s what happens anyway. And the fact that a tool can cover many different use cases also contributes to this popularity and this adoption. And so, it’s a feedback that increases its popularity and its complexity.
JESSICA: What’s the difference between popularity and adoption? What do you mean?
MICHEL: No, it’s the same. Popularity and adoption, it’s the same. What I think is that as to tool becomes more complex and needs more contributors and solves many different problems, more users can benefit from it. And that drives adoption. So, it’s a bit sad that as the tool becomes more complex, it gets used by more people.
CHUCK: So, I want to give a counterpoint here. You’ve written Cuba. It’s very, very simple. Or we could talk about Sinatra or Padrino versus say Rails. Padrino is more complicated than Sinatra. Rails is probably more complicated than Padrino. But it seems like they do a lot for you. They have a lot of things that work together in order to create this overall system that isn’t necessarily simple. I don’t know if I would call Rails elegant either. But it’s pretty handy.
MICHEL: Yeah, I agree there. It’s handy. Otherwise, people wouldn’t use it. But it’s handy because it’s like, let’s say you have to build a website of some type and you have a repository that you can clone and start working to solve the problem. So, that’s what Rails is in a way. It was many problems already solved. And I think you’re right when you say it’s handy. But then you have people using Rails that have to run an update or upgrade Rails each time a new vulnerability is discovered. Or when they run into a bug they can’t fix it themselves. So, they have to report it and then you have some hero that goes and tackles all those issues and solves them for everyone. But that complexity is a bit painful in a way, because we recognize those heroes. But it’s a lot of work. Not everyone can contribute.
The way I see it is like you have an object and you can apply a force to move it in some direction, or you can have many, many different forces, some that cancel each other, and the object will moves in that same direction. But the effort involved is huge. And all that complexity is like the price you’re paying for the problem you’re solving. So, I think somebody, let’s say somebody gets the Rails codebase to a tenth of what it is today, it would be a huge improvement. But it keeps growing and growing. And I think it should be the other way around.
JESSICA: You said that getting a fix for Rails requires a hero and implying that there’s glory in that to be found in these complex systems. Contrasting with what you said earlier about programs like ls or cat where nobody knows who wrote them anymore. That’s really interesting that it’s these simple programs help the world the most without getting glory for their authors.
MICHEL: Yeah, that’s my view in a way. There are two heroes in the way that, what I mean is for instance you have people like Aaron Patterson or Luis Lavena. They try to solve problems for everyone. And I have to say, it’s very tough problems. I don’t want this to be derogatory to them. It’s just pointing out that when it becomes so complex you need somebody very, very skilled to deal with this problem and fix it for everyone. And for very small tools, you don’t need that. And everyone can create a very small tool and make it feature complete. Nobody will notice, but it will be useful anyway.
DAVID: I think it’s a key note that if you’re going to write Rails, you need an army because you’re taking on a land war in Asia type problem.
MICHEL: [Chuckles] Yeah.
DAVID: Where if you want to write just a quick router solution or if you want to write a quick sorting algorithm or a quick tool to handle date-times, this is something that one person can do in their garage. And if we focus on keeping things simple and uncomplicated, then we end up with things that we can build ourselves or that we can maintain.
And I think this actually does scale up into Rails where, you were talking about there’s forces that are all over the map. And sometimes those forces cancel each other out. But if each person on the Rails team is focusing on a tiny piece, or if the pieces are kept small, right, you don’t necessarily want people owning a specific piece. But if each piece is small and simple, then somebody can come in and fix it and maintain it.
And it’s a manager’s job. It’s DHH’s job to make sure all the pieces fit together and they’re not cancelling each other out. Or it’s Aaron Patterson’s job to make sure everything fits together. But if you keep individual things simple, then I think it pushes some of the complexity out of the end code. It pushes it up into the way things interconnect. And I kind of…
DAVID: What’s that?
JESSICA: Is that a win to push the complexity up into the way things interconnect?
DAVID: That’s a good question. I don’t know if it’s a win. I think it’s a tradeoff. If there’s nobody managing the complexity at that level, I think it’s a loss, because now you have unmanaged complexity. And I’ve seen teams do that. I’ve seen teams where every person on the team is trying to say, “Oh, my stuff has to be simple so I’m going to push all the hassle off onto my teammates.” [Chuckles] But if you have somebody that’s managing the comple-… if you have a project manager who’s, or a product owner who is in charge of making sure all the pieces work together, or if you just have a good acceptance test suite, sometimes you can manage things that way.
And the point of that is that the big thing that I see contrasting that is you’ll have a team of five or six people all working on a single product that’s large. And everybody’s everywhere. They’re not keeping thing simple. And so, if you want to fix anything then all five of you have to be involved because you’re touching everything all the time. Does that make sense? Did that ramble make any sense at all? [Chuckles]
CHUCK: Can I rephrase it a little bit?
CHUCK: And you can tell me where I deviate from what you said. But my understanding is that…
DAVID: Right there.
CHUCK: [Chuckles] is that Rails absorbs some of the complexity for you. And it helps you organize where you want to put things where with these smaller systems or these simpler systems, you wind up creating the complexity on your own. And so, if you try and keep your stuff simple you wind up trading off your complexity by pushing the complexity into another part of the code.
JESSICA: Or is it that you’re trading off simpler now, handy is a good word. You used the word handy. You’re trading off what’s handy now for what Michel talked about that he’s trying to avoid, which is complexity and difficulty in the future when you’ve reached the edge cases.
DAVID: Right. I think there are two different aspects here. I think what I was trying to touch on, especially with the where people are pushing complexity out of their code into other people’s code, that’s a case where if you’re trying to solve a problem that is necessarily complex. A given has a certain amount of complexity. And your solution has to have that much complexity in order to solve it. It just does. And additional complexity is just waste and technical debt. And if you have people that are pushing all the complexity out of their code and just dumping it on their coworkers, this creates a huge amount of accidental complexity because they tend to oversimplify their pieces.
Where what Jessica’s talking about and we all do this I think (at least I do this anyway, so I assume everybody else does because I’m a narcissist). But anyway, we do that. We take the piece that we’re working on and we think, “Oh, it would be cool if we could do this, or it would be cool if we could do that.” We call them cool ifs in product planning where we basically say, “It’d be cool if we could do that.”
And you have to learn to make that the kiss of death when somebody says, “It would be cool if we could do this.” You’d say, “Yes, but that is not part of what we want to do with this.” That is accidental complexity or complexity introduced by enthusiasm. And you just have to wield the YAGNI hammer and say, “We don’t need this right now. We’ll add it later. Write it simple and extensible and we can mix it in later.” Does that make sense?
MICHEL: Yeah. One idea that I [inaudible] is that if you don’t use Rails you end up rewriting Rails on your own.
MICHEL: Because that assumes that there’s a fixed amount of complexity that has to be in every project.
MICHEL: And also, or it makes the assumption that Rails, the idea of Rails, is perfectly implementing in Rails. So, there’s no possible improvement in that [inaudible]. That’s why I was saying that if somebody comes up with a Rails that is one-tenth of its current size, it’s a huge improvement.
MICHEL: And also, I gave a presentation in Brazil and somebody asked me if I end up writing all the complexity on my own to level up with Rails. But it’s actually the other way around. At least I did a survey and what I noticed is that people that use simpler tools end up writing applications that are way smaller. So for instance, you can have a stack that is composed of tiny tools and your application is 3,000 lines of code. And with Rails, maybe a default application is like that. And you end up with an application that is four or I don’t know, maybe ten times bigger on the outside. And then you have Rails which is I don’t know, it has 250,000 lines of code.
So, the total complexity is way bigger than what you need to solve a problem, because you are actually using a tool that it’s solving already a lot of problems that you don’t have. And many times, it happens that somebody has to update Rails because there was a vulnerability in something they will never plan to use.
MICHEL: Like parsing XML with [inaudible]. So, even if you never thought about using that, you still have to upgrade it because Rails is solving that problem for you that you never needed.
DAVID: Right. Yeah, there’s a law that I like to quote. I call it Lever’s Law because the guy who introduced it to me was named Don Lever. But everything the system does for you, the system also does to you. And Rails is like that. Rails is the poster child for that. You have no intention of ever parsing XML, because why would you? XML’s a four-letter word. But if you install Rails, you have an XML parser. And an attacker can send XML now at your application. And guess what? Your application will parse that XML. And it will hit that bug and you have an exploit.
CHUCK: So, I want to change gears just a little bit. We’ve talked a bit about using tools that are pretty simple. And what I’m wondering is, let’s say that I decide I want to write a library that does something.
DAVID: Actually Chuck, before we do that, can I ask one more question on the [inaudible]?
CHUCK: Yeah, go ahead.
DAVID: So, I just had a stroke of inspiration here. It seems like what we’re talking about when we talk about writing small, simple libraries that manage their responsibilities well and don’t push off responsibility that they shouldn’t push off, but they don’t take on responsibility that they shouldn’t take on, it seems like when you mix those modules together, the connection of them adds complexity. But it adds less complexity it seems like to me, than what happens when you have modules that take on too much responsibility or push off too much. Trying to mix those together adds much more complexity.
And I almost wonder, Michel you talked a little bit about how when you start putting all these pieces together, there’s extra complexity that appears. And I wonder. It’s almost like sometimes I feel like when you put together a bunch of modules, there’s the complexity in the interstitial spaces between these modules. I feel like that complexity is n squared, where n is the number of modules. So, each time you add something, you’re adding this exponential amount of complexity to the entire application. Where I think if you keep things really simple, it’s almost like, and not to go all Big O Notation here, but it’s almost like you’re adding log n complexity or n log n or whatever it is.
So, it’s like you could add ten modules and you add an eleventh module and now instead of basically multiplying the complexity by basically doubling or tripling it, all you’ve done is you’ve added another ten percent complexity to the project in addition to the module that you’ve added. Do you think that’s fair? Is that a fair approximation?
MICHEL: Yeah, maybe less than that actually.
DAVID: Yeah, okay.
MICHEL: Because, yeah what I was thinking is that if you write functions and okay, methods, whatever, that don’t use very complex objects, if you lower that barrier and your functions use just, let’s say strings and numbers, then you don’t have a lot of glue to write. Why? Because you’ll need modules to have a lot of knowledge of other objects or things like that. So, if you think about that as using just functions, then all the complexity you will be adding will be essential complexity to the problem you’re solving. So, the ideal module just adds functions that deal with basic data types or basic data structures. Then all the complexity will be essential.
JESSICA: Exactly like in Unix, when you cat something and pipe it to something else.
JESSICA: [Inaudible] something on a very simple standard in, standard out.
DAVID: By the way, just as a point of trivia, ls was written by Richard M. Stallman and David MacKenzie. And cat was written by Torbjorn Granlund and Richard M. Stallman.
DAVID: Bless those guys. I just pulled up the man pages. I’m like, “Who did write those?”
JESSICA: Bless those people.
AVDI: The GNU versions, anyway.
DAVID: Yes. Oh, that’s fair. The Linux, the new versions, yeah.
AVDI: There are BSD versions.
MICHEL: Like for instance, you go to Ruby Toolbox which is an assigned directory, those projects will be in red like dead, because that’s what’s been happening lately, that a program that’s feature complete, it’s regarded as dead code. It doesn’t get updates every month.
DAVID: Right, right. That’s interesting, that Ruby Toolbox considers stable as dead.
CHUCK: Right, because yeah, it’s not getting any more commits on the Git or any new versions published. So, I want to ask my question now. And the question is we talked a little bit about the cool ifs. I think Dave pointed that out.
CHUCK: How do I keep my library from getting overwhelmed by cool ifs? How do I narrow things down so that it’s, “Okay, this doesn’t belong in here. This actually belongs in some kind of system that plugs in next to mine?”
MICHEL: Yeah, I think that comes from the effort to try to distill the essence of the problem you’re solving. It requires more effort than a tool that solves many different problems. So I think, yeah and after that you gain experience. And next time you have to tackle problems, you can rely on that experience. But I think a lot of heuristics like number of lines of code or the length of a method or [de meter], all those metrics, those rules, you can apply those and try to use this common denominator of very low-level data structure or some low-level data types. And I think if you regard code as the price you are paying and you want to keep that cost to a minimum, the rest will follow. If you try to make it simpler and focused, I think it’s a very clear goal that we can follow.
JESSICA: This part of functions operating on simple data types, that’s very core to the Clojure philosophy. Michel, have you worked in any other languages that lend themselves even better to this than Ruby?
MICHEL: Yeah. I like to explore programming languages. Of course, Scheme or Lua are better than Ruby at that. Ruby’s very rich in terms of the context it gives you. But it also has a lot of problems because it’s not well-suited for modular programming. And in the way that, when you require a file you can contaminate the environment where this file is loaded, because you can’t prevent it from exporting constants.
MICHEL: And from modifying everything. That’s a bit painful. So, that’s something that other languages solve better.
DAVID: I’ve ranted before that Ruby is not a lexically-scoped block-oriented language. And it looks like one. It really looks like if you put curly braces around something, you should be safe. But you’re not. You can define a class and in that class you can define a function. And inside that function you can require a file. And that file can add constants, modify things, delete things. Yeah, it can escape the lexical scope.
JESSICA: That’s interesting.
MICHEL: Yeah, yeah.
DAVID: Ruby? Yeah.
DAVID: Yeah, the running joke in Ruby is that constants aren’t. And the other…
AVDI: They’re advisory constants.
DAVID: Yes, yes.
CHUCK: Kind of like this show. It’s an advisory constant.
DAVID: [Chuckles] Yeah.
AVDI: It’s an interesting collision of philosophies. I was talking to somebody about some stuff sort of like this recently. They were frustrated with the way we sort of modify things in Ruby. And I think one of the things to understand when working with Ruby is that Ruby’s biggest influence is Lisp. And actually, Lisp via Emacs, because Matz has said that Emacs Lisp was a huge influence on Ruby. And one of the things that makes Emacs so complex but so powerful is the fact that it’s basically just a Lisp machine. And every possible thing can be changed. Every function that’s defined can be overwritten, or can be advised to do extra stuff, or can be hooked, et cetera, et cetera. And so, you can change anything at will.
And the classic Lisp ideal is that you build out your language to match your problem space. But there are definitely, there are ups and downs to that. You’ve got Rails which is very much building out Ruby to match the web application, or a common web application problem space. It’s effectively a language for defining web applications. But a lot of complexity goes into that.
MICHEL: Yeah, but I think it could be powerful. I mean, it is powerful because you can yeah pretty much modify everything. But if we think about our happiness as developers, it is the opposite of what we want. Because for instance, I remember a presentation from somebody in, I think it was [inaudible] that it was about how he managed to debug something in Rails. And the problem was that the function or the method URL for was defined 15 times.
MICHEL: And in, I don’t know, maybe in as many classes. And you have to find out who is modifying that. And it creates a hell for the programmer.
MICHEL: So, I agree that in my script I can modify I don’t know, a string or hash or anything. It’s powerful but in the long-term it makes me [chuckles] a very sad person because I would have to deal with…
MICHEL: More complex products.
AVDI: Yeah. I feel like when a language’s ability to be self-modifying outstrips its ability to introspect, that’s a big part of where you run into trouble. The flipside of Emacs Lisp is that I dare anyone to find an environment which is as self-reflective and introspective as Emacs Lisp, because you can pretty much ask a running Emacs anything about itself. If you have a function that’s been advised by other functions, I’m pretty sure you can ask it, “Okay, what are you advised by and where can I find that code? Where is this function currently defined? Open the file. Show me the exact point.” A lot of that stuff Ruby either doesn’t have or is just now acquiring.
AVDI: Now you can finally ask, create a method object and ask it where its source location is. But you still can’t do that with procs out of the box. So, I feel like yeah, some of this stuff might be a little bit more manageable if we had better tools for introspection. But the trouble is you can make a change and then it’s not at all obvious how you find out about the change down the road.
MICHEL: Or even if you could choose whether or not you want to include libraries that will modify this environment, because right now Ruby doesn’t have that, doesn’t provide any means to do that. So, for instance in Lua you import a file and it can’t contaminate the environment. And there’s a way to load a file with the load keyword and make it load all the code inside an anonymous module. But anyway, that code can modify basic data types. So, there’s no way to avoid it.
AVDI: Yeah. Yeah, one of my favorite things about the Tcl language was that any time you wanted you could always fork off a sub-interpreter. And it would have all the modifications that you’d made to the main interpreter, like forking off a process. But if you then loaded some file inside that, any modifications it made would be scoped to the sub-interpreter. And it’d be cool if we could do that in Ruby. Unfortunately we can’t yet.
DAVID: Wouldn’t it be cool if there was a way that you could monkey patch something just in one file and have it be monkey patched…
DAVID: Didn’t we…
JESSICA: David, did you just use a cool if?
DAVID: No, I didn’t.
DAVID: I’m actually mocking a feature of Ruby that should never have gotten put into Ruby 2. I can’t remember what it’s called. It starts with an R.
AVDI: Yes, it should have been in Ruby…
AVDI: It should have been in Ruby 1.
DAVID: Yes. And it’s implemented very badly. It’s implemented at file scope, which makes parsing very hard, because nothing else in Ruby is at file scope. So, it’s an entire new scope.
AVDI: I will respectfully disagree with that.
DAVID: Okay. I thank you for that.
DAVID: And I yield to the wisdom from the gentleman from York.
DAVID: But I agree. I love the concept of what refinements promises. I think it’s not quite perfectly implemented. The point that I did want to make is that I remember when I first came to Ruby and there was no static typing, right? And everyone, this is in 2004, everyone was just losing their mind over the fact that there’s no static typing. How can you write production code with no static types? It’s just crazy. And everyone said, “Well, unit test, idiot.” You have to have this engineering discipline to compensate for, there’s a tradeoff being made. There’s this implicit interface instead of an explicit interface. And that gives you all this freedom and all this power. And you can make a huge mess very fast, right? Because as soon as you mix in seventeen modules, you have no idea what the hell this object is going to respond to, right?
DAVID: It’s all over the map. But if you’ve got a good unit test suite with good coverage, now you can, and plus there’s good reflection with respond to and ancestors and that sort of thing. You can look into a class and say, “Okay, where did you get this method from? Who taught you to do this?” and that sort of thing.
And when I hear people talking about monkey patching, and monkey patching of course is a four-letter word, but I love monkey patching. I don’t mean that I like to go out and monkey patch all the things. What I mean is I love having the power to monkey patch if I need to. But I also respect that it’s like a plasma torch tied to a chainsaw. [Chuckles] It’s a very dangerous tool to use. And so, if you pick that tool up, there is a lot of engineering discipline that you must bring to the table or you’re going to make a big mess. You’re going to make people sad. You’re going to have this huge thing.
And I wrote a blogpost or a, actually no, I think it was a talk. And I basically ranted about this. And I basically said, “It’s okay to monkey patch. But you need to do them very rarely. You need to do them only when they’re very necessary. And you need to apart from the code, you need to stand up and gather the whole team together and tell them using verbal language.” In other words, away from the computer, you have to use out of band communication and say, “Hey guys. I just monkey patched the to_i method on object,” or whatever. “I just changed some crazy thing. Here’s why I did it. Here’s what it gives us and here’s the way the language, the whole language, will now act weird if you’re not expecting it.” And everyone on the team goes, “Ah, ok. Got it.” And we can now proceed.
CHUCK: Or they lynch you.
DAVID: Or they lynch you, yeah. And I’ve had both things happen. I’ve had people go, “Oh my god. Get that out of my code.” And other people go, “That’s really genius. That should totally be in our project.” And…
JESSICA: David, you’re really selling me on Michel’s philosophy of keeping things very simple.
DAVID: Yes, yes.
JESSICA: [Inaudible] on small tools rather than heroes changing the entire language underneath us.
JESSICA: But I have a question for Michel.
DAVID: Okay, yeah.
JESSICA: As much as you love modularity, and I admire this, and you said that Ruby is not a good language, is not a language well-suited to modular programming, why do you work in Ruby?
MICHEL: I work in Ruby and many other languages. But I think what I liked about Ruby when I first started is the fact that if you, this is maybe a lame example, but if you want to write a poem you want a language that gives you a lot of context to draw meaning. And Ruby gives you that very large context. So, whatever you write can be very concise, very small, because it’s drawing its meaning from a huge language. If you want to do the same in C which is minimalistic, you have to write a lot more to explain your idea. So, the fact that you can express ideas in a very simple way, very concise code, that’s what I liked about Ruby.
JESSICA: That’s beautiful, thank you.
CHUCK: I have another question that I’d like to ask. And that is that you mentioned that if Rails was cut down to a tenth of its size, it would be a lot better. I don’t know if there’s a good answer for this, but at what level is the right level of complexity? Because you have to create some complexity to create useful solutions, but if you create too much complexity then maybe the pain outweighs the usefulness. So, how do you find that balance? I don’t know if there’s a direct X is the right amount. But maybe some tips on approaching that.
MICHEL: I don’t know if there’s a straight answer. So, I know that I can create an application as I said earlier with 3,000 lines of code. And if I install Rails it’s already 10 times bigger. So, somewhere in the middle maybe a good number. But also you can instead of setting this new number of how big it should be, you can try to improve it not by adding code but by removing code. And I’m not very familiar with the Rails codebase, but for instance if you, okay this is a bit technical but you know the flash in Rails? That lets you…
MICHEL: Okay, so that feature, you can get the same result by using the session directly because behind the scenes, flash uses a session.
MICHEL: And whenever you want to display the message that you stored in flash, if you use the session directly you just delete that value and that’s it. So, that means that you can get the same result without using flash. And you won’t be moving any complexity to your code because it’s the same complexity. It’s just the same line. But in order to have flash in it, I think it’s like 150 lines of code just for flash to work. So, if somebody comes and says, “Okay, let’s not use flash. Let’s use session directly,” or something like that, it will remove 150 lines of code from Rails, which is not trivial. If you do that in every piece of code of Rails, you will get a more realistic number of how big a good implementation should be. But also, Rails has this tendency of importing everything they find interesting.
MICHEL: And also, there’s also the adapter pattern which I think is an anti-pattern. But it’s something that, let’s say, or now Rails has an adapter for queues. And now whoever maintains Rails has to keep in mind that it should work with every new version of all those queue engines. So, that adapter is also a bad idea if you want to maintain software or make software safe. And I think decoupling of those pieces and trying to reduce to the essentials, each of those pieces is what should be done.
AVDI: But the flipside of that is that what this means, for basic queue use, I as an application developer don’t have to couple my application directly to some queue implementation. So, it’s simpler for me.
CHUCK: Right, you just use Active Job.
AVDI: So, the coupling is pushed off into Rails.
MICHEL: Yeah, but who knows if it’s a good thing or not? People have been using…
AVDI: I would actually assert that it’s a good thing.
AVDI: I’m going to push back on that a little bit.
JESSICA: But when Rails’ life is harder, does that mean everyone who uses Rails’ life is harder? Because they all have to deal with the vulnerabilities and the upgrades and blah, blah, blah. Just so you can use a different queue implementation now and then hypothetically.
DAVID: Gosh Avdi, yeah.
DAVID: This is…
AVDI: Yes, I admit that I am the sort of horrible person who expects vendors to take on some of the complexity so that I don’t have to.
DAVID: I liked Michel’s assertion that Rails like to pick up things. And it made me realize that Rails kind of is the Katamari of the software world. I don’t know if anybody’s played Katamari Damacy, but big ball of garbage rolling around, sticking to everything it touches. But Michel, you talked about the flash and you talked about going straight to the session. And this, this I think cuts to one of the key, there’s a lot of people who love Rich Hickey and a lot of people who would love to crucify him figuratively, especially for his discussion of always using simple data types and that sort of thing. And this using the session directly touches on that.
If you take away the 150 lines of code that let you interact with the flash, don’t you use some of the intention-revealing nature of the code? I’m reading through the code and then I see somebody screwing around with the session versus I’m reading through the code and I see somebody setting the flash. And I go, “Ah, you are setting the flash. I know what you’re doing.” Whereas if I see somebody monkeying with the session, I have to go, “Okay, what are you setting on the session? Oh you’re setting the flash variable. Okay, I can decode that. That makes sense,” and you move on.
And I wonder. A lot of the OO purists versus the, this is one of the key battlegrounds between the war between the good guys from OO and the evil people from FP. Not that I’m trying to unfairly characterize these people, but the FP people are evil. The OO people want to say, “Let’s put objects around people.” That was meant to be a joke, but anyway, sorry. The OO people want to wrap everything in intention-revealing code. So, taking the time to put the concept of a flash into one library seems to make sense. But I can also see it from your point that you’ve just added 150 lines of code. And I’ll be honest, I haven’t used a Rails app in two years that actually used the flash, because we didn’t like the way Rails implemented the flash. So, we didn’t use it. So, it was just cruft sitting around in our codebase.
MICHEL: Yeah, I think the way you can use the session for that by just storing the message and then deleting it from the session, if you wanted to write flash object would be more revealing. You can write it three lines of code.
MICHEL: And you can have a…
DAVID: You could write your own set flash, clear flash.
DAVID: Yeah, that makes sense.
MICHEL: It’s four, five lines of code.
MICHEL: But I think the complexity in flash is the fact that it has to detect if the user is being redirected to some other location or what’s happening if it’s rendering. So, depending on that it has to either remove the message from the session or story or whatever. So, that’s where the complexity of flash lies. And yes, you can create methods or even an object called flash to store that complexity.
MICHEL: And make it more intention-revealing.
DAVID: Okay. So, you’re asserting that the way Rails has implemented flash is over complicated and bloated and adds way to many features then?
DAVID: Okay. I can get behind that. That strokes my object-oriented fur in the right way.
DAVID: I wanted to ask another question. I feel like I need to defend monkey patching’s honor now that Jessica has impugned it.
DAVID: This is a fun episode, guys.
CHUCK: Gauntlet dropped.
JESSICA: I’m trying to [Inaudible].
AVDI: Wait a second. You just spent five minutes attacking monkey patching.
DAVID: No. I spent five minutes defending it badly.
JESSICA: And telling us how much he loves power.
AVDI: [Inaudible] like you, David.
DAVID: Yes, with friends like me, who needs enemas? So anyway, the thing that I was trying to say is that if you’re going to introduce power, you can’t introduce it in an uncontrolled way. And I don’t want to work in a language that says, “Power is dangerous. We’re going to get rid of the power.” I don’t like that. I like Lua. I like the fact that you can import something and it cannot pollute your current environment. I can’t remember if Lua has a way to allow you to import something into the current environment.
But there’s a discipline that’s starting to appear. It’s a design pattern, if you will, that’s starting to appear in Ruby that I’m really liking where, for example the Sequel gem. It has a bunch of monkey patches in it. It will patch the symbol class, which is a core class. It will patch symbol to have dataset manipulation and SQL query stuff. You can do :person.like or :person.where and then in the parentheses you can say :name.like and then Fred. And my gosh, you’re calling the like method and it’s going to set up a query that’s going to do a select from where name like da-da-da-da-da. When I saw that, I was like, “Aaah! Who’s monkey patching symbol without permission?”
And then I read a little further and I found out that no, if you require Sequel, you have to do sequel.like and then give it the symbol and then give it the string that it’s like. But if you require the Sequel extensions, it will, and this is, I like using the word monkey patching just because it upsets people, but the proper engineering term is extension. And if you load the Sequel extensions, then it will patch, it will pollute your global space deliberately and because you asked it to.
And I’m seeing this in a couple of other modules where basically if you require it, it stays in its own place. But if you require the module/extensions, then it will monkey patch and it will give you the convenience that you want. But it won’t infect you without your permission, in fact without your explicit request. And this ability to choose not to be infected by something, it feels like an additional bit of complexity because you’ve got one version of the code that does one thing and one version of the code that does another thing. But I like the way the ability to expose to somebody, “Here’s my tiny little module and here’s an adapter layer that you can choose to use but you don’t have to.”
I’d like to ask for your comment on that, or Jessica to crucify me again. [Chuckles] But also, how do you feel about modules that can be easily separated, that don’t necessarily have to talk? Because you don’t have to pipe ls and cat. You can go all day without using ls or cat and you can go for a week without using them together. They can be separated and the system doesn’t break. Is that part of the simplicity aspect that you feel is important?
MICHEL: Yeah, absolutely. I like the idea of giving the user the option of either modifying everything or not. I think in, anyway, the version that doesn’t extend symbol is better and should be preferred even if you have to type five characters more. And I think the problem is if you want to use interactive Ruby and you want to extend everything then that’s fine. The problem is when you modify core classes for everyone. So, I wouldn’t do that in a project or in a library. I wouldn’t dare to modify symbol for everyone. So I think that’s, the problem is that we are terrible at dealing with this kind of problems where it does something that’s slightly wrong.
So, what happens with monkey patching is just that something is not behaving exactly how it should. So, it’s very hard to detect the problem. Usually when you detect it it’s too late. And you are limiting, it’s like if implement symbol.like, you are grabbing that method and you’re preventing everyone else from using that same method. The same happens with constants in Ruby. So, that’s one of the problems with the way modules work, because you are limiting the freedom of all the other programmers to interact with the language.
JESSICA: Oh yeah, like adding that flash method thingy to Rails increases the complexity of every Rails installation, not just yours when you need it.
DAVID: Right, right.
MICHEL: Yeah, yeah.
JESSICA: Michel, does your own library use monkey patching?
MICHEL: No, no.
AVDI: Since we’re talking about monkey patching some more, I just want to say this is why refinements are awesome. And I know I’m the one person in the Ruby universe who thinks so. But they’re basically the two ends of the spectrum, the midpoint of the two ends of the spectrum that David described, because they are complexity that you have to explicitly ask for. And even when you explicitly ask for it, they don’t infect anyone else.
AVDI: And I will go on to say that the reason that the file scope makes so much sense with refinements is that it is impossible, as far as I have found, I haven’t found any loopholes, as far as I have found it is impossible to have a refinement in effect without also being able to scroll up in the same file and see what refinements are in effect.
AVDI: It is not possible to bring in a refinement silently.
AVDI: So, either inside a module or just at the file level, if there’s some method that it has been modified or has been added on a core class, you will be able to scroll up in the current file and find out what refinements are in effect.
AVDI: Whereas with monkey patching, you request it in one place and then spooky action at a distance, it updates those objects everywhere. And if some library somewhere expected them to behave differently, well then now you’ve broken something at a distance.
CHUCK: So, just to clarify for our listeners who aren’t familiar with the feature of refinements in Ruby. So, monkey patching is you open a class, you make a modification, you close the class. Refinements are a way of essentially defining some functionality and then you can add that to a module or another class inside of the same file. And what Avdi is pointing out is that you can’t require something that refines your global scope. You can monkey patch it that way, but you can’t use a refinement to do it. And so, the advantage of the refinement is essentially that you have to be more explicit. And your refinement has to be within the same file as where you’re using the refinement. So, it’s easier to find and it’s scoped directly to wherever you put it.
AVDI: Yeah. Think of it as a localized monkey patch.
AVDI: It’s a monkey patch that can’t escape the current file.
JESSICA: Right. And the file scope makes sense there because that refinement exists for you as a developer. And the file is the scope you happen to have to use.
AVDI: Yeah. Yeah, and you can also scope it down inside a module within the current file. But it’s always lexical. It doesn’t use any module scoping or anything where it could escape and affect something somewhere else where somebody doesn’t realized that there’s a refinement in effect.
JESSICA: Michel, how does this work differently in other languages that you work in? Can you contrast some?
MICHEL: Yeah. For example in Lua, when you import a module that module is exporting something. And whatever it exports you have to store it in some variable and then you can use it. In npm, Node works that same way. And yeah, the basic idea is that you can export something from your library and store it somewhere. And it doesn’t matter the name of the variable where you are storing that module. So for instance in Lua, you can potentially use two versions of the same library, or the same in Node, you could do that. In Ruby, it’s absolutely forbidden. You cannot possibly load two versions of the same library. And I think that’s very good for the programmer because for us humans it’s very important, this locality of information because that’s what helps us understand what’s happening. And [inaudible] otherwise, it’s very hard. Like what you were saying, monkey patching spread all over your code or 15 definitions of the same method.
MICHEL: That’s very, very tough work.
CHUCK: Alright. Well, should we get to some picks? Jessica, do you want to start us off with picks?
JESSICA: Is it fair to pick a pick that’s like a preview of a future Rogues?
JESSICA: Okay. Then you should all totally go watch this talk. It’s a couple of years old and it’s totally relevant. Ben Hammersley has a talk online called ‘The Flower, the field, and the stack’. And I still have no idea what the title is. I don’t really get it yet. But the content of the talk is amazing. And it explains why programming is hard, why technology is hard, why most of the people in the world don’t get it. And it also explains why we feel such distress when we’re more than three feet away from our cellphone. Highly recommended. It’s about an hour and got me really excited.
CHUCK: Very nice. Avdi, what are your picks?
AVDI: I don’t really have any programming picks this time around. I do have a note in my picks file that says to pick the Halo series. I surprised myself by playing through most of the Halo games over the course of the last few months. When I was too completely fried from work I would go and shoot some aliens for a while. And this is not a new or interesting pick, but I just want to say it is such a great series of video games. Obviously, it’s not deep thought material but they’re so very well put together. The gameplay is great. The storyline is a thousand times better than it has any right to be in an action game. And the voice acting is always terrific. I found the end of Halo 4 genuinely moving. It’s just such a great series and very dependable for some just shooting catharsis. So, that’s one thing that’s made my life nicer recently.
Here’s another random one. If you happen to be, live in or be visiting Chicago, check out the restaurant the Publican. It’s really, really good. That’s all I have to say about that. So yeah, I think that about wraps it up for me.
CHUCK: Awesome. David, what are your picks?
DAVID: Okay, so I wanted to do another hot sauce pick but the last time I did one I ran on for 14 minutes. So, I’m going to keep my picks [chuckles] short and sweet today.
The first one is the iPad game The Room has been picked two or three times in the past. There’s a sequel to it called The Room 2. And it’s every bit as fun as the original Room. And it also explains a little bit more of what’s going on in the universe of The Room, which I found to be kind of fun. The ending’s kind of fun and exciting.
My second pick is another game which is, I’m confident that somebody has picked Monument Valley, the iPad game. But I don’t see it on our picks page. So, I’m going to pick Monument Valley. The reason I’m picking it however is because there’s now an expansion for it. There are new levels for Monument Valley. It’s called Forgotten Shores and it’s two bucks. Monument Valley is a game that you can finish in half an hour to an hour. But it is worth every penny. It’s just a fantastic 3D puzzler. Basically it’s like an Escher painting and you can rotate the painting and it makes the stairs move. And you can walk, if you make it so that the path goes up a wall, your little girl princess, she just walks right up the wall. And now she’s walking on a different surface. And you have to figure out how to move things around to make them fit. And so, Monument Valley is a lot of fun.
And I’m just going to stop there. I’m going to give people a reprieve from epic, laborious, D. Brady picks.
CHUCK: Very cool. I’m going to pick some libraries that I’ve been using recently. We’ve talked about some of them. They are Michel’s creations and I just, I really like them. So, I’m going to tell people about them.
The first one is Cuba which is the web framework. It’s built on Rack. If you understand how Rack works, the routing layer on top of it is semi-transparent. And if you don’t understand how Rack works, it’s just easy. And yeah, the thing I like about it, he mentioned that you can nest the blocks. And essentially what you can do then is you can say if it is a Git request, do, and then you can say if it has this path, do. And then if you have some other criteria on it, you can make it do that. And so, you can basically, your furthest out scope you can put authentication or some other check or things like that. So, it’s really cool.
The other one that I just, I tried it and I was like, “Oh my gosh. I just love this,” and that is Ohm. Ohm is like I said, an ORM for Redis. And it’s really simple. Like I said, I’m using it on the JSRemoteConf website. And essentially when you submit a call for proposals or sign up as a single attendee or a users’ group, it creates a record in Redis. But it’s so simple. And pulling things out of it is also really simple. And it’s really, really fast. So, I’m using Redis to backend both my queues with Resque and with Ohm. And yeah, they’re just really awesome libraries. And I’ve looked around at some of the other ones, but those are the ones that I’ve been using lately.
And the other nice thing about Cuba, I should point out, is that a lot of the other functionality you want to add in, you can just pull in with regular old Rack plugins, Rack middleware. So, extending it is pretty simple. And a lot of the stuff is stuff that’s been written that you can use to extend other Rack systems like Rails or Sinatra if you need them. So anyway, those are my picks. And Michel, what are your picks?
MICHEL: Okay. I want to recommend some books I really like. One is ‘A Pattern Language’. I think it’s a very famous book by Christopher Alexander. It’s about architecture. And I like it because he tries to build a language of patterns. But for each pattern he studies what are the ways for making the human being better. And it’s very deep, very good reading.
And well from there is that we got ‘Patterns in Software’. But it’s also good, a presentation he gave at Silicon Valley 20 years after the publication of his book. That presentation is mostly about how we developers got everything wrong from that book. And there’s another book from Richard Gabriel called ‘Patterns of Software’ which is like a follow-up to reading ‘A Pattern Language’. And it applies to our industry. It’s very good.
Then I like, I think it’s a paper. I don’t know if it’s a book or a paper. It’s called ‘Out of the Tar pit’. It’s about how to deal with complexity in software. Very good in my opinion.
Also, another book that’s called ‘Lessons in the Fundamentals of Go’. It’s about the game of Go, not the language. And I think even if you don’t know how to play Go, it’s one of my favorite books ever. And the message is how to focus on the fundamentals.
And the last pick is a book called ‘Human Error’. It’s from the 90s I think. It’s about how to classify human errors, how to try to cope with human errors. Most of, or maybe all of our problems with software development are human errors, even if we display those errors as bugs . But I think it’s very good to know the psychological part of what we do. And that helps us to prevent this kind of mistakes like monkey patching everything and make our life more difficult than it needs to be. I think that’s it.
CHUCK: Well, if people want to follow up or find out more about what you’ve been working on, what are the best ways to do that?
MICHEL: Yeah, maybe Twitter. I’m not a big user of Twitter but my username there is soveran. And maybe GitHub. Everything I post to GitHub. And well also lately, we created a group called lesscode. It’s a subreddit. So, I also put some links there from time to time. And as it’s ready, everyone can collaborate with that.
CHUCK: Very nice.
JESSICA: Thank you.
CHUCK: Alright. One other thing that I want to put out there really quickly. We are looking at picking our next book club book. So, if you have recommendations, you can either tweet @RubyRogues or if you’re on Parley, then we will start a thread there and start discussing.
[This episode is sponsored by MadGlory. You’ve been building software for a long time and sometimes it’s get a little overwhelming. Work piles up, hiring sucks, and it’s hard to get projects out the door. Check out MadGlory. They’re a small shop with experience shipping big products. They’re smart, dedicated, will augment your team and work as hard as you do. Find them online at MadGlory.com or on Twitter at MadGlory.]
[This episode is sponsored by Ninefold. Ninefold provides solid infrastructure and easy setup and deployment for your Ruby on Rails applications. They make it easy to scale and provide guided help in migrating your application. Go sign up at Ninefold.com.]
[Hosting and bandwidth provided by the Blue Box Group. Check them out at Blubox.net.]
[Bandwidth for this segment is provided by CacheFly, the world’s fastest CDN. Deliver your content fast with CacheFly. Visit CacheFly.com to learn more.]
[Would you like to join a conversation with the Rogues and their guests? Want to support the show? We have a forum that allows you to join the conversation and support the show at the same time. You can sign up at RubyRogues.com/Parley.]