Thursday, October 24, 2013

Vendor your Bundle

   Has this ever happened to you?

   You're working on a Rails project, that requires version X of some gem.  But you're also working on another project, that requires version Y.  If you use the right version on one, and ever clean things up, you break the other.  And if you ever need to look at the source of a gem, it's squirreled away in some directory far from the projects.  What to do, what to do?

   You could use rvm, to create a new gemset for each one.  After a few years of projects, you wind up with a gazillion gemsets.  And if you ever try to upgrade the Ruby a project uses, by so much as a patchlevel, you have the hassle of moving all those gems.  And the paths to your gems get even hairier.

   Alternative Ruby-management tools like rbenv and chruby might offer some relief, frankly I don't know... but I'm not holding my breath.

   But there's still hope!

   You could stash each project's gems safely away from all other projects, inside the project!  How, you wonder?

   When you create a new Rails app, don't just do rails new myproject.  Instead, do rails new myproject --skip-bundle.  This will cause Rails not to install your gems... yet.

   Now, cd into your project directory.  Edit your Gemfile; you know you would anyway!  When your Gemfile is all to your satisfaction, now comes the magic: bundle install --path vendor.

   What's that do, you wonder?  Simply put, it puts your gems down inside your vendor subdirectory -- yes, the same one that would normally hold plugins, "vendored" assets, etc.  There will be a new subdirectory in there called ruby, under which will be subdirectories called bin, bundler, cache, doc, specifications, and the one we're interested in here: gems.

   Now you can upgrade your gems without fear of interfering with another project.  You can also treat the project directory as a complete self-contained unit.

   But wait!  There's more!  As an extra special bonus, if you want to absolutely ensure that there is complete separation between projects (handy if you're a consultant, like me), you can even make these project directories entirely separate disk images!  For even more security, you can then encrypt them, without having to encrypt other non-sensitive information, let alone your whole drive.  Now how much would you pay?  ;-)

   In the interests of fairness, though, I must admit there is a downside to this approach: duplication of gems.  Suppose Projects A, B, and C all depend on version X of gem Y.  Each project will have its own copy.  For large projects, that can soak up a gigabyte of disk space each.  You can cut down on this by making the gems symlinks or hardlinks to a central gem directory... but why bother, in this age when disk space is so cheap?

   If you know of a better way, or more downsides to this, or have any other commentary, please speak up!  Meanwhile, go try it for yourself, at least on a little toy side-project.  I think you'll be please with the simplified gem-source access, and much looser coupling between projects.

   UPDATE:  Some people read the above and thought I meant to put the installed gems in your source code repository (e.g., git), so that the gems would be put into your staging and production environments from there.  This is a serious problem for gems with C-extensions to compile, if your staging and/or production environments are on different system types from your development environment.  That situation is very common, as many (if not most) Rails developers prefer Macs, and the production machine (and staging if any) is typically Linux, or occasionally one of the BSD family.

   This is not what I meant.  Instead, you probably want to put your gem directory (usually vendor/ruby) into your .gitignore file (or equivalent for whatever other SCM system you may be using), so that your SCM repo will ignore them.  Do still SCM your Gemfile and Gemfile.lock.  Then, when you install to staging or production, you will get the same versions of the same bunch of gems, but the C-extensions will still be compiled for the particular environment.

Sunday, October 6, 2013

Ruby Day Camp Review

   Some of you, especially locals, may recall that I got waitlisted for RubyDCamp, and decided to put on Ruby DAY Camp for us poor shlubs.  Some of you have been asking how it went.  So, forthwith, a review:

===8<---cut here---

   TL;DR: Ruby Day Camp was a qualified success, with a fun and educational time had by all of the handful who showed up.

