Includable ActiveRecord

I created a Ruby gem recently, called includable-activerecord. It’s pretty small, but I thought I might explain why I created it, and discuss its implementation.

Classical Inheritance

When you use ActiveRecord, you normally include it in your model like this:

class User < ActiveRecord::Base
  # ...
end

Your User class is inheriting from the ActiveRecord::Base class. This is class-based inheritance, also called “classical” inheritance. (That’s “classical” as in “class”, not as a synonym for “traditional”.) Class-based inheritance represents an “is-a” relationship. So we’re saying that a user is an ActiveRecord base. Another way to say this is that User is a subclass of ActiveRecord::Base.

There are a few problems with this. First, what is a “base”? The name was chosen because it’s a base class. But just like we don’t give factory classes names like UserFactory (at least not in Ruby), we shouldn’t name base classes Base.

I suppose that we’re trying to say that this is an ActiveRecord model. That sounds fine at first glance — this is our model for users. But what if we also want to say that a user is a person? Ruby doesn’t allow inheriting from multiple classes. Now we have to choose whether to inherit from ActiveRecord::Base or Person. Person makes more sense, because it fills the “is-a” rule better. Class inheritance is intended for a hierarchical “is-a” relationship, such as “a user is a person”, or “a circle is a shape”. But since ActiveRecord::Base is a base class, we have to use it as our base class.

We could work around this problem by subclassing Person from ActiveRecord::Base and then subclassing User from Person. That’s fine if Person is also a model that we store in the database. But if that’s not the case, then we have a problem.

Mixins

Ruby provides another way of implementing inheritance — mixins. We often don’t think of this as an inheritance model, but it really is. When we include a module, that module gets added to the class’s ancestor chain. We can mix in as many modules as we want.

Mixins indicate more of an “acts like” relationship than an “is-a” relationship. It’s for shared behavior between classes that don’t have a hierarchical relationship. For example, when we mix in the Enumerable module, we’re saying that we want our class to act like other classes that include Enumerable. That sounds more like what we want ActiveRecord to be. We want our user model to behave like other ActiveRecord models, in the way that they can persist to a database.

But ActiveRecord doesn’t support that. Almost all the other Ruby ORMs do; as we’ve shown above, this is for good reasons.

Implementation

So I decided to see if I could implement the equivalent of the ActiveRecord::Base class as a module that could be mixed into model classes. I decided to call my mixin module ActiveRecord::Model, because classes that mix it in will behave as ActiveRecord models.

It turns out that ActiveRecord::Base is a pretty complex class. It includes and extends a lot of other modules. Luckily, as of ActiveRecord 4.0, that’s all the code it includes.

The module only defines a single class method, included. This is one of Ruby’s many hook methods. It gets called when the module in question gets included in another module, and receives that other model as its argument. All we need to have this method do is to include everything that ActiveRecord::Base includes, and extend everything that ActiveRecord::Base extends. Ruby provides a method that’s defined on all classes, called included_modules, which we can use to get the list of everything that’s included in ActiveRecord::Base. Unfortunately, there’s no equivalent list of extended_modules. But a quick search on Stack Overflow found an implementation of extended_modules that we could use.

So with a bit of magic (i.e. hooks and meta-programming), we can get the lists of constituent modules from the ActiveRecord::Base class, and include them in our ActiveRecord::Model module.

So with all that, we can now include the includable-activerecord gem and mix it in, with all the advantages that provides:

class User
  include ActiveRecord::Model
  # ...
end

It was exciting to be able to make this work. Since I wrote it as a proof of concept, I haven’t written any tests yet. But it seems to be working just fine. The main thing I really need to look into is making sure that plugins that extend ActiveRecord::Base from their own code will still work. I’m pretty sure this will work out of the box, because the ActiveRecord::Model.included doesn’t run until the model class is loaded, and that happens after those plugins have initialized themselves.

Empathy

