Backend Pattern Concern - department-of-veterans-affairs/caseflow GitHub Wiki

[Pattern] Concern

Description

Concerns are a builtin of the Ruby on Rails Active Support component.
The high level concerpt of a concern is to contain functionality that may be used by multiple, otherwise unrelated models or controllers.

Location

All Caseflow concerns live in app/models/concerns or app/controllers/concerns

Caseflow Concerns, as of April 2020:
Controller Concerns:

authenticated_controller_action.rb  hearings_concerns.rb
collect_data_dog_metrics.rb         pagination_concern.rb
errors.rb                           track_request_id.rb

Model Concerns:

ama_case_distribution.rb                has_task_history.rb
appeal_available_hearing_locations.rb   has_virtual_hearing.rb
appeal_concern.rb                       hearing_time_concern.rb
associated_bgs_record.rb                issue_updater.rb
associated_vacols_model.rb              latest_rating_disability_evaluation.rb
asyncable.rb                            prints_task_tree.rb
bgs_service.rb                          proportion_hash.rb
business_line_task.rb                   run_asyncable.rb
cached_attributes.rb                    taskable.rb
case_review_concern.rb                  task_extension_for_hearings.rb
decision_syncable.rb                    task_tree_render_module.rb
has_business_line.rb                    timeable_task.rb
has_hearing_task.rb                     uploadable_document.rb

Best Practices

  • Rails best practice places all concerns inside of app/models/concerns/ or app/controllers/concerns, and Caseflow follows that norm.
  • Rails also favors naming concerns with as an adjective with the -able prefix. Caseflow sometimes follows this norm.
  • Concerns should focus on a single capability shared by unrelated objects
  • Concerns should have limited dependencies to avoid collisions and conflicts in the importing models
  • Concerns should name their functions thoughtfully, as those functions will be pulled into the utilizing code scope

Tradeoffs

Cost
Concerns DRY up the code at the cost of obscuring of dependencies.

Alternatives

  • If the two models are related, consider Inheritance
  • If the functionality exists in only one model, consider a PORO (Plain Old Ruby Object)

Resources

Examples in Caseflow

Examples of good concerns in Caseflow:
has_task_history.rb - gives both Appeal and LegacyAppeal the ability to access versions through the AppealTaskHistory service.

Additional Reading

Related Patterns

Aggregation
Composition
Decorator

⚠️ **GitHub.com Fallback** ⚠️