justin808/fat-code-refactoring-techniques — pull request #3 by justin808 (2014-03-31 18:37:22+00:00)
Title: Concerns

# Rails Concerns
- http://api.rubyonrails.org/classes/ActiveSupport/Concern.html
- Simplest safest refactoring
- Just cut and paste the code
- Default part of Rails
- Not just for code shared across models, but super to simply divide change a
large model file into logical chunks with associated tests.

## Why Concerns and Not Plain Ruby
- Simple to consistently follow the pattern
- Concerns can include other concerns
- Single concern includes all of:
- instance methods
- class methods
- code to run on model including the concern, such as =has_many=, =scope=,
etc.
- Yes, you can do the same with include, extend, etc., but why risk the
pitfalls and why not the consistency of Concerns?

## Where to put concerns
- If just one concern for model, or if shared among models, then in
`app/models/concerns`.
- If multiple concerns for single model, group in subdirectory under models,
such as `app/models/user/`.

## Steps
- Create file for Concern with skeleton structure:
```ruby
module ModelName::ConcernName
extend ActiveSupport::Concern

included do
# your class level code
end

# move your instance methods here

module ClassMethods
# your class methods, removing self.
end
end
```
- Move class level code to `included` block.
- Move class methods to inside of module ClassMethods.
- Move instance methods to module.
- Place `include` statement in original model class:
```ruby
include ModelName::ConcernName
```

## Another Concern Example
- Break out methods concerning a user's feed.
- Now the User is broken up into:
- user/find_methods.rb
- user/feed_methods.rb
- Tests similarly matched up.
- I like the smaller files!
- Safe, easy way to slice up huge model files.
- Could be first step to further refactoring.

## Concerns: Didn't Show You But Useful!
- Sharing a concern in multiple models
- Nesting concerns (concerns loading concerns)
- Applies to controllers as well as models

# Concerns Summary
## Applicable Situation
- A giant model file with corresponding giant spec file.
- Duplicated code in multiple models.

## Solution
The giant model can safely and easily be broken down into logical chunks (concerns), each with a
correspondingly smaller spec file per concern.

## Advantages
1. **Ease and safety of refactoring.** Concerns are a great first refactoring step
because using concerns involves simply moving the methods and tests into
separate files. And code accessing those methods does not need to change.
2. A core part of Rails 4, so one can expect familiarity among Rails developers.
3. Simplicity. It's just a code organization that makes it easier to navigate to
the right source and test file.
4. Can DRY up code when a concern is shared among multiple models.

## Disadvantages
1. The model object does not become more cohesive. The code is just better
organized. In other words, there's no real changes to the API of the model.
2. For a complex operation involving many different methods, and possibly
multiple models, a Service Object, aka PORO, better groups the logic.
3. If the code view-centric, and relies on helpers, then a Decorator is a better
choice.

# Concerns References

- [Put chubby models on a diet with concerns](http://signalvnoise.com/posts/3372-put-chubby-models-on-a-diet-with-concerns) by @dhh
- [Reading Rails - Concern](http://monkeyandcrow.com/blog/reading_rails_concern/) by Adam Sanderson
- [Module ActiveSupport::Concern](http://api.rubyonrails.org/classes/ActiveSupport/Concern.html)