Spaghetti Model Part 5: Safely Remove ActiveSupport Concerns
Note: This is one part of my journey to tame a spaghetti model or god object. Start with Post 1: Unraveling a Spaghetti Model to see how I chose to tackle this problem.
Your spaghetti model has been a dumping ground of methods and associations for years. In our case, it’s the company model. We know we need to add functionality to the system, so we place the new capability on the company because it’s convenient. We may rationalize it with “Besides, the company should know whether it has active medical benefits.”
Overview
To deal with models with way too many methods, Rails 4 introduced ActiveSupport Concerns as a way of partitioning and reusing model code. Methods and associations that worked together could be extracted into a Concern.
While this made the code more manageable in the short term, each spaghetti model still had the same number of methods. Further, these concerns may or may not be good abstractions. Instead, we’d like to move domain logic into domain APIs.
An Example
Here is an example ActiveSupport::Concern, the company model now has the method company.origination_bank
, the association company.payer_origination_banks
, and a lifecycle callback setup_banking!
that is called each time the company is saved.
Analysis
- List all of the active support concerns and identify which contain domain logic that should be moved to other packs.
Concern | Decision | # Models |
---|---|---|
Sluggable | Stay | 1 |
Bank Accountable | Move to domains | 1 |
Analytics:Identifyable | Unused so deleted | 2 |
PaymentsAndFilingsReschedulable | Move to payments | 15 |
RiskAssessable | Move to risk | 1 |
BankAccountable | Move to payments | 2 |
AttrSquishable | Stay | 14 |
CompanyFormsObserver | Move to forms | 1 |
CompanyOnboardingFunnelUpdateable | Move to onboarding | 5 |
ZensaObserver | Stay | 36 |
AttrBoolean | Stay | 27 |
DirtyNestedAttributes | Stay | 14 |
AttrMemoized | Stay | 49 |
ExternalIdentities::IdentityDeletable | Stay | 4 |
2. Start with active support concerns that are used by 1 model.
Action
Our goal is to move or remove all the methods, associations, and lifecycle callbacks in the ActiveSupport::Concern.
Steps
- For each method in the ActiveSupport::Concern, identify where it should live and then follow the techniques in https://engineering.gusto.com/spaghetti-model-part-3-safely-remove-methods/
2. Move active model lifecycle methods to the model. You can remove the concern now and deal with lifecycle methods later.
3. When all that is left is an empty concern, let’s celebrate! 🎉
It’s time to say goodbye. 👋
Summary
Tackling an ActiveSupport::Concern is the same as handling methods, associations, and lifecycle callbacks.
Originally published at https://sedano.org on September 27, 2023.