Method name collisions become a big problem when you rely too much on modules

Jamis at 37 Signals has up a strange post in which he is critical of modules. I say “strange” because his tone is defensive and he interrupts his post to repeatedly to insist that modules are really great:

The code remains really clean, overall, because we’ve continued to follow the pattern of moving related methods into modules, and just including those modules in the base model.

Got that? Refactoring code out of your main classes and into modules is  a great way to keep your code clean. He emphasizes:

Don’t misunderstand me, though. Modules are awesome. We use them a bunch, and love them.

and then:

Modules are very handy, and as I said before, we still use them extensively.

He seems worried that someone is going to criticize him because of his criticism of modules. Yet his criticism is almost the same as Michele Simionato wrote in last month’s explicitly anti-module post.

Jamis writes:

However, there are two issues with this approach. First, when a class includes lots of modules (as some of ours do), it becomes hard to keep track of where different methods are defined, and even which methods are defined. This can lead to confusion when trying to find the definition of a method, and (worst case) can allow two or more methods with the same name, which is bad. There is no warning if you have methods with the same name in multiple modules, so it isn’t hard to wind up with bugs where you’ve clobbered a method with another. You wind up double-namespacing your methods (e.g., method names in the Avatar module being prefixed with avatar_), to avoid collisions.

…There are more issues with the module approach. What if you have different kinds of avatars (e.g., person versus group, or company)? You can’t subclass modules in Ruby, so you wind up finding other ways to solve it (like including modules in modules, etc.). Also, you can’t reference the avatar as a separate entity; instead, controllers that deal with avatars need to deal with the entity to which the avatar is attached.

And what solution does he offer for these problems? I was thinking he was going to say something really original, because it sounded like he was really wedded to the idea of using modules. But in the end, his solution is to simply not use modules:

Can the avatar code be split out further, somehow? Yes, it can. We’ll do this by making avatars a model of their own and using aggregation (rather than module inclusion, or inheritance) to pull it into Person.

So the solution is simple: don’t use modules, use independent classes and then build your objects through composition. This is probably very good advice, though I was a little surprised by his conclusions, given that he started off sounding like a big fan of modules.

Leave a Reply