I facilitated our team retrospective this morning. I felt like we made a little forward progress, but not as much as I would have liked. But it really brought one thing to the forefront of my thoughts today — empathy gained through communication.

We have a pretty large team by Agile standards — we had 20 people in our retro: 16 developers, 3 QA folks, and 1 manager. Out of those, only about 5 or 6 speak up regularly. I recently sent out a survey to the team, trying to get feedback on how we could improve our retros. A couple of the questions tried to get a feel for why people aren’t speaking up more. Only about half the people responded, and the answers didn’t really answer my question as well as I had hoped.

So on Amos‘s suggestion, we did the Safety Check exercise. We got a good set of answers to why people don’t feel safe. About half of the answers were about the fear of looking stupid in front of other people. About half of those mentioned the manager — they’re worried they might get in trouble for what they say. We talked some about fear and how it’s more often than not misplaced. And that the worst consequences are usually not as bad as you might think. But then we got to the crux of the problem — there’s not enough trust amongst the team, and especially between the team members and the manager.

About half of our team is new (within the past 6 months) — including the manager. While the developers have made some good progress building trust amongst each other, we haven’t had as much time with the manager to build trust between him and the rest of the team. So the lack of trust isn’t at all surprising.

Honestly, I already knew we had trust issues, and wanted to address them, but needed a way to lead the team to that same realization. With this exercise driving out the issue, we were then able to have a conversation about trust. The conversation was pretty good. We got more voices to contribute than probably any other topic we’d previously covered. (I was disappointed that the manager kept quiet though. I later found that he was trying to mitigate people’s fears by keeping quiet, but I urged him to contribute more in the future.)

But one point really stood out in my mind — a point of view that I hadn’t previously thought much about. Lauren, one of our QA analysts, pointed out that most human communication is non-verbal. We give tons of cues via body language, facial expressions, eye contact, tone of voice, even posture. I don’t recall if Lauren said it explicitly, but she pointed out that these cues build empathy between the speakers. She encouraged us to use more voice chat and video chat, as opposed to IRC text chat, because it would create more empathy between the people communicating, which would lead to more trust.

I spent most of the rest of the day talking to people on the phone or via Google Hangouts voice. And every single time, I consciously noticed that I was gaining empathy for the person I was speaking with. I assume (and hope) that that’s working both ways. I suppose that it’s always been happening, but I never really noticed it.

I’ve heard a lot of talk about empathy among Agile practitioners lately. It’s been mentioned on the Ruby Rogues podcast, and Angela Harms has been preaching it for years. I already understood how important it is. But until today, I didn’t really feel it happening.

So if you’re looking to build trust with someone, spend some time talking with them. Preferably in person, but if that’s not possible, seriously consider video or voice modes of communication, instead of sending an email or an instant message.

 

What I Want in a Blog Engine

I’m considering moving away from WordPress, for a couple reasons:

  • Security. There have been several vulnerabilities over the past few years, and I’ve never really had a high level of confidence that it’s secure. In addition, I now find the whole PHP model — every web app running as a single user, instead of leveraging UNIX permissions — to be broken.
  • Speed. I started to realize a couple years ago that a blog engine should generate static pages. The static pages should be updated whenever new content is added. There’s really no reason to re-generate the page every time someone wants to read it. At the very least, Server-Side Includes (SSI) or Edge-Side Includes (ESI) should be used.

Now that I’m starting to actually blog consistently, it makes sense to change. But before I move to something different, I want to be sure that I find all the features that I need. This post is my thought process about what I want.

