Naming - The hardest problem of Software Development

I have been coding for a Rails project for several years (3~4 years maybe?)
And I still have no idea what is a “good”/suitable set of rules for naming classes (including namespace).

I got several types of classes:

  • Active Record Models
  • Non Active Record Models
  • Controller
  • Operations (something like service object, no gem used)
  • Cells (using gem cells, view component related)
  • Mailers
  • Background workers (currently using gem sidekiq)

How do you guys name your classes?
I would love to hear :smile:

2 Likes

I tend to use descriptive but-as-succinct-as-possible names :slight_smile:

Such as UrlChecker and ProfileRipper (two of my own classes in one of my Rails app).

The models are always easy to name I think, because their names should reflect the actually model, right? So if you are modelling a client, you name the model Client.

The controllers are sorta the same way, you name them from way models they control. I know that sometimes you want to control two thinks in one controller, and then the naming gets weird, but you could have a ClientRelationsController then.

The service objects in my projects all have Service at the end. If it’s a service object with does something with/for clients, it’s name would be ClientService.

1 Like

I basically follow what @Ohm has said. For me method naming is more of an issue when you have to consider potential conflicts. Like writing a library that adds additional methods onto ActiveRecord objects. Lots of libraries do this, so a common name may conflict. For my gem PolyBelongsTo I put pbt_ in front of each method name to “namespace them”. There are only two methods I didn’t do this for :poly? and :orphan?. I figured those would be relatively safe to take ownership of.

The popular library acts_as_messageable has a method naming conflict for a method named :search for which I’ve made a patch. I admit it’s not a wise implementation… I should have hard-coded an alternate.

As far as Class and Module names go it’s mostly Thing or ThingCategory-purpose.

2 Likes

I also just want to mention the joke about hard computer sciece problems, because I think it’s funny:

The two hardest things in computer science:

  • Naming things
  • Cache invalidations
  • Off-by-one errors

:wink:

4 Likes

I wanted to tell you a UDP joke, but I’m afraid you wouldn’t get it.

2 Likes

If I have a group of similar objects, such as @Ohm’s services, I’ll group them via a name space. So rather than

OneService, TwoService, ThreeService

I’ll use:

Service::One, Service::Two, Service::Three

The main advantage I find with that approach is that it simplifies the class and module names within that name space. For example, I might us a Base class to define methods that all the services use, or have modules that are shared between some of the related classes.

So rather than:

class FooService < BaseService   
  extends BarService
end

I’ll have

module Service
  class Foo < Base
    extends Bar
  end
end
1 Like

I really don’t like the idea of name spacing methods. It takes me back to the bad old days when people would make SQL field names up from app prefix + name + field type suffix. Like myapp_first_name_str.

1 Like

I’m inclined to agree with you. I’m treating the methods like second class citizens and that’s not good. At the time I just wanted to guarantee no conflicts in an overcrowded method environment. I was hoping I could graduate the methods to first class citizens and remove the namespace… but this will be a breaking change and needs to be done only in a major version release.

I’m considering when I do make that big change to have a method available :use_old_method_names which will use Forwardable with all the old method names.

1 Like

Could you attach an object to a model instance, that knew the properties of the instance it was attached to.

Something like:

class MyPolyBelongsTo
   attr_reader :model

  def initialize(model)
    @model = model
  end

  def belongs_to_multiple
    .... some code that gets the information from model ....
  end
end

Then add an instance method to ActiveRecord::Base that loads and returns that object.

def pbt
  @pbt ||= MyPolyBelongsTo.new(self)
end

You’d them be able to:

model.pbt.belongs_to_multiple

That way the only method you need to worry about clashing is pbt. And users would be able to add the methods to the model easily via delegate:

delegate :belongs_to_multiple, to: :pbt

In fact, if you make the names consistent with the existing ones, you may be able to get backward compatibility by adding something like:

delegate *MyPolyBelongsTo.public_instance_methods, to: :pbt, prefix: true
2 Likes

For active record models I name them like City::Record
Since:

  • They are really records of something, not something itself
  • I can make City a module now, no need to specify City < ActiveRecord::Base in other nested module files

I even wanted to name them like App::City::Record,
but I gave up that idea since that might be too long :sweat_smile:

1 Like