RYAN: We’re potty training my son right now. So, I was up like eight times cleaning poo off of everything.
[Hosting and bandwidth provided by the Blue Box Group. Check them out at BlueBox.net.]
[This episode is sponsored by Component One, makers of Wijmo. If you need stunning UI elements or awesome graphs and charts, then go to Wijmo.com and check them out.]
[This podcast is sponsored by JetBrains, makers of WebStorm. Whether you’re working with Node.js or building the frontend of your web application, WebStorm is the tool for you. It has great code quality and code exploration tools and works with HTML5, Node, TypeScript, CoffeeScript, Harmony, LESS, Sass, Jade, JSLint, JSHint, and the Google Closure Compiler. Check it out at JetBrains.com/WebStorm.]
AJ: I’m eating beef jerky.
CHUCK: Jamison Dance.
CHUCK: We have a special guest. I guess you’re a guest in filling in for Merrick and Joe and that’s Ryan Florence.
RYAN: Hey, how’s it going? I don’t know if I can fill two shoes, but I will try.
CHUCK: Well, you have two feet, right?
RYAN: Okay. Well, that’s four shoes.
CHUCK: [Chuckles] I’m Charles Max Wood from DevChat.TV. We also have another special guest and that is Ben Alman.
BEN: Yo! What’s up, everyone?
CHUCK: So, do you want to introduce your self, Ben, since you haven’t been on the show before?
BEN: I’m Ben Alman. Oh, okay.
AJ: That’s not conceited.
RYAN: That’s really all he needs.
BEN: That’s it. The show’s over, roll credits. So yeah, I’m Ben. You can find me online as @cowboy on Twitter or GitHub and I’m at BenAlman.com. And if you Google me, I have finally got enough SEO juice to beat the other Ben Alman who’s the Orthopedic Surgeon for sick children in Canada. So screw you, guy who helps sick kids.
CHUCK: Awesome. So, I have to ask before we get into the topic of the show, you’ve got the Twitter handle @cowboy. Did you have to join like number four to get that or something?
BEN: You know, one day in 2007, I don’t even know. Someone was like, “Hey, there’s this thing. Check it out.” And I was like, “Okay.” And I went to Twitter and I signed up and I literally didn’t use it for two years. I just had cowboy and nobody requested cowboy, or I don’t know how it works with those guys. I know enough people at Twitter now where I could probably be like, “Yo, bro, hook me up,” or something.
JAMISON: Maybe Obama.
BEN: [Chuckles] Yeah, exactly. But at the time, I just registered it and I didn’t touch it for a couple of years until finally Twitter was blowing up and it was like, “Huh. People are actually using this thing that I don’t really want to use.” I think pretty much everything, I'm very reluctant to try new technologies. So, it was really hard to get me into using Node at first. And now, hey, it’s all I do.
But Twitter, yeah I had it. It just sat there for two years with one tweet, which was, “Is this thing on?” And then finally, I started using it. And now, I get tons of mistweets from, let’s see, @Cowboy_Stadium, @Cowboy_J_Storm, @cowboytroy, @cowboygrill, cowboy everything, all the time. It’s pretty awesome. In retrospect, cowboy is cool. It’s a nickname I’ve actually had in real life since about 1995. And I managed to get it online in a few places, like GitHub and Twitter, which is cool. But in retrospect, I don’t know. It’s almost a liability.
BEN: Just because all the crap it gets thrown at me on Twitter.
CHUCK: So, are you a Cowboy Coder?
BEN: You know what? It’s really funny. I am the opposite of a Cowboy Coder. I love to work in groups with other people. I’m constantly trying to find people to bounce ideas off of to get second opinions. I’ve been doing this for a long time so I generally trust my intuition. But I really, really value working with other people on projects, not just for the other point of view. But also, it helps. You can help motivate each other and you can look at each other’s code and you can catch mistakes, or someone just comes up with some idea you never thought of before and it’s like, “Oh, that’s brilliant. I never would have thought of that.” So, I love to work people. I’m at conferences all the time talking about the latest thing I’m working on just asking people, “How would you use something like this,” and getting their ideas. So yeah, it’s ironic. I’m not a Cowboy Coder at all.
RYAN: I think I’ve got a great intro and segue from what you just said for this episode.
AJ: Wait, wait. What is a Cowboy Coder?
BEN: Well, it’s someone who just goes out and just does their own thing recklessly, without really heeding, like, “Oh, screw that story that I have to work on. I’m just going to work on some stuff that I want to work on. Who cares?” Or not following code guidelines. They’re just not really fitting in. Someone who’s just, I don’t know.
JAMISON: A loose cannon.
BEN: Yeah, a loose cannon.
CHUCK: Yeah. They’ll get the feature halfway done, check it in, totally bust everything.
AJ: Yeah. That sounds awesome. I’m going to start doing that.
BEN: Yeah. It’s funny. In the classes I teach, there’s a lot of stuff that I would just call best practices that’s come out of me doing things the wrong way and working in teams and just making mistakes for the last 14 years or whatever, that I try to really teach people to not be Cowboy Coders. And I don’t use the term or anything, but the whole idea is you’re most likely part of a team.
CHUCK: So Ryan, what were you going to say?
BEN: Yeah, sure.
RYAN: It was, no, not Smalltalk.
CHUCK: Oh, that’s Amber. Okay.
RYAN: Yeah, that’s Amber. So Ender, it’s still around. Anyway, it’s a little frontend package manager, a little bit like Bower I guess now.
BEN: It’s kind of a tool that helped you build your things into packages for deployment.
RYAN: Yeah. So, I was pretty interested in it. And so, as an experiment, I had split up all of jQuery UI into these little repositories for each little component.
BEN: Oh, yeah, right, I do remember this. Yeah. And I think I thought you were insane at the time.
RYAN: Well yeah, I still am.
BEN: Just because jQuery UI is huge and that was a lot of work.
RYAN: Yeah, it was a lot of work. But I got it done. You can just do ender install jquery-ui-autocomplete and it would pull in just the pieces of jQuery UI that autocomplete needed and then make the build. And you and I were talking about, “Man, this is cool. But splitting this up into several repositories, it’s just so painful especially because of the tooling,” because all of the jQuery UI components wanted the same kind of tests and just all these tools to build the library.
So, we were talking about the difficulties and what we could do about that. And then you started to tell me that you had been thinking about this as well, because you wanted to split it up or just work on smaller projects but you didn’t know how to share the tooling and you wanted to build something to fix that. Then I think right then, you started to write code to what eventually became Grunt.
BEN: Yeah, well I started working -- this has been a long process for me. So, I’m not just this guy who two years ago was like, “Hey everyone, check out this Grunt thing that I just thought of.” I’ve been thinking about automation and basically making my life easier. I’m a lazy coder and I want to do the best job I can with the least effort possible. And so, for a long time, okay, so I’ve got 50 jQuery plugins. I’m the Grunt guy now, but I used to be the jQuery plugin guy.
RYAN: Yeah. When the repository went down, I remember one tweeted saying, “Oh hey, the new jQuery plugins website is just cowboy’s website.”
BEN: Just like that, [inaudible].
BEN: Basically. Yeah, so I was the jQuery plugin guy. Now, I’m the Grunt guy. So, in case you guys are listening, some of you haven’t really got the message yet, I’m now the Grunt guy. So, don’t ask me about jQuery plugins anymore.
I actually started, before writing Grunt, I had a bunch of shell scripts I would use in all of my jQuery plugins. Every time I would release one, I would build a documentation using Natural Docs. It was a Perl thing that looked at code comments and built a whole website for documentation. And I would lint my code and I would run unit tests and do a whole bunch of stuff to build the project to release it. They were pretty customized shell scripts. And I lost that machine or something happened where I changed my development practice and I no longer had these shell scripts. I was like, “Wow, maintaining these projects sucks now because I have a whole bunch of them and people are filing issues.” And I literally don’t want to fix the issues because then I would have to rebuild my build process. So, just nothing was getting fixed.
I was like, “Okay, I need to come up with a better way. I want to be able to check something in with each project instead of having it just floating around on my dev machine so that I will no longer ever lose my build process. It’ll just be part of the project.” So, I started looking into things. I didn’t want to use make because the main reason I didn’t want to use make is because I was dealing with JSON files here and there and it runs bash commands. I don’t know if you’ve ever tried to deal with JSON in bash, but it’s a nightmare. You could get one value out of a JSON file and then get it into something else, but if you want to use JSON to build templates of things or something, it is a nightmare. So, make was out. I started looking at rake. I was fooling around with Ruby a bit then.
Now maybe what I should have done is just make a bunch of little modules that I could have published individually and then required in my jakefile. But I didn’t want that. I want a command I can type. And I don’t even know when I came up with the name Grunt, but I came up with the name Grunt. And it was like, “Sweet, I have a command.” But eventually, yeah, I was working with Rick Waldron who was dealing with jQuery and he was using my jakefile in jQuery. And I started working on this tool, this thing that I was calling Grunt, that it would have all of the common stuff built-in like JSHint would be built-in and concatenation and uglification, uglify for minification, those would all be built-in. Unit testing would be built-in, et cetera. I actually had a whole thing built-in also that I added after the fact as an afterthought to do scaffolding of new projects, which didn’t really fit in but I made it work because it was something I really wanted to use.
So then, I published it as Grunt a couple of years ago and people started using it. It was pretty interesting. People like that it was just something they would install globally and it did all of this stuff for them. The problem is, is because you installed it globally and all of these things were built-in, every time someone wanted to like, “Oh, Ben, we need you to update the version of JSHint that’s inside of Grunt,” and then I would do that and I would release a new version of Grunt. But that version of JSHint would have slightly different behavior and it would cause a regression somewhere else so that other people using Grunt would all of a sudden have problems.
So, we realized that having the plugins, the core functionality, all the things I would now [inaudible] are now plugins, having those built into Grunt was a mistake because it meant we had to literally release a new version of Grunt every time we wanted to update one of the little plugins. So for the latest version we made them all plugins. They’re all totally separate Grunt loads. You just install Grunt and then you install plugins separately and put them all together.
RYAN: I actually remember being put off by that. I was like, “Whoa. These things are just a part of it?” Yeah, that’s why I didn’t give it a fair shake in the early days.
BEN: I have learned so many things about releasing a tool like this since I started. I did so many things the wrong way. Even thinking about having a tool like Grunt that consumes plugins, a lot of people say that’s the wrong way to do it. I don’t necessarily agree with that. It’s nice to have modules that you can require and use independently. Why have a Grunt JSHint plugin? Why not just require JSHint and use it? So what’s nice about having the plugin approach is because they all go through Grunt. They all have a really standard interface. You use them all in the same kind of way. If you’re using the JSHint plugin and using the uglify plugin, you’re going to configure them almost exactly the same way. They’ll connect with Grunt the same way. So it’s nice that they’re plugins.
That being said, I could have also come up with a spec for how this kind of what is now a Grunt plugin could behave like. It could be a generic Node task and then as long as your task follows the spec, it would just work and you could string them together, which is actually something that we’ve been working on behind the scenes for a future version of Grunt.
RYAN: Actually, I just barely crossed that gap. I know that you follow me on Twitter so you’ve probably seen me complain about Grunt. And I just now, the last couple of months, crossed that gap of realizing, “Okay, this is great. These all have the same interface.” Sure there’s Sass already has its own binary, JSHint already has its own binary, but I’ve caught that, I guess, realization that, “Wow, this is great,” because I can declaratively configure these things.
CHUCK: Hold on. So, when you’re talking about what you were complaining about before, now you understand, can you just specify what the pain was and what you didn’t understand? Because I didn’t totally follow that.
BEN: For example, one of the things I didn’t understand is that I thought that you could take a tool like this and publish it globally and then everyone could just use it in their projects. Why have local Node modules for your project? Just use the globally installed Grunt. So the problem there is, let’s say you have Grunt 0.3 installed and you’re using that in five of your projects. And then someone else, you have to clone someone’s project, and they’re using 0.3.5 because that made some really awesome change to the JSHint functionality that was built-in in the global install of Grunt. And that’s awesome. It’s great for their project. But it doesn’t work with 0.3 because that change maybe happened in 0.3.5. So you’re like, “Okay, I’m going to uninstall 0.3 globally and I’ll install 0.3.5” Great, now the new project works, but if you go back to the other projects that use 0.3, they’re like, “Oh, well we’re not compatible with 0.3.5 because not only did they add some cool features, they’ve changed some of the old stuff that we were dealing with.”
So, it became very obvious very quickly that you can’t have multiple different versions of Grunt installed globally simultaneously. So it doesn’t actually scale if you’re working on different projects that might use different versions of Grunt. So we had to change the way that people use Grunt. Instead of installing Grunt globally, Grunt is actually installed locally into your project. You put it in your project’s package JSON file. When you type in npm install, you’ll get the version of Grunt that you want installed locally in your project. So every different project can have its own version of Grunt. Now if every one of your projects happened to use the same version of Grunt, well it’s going to occupy a little bit of extra space in your hard drive and that’s a problem honestly, for npm to solve in how they manage their redundant installs of things if they want to optimize for that. But that was something we learned with Grunt. Don’t install Grunt globally, install it locally.
Now that being said, installing it globally gives you the Grunt command. So you could install it locally, but then you’d have to type in npm grunt this, npm grunt that. And I didn’t want people to have to do that, because it’s just nice to type in grunt. So we created a separate tool called Grunt-cli. You just install that globally and all that does is it finds the local version of Grunt that you have installed in your projects and runs that. So contextually, whenever you’re in any project, it will just tie the Grunt command to whichever Grunt that project happens to have installed locally. But this was something we had to learn the hard way.
There are a lot of things like this. Breaking up plugins so that they’re no longer installed, they no longer come bundled with Grunt, that allows us to maintain the plugins in Grunt separately, which is huge, absolutely gigantic for maintenance and it’s really opened it up so that there’s 1300 Grunt plugins now. It’s ridiculous. I don’t know if any of them work. But there’s 1300 of them out there.
Here’s another thing I learned. I use Underscore, I use Lo-Dash actually, inside of Grunt. It was Underscore. We switched it over to Lo-Dash. Inside of Grunt, anytime you’re dealing with templates in Grunt, it just uses that version of Lo-Dash. What I did is I exposed that version of Lo-Dash as Grunt.underscore. So you could actually use Lo-Dash in any of your projects, too. You wouldn’t have to install it in your package JSON as a dependency and require it. It was built into Grunt. So people are like, “Hey, we want you to update the version of Lo-Dash that’s in Grunt because it’s added some stuff that they want.” Well the problem is that it works just fine for Grunt. And all the unit tests that I care about pass with the version that’s in there, even though it’s not the latest version. The instant I upgrade to a new version, maybe [inaudible] the tests will still pass, but someone using Grunt somewhere out there, they might be using some of that old functionality that all of a sudden is going to be broken.
So, if I was going to upgrade anything that I’ve got built into Grunt that I happen to expose like Lo-Dash or async or one of the other libraries that I happen to have exposed in Grunt, it means I have to actually go from 0.4 to 0.5 instead of releasing as 0.4.2 because it would introduce backwards breaking changes. So this is the thing. When you have a project that is used by this many people, and I’m looking at it, it’s downloaded 200,000 times a month. This is redonkulous, right? I have to be very responsible about how I manage the project and how I release new versions. There are a lot of issues where people are like, “Hey, do this. Hey, do this,” and I’m like, “I just can’t do it.” I can’t do that thing that seems totally reasonable because it’s going to screw a bunch of people over and I have to be super careful. So I’ve learned a lot of things about this.
RYAN: Yeah. If you haven’t done something that’s scaled before, it’s hard to understand why someone who is doing something that scale is saying no to you.
BEN: Yeah. And my whole thing is if someone wants a feature, that’s awesome. File an issue, maybe if it makes sense, we’ll go in there. But I’m only going to add features that really, really, really, really, really make sense. Because once I add something in there, it’s really hard. Any of you guys who’ve made an API before know it’s really hard to remove something once you’ve added it into an API. And I am not going to do anything half-assed. Or I’m going to try really hard to avoid doing anything half-assed. So things take time.
The good thing though is that Grunt 0.4.1 is out. I want to release 0.4.2 and fix a handful of bugs that are totally legit, that shouldn’t cause any major problems and just help people out. But it’s been pretty stable and people have used it. We’ve been able to close most of the issues that people have filed because they’re not really problems or they can be worked around. So it’s gotten a lot of use and I’ve been sitting back and watching it trying to figure out how I want to do things next. And we’re actually tackling that now by working on some of the underlying libs and breaking them up as separate libraries. I’m doing a logging library right now and I’ll do the file library next. And I already did the globbing wildcard handling library.
CHUCK: That’s really cool. I’m going to jump in here really quickly because we had a couple of things come up in the chatroom, our little behind the scenes chat, and one of them was I’m not sure we explicitly stated what Grunt is, what it does.
CHUCK: You’ve mentioned the main purpose of it, initially at least, was to manage a build process. And we’ve compared it to make and rake which are task systems. Is that all it is? Is it just a system to run tasks in your system, in your app, or is there more to it than that?
Some people complain that Grunt files are a little wordy, they’re a little verbose, it’s a lot of configuration. But the whole point of that is so that when you want to switch from a JSHint task to an Esprima task or something, the configuration is going to be largely the same. It’ll just have different options. But if you’re using cli tools, there’s a JSHint cli tool and an Esprima cli tool, the way you use those cli tools is completely differently. The options are passed totally differently. They work totally differently. So the whole point of using Grunt is so that once you get to use it a little bit, you can just start using plugins and it’s very quick to ramp up and use new plugins.
RYAN: Earlier, I said that I crossed a gap that you were talking about and that’s exactly it. What clicked for me is I realized, “Oh, Ben is jQuery guy or used to be and Grunt is jQuery for command line tasks.” It wraps it up. It gives you the same API to all of these tools just like jQuery wraps up all the different DOM things like back when we had attachEvent versus addEvent in IE versus other browsers. So that’s what clicked, is now I’ve got this API that’s going to be the same no matter which tool I’m using in my build chain.
BEN: Yeah. That’s the whole thing. There are so many plugins for Grunt. There’s one that allows you to shell out. One of the plugins we maintain is a Sass plugin. Now Sass is Ruby and we looked into using libsass, which is there’s a Node version of Sass as a lib. It’s a little bleeding edge right now and it doesn’t meet everyone’s use cases so we’re not using that. We actually shell out to Sass. So you’d need to have Ruby and Sass installed in your system, in your path, for the Sass contrib, officially maintained Sass plugin to work. So there’s a performance hit because it has to shell out and do that. But it does work.
RYAN: Yeah. So you said, I’m going to bring in a little Grunt grumpy here, you want the build to go as fast as possible, right? I know you’ve sat down with Yehuda Katz and Tom Dale recently about Grunt and then looking at using it for Ember and talking about rake pipeline and possibly Grunt pipeline where basically with Grunt, you have to copy your whole directory over and then perform tasks on those files. And you’re writing in and out to the file system and it takes a long time especially for big projects, you even end up hitting the file descriptor limits and things like that. Tell us about that conversation about Grunt pipeline.
And let me introduce that real quick. The idea of rake pipeline is instead of working with a bunch of files, instead you have a single stream that you just move through a bunch of tasks and you can pipe things in a command line tool pipe a string to another program, to another program. The pipeline does the same thing with this build of your file. So can you tell us about if you’re working on that, what the conversation was like with Yehuda, et cetera?
BEN: Well, I’ve talked to Yehuda and Tom. I work with Joe Liss as well and Tyler Kellen who has been working with me on Grunt for a while. He’s worked on something called Node task which is a preliminary idea for how we can, instead of having Grunt plugins, just a more general, “This is a spec that tells a task runner like Grunt how to interact with your thing that will be configured in a standard way.” There are a few pain points when dealing with Grunt projects when you’re dealing with a lot of files. Now first of all, when I created Grunt I created it to help me manage my jQuery plugins, which are six files each. There’s a unit test file, there’s a source file, there’s a license. There’s not a whole heck of a lot going on.
RYAN: Yeah, not a million line count.
RYAN: Guard. Guard in Ruby is pretty popular.
RYAN: That’d be awesome.
BEN: Yeah. So, this is something we want to do. But this is a large undertaking because basically what that means is that Grunt will have to say to a plugin, “Hey plugin, given this dependency, what are some additional dependencies?” The plugin’s going to have to actually respond back and give it some. Then now Grunt knows what to watch. When Grunt actually watches files for changing, it’ll watch all of the files that it knows about and then it’ll take the subset. It’ll have to intelligently pass those into a plugin using the correct configuration. I have a feeling really, it’s going to require a rewrite of Grunt. But that’s something I’m working on. I’m just working on it from the ground up because in order to get to that part of Grunt, I have to do so many other things.
Right now, I’m working on the logging system and this is me. I’ve spent weeks working on the logging system. Well, more than weeks, I don’t know, because I want to get it right and I have a lot of requirements. [Chuckles] Here’s something that’s going to be in an upcoming version of Grunt. Tasks will have their own level of logging and Grunt itself will have a global logging system and task logging will be streamed into Grunt’s global logging system. So all of the errors and success messages and all that stuff can be sent to standard error, standard out, at the Grunt level, but we could say for every single task, write all of the tasks logging output to a file.
So for example, for continuous integration people, they’re going to love that. You’d be able to run Grunt, all of Grunt’s output will be standard out, standard error, pipeable, streamable, whatever you want. But then if you want to, you could say every single task will get its own log file written out in a directory or something like that. So these are the kinds of things we’re thinking about but I have to write this code. So we’re writing it and experimenting with it.
RYAN: As I’ve been writing some command line tools lately, I built ember-tools and recently loom for generating things, I really like the way that Grunt outputs things. And I keep wishing, “Man I wish that thing were a separate component.” Are you thinking about doing that?
BEN: Oh yeah, the logger, I’m working on this thing called prolog, not to be confused with the language. It’s really a work in progress. It’s in my own cowboy, GitHub.com/cowboy/node-prolog.
BEN: And right now, it doesn’t look anything like Grunt’s output because I’m trying to make it general. It looks a lot more like npm log. And I’m trying to figure out exactly how I want Grunt’s output to look. So I’m going to figure that out. But I’m trying to make it super uber customizable and it’s all event-based. It’s going to use streams as well, so you’ll be able to pipe things everywhere you want in a bazillion different ways with different levels and stuff like that. So that’s just one of the things we’re working on. We definitely want to improve Grunt performance for large projects.
But let me put it this way. Say you have a task that builds CoffeeScript files. If you wanted that plugin that you wrote to have all of that Guard functionality built-in, imagine this. Imagine you write a little library that takes a list of files and give it a temporary directory, point it to, and all that does is it takes, when you say, “Hey CoffeeScript plugin, compile all this stuff,” it will take that entire list of CoffeeScript files. It will use that little module that you’re requiring that takes that list of files, checks to see if they have been modified since the last mtime stored in a temp file in that temp directory and then that will actually filter that list to a subset of files that will then get compiled.
It would be very easy for anyone to write a lib that takes a list of files and maybe a temp directory and checks mtimes to see if the file should be recompiled. And you could make a smart CoffeeScript Grunt plugin using that lib and if you make the lib generic enough, every single Grunt plugin could use that. You wouldn’t even have to be part of Grunt. I’m just saying, if you want to solve the problem right now, just write a little lib to do that. Trivial, right? It’s actually very easy.
RYAN: That’s exactly what I started doing last night for the ES 6 module transpiler. [Chuckles]
BEN: That’s what I said. Yehuda and Tom, they want to be able to use Grunt in Ember, but it’s just not fast enough for them. And I said write this lib. Put it in the task you’re going to use. Problem solved. We can write other tools instead of Grunt or we can wait until Grunt has it, but for right now, we can solve the problem. This is not rocket science. It’s actually pretty simple and it would totally do the job. Then later on, once Grunt’s smarter, that could just be obsolete. But right now, that would totally work for compiling large sets of files.
JAMISON: So I have a little question. It seems like Grunt has taken off for sure in frontend development. It feels like there’s a little bit of reluctance or opposition to it in the Node community specifically. Have you noticed that or am I just [inaudible]?
BEN: I know some people who use Grunt for their Node stuff. I know some people who don’t. The Node community is interesting and I don’t really consider myself to be a member of it even though I use Node all the time, because I hear a lot of people referring to the Node community as this insular negative thing. And I don’t know what it is. I don’t really understand. I don’t really care. It doesn’t matter to me because I’m not trying to address any community’s needs. I’m trying to make something that works good for me which is always what I’ve done and people seem to like the stuff that I make for me. Of course, I’ve got a lot of feedback from other people so that’s of course invaluable. But if people think it’s going to meet their needs, that’s great. It’s awesome.
BEN: Or the old Grunt init. But when I create a Node project, I use my Grunt init template which is the old init thing that was built into Grunt as a separate tool and I have a template for a Node project that just gives me all of the stuff that I need with basic unit testing, the scaffolding that I need to get it set up, and I just fill in the blanks. It just makes it less work for me. So that’s why I use it. But I don’t know. I’m not going to change anyone’s mind because until I needed to use Grunt, I didn’t start looking for alternatives. I just did what I was doing. I used shell scripts. That was great for me. It was only once I developed a need to change it that I really started researching and looking around and finally ended up giving up on all that and writing my own thing.
JAMISON: Sure, that makes sense.
BEN: To be honest, a lot of people in the “Node community”, they’re the kind of people that when I seriously went into the Node.js channel that first time and said, “Alright. I need to manage some kind of queue of callbacks that are all going to happen asynchronously. Does anyone recommend a library? Can anyone recommend a library for me to use?” and three people were like, “Just write it yourself.” And I’m like, “Guys, I can write it myself. But I just want to work on the other stuff.” So I ended up using async. It works great. But there’s a whole bunch of other things. Promises, I can’t wait to use promises. And yield and generators and all that kind of stuff. Yippee skippee. But at the time, the kind of vibe I got was like, “Hey, write your own.” And I’m like, “Great. That’s not really the answer I was looking for.” And that’s the “Node community”, seems to be very like, “Hey, do it yourself,” which is cool.
AJ: Unless you hate that. It gets on my nerves so much because I think there should be simple ways to do simple things like what you’re saying.
BEN: And there are. There are a lot of ways to do it. There’s a lot of stuff out there. There’s npm-search. It will get you what you need to find. You can find it now. But IRC chat rooms, the way people are, you ask them a question that you totally don’t understand and they answer it and then they say, “Of course,” at the end.
BEN: Of course you know the answer to this, even though you just asked the question because you had no idea what the answer was. Of course, right? It’s that kind of attitude. Long story short, I don’t really care who uses it. I love it when people use it and I really especially love it when people use it in a way that I hadn’t anticipated and give me feedback that helps me make it better. That is really, really awesome.
Or when someone is like, “Oh wow, Grunt is being used by some of the LESS CSS guys,” who created this thing called automate, which is basically kind of like Jekyll but as a Grunt plugin. It builds a static site. It’s a static site generator. That’s cool and they use Grunt to power that. Okay. Because Grunt makes the wildcard handling and some of the file stuff easy for them. That’s some of the stuff I built into Grunt because I don’t want to have to create a directory, an entire series of directories, to create a file in foo/bar/bash/test.js. I want something that does that for me automatically so I have a mkdir -p function that gets called inside of my file create method automatically if it needs to be called, because I’m lazy like that. People like that. So that’s why they use Grunt. If you don’t need that, don’t use Grunt. Whatever.
JAMISON: So I want to jump in with a specific question. I’m a relative Grunt newcomer. There are other people at work that are a lot more familiar with it than I am. But my first impression in using it was that it seemed I didn’t understand the decision to separate the task loading from the task configuration. I guess that’s where I was going with my Node question. It’s written in Node but it doesn’t feel very Node-like. I don’t understand all the internals very well, but just off the top of my head, if I was doing something like this, I’d make loading tasks, you require a file that gives you a function that you pass in the configuration. But Grunt does things very differently where you have your configuration object and then you call load task and stuff like that. Do you want to talk about the why of some of those decisions?
RYAN: It’s DOM ready.
BEN: Well, the why was that I just didn’t know enough about Node to do it the way you’re suggesting. In the future, I would like to have more like when you have a Grunt plugin in your package JSON file, instead of saying grunt.loadNpmTasks grunt/foo, you would require grunt/foo in some way and do it in a more Node-like way. So this came out of me not really knowing enough about Node and really wanting to fight a lot of the design decisions in Node because they frustrated me because I didn’t understand them at the time. I understand them a lot better now.
JAMISON: That’s a really honest thing to say.
BEN: Oh well, this has been a huge learning process for me. Grunt works and I put a lot of effort into making it work and I try to make it as elegant as possible, but I fought the npm and Node conventions very, very hard for a long time. In fact, I’m still fighting some of them, some that I legitimately am not a huge fan of. But a lot of it are mistakes, like Grunt shouldn’t have been installed globally.
Although that being said, when it was first installed globally, it probably got a lot of people who would otherwise have been scared of it to use it that wouldn’t have used it. Then when it got them to they had to migrate over, they complained about it but they did it. And now they’re using it. Now they’re doing it the right way. It was probably good that I did it wrong to start because it got a lot of people who otherwise would have just been like, “Oh god, another local npm, blah, blah, blah. I hate this thing,” to try it, install it globally, and then reluctantly switch over to having it be local later on. Although, I still get people asking why they can’t install it globally and we just have a set response for that. But yeah, I’ve done a lot of things the wrong way.
If you didn’t want to, seriously, you can literally register a task that is a function that just does whatever the heck you want in the function. Tasks are functions. Write a function. The only think you might be surprised at is that by default, all functions, all tasks, are synchronous. You actually have to set a flag to make them asynchronous. Because you know why? Because most people using Grunt aren’t super familiar with Node and they don’t really understand the whole asynchronous thing. So I’m using synchronous methods everywhere. Under the hood, it’s all async. But all the file methods and stuff, they’re all synchronous. Now, I want to add promises. I have a lot of ideas about what I want to do there. Things will change. I want them to still be just as easy to use for people, but I want them to be much more powerful for people who want to step outside the bounds of the super simple Grunt scripting. But these are on the drawing board.
CHUCK: Awesome. It’s really interesting to hear you talk about where this could go and some of the things that you could do with it and just spell out some of the processes that you went through in evolving this from a really simple tool to a tool that people use to do all kinds of process things and tasks they need for their applications.
BEN: All I can say is the best thing I ever did was, Tyler Kellen basically came up to me and he was like, “I want to maintain a set of official contrib plugins and I don’t want them to be in Grunt,” and he had to explain it to me, because I was like, “No, they should be in Grunt. And we should install it globally.” And we talked about it for a while and he really helped me understand a few things. He’s done some stuff with Ruby and stuff in the past. He’s a pretty smart guy when it comes to this stuff. He really helped me understand that these Grunt plugins need to be separate things. And oh my god, by making them separate projects, they all have their own issues repo, people can maintain them.
I’ve got a couple of people helping me. Sindresorhus, vladikoff, Kyle Robinson, Tyler Kellen, these guys are helping me maintain some of the plugins and Grunt itself. Those guys, they can republish a plugin, I don’t care. The only thing I care about is Grunt itself. I need to make sure that that is exactly what I’m expecting. But the plugins, they’re maintained by other people. I don’t have to think about that anymore. So they’re in good hands. The official ones are being maintained by the smart guys on the Grunt team. And I’m not really worrying about that. It takes a lot of the burden off of my shoulders.
So I’ve had some really, really amazing suggestions come from members of the community who have gone on to maintain plugins themselves or actually contribute code to Grunt or just to help me come up with ideas. It’s been a lot of work and it will continue to be a lot of work and it’s taking up most of my time. But it’s been a great experience in helping people contribute to an open source project in a meaningful way. It’s been pretty cool.
CHUCK: One other question I have, and this is something that I like to do on open source projects on GitHub, is if you click on the contributors list, now usually on a lot of these projects of the size that we’re talking about here with Grunt, you usually see a handful of people who are the top committers. And on this one, it’s interesting because you’ve got over a thousand commits and the next person has 26 commits. I’m a little curious to hear what you have to say. What does that say about the project as a whole?
BEN: You’re talking about Grunt itself?
CHUCK: Grunt itself, yes.
BEN: Yeah, well--
RYAN: It’s the plugins, right? It’s everything you’ve been talking about, because everyone else maintains the plugins and Grunt, most part works.
BEN: Yeah, the plugins have got a lot of activity. The thing with Grunt is that I’m still trying to figure out exactly how I want it to behave. I have yet to meet somebody who is on the same page with me. If someone came into the Grunt channel and was literally like I could see that they had my same vision for how Grunt would behave, then they might be committing to it and making changes. But all the time, I’m getting people making suggestions. We have to close PRs all the time. I spend a lot of time just closing PRs. I want community involvement, but I just find that the vast majority of people are not putting the level of thought into the changes that they make that they need to put into something that is this important. It’s very important to me. I think it’s important to a lot of other people.
But all the time, I see changes where someone, it’s very obviously a band aid. Someone is approaching something from the completely wrong direction or it just opens up a whole can of worms. I hate to say this, but I feel that a lot of people just don’t really get what I’m doing. I see a lot of code that’s just not great, honestly. I have had some great contributions. There haven’t been many. And actually, there were probably more but a while back I did this weird rebase and, back from going from 0.3 to 0.4, so maybe a lot of those contributions might have gotten lost. I don’t really know. I know I’ve been very territorial with Grunt itself with commits, but I know I did some crazy rebase thing back when I released 0.4 going around there that had caused me to rewrite all the history. But yeah, I’m totally open to stuff.
But if you want something in Grunt, you need to really, really be able to defend it. I’m not going to put anything in there unless there’s a really, really good reason. Just think about, it’s probably really hard to get something into Node core, because you really need to defend it. I feel very strongly about Grunt. I take it very seriously. I’m open to ideas, by all means, but I’m not going to just throw something in there because it seems like a good idea. It has to be, I have to see it and be like a light dawns on me and I’m like, “Oh my god. That is absolutely correct. That is what we need.” So I guess I’m just picky.
CHUCK: Yeah, maybe. It cuts both ways. That feature that I absolutely feel like I need, it makes it harder for me to get that in. The flipside is if I’m the only person that needs it, then it means that if you put it in then you have to maintain it and everybody else has to deal with the consequences of adding that code. All the other users have to deal with any consequences of adding that code to the project. So it makes sense. It just depends on where you’re coming from with it.
BEN: Grunt at its core is like a task running system. There is not a lot that you need in Grunt, to be honest. There are a few things that I definitely want to add in there functionality-wise and there are some issues around flushing things to standard out because of the way Node handles it. There are definitely a few things that I need to get in there and fix. But a lot of the things that people need, they don’t really need. They can do them in totally different ways. They just are not aware of it. So a lot of tickets are generally closed with, “Oh no, you can actually do that this way. But we really appreciate the code. Thanks anyways. Do this instead.”
CHUCK: Yeah. So we’re winding down on time. Are there other questions that you guys have about Grunt? Or anything that you feel like we should have talked about, Ben?
BEN: No. I’m just really psyched that so many people have been interested in the project and have used it and written tutorials. I’m trying to figure out a few things right now with the project. There have been three blog posts on GruntJS.com because I don’t have the time to do that. We’re trying to figure out some way to, if anyone out there is really interested in Grunt and wants to work on community stuff with us, that would be great. Writing tutorials or at least even maintaining things or tweeting or whatever. We’re always looking for help for maintaining plugins. If you have really cool ideas about how Grunt could be better, please talk to us.
I’ve probably thought about whatever you’re going to throw at me more than you have so it’s going to be hard to convince me, but it has been done. Grunt has definitely been made better as a result of some people taking a little bit of effort and explaining to me, really letting me understand why it should be better and showing me some examples and stuff like that. So I’m totally open. I’m just super psyched that people are using this thing and thankful. It’s been a good experience.
RYAN: I’ve got one more question for you, Ben.
RYAN: How’s the bass coming?
BEN: You know, with my back, it’s been tough. I haven’t really been playing it very much lately. But I’ve been playing a lot of piano.
BEN: Yeah. I have it right there next to me. I haven’t played it in a couple of hours, but [Piano playing] I don’t know if you can hear it.
JAMISON: Oh, new intro song.
CHUCK: Yeah, we can hear it.
JAMISON: Boom. It’s done.
JAMISON: That’s so rad. You’re good with piano. I just wanted to ask if there’s, he’s still jamming.
BEN: I’m done.
JAMISON: Okay. I wanted to ask if there’s--
BEN: No, no. I want to play the bass, dude. I can’t play the keyboards in a band. I just play my own stuff. I’ll play the bass.
RYAN: Okay. Sorry, Jamison.
BEN: But it has to be funky.
JAMISON: I could play the bass, too, because then we can have two basses. That’d be pretty rad.
JAMISON: No, I’m just kidding. So is there anything you would do differently if you were starting Grunt over from scratch?
BEN: [Laughter] Yeah, everything.
BEN: So it’s a chicken and egg kind of thing. A lot of the things that I’m doing right now are breaking out some of the functionality that’s been built into Grunt into separate modules, which I couldn’t really have done early on because I didn’t know what I was going to need until I made it.
JAMISON: Yeah, it’s like a scaling problem.
BEN: Yeah, and I don’t really have a long history of building very super modular projects. Basically, I build something monolithic and then I break it up into little pieces. That’s how my brain works. So I would like to say that I would have built all the modular first and then made it easier to maintain. But I just know that my brain doesn’t think that way. That’s one of those, “That would have been nice, but forget it.” So in terms of having really done things differently, I would have done a better job of, okay, the single biggest thing, I would have made Grunt an instance instead of a singleton so that I can create multiple instances, each with their own state, so that I could test it much easier and you can test Grunt plugins much easier. That’s the single biggest thing.
And I tweeted a while back. [Chuckles] I tweeted a month or two ago. I just said, “Singletons are the problem,” because every time you make something a singleton, it just means that if you want to test it, you can’t use it in the thing that you’re using to do the testing. And I found that out to be the hard way. I use Grunt to test Grunt, but in a very limited way. And the way I make all my libs now pretty much, I make them as instances so that I can create a new instance of my logging library. So I can have ten logging libraries and they could all work side by side or whatever, lots more flexibility. That’s one of the biggest things I would have done, would have made Grunt have a Grunt constructor and create a new instance. That would have all been transparent behind the scenes, but it would have allowed me to test it better.
And another thing I would have done is I would have decoupled the CLI behaviors from the lib, the underlying lib behaviors, more. I did it, but I did it as an afterthought. So as a result, if you’re trying, you can use Grunt as a lib but you can do certain things in Grunt that are just going to take down your whole app because Grunt will consume, it will do process.exit and stuff like that. So I would have been a little smarter and that’s one of the things I’ll do moving forward in Grunt. Things that I want to do in Grunt, I want to make it completely usable as a standalone lib and the CLI will be built around that so that you don’t have to worry about it misbehaving if you’re using it as a lib. You’ll be able to create an instance of Grunt. Plugins will be more generic and they won’t necessarily be Grunt plugins. Although that would be really nice to have, a lot of work would be needed to have that happen.
I would love to use alternative flow control like promises in tasks or at least support that. So I don’t really know how I would do that yet, but I’ve been giving it some thought. And I want to make things just more extensible. I added an event emitter into Grunt for 0.4 but I haven’t really used it. So it’s not really doing anyone any good. Certain plugins utilize it, but Grunt itself doesn’t do that to say, “Hey, a task has started. A task is ending.” So I will emit a lot more events in the future version of Grunt. And those are all things that I wish I had done earlier, but they will get added in there. The big challenge, the single biggest challenge is the upgrade path for people. I want to add all this stuff into Grunt, but so many people complained about how hard it was to upgrade from Grunt 0.3 to 0.4. It wasn’t really that hard, but people, they didn’t like that.
So I want to make it easier for people to upgrade from 0.4 to whatever future version I’m going to have that uses just maybe some kind of lib inside that’s a back compact library or something like that. I don’t know what that’s going to be but that’s one of the things. I really want to keep the users happy. But that’s my list. And it’s not really a big list. I feel really happy about what is done. I just have never actually got to use Grunt to republish all my jQuery plugins.
JAMISON: The original purpose.
BEN: The reason I created it, I’m not the jQuery plugin guy anymore. I’m the Grunt guy. So I haven’t had any time to really adapt it into my plugins yet. So, there’s that. But I get no complaints. It’s all good.
CHUCK: That’s awesome.
JAMISON: That’s sweet.
CHUCK: Well, we’re at the end of our time, so I’m going to wrap this up. We’ll get into the picks. Let’s have Ryan go first.
RYAN: Alright. I’ve got two picks. Number one is Web Components. If you’re using Angular or Ember or neither, just start messing around with Web Components, whether it’s Ember’s component or an Angular directive. Or go grab Polymer and grab just the platform library and start screwing around with it. It really changes the way that you do frontend development, or at least gives you a better way to do what you wish you always could have. And man, I am just having a blast. I’m an Ember component Rambo right now.
Then my second pick is something that I’ve been doing in my personal life lately. I have removed all sarcasm, or at least attempted to. I’ve got to tell you, it is life changing. All relationships are better. Communicating with people is always better. My wife said to me when I told her I was going to do that, she said, “Well are you not going to be funny anymore?”
RYAN: And as it turns out, there’s always a meta-joke. If you’re going to give a joke sarcastically, there’s this joke behind the words that you can tell in a way that is not sarcastic. Or instead, it’s a joke that you’re trying to convey some sort of feelings and maybe you can’t present it as a joke if you’re actually being sincere. But then, instead of the person on the other end wondering, “Oh no, what does he really think about me?” instead they know what you think and it’s usually a really high compliment to them and makes them feel good. So basically, if you’re going to say something sarcastic, there’s a way to say it non-sarcastically that always leads to better communication. And if you can’t think of a way to say it non-sarcastically, it’s not worth what it might do to the other person’s thoughts.
BEN: That’s a good one.
JAMISON: I agree wholeheartedly.
BEN: You know, I need to say that I try to be relatively non-sarcastic and the toughest thing for me honestly is hearing other people be sarcastic and you just want to be like, “No, you don’t have to do that. You don’t have to be that way,” and it’s just tough. But yeah, just lead by example. It’s positivity, man. It’s badass.
RYAN: Yeah, I’m hypersensitive now to when people are sarcastic and I don’t say anything. I don’t get all, “Oh, you shouldn’t do that,” but yeah, it’s been great. I’m actually am planning on maybe writing a little article and putting it online or something about, I’ve got a bunch of examples of things that I said that were sarcastic and then I’m like, “Oh wait, let me take that back and actually tell you what I’m really feeling,” or, “Let me try to tell that joke differently.” And I do that every time I catch myself being sarcastic. I say, “I’m sorry. Let me try that again.” And it’s now to the point where I don’t really do that anymore. But yeah, it’s been awesome. Give it a shot.
CHUCK: Awesome. Jamison, what are your picks?
JAMISON: I have one pick and it is the greatest pick that I have ever picked. It’s this cartoon that’s on YouTube called ‘Bee and PuppyCat’ by one of the storyboard artists behind Adventure Time.
JAMISON: And it’s just ten minutes of bliss. It’s so good.
BEN: It is so absurdist.
JAMISON: It’s amazing.
RYAN: I watched it after you tweeted it and yeah, it’s awesome.
JAMISON: Yeah. Other people might not love it as much as I do.
JAMISON: But it’s the perfect sense of humor for my brain just crafted directly for me. Yeah, it’s wonderful. It’s really sweet. You could show it to your kids. I don’t know if they’d think it was as funny as I did. But it’s amazing. So yeah, that’s my pick. Watch Bee and PuppyCat. Ten minutes long.
CHUCK: Awesome. AJ, what are your picks?
AJ: So I’ve picked this before, I’m pretty sure, but I’m going to pick it again because I love Monoprice. It makes my heart happy almost as much as Amazon. Lots of really...
JAMISON: I don’t know what Monoprice is.
AJ: What? You’ve been living less than your potential.
RYAN: No, he’s got Bee and PuppyCat.
JAMISON: Yeah, man.
AJ: Oh, okay. That’s possibly true. So Monoprice is, you know those monster cables that they sell at Best Buy for $150 for three feet of cable?
JAMISON: Oh yeah, that sounds so good.
AJ: Yeah, Monoprice has all of those for 50 cents. Well, they have 50 cents for the cheap ones that normally cost $8 and then it’s $3 for the ones that normally cost $50. So it’s just all your cables and stuff and they’re branching out and they’re starting to do more things. They have an extremely highly well-reviewed 5.1 home theater system but it doesn’t come with a receiver so I haven’t bought it. I don’t know about how awesome it is. But I’ve bought some of their other stuff that’s not just cables and connectors but that’s actual legitimate product. I can’t remember off the top of my head what, but I know I have. And all their stuff is good.
If you buy the cheap stuff that’s 50 cents, then you get cheap crappy 50 cent stuff like you expect, but if you pay the $3 for the same cable to get the premium version, it’s really, really good. By the way, if you’re ever having problems with audio, it’s either that you’ve got a ground loop, you’ve got noisy power, or you’re using bad cables. And if you’re using Monoprice premium cables, you’re not using bad cables.
BEN: And you can go with iPhone cables from them for $2, right?
AJ: Yeah. Now the iPhone cables they have, I think they might have some premium ones now. But they’re the ones where you’re going to want to buy 20 of them for $5 or whatever it comes out to be. They’re really, really cheap and they’re not good. They will break. But they may have a premium one now. I haven’t looked. Oh, actually, they do have a premium one. They have a three in one that is both an iPod and an Android and a camera USB connector. And that one holds up really well. It’s a nice thick cable. The cheaper ones, the cheaper iPod alone ones, are super flimsy and they’ll eventually break.
But the other thing that I was going to mention is I have this screencast on Grunt because Merrick introduced me to Grunt and I fell in love with it after about 15 seconds. I think he was mid-sentence explaining and the vision came clear.
BEN: Wait, wait, wait, wait. What did Merrick have to say about Grunt? I’m curious.
JAMISON: He loves Grunt.
JAMISON: He was really bummed he couldn’t be here.
BEN: Oh, I had no idea. He seems like a thoughtful yet very skeptical guy.
RYAN: He is.
BEN: I didn’t know he’d feel about it. Alright, that’s cool.
JAMISON: He’s probably the biggest Grunt fan on the show.
AJ: Yeah, so he introduced me and fell in love with it and I made a screencast because I wanted to be able to remember what it was that he had taught me. And it’s my most popular screencast.
BEN: Here’s the thing. I’ve written some documentation on Grunt. There’s a getting started guide and there’s a configuring tasks guide, which are the two biggies. But there’s nothing like actually seeing a Grunt file or having someone explain it to you, because this stuff, there’s a lot of stuff to ingest. Your brain is going to overflow with, “Oh my god, syntax declarative blah, blah insanity.” So having those little guides for someone that’s like, “And this is what I do and here’s the file and watch. I’ll change this and see what happens,” I find those to be so helpful. So, I’m glad. I’m glad. That’s really cool.
RYAN: It took me 15 months, not 15 minutes.
AJ: I had been working on building something similar and Jamison, I think, you actually were part of that at one point, right?
JAMISON: No, I think that was after I left.
AJ: Okay. Well anyway, I was building something similar to Grunt and then Grunt came along and I was like, “Okay, this does everything that I want and I don’t have to write it myself.” And a lot of times, I’ll still write stuff myself because most people’s stuff, no, that would be a wrong way to say this. There’s a lot of stuff out there. 90% of it’s crap. 10% of it’s really good. And sometimes, I can’t find that 10% that I feel is good or that I think is good. So I just write my own stuff. But Grunt was very clearly a win. And it had just moved to 0.4, so that was my introduction to it. That might be why I didn’t have the abrasiveness that some other people with 0.3 had.
CHUCK: Very nice. Alright, I’m going to do my picks. So the first one is a Wired article and it is how segregated your city is. And it was really interesting because they were talking about geographic segregation. I think people in general feel like we do pretty well these days with blending in our cities so that you don’t have huge sections of the town that are one particular ethnicity or another. And this was pretty interesting to see how several large cities are actually broken up by, this is racial or ethnic groupings. And you’ll sit there and you’ll scroll through it and see that there are actually certain areas that certain ethnicities tend to have. So yeah, a very, very interesting way of looking at it. They do have a map of the entire US and that was also interesting to see. So, go check that out.
The other pick I have is more of an abstract pick, like not being sarcastic, and that is clean off your desk. It’s amazing how much easier it is for me to sit down and get to work. It’s not so much that I had stuff in my way that physically prevented me from getting to work, but I would sit down and I would always feel like there was all this stuff weighing on me. And having cleaned off my desk, I just feel like I can sit down and get to work and it’s a mental thing. I don’t completely understand it, but it’s real and it made a huge difference just getting everything cleared off. I scanned a whole bunch of paper and then threw it away and things like that. But all of those things really contributed to my overall feeling of wellbeing when I sit at my desk. So I’m going to pick that, too. Ben, what are your picks?
BEN: I’ve got a couple. Let’s see. One of the picks I have is Polygon.com. I’m really into gaming, video games, et cetera. I’ve been playing games with a handful of people for 14 years. This site really stands out above and beyond a lot of the other review sites. They have a very strong ethical mission. They are very sensitive to things that a lot of review sites brush under the rug or take for granted, like regarding a lot of the game tropes with misogynistic overtones and stuff like that. They seem to be really sensitive to that. Plus they’re really funny guys.
They put out a podcast every week called ‘The Besties’, which I find hilarious. I just think it’s really, really, really a fantastic site to get really good quality game reviews, opinions, information. Just really great. I strongly recommend checking out Polygon.com. Those guys also put out, the guys that run it put out another podcast called ‘My Brother, My Brother, and Me’, which I also think is hilarious. So that’s one of my picks, Polygon. I guess I’ll probably give you a link to ‘My Brother, My Brother and Me’. They have a website as well.
Then my other pick is Echofon. I want to mention, this is the Twitter client that I use on my Mac. I think they discontinued it and they brought it back. I don’t know. I’m using a really old version. The reason I use it is because it’s very easy to block people because so many friggin’ people mistweet @cowboy everything at me all the time. @cowboy_stadium, “Hey drinking beers at Cowboy Stadium,” ten in a row.
BEN: I can block that person once and all of their tweets just disappear. I choose my Twitter client by ease of blocking people. And Echofon is really good at that.
And this isn’t a pick or anything, but I do just want to say thank you guys so much for having me on. And I also want to thank all the people at Bocoup that I work with. They’re super awesome and they’re super helpful. And Bocoup is, we’re a company, we do stuff. We do consulting and training. But also Bocoup is really, really committed to open source and I’m really glad that I’m able to work on Grunt and add the kind of value that Grunt brings into our community. And Bocoup helps me and lets me do that. So that’s super cool. I just wanted to thank them. So that’s it.
JAMISON: It’s cool that your company has made the web better, not just made you guys money.
CHUCK: Awesome. Yeah, we love companies that do that. So yeah, thanks to them, too. We’ll go ahead and wrap up the show. Thanks guys for coming and thanks again, Ben, for coming and talking to us about Grunt.
JAMISON: Yeah, thank you so much.
BEN: Thanks for having me.
CHUCK: Alright. Well, we’ll catch you all next week. Thank you.