Requirements

  • Self hosted. I like to run my own servers. Partly so I can keep full control, and partly because I enjoy doing some system admin stuff (as long as it doesn’t take too much time).
  • Generation of static pages. Almost everything should be a static page by the time a user requests a page. Obviously, submitting comments would hit a dynamic page, and comment approval would likely be done through a dynamic part of the site. But publishing a blog post or comments should generate static files to be served by Apache or nginx.
  • Categories (or maybe tags). I want readers to be able to find other things that I’ve written that might interest them. A list of categories in a sidebar would help them find what interests them.
  • Site map. Especially an XML sitemap, so Google can index better. I also like the idea of readers being able to see everything in one place.
  • Archives. This is another way of letting readers see everything I’ve written, organized by publication date.
  • RSS and/or Atom. I want readers to be able to subscribe to my blog.
  • Media. I don’t think I necessarily need a media manager, just a simple way to add pictures to blog posts.
  • Comments. I want to allow comments, but I don’t want to use anything like Disqus. I want the comments to be in my own database, so they won’t disappear. I also dislike requiring JavaScript just to see comments. And I’ve worked at places where Disqus wouldn’t work, due to web proxy servers. Comments should be moderated by the site admin, editor, or author. Readers should not have to log in to post a comment, but it would be nice to allow users to log into Twitter or some other social network to provide their info.
  • Pingbacks and Tweetbacks. I’d like to be able to see who’s referring to my articles.

Nice to Have

  • Free. I almost consider this to be a requirement, but I’d be willing to entertain a 1-time payment for something that meets my needs really well. I need to try to counteract my DIY-at-all-non-monetary-costs mentality.
  • Open Source. I think Open Source is likely to provide a more useful product, especially in this space. An Open Source option is more likely to improve over time.
  • Not PHP. I’ve got several problems with PHP. First, the whole PHP model of running in the same context as Apache (or nginx) breaks UNIX conventions. A security issue in a PHP program exposes more than just the program itself — it exposes Apache and every other PHP program. Under the UNIX model, each program runs in a different user context, isolating bugs to that program only. PHP is also a “hacky” language. PHP programmers tend to not be as rigorous (in many ways), leading to more vulnerabilities. Finally, the PHP language itself has had several misfeatures that have lead to security issues — much more than Ruby or Java.
  • Not MySQL. I’d like to be able to remove MySQL from my servers. PostgreSQL would be much preferred. Storing everything in git would be fine too — maybe even preferred. I’d even be fine with MongoDB or some other simple NoSQL database.
  • Admin console. I can’t imagine approving comments without this, but I’m not closed to that possibility.
  • Edit history. I want to be able to update posts, but see what the previous versions looked like. (Not sure if I care whether the public can or cannot see the various revisions.)
  • WYSIWYG. I’d be willing to settle for Markdown. In fact, I’d prefer (extended) Markdown as the canonical form behind the WYSIWYG.
  • Code highlighting. A lot of my blog posts (will) include code in various languages. I’d like the blogging software to be able to handle that well. Syntax highlighting would be great. Any other related features would also be nice.
  • Through-the-web editing. I’d like to be able to edit a page from any device from anywhere that has Internet access.
  • Reader-submitted edits. This is probably going to be the hardest thing to find, but I’d like a really easy way for readers to let me know of typos and such by simply submitting a fix for them. The author or editor of the post would have to approve the edits, obviously.
  • Import from WordPress. I don’t have a ton of content in WordPress, or else this would probably be a more firm requirement.
  • Community. Community helps software thrive, adding improvements and ensuring security.
  • Plugins. It would be nice for the blog engine to be extensible.
  • Unpublished drafts and previews. I’d really like to be able to see by blog posts before I release them to the world.
  • CMS abilities. I’d really like the ability to edit non-blog web pages the same way as blog entries.
  • Themes. It would be nice to have decently looking themes, so I could have other people help me make the site look nice.
  • Posting my tweets in a sidebar area. I’d be OK with this being done in client-side JavaScript. I’d also be OK with periodic polling of my Twitter feed, and updating the static content when appropriate.

Candidates

I’ve been playing with Jekyll lately, using it to generate a simple static site that can be updated easily. It’s pretty nice, and pretty easy to use. Something based on Jekyll would work well. The trickiest part will be figuring out how to manage comments. Or maybe I’ll just have to learn to live more minimally.