The Good:

   A fun and educational time was had by all, with great camaraderie and surprisingly good lunch.

   We started with a couple rounds of code-retreat (doing the Game of Life), had lunch, and spent the rest of Saturday and Sunday as an unconference.  There were discussions on Ruby Gotchas, NoSQL databases, Big Data, freelancing, consulting, and other random topics, mostly at least somewhat Ruby-related.  We wrapped up with a four-way round of code retreat.  It started as a three-way rotation among the more advanced Rubyists, while the other advanced ones, and a few newer ones, watched on a large monitor.  A fourth advanced Rubyist joined us late in the day.  Since the even number would mean that each person would always be in the same role (writing either tests or production code), we decided to mix it up, with the next “player” chosen randomly (by a Ruby script).  All in all, a good weekend-ful of Ruby (and related) geekery.

   The weather was perfect, a bit cool in the morning, warming up to very comfortable in the afternoon, especially in the shaded shelter.  Just as with RubyDCamp, a great time to hold a semi-outdoor event.

   The venue was wonderful, a shelter at Pohick Bay Regional Park (about halfway between the Beltway and RubyDCamp), with good power (once we went to the ranger station and had it turned on), and grills.  The only downsides were a fairly long trek to the bathrooms, and lack of Metro access (but still better than RubyDCamp).  At least said bathrooms were fairly clean.

   Saturday’s lunch was a bit chaotic, but it all worked out.  Some brought something for themselves, but some did not, and needed to make a fast food run.  Some had brought enough to share, such as sausages heated up on the grills, using charcoal bought on-site.  More people brought things to share on Sunday, so we even had some bagels and cream cheese for breakfast, in addition to the sausages, hot dogs, and hamburgers for lunch.  There were even leftovers! It was a great example of a self-organizing agile team.  :-)

The Not-So-Good:

   Attendance was very low; even with a couple of walk-ins, we only had seven people, including myself.  There were several no-shows, some without notice.  This can be mitigated by starting to advertise it earlier, and maybe more widely.  The financial effects on the organizer (or whoever ponies up for the shelter reservations) can also be mitigated by starting off on a “donate to register” basis, rather than “register for free and we’ll pass the hat there”, as I had initially done.  Of course, full corporate sponsorship would help with both!

   The low attendance made it impossible to support multiple tracks, as I had hoped to have.  But even so, we managed (I think) to hold discussions that provided value for the advanced Rubyists without overly confusing the new ones.

   Scheduling got very sloppy.  We started late, ended early on Saturday (late on Sunday but that’s because we basically decided to keep going), and had long lunch breaks.  Some of this can be fixed by experience (so we know how long some things are likely to take, like lighting charcoal without lighter fluid), keeping a better eye on the time, writing out a schedule in advance, doing some things differently (e.g., get funding and bring lunch makings, or coordinate potluck, and publish an earlier start time), or by just “going with the flow”.  Making a map and giving directions might also help people arrive on time for the first day.

   The list of topics for agenda-bashing was a bit much.  That was my fault entirely.  I should have stuck to the usual way (having participants fill out cards for each topic they really wanted to talk about), rather than brainstorming and writing down whatever topics came to us.

   Only about half the expenses got covered.  Again, more time would probably mean more signups (which, since it was “donate to register”, meant donations), plus maybe more ability to get corporate sponsors.  We could also raise the suggested donation.  But, since the expenses were fairly low (about $400), it’s not a big deal.  (The suggested donation was $20.  Donations ranged from $1, from someone who didn’t show, to $50, from someone who did.  Most others donated at the suggested level.)

Next Time?

   Next year of course I’ll be trying again to get into RubyDCamp.  But if I can’t, I would consider doing Ruby Day Camp again instead.  At least I’ve got this year’s experience to build on.  If there are enough registrations (or corporate funding), we could even add perks, like food and maybe even overnight lodgings.

   If I do get a RubyDCamp slot, I’d still encourage someone else to run Ruby Day Camp.  I’d gladly help put it together, even if I wouldn’t be attending.

   Alternately, I could do it in the spring, or some other time that would not compete with RubyDCamp...  but then RubyDCamp waitlistees wouldn’t have an alternate activity, for a weekend they may have carefully blocked out on their calendars.  But then again, we’ve all got side projects we could be working on!