I think we’d do well to explain concerns better. I’ve been writing code with mixins for so long that I’ve taken it completely for granted that this is a wonderful way to structure separate domain concerns.
But I also agree that concerns do not warrant a generator. A lot of concerns are simply Ruby modules that are mixed in, with no additional stuff added. And then for a few cases, like when your concern includes both class and instance methods, or you want to call class methods on mixin, you can use extend ActiveSupport::Concern.
I’d also just put my two cents here that I’m actually not that big a fan of Concerning. That is adding inline concerns in a class. We don’t use that at Basecamp any more. It was an approach introduced by @bitsweat, so I’ll let him speak to what he thinks about it.
But I went over the way we use concerns at Basecamp at length in that video that was linked above. Here’s another example from HEY:
class Identity < ApplicationRecord
include Accessor, Authenticable, Boxes, ClearancePreapproval, Clipper, Creator, Eventable,
Examiner, Filer, Member, PasswordReset, Poster, Reaching, Regional, TopicMerger
end
module Identity::Accessor
def accessible_topics
Topic.joins(:accesses).where(accesses: { contact: contacts })
end
def accessible_entries
Entry.joins(:topic).merge(accessible_topics)
end
end
As you can see, we often put as little as 1-2 methods into a concern that encapsulates that specific concern. The way you reach accessible objects. These objects absolutely could just have been declared in Identity, but add all those concerns up we have in Identity, and you’ll see that Identity would be a big basket of dozens of methods. Sure, all these methods are about Identity, but there’s a grouping below that. That’s what concerns are: A way to group related methods together, while still living under a single class.
You can think of it like this: The class is an H1, the concern is a H2, the public method is an H3, and private methods could play H4/p. It’s a way to structure a large argument. Sit down, and lemme tell you about the Identity class! Let’s start by talking about how the Identity acts as an Accessor, and you should reach what that identity can see as an accessor through the accessible_* methods declared in the Accessor role.
It’s structured writing.