Octopress is the obvious candidate. It fits most of my needs and wants. Most likely I’ll write my own commenting engine and add it to my Octopress template.

The only other candidate that I’ve found is Ghost. It’s written in JavaScript and runs on Node. I don’t find Node to be that compelling, but the templates look great, and it’s designed for coding blogs.

I’ll probably take a quick look at Droplets, too. It’s written in PHP, but seems to fit my other requirements.

Unfortunately, that seems to be all there is in this space. Maybe I need to investigate more. Or maybe Octopress just has the static blog generation marked cornered. Either way, I’ll probably change my blogging software in the next month or two. Wish me luck!

 

Testing Rails Validators

It’s challenging to test Rails custom validators.

I recently had to write a validator to require that an entered date is before or after a specified date.

It didn’t seem like writing the validator would be too difficult – I’ve written custom validators before, and date comparisons aren’t all that tricky. But when it came time to write the tests, I ran into several issues. And since I always try to follow TDD / test-first, I was blocked before I even began.

The biggest issue was the ActiveModel::EachValidator#validates_each API. It’s definitely not a well-designed API. You write your validator as a subclass, overriding validates_each. The method takes a model object, the name of the attribute of the model being tested, and the value of that attribute. You can also get the options passed to the custom validator via the options method. To perform a validation, you have to update the model’s errors hash.

The big flaw in the API is that instead of returning a result, you have to update the model. This needlessly couples the model and the validator. And it violates the Single Responsibility Principle — it has to determine validity of the field, and it has to update the errors hash of the model. This is not conducive to testing. Testing this method requires testing that the side-effect has taken place in the collaborator (model), which means it’s not really a unit test any more.

So to make it easier to unit test the validator, I broke the coupling by breaking it into 2 pieces, one for each responsibility. I moved the responsibility for determining validity to a separate method, which I called errors_for. It returns a hash of the errors found. This simplified the validates_each method to simply take the result of errors_for and update the errors hash of the model:

def validate_each(record, attribute_name, attribute_value)
  record.errors[attribute_name].concat(errors_for(attribute_value, options))
end

This made it much easier to unit test the errors_for method. This method doesn’t even need to know about the model — only about the value of the attribute we’re trying to validate. We simply pass in the attribute’s value and the options.

So we could write the tests without even pulling in ActiveRecord or any models:

describe DateValidator do
  let(:validator) { DateValidator.new(attributes: :attribute_name) }
  let(:errors) { validator.errors_for(attribute_value, validation_options) }

  describe 'when attribute value is NOT a valid date' do
    let(:attribute_value) { 'not a valid date' }
    it { errors.must_include 'is not a valid date' }
  end

  describe 'when attribute value IS a valid date' do
    let(:attribute_value) { Date.parse('2013-12-11') }
    it { errors.must_be :empty? }
  end
end

And the errors_for method looked something like this:

def errors_for(attribute_value, options)
  unless attribute_value.is_a?(Date)
    return [options.fetch(:message, "is not a valid date")]
  end
  []
end

Integration testing can also be a bit of a challenge. I recommend following the example from this Stack Overflow answer. Basically, create a minimal model object that contains the field and the validation. Then test that the model behaves like you expect with different values and validations.

Introspective

Today I was informed that I’ve been impeding progress on our team.
This was somewhat shocking, since I feel like I’m always pushing
forward to make our team and myself better.

Like most anyone, my initial reaction to criticism was defensiveness.
I don’t handle criticism well. (You might find that hard to believe,
after reading the rest of this post. Maybe it’s just the confrontation
part I don’t handle well.) Thankfully the blow was softened somewhat,
because the person providing the criticism didn’t tell me directly —
they told Amos, a trusted colleague of mine. Amos then passed it on to
me. I’m grateful for that — this is the best way for me to have received
that criticism.

