{"id":13880304,"url":"https://github.com/basecamp/concerning","last_synced_at":"2025-07-16T16:31:31.347Z","repository":{"id":9295431,"uuid":"11131664","full_name":"basecamp/concerning","owner":"basecamp","description":"Bite-sized separation of concerns","archived":true,"fork":false,"pushed_at":"2023-03-16T01:18:02.000Z","size":18,"stargazers_count":202,"open_issues_count":2,"forks_count":5,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-07-10T16:09:30.590Z","etag":null,"topics":["ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/basecamp.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"MIT-LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-07-02T18:17:27.000Z","updated_at":"2025-05-31T03:13:21.000Z","dependencies_parsed_at":"2024-06-19T22:51:29.535Z","dependency_job_id":"4ae171a1-11ef-4d97-925e-534a1763129d","html_url":"https://github.com/basecamp/concerning","commit_stats":{"total_commits":13,"total_committers":2,"mean_commits":6.5,"dds":0.07692307692307687,"last_synced_commit":"0173f835884963449c19b35af53aa345fa10c313"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/basecamp/concerning","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basecamp%2Fconcerning","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basecamp%2Fconcerning/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basecamp%2Fconcerning/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basecamp%2Fconcerning/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/basecamp","download_url":"https://codeload.github.com/basecamp/concerning/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/basecamp%2Fconcerning/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265524632,"owners_count":23782016,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ruby"],"created_at":"2024-08-06T08:02:55.903Z","updated_at":"2025-07-16T16:31:31.020Z","avatar_url":"https://github.com/basecamp.png","language":"Ruby","readme":"## Bite-sized separation of concerns\n\n(*Note!* Module#concerning is included in Rails 4.1. You can still use this\nlibrary, but it will defer to Active Support's implementation if available.)\n\nWe often find ourselves with a medium-sized chunk of behavior that we'd\nlike to extract, but only mix in to a single class.\n\nExtracting a plain old Ruby object to encapsulate it and collaborate or\ndelegate to the original object is often a good choice, but when there's\nno additional state to encapsulate or we're making DSL-style declarations\nabout the parent class, introducing new collaborators can obfuscate rather\nthan simplify.\n\nThe typical route is to just dump everything in a monolithic class, perhaps\nwith a comment, as a least-bad alternative. Using modules in separate files\nmeans tedious sifting to get a big-picture view.\n\n## Dissatisfying ways to separate small concerns\n\n#### Using comments:\n\n```ruby\nclass Todo\n  # Other todo implementation\n  # ...\n\n  ## Event tracking\n  has_many :events\n\n  before_create :track_creation\n  after_destroy :track_deletion\n\n  def self.next_by_event\n    # ...\n  end\n\n\n  private\n    def track_creation\n      # ...\n    end\nend\n```\n\n#### With an inline module:\n\nNoisy syntax.\n\n```ruby\nclass Todo\n  # Other todo implementation\n  # ...\n\n  module EventTracking\n    extend ActiveSupport::Concern\n\n    included do\n      has_many :events\n      before_create :track_creation\n      after_destroy :track_deletion\n    end\n\n    module ClassMethods\n      def next_by_event\n        # ...\n      end\n    end\n\n    private\n      def track_creation\n        # ...\n      end\n  end\n  include EventTracking\nend\n```\n\n#### Mix-in noise exiled to its own file:\n\nOnce our chunk of behavior starts pushing the scroll-to-understand it\nboundary, we give in and move it to a separate file. At this size, the\noverhead feels in good proportion to the size of our extraction, despite\ndiluting our at-a-glance sense of how things really work.\n\n```ruby\nclass Todo\n  # Other todo implementation\n  # ...\n\n  include TodoEventTracking\nend\n```\n\n## Introducing Module#concerning\n\nBy quieting the mix-in noise, we arrive at a natural, low-ceremony way to\nseparate bite-sized concerns.\n\n```ruby\n  class Todo\n    # Other todo implementation\n    # ...\n\n    concerning :EventTracking do\n      included do\n        has_many :events\n        before_create :track_creation\n        after_destroy :track_deletion\n      end\n\n      class_methods do\n        def next_by_event\n          # ...\n        end\n      end\n\n      private\n        def track_creation\n          # ...\n        end\n    end\n  end\n\n  Todo.ancestors\n  # =\u003e Todo, Todo::EventTracking, Object\n```\n\nThis small step has some wonderful ripple effects. We can\n* grok the behavior of our class in one glance,\n* clean up monolithic junk-drawer classes by separating their concerns, and\n* stop leaning on protected/private for crude \"this is internal stuff\" modularity.\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasecamp%2Fconcerning","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbasecamp%2Fconcerning","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbasecamp%2Fconcerning/lists"}