soliciting advice about organizing classes/modules

14 views
Skip to first unread message

Bill Kayser

unread,
Feb 6, 2012, 7:16:19 PM2/6/12
to pdx...@googlegroups.com

I would like to know what people's opinions are about best practices with respect to breaking up Ruby classes into different concerns. In particular as classes get larger it might make sense to separate out modules for different related behavior. Rails uses a an idiom where all files go into a single subdirectory/module that names the concern (ie, ActiveRecord) and the file called base.rb is reserved for the concrete base class named *::Base.

I've been told that creating a class in the top level namespace and using that class name to scope the different modules included by the class is a bad idea (I would like to know why). So that would be where you would have a class called ActiveRecord defined in active_record.rb, and a folder named active_record in the same directory.

Related to that is the question of how you would scope subclasses. Would you put the parent class and all subclasses into a single module?

Are there naming conventions for the names of the modules, abstract classes, their subclasses?

Bill

Sam Livingston-Gray

unread,
Feb 6, 2012, 7:39:43 PM2/6/12
to pdx...@googlegroups.com
I can spare a few minutes for this while I wait for a test run... (=

On the topic of Base classes, please see: https://github.com/garybernhardt/base

I also posted a mini-rant to another group recently about the use of
modules as mixins:
http://groups.google.com/group/objects-on-rails/browse_thread/thread/109b7fb8e9c13d91

I tend to start out with classes and modules nested inside one
another, and then split them out into their own files as they get
larger. For things I'm using in Rails, I also always put a file in
the path where Rails' const_missing autoload will look for it, even if
it's just a stub file with a one-line module definition.

For an example, here's a proof-of-concept library I wrote today:
https://github.com/geeksam/cordon

Hope this helps,
-Sam

> --
> You received this message because you are subscribed to the Google Groups "pdxruby" group.
> To post to this group, send email to pdx...@googlegroups.com.
> To unsubscribe from this group, send email to pdxruby+u...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/pdxruby?hl=en.
>

John Wilger

unread,
Feb 6, 2012, 7:40:23 PM2/6/12
to pdx...@googlegroups.com
On Mon, Feb 6, 2012 at 4:16 PM, Bill Kayser <penn...@gmail.com> wrote:
>
> I would like to know what people's opinions are about best practices with respect to breaking up Ruby classes into different concerns.  In particular as classes get larger it might make sense to separate out modules for different related behavior.  Rails uses a an idiom where all files go into a single subdirectory/module that names the concern (ie, ActiveRecord) and the file called base.rb is reserved for the concrete base class named *::Base.

If you have a class named `*::Base`, you are DOING IT WRONG. And yes,
Rails does this wrong. A lot. No, my `Person` is not an
`ActiveRecord::Base`, it's an `ActiveRecord`. Well, it's not even
that, really.

If we cared about OO principles, Person might have a #person_record
attribute that is a `PersonRecord`, which is a subclass of
`ActiveRecord`. Whether that's actually a `Person::PersonRecord` or a
`MyDogFluffy::PersonRecord` is probably less important than properly
using composition (although I'd avoid ActiveRecord::PersonRecord,
since you don't "own" that namespace.)

>
> I've been told that creating a class in the top level namespace and using that class name to scope the different modules included by the class is a bad idea (I would like to know why).  So that would be where you would have a class called ActiveRecord defined in active_record.rb, and a folder named active_record in the same directory.

I'm not sure why that's a bad idea. I do that and have never found it
to be a problem.

> Related to that is the question of how you would scope subclasses.  Would you put the parent class and all subclasses into a single module?

That depends entirely on context, and I don't think a single guideline
can be useful here.

--
Regards,
John Wilger

johnw...@gmail.com
971-678-0999

Tyler Hunt

unread,
Feb 6, 2012, 7:40:27 PM2/6/12
to pdx...@googlegroups.com
On Feb 6, 2012, at 4:16 PM, Bill Kayser wrote:

> I would like to know what people's opinions are about best practices with respect to breaking up Ruby classes into different concerns. In particular as classes get larger it might make sense to separate out modules for different related behavior. Rails uses a an idiom where all files go into a single subdirectory/module that names the concern (ie, ActiveRecord) and the file called base.rb is reserved for the concrete base class named *::Base.

I think the general consensus is that the "Base" naming convention is a bad idea, and that a more descriptive name should be used, like ActiveRecord::Model in your example.

> I've been told that creating a class in the top level namespace and using that class name to scope the different modules included by the class is a bad idea (I would like to know why). So that would be where you would have a class called ActiveRecord defined in active_record.rb, and a folder named active_record in the same directory.

I've never heard that described as a bad idea, and this is the way most decent Ruby Gems organize their code. The files you put at the top level are especially important when it comes to Gems, since the lib directory in the Gem is added to the load path. This means you generally have lib/gem_name.rb as the only file in the Gem's lib directory, and the rest of your code would go under the lib/gem_name directory and be namespaced inside the GemName module.

> Related to that is the question of how you would scope subclasses. Would you put the parent class and all subclasses into a single module?

Most of the common cases I can think of use a module at the top level, and nest classes and other modules under it, but there's nothing from stopping you from defining additional classes or modules inside a class. I've found myself doing this lately even in Rails apps for adding extra functionality related to my AR models, like this:

app/models/product.rb
app/models/product/sync.rb

Here, Product and Product::Sync are both classes, with Product::Sync just defining the logic for synchronizing products.

I've seen people split up their models into multiple modules, and then include those modules into the AR class, but if you aren't careful this can be very confusing to other people trying to work on your app because you end up with modules defined outside where you would expect to find the code. The rule I try to stick to is to not extract a module until there's a clear case where that module can be used by more than one class.

Recently, I've begun to create a directory under lib inside of my Rails apps to keep additional shared code for the app. I name it after the same name as the module Rails uses to encapsulate the Application class it defines in config/application.rb. If your generated app directory is called my_app, this module would be called MyApp, so I would create the directory lib/my_app, and namespace everything under it inside the MyApp module.

I then add the lib directory to the autoload paths in config/application.rb like so:

config.autoload_paths << config.root.join('lib')

I find this especially useful for things like app-wide form builder customizations. It lets me use MyApp::FormBuilder instead of cluttering up the root namespace with a FormBuilder constant. It also centralizes all of this additional functionality in a single place, and the module prefix makes it relative easy to find where the code is defined. I'd love to see something like this become a standard part of the generated Rails app. I finally broke down and started working on my own app generator (http://github.com/tylerhunt/hightail) to handle this and some other conventions I tend to use in my apps.

> Are there naming conventions for the names of the modules, abstract classes, their subclasses?

The only one that comes to mind is Base, but, as I mentioned, I'd try to avoid that one. I just try to pick names that are short, descriptive, and stick to a single word when possible.

Hopefully this is helpful,

Tyler

Steve Jorgensen

unread,
Feb 7, 2012, 2:48:34 AM2/7/12
to pdx...@googlegroups.com
On 02/06/2012 04:40 PM, Tyler Hunt wrote:

<snip>

Recently, I've begun to create a directory under lib inside of my Rails apps to keep additional shared code for the app. I name it after the same name as the module Rails uses to encapsulate the Application class it defines in config/application.rb. If your generated app directory is called my_app, this module would be called MyApp, so I would create the directory lib/my_app, and namespace everything under it inside the MyApp module.

I then add the lib directory to the autoload paths in config/application.rb like so:

	config.autoload_paths << config.root.join('lib')

Be careful with that. If any modules in 'lib' are configured in Rails initializers, then re-loading those modules will effectively discard the configuration when running in development mode. This can be very frustrating and hard to diagnose. Consider adding 'lib' to config.autoload_once_paths instead of config.autoload_paths .

-- Steve J.

Sidu Ponnappa

unread,
Feb 8, 2012, 7:30:48 AM2/8/12
to pdx...@googlegroups.com
Bill,

It seems like you're conflating two distinct problems - namespacing
your code and refactoring your classes to maintain the Single
Responsibility Principle as they grow.

First, namespacing - this is one glaring problem in Ruby. There's no
clean way to namespace your code that I've come across. What does
exist is a weird, hacky solution that piggybacks off the existence of
Modules, which have nothing to do with namespacing. I don't have any
good answers here, except to agree with John Wilger that I see nothing
wrong with using a class as namespace (after all, in Ruby a class is a
module). It's no worse than using a module, and has exactly the same
disadvantages. I've done this myself across multiple Ruby codebases
that are now several years old and never really seen any problem.

> Rails uses a an idiom where

Generally, Rails is not a great guide to how things should be done
from an OO perspective though this has improved considerably since 3.0
and up. It's often hard to judge what bits are now a good template to
follow, and which bits are Bad Ideas. I'd recommend looking at smaller
codebases written/maintained by folks like wycats and dchelimsky for
style guidelines rather than look at Rails.

> In particular as classes get larger it might make sense to separate out modules for different related behavior.

My two rules of thumb for creating a module is that the module should
have a clear contract in terms of methods it depends on (for example,
Enumerable depends on the existence of 'each' ) and should never, ever
depend on or use the instance variable of a class it interacts with.
Usually, this only happens when I'm writing generic library code where
I don't know exactly how it might be used. In app code, pretty much
all my refactoring of classes results in more classes. That said,
YMMV.

Best,
Sidu Ponnappa.

http://c42.in
http://rubymonk.com
http://twitter.com/ponnappa

Bill Kayser

unread,
Feb 9, 2012, 10:32:34 PM2/9/12
to pdx...@googlegroups.com
Thanks to everyone who took the time to respond! I learned a lot.

Bill

On Feb 6, 2012, at 4:16 PM, Bill Kayser wrote:

Reply all
Reply to author
Forward
0 new messages