What I did next is the astonishing thing. I swallowed my pride for a
minute. Not an easy thing for me to do, for all the usual reasons, and
more. I decided to address the problem head on. If someone was telling
someone else that I was causing some sort of a problem, then even that
perception was a problem that I needed to address. So I decided to hold
a retrospective for myself. Retrospectives are the way Agile teams address
problems and improve how they work. If it would work for a team, I figured
it should work for an individual.

I’d held retrospectives by myself before. Before I even knew about
retrospectives, I’d taken some time to assess how I had done things
on a couple of projects I had worked on as an independent contractor. But
those were about technical decisions I had made and processes I had
followed. This one would be different. This one was about a personal
shortcoming, an action of mine that had caused some harm. This one
involved feelings and emotions.

So I asked Amos to facilitate my one-person retro. We’d both done a lot
of retrospectives, but neither one of us had done anything like this before.
We had a bit of trouble getting started. We didn’t have any details
about why the anonymous person felt the way he felt. So it was hard
to address something that nebulous. So I asked Amos if he could follow
up with the person. Luckily, the person was online and able to respond
in real time.

So we talked things through some. We went on some tangents. We made some
progress — things that I could write down as take-aways and action items.
We got off-topic again, and then came back to it. Then Amos decided to
play The Why Game. This worked amazingly well. It helped me to find the
root reasons why I was holding back change. Basically I’m afraid of
failure. Going deeper, we looked into why I’m afraid of failure. This
line of inquiry was particularly effective. Hopefully it’ll be enough for
me to stop being an impediment to change. Here are my notes / take-aways:

  • Be careful playing devil’s advocate in public.
    • People will think I’m taking that stance.
  • Don’t always take the boss’s side in public.
  • Don’t be the person to allow the team to take the easy path.
  • Why do I think that managers won’t let us try a 2nd time?
  • Why do I think we might fail the first time?
    • I want to put us in a better position to succeed.
  • I’m being too conservative.
  • Be willing to fail. Don’t fail to try.
  • Don’t say we shouldn’t try because I think other people don’t want to try.
    • That is just self-perpetuating.
  • I’m afraid of failing because I haven’t done it much.
    • Because I’m good at learning from other people’s failures.
    • But this is holding me back and making me cautious.
      • Despite the fact that I try to not be cautious.
    • So I need to work to counter-act those fears.

At first, I thought that I’d never heard of anyone doing anything like
this. But then I recalled that I’d heard about somewhere that everyone
does this, with their whole team. That would be hard. I’d have to
trust everyone in the room.

But I would recommend this for anyone that can pull it off. It’s hard,
but it has a large payoff. Just like a team retrospective, it feels good
making this kind of breakthrough, and knowing that just spending that
little amount of time has made me a better person. (Mine took about an hour.)
I think the hardest part is finding someone (or a group of people) you
trust to be your facilitator.

I’ve decided to call this thing an introspective. A retrospective is
about looking back. This is about looking inward. I’d be interested to
find out who is doing this kind of thing. Does it have a commonly accepted
name? How does it work? What techniques work best? If you’ve got any answers or ideas, please comment below, or tweet me @CraigBuchek.

So thank you to that anonymous person. Your way of addressing this was
probably more effective than you could have imagined that it might be.
I hope that this exercise will help me make the changes required, to make
me a better person, and help the team become the best that we can be.

Amos has written up his thoughts on the introspective.

What’s Your Open Source Resolution?

I’ve been using GNU/Linux since 1994, starting with a Slackware 2.2 CD-ROM I ordered from the back of a magazine. I’ve been heavily involved in my local GNU/Linux community since 1999, and I give frequent presentations at various groups. I’ve made some small contributions to several Open Source projects.

But I don’t feel like I’ve done enough to contribute to the wider community. So this year, I’m going to resolve to step up my contributions, and do more.

Change my role in the LUG

I was lucky enough this past year to find someone interested in helping to run the St. Louis GNU/Linux Users Group (STLLUG). I’ve been running the group so long that I’ve somewhat stagnated. It’s great to find someone who will bring a fresh energy and new ideas. Thanks, Andrew!

Mostly freed from the more general administrative tasks (mostly planning meeting topics and speakers), I’m hoping to find the time to work on a few projects. First, I want to overhaul the web site. It needs a new look, as well as an easier way to update it. I’m planning to implement some sort of CMS — possibly WordPress or Octopress, or at the very least, a git repo to manage updates.

Blog regularly

I installed WordPress a long time ago, but I haven’t published many posts. I’ve got a few drafts in various stages. So this year I’m going to actually get the blog going, and hopefully post about once a week. I’ll be sharing things I learn on the Internet, as well as some of the things I learn from my experiences with various technologies and techniques.

Contribute more significant patches

There are a few items I’ve been meaning to work on and contribute. I’d like to finally get around to them:

  • Make the GNU sort command be able to (easily) sort a list of IP addresses, or semantic version numbers.
  • Add MySQL-style commands to PostgreSQL: SHOW DATABASES; SHOW TABLES; DESCRIBE table. (I’m not sure how welcome these additions might be, but I think they’d make transitioning from MySQL easier for people.)

Publish and maintain several Ruby gems

I’ve been working on a few Ruby gems. I’d like to get them to a state where they’re useful to more people. These include:

  • A way to simplify standard CRUD controller actions
  • A way to declare list views in a manner similar to SimpleForm or Formtastic
  • A way to declare ActiveRecord attributes in models using Virtus
  • A higher-level interface to ROM (Ruby Object Mapper)
  • A similar high-level way to define Perpetuity attributes in models using Virtus
  • My Rails template, making it much easier to start a Rails app

Build some apps

I enjoyed building a quick Rails app during last year’s Rails Rumble, even if it doesn’t turn out to be useful or make any money. I’d like to create a few small apps again this year, either in Rails or Apache Cordova. I’ve got some ideas — we’ll see how if they turn into anything useful or worth selling.

Podcast more often

Last year, I started joining the This Agile Life podcast. I enjoy it. I’m hoping to continue with that, and possibly doing some podcasting about Ruby and Rails.

Present at a conference

I’m going to attempt to give a presentation at a conference. I often give presentations at local groups, but haven’t addressed a larger audience. I’ve got a few ideas rattling around, and will see if I can turn them into presentations worthy of a larger conference.

What’s your Open Source resolution?

My Thoughts on Python vs. Ruby

I’ve been using Python at work for the past few months.  I learned Python back in the early 2000s, but never used it for any large projects.  I learned Ruby in late 2005, and it quickly became my language of choice for most cases.

So while I still prefer Ruby, and will likely use Ruby more in the future than Python, I wanted to assess the strengths and weaknesses of Python in relation to Ruby.  Perhaps some of the lessons could be applied when writing Ruby, and it could help to decide when to use each.  Also, I’m interested in programming language design, and wanted to document pros and cons in that light.

Where Python Sucks (As Compared to Ruby)

  • Have to explicitly include self in EVERY method declaration.
    • Including @classmethod declarations (although people usually use the name cls instead of self there).
    • Except @staticmethod declarations.
  • Have to use self everywhere to reference an object’s own attributes.
  • Inconsistency of things like the len() function, when everything else is a method.
  • Inconsistency of having some built-in classes with lower-case names.
    • And they’re not whole words, so you have to memorize them: list, dict, str, int.
    • Even more bizarre is dict vs. OrderedDict.
  • I’m not a fan of True and False being uppercase.
    • I’m a bit less concerned about None, for some reason.
    • If they’re going to be uppercase, they might as well be all caps, in my opinion.
  • Inconsistency of camelCase versus snake_case in some modules.
  • Claims to prefer explicit over implicit, yet does not use new to create an object.
    • It is nicely concise, but makes it look too much like a regular function call.
  • The implementation of lambdas is too limited.
    • Makes using map function not very useful.
  • Class methods are less than ideal to implement.
    • Probably better to use functions within a module instead, in many cases.
  • Lack of good functional programming tools makes it harder to manipulate lists.
    • Have to often resort to creating an initial list and adding to it in a for loop.
  • I don’t understand why r’regex_string’ doesn’t just create an actual regular expression object.
  • I miss Ruby’s method-call-or-property-getter syntax.
    • Nice that I can get it by adding @property to method definitions, but that’s a bit messy.
  • I don’t understand why lists don’t have a join() method; it seems backwards to call join on the string used to connect the list elements.
  • I miss unless; seems like with all the keywords, Python would have added that.
  • I really miss ||= to memoize.
    • The distinction between unset variables and variables set to None makes it hard.
    • I also miss +=.
  • I really miss statement modifiers (if or unless at the end of the statement/expression instead of the beginning).
  • I miss being able to assign to a compound statement (x = if True: 1; else: 2).
    • While Python does allow this simple case, it does not allow more complex cases.
  • The way modules, files, and classes work, I either have a lot of classes in one file, or have to come up with more module names in order to split classes into different files.
  • The preference for bare functions within modules over class methods often leads to functions outside of classes, when they’d make more sense more closely associated with the class.
  • I don’t quite understand the necessity for pass.
    • Seems like allowing 0 lines of indented code would suffice instead.
  • I miss implicit return.
    • Explicit return looks a bit nicer, but is less concise, and I’ve gotten out of the habit.
  • Mixins turn out to be more useful than multiple inheritance.
  • I miss string interpolation.
  • I really miss Array#first and Array#last.
  • I really don’t like that 0 is falsey.
    • I could live with empty lists and dicts being false, but not 0.0 and 0.
  • Comparing a string to a regular expression seems harder than it should be.
  • Converting to a Boolean is not as easy a Ruby’s !! syntax.
    • OK, bool(expression) isn’t so bad, I guess.

Where Python Rocks

  • Indentation removes the need for end everywhere.
  • Import statements are nice.
    • Can import everything, or just a few things.
  • Annotations are nice for aspect-oriented modification of methods.
    • Does it make it hard to debug though, like alias_method_chain in Ruby?
    • It’s kind of tricky to write them though, due to doubly-nested function definitions.
  • List comprehensions are more powerful than map.
    • But map can be more concise for the most common cases.
  • Can add arbitrary attributes to any object, class, or module.
  • The object creation syntax is nicely concise.
  • Sometimes the ability to add a bare function within a module is nice.
  • Keyword arguments are nicely done.
    • Ruby’s emulation via hashes without braces is OK, but the corner cases are problematic.
  • Docstrings as part of the language is nice.
  • The new with keyword looks like a halfway-decent replacement for blocks.
    • Seems like a lot more work that using blocks and yield though.
  • Python 3 drops support for octal literals starting with a 0.
    • Still allows it via a 0o prefix.
  • No support for all the crazy Perl-inspired globals.
  • The names list and dictionary are better than array and hash.
    • The Ruby names are more about the implementation, especially hash.
    • I’d much prefer the name map over hash, or even dictionary.
    • The name list is only slightly better than array.
  • List and string slicing is quite nice.
    • I do wish that the syntax was “..” instead of “:” though.
    • Slice assignment is even cooler.
  • I prefer the Python dict syntax over the Ruby hash syntax (“:” vs. “=>”).
    • The Ruby 1.9 symbol hash syntax is an improvement, but not quite as good.
  • Checking for string containment is nice: if substring in string.

Where Ruby Rocks

  • Consistency.
  • Blocks.
  • Excellent functional tools to deal with Enumerable.
  • Meta-programming.
  • Optional parentheses.
  • Modules and classes are also objects.

 

Debugging Pattern – Grenade

I’ve been more interested in programming patterns lately, partly due to the Ruby community’s recent interest — especially the Ruby Rogue podcast’s love affair with “Smalltalk Best Practice Patterns”.

I consider most of the patterns in “Smalltalk Best Practice Patterns” to be patterns “in the small” — things that are typically employed on a single line or method. The Gang Of Four patterns are more medium sized, dealing with methods and classes. The PEAA book covers architectural-scale patterns. I suppose “The Pragmatic Programmer” and similar books could (should!) be considered to be very general patterns, mostly about the practice of programming.

One type of pattern that I have not seen discussed much is debugging patterns. I’m not exactly sure why that is; probably just our general concentration on designing the program code itself. There are definitely testing patterns. But I can’t think of anything that I’ve seen that covers debugging patterns. A quick search on the Internet doesn’t turn up too much.

Anyway, a co-worker (Helena) and I were debugging recently, and were having trouble figuring out where a certain method on a certain object was being called. We came up with a really cool solution. We immediately called it a grenade, because its entire purpose is to blow up (raise an exception) and display a backtrace to show us the caller of the method that we’re looking for.

Here’s our implementation in Ruby:


module Grenade
  def method_under_investigation(*)
    raise "method_under_investigation called"
  end
end

class Xyz
  ...
  def xyz
    object_under_investigation.extend(Grenade)
  end
  ...
end

I’m sure we could wrap that in some more semantic sugar, even going as far as making it look something like this:


class Xyz
  ...
  def xyz
    object_under_investigation.blow_up_when_method_called(:method_under_investigation)
  end
  ...
end

I’m not sure that would really be worth it though, unless we were to add it to some sort of library.

So that’s our contribution to the (small) list of debugging patterns.

Write Comments For Yourself

Amos and I got in a heated discussion recently on whether we should write a single line comment to better explain some code. (The code in question was Amos’s very elegant solution to testing whether a job got sent to Resque.)

Amos doesn’t believe in writing comments much at all. He thinks that if you’re writing a comment, it means that you’re doing something wrong, and that you probably need to write the code more clearly.

I agree with that, to a point. First off, it’s not necessary to write perfect code. If you can change a class or method name to better describe what you’re doing (and more importantly, why you’re doing it) then you should definitely do so. But it’s not always worth refactoring until you get every “why” answered. More importantly, I don’t think it’s even possible to capture everything in the code that is worth capturing. For example, why did you choose this implementation, as opposed to another that might be more obvious or common?

After our argument, I came up with a good rule of thumb (or “pattern”):

Write comments for your (future) self.1

In other words, if your comment will help you to understand the code more quickly when you look at it in the future, then it’s a valid comment. It also means that you can assume that the reader has about as much general programming knowledge as you currently do. (Your future self will have more general knowledge, but possibly less specific knowledge of the lines of code in question. And because of this, your current solution might not make as much sense in the future. You might know of a better solution in the future, but you’ll have to know all the constraints that you had when you originally wrote the code.)

This is not to say that you should not write comments in clear English, that others can understand. The comment is written for a future maintainer. That may be you (which is why the rule works well), or it may be someone else. The rule is more about when to write a comment, and what level of competence you should assume of the reader.

1 Perhaps it should be “Write comments TO your (future) self”.

Bulk Rename in Bash

Here’s a relatively simple way to rename a bunch of files from the command line. It uses sed within a command substitution to compute the new names from the old names.

In this example, we’re renaming files that start with “ABC” to start with “XYZ” instead:

  for i in ABC*; do mv $i $(echo $i | sed -e s/^ABC/XYZ/); done

You’ll have to use shell globbing (wildcards) in the first part, to determine which files will be the source of the renaming, and regular expressions in the second part to translate the old names into the new names.

It’s a good idea to use echo in place of mv before running this, to see what the results will be, so you don’t make a mistake.

Depending on the situation, you may need to adapt this for your particular needs. For example, if you have too many files to rename, you would need to use xargs. Or sed might not be up for the task of transforming the names that you want. Or you might need to use find to find files within a hierarchy. As with any UNIX idiom, there are hundreds of variations on the theme.