-
Notifications
You must be signed in to change notification settings - Fork 1
Home
vhl/docs/code_quality/how_to_review_a_pull_request.md Leaving out syntactical nitpicking included in this doc for now.
- There should be a
describeblock for each method - Use a new
describeblock for any validations or scopes that are tested - Complex or multiple
itstatements should go in acontextblock (a single, shortitcan stand alone) - Context blocks should almost always begin with one of three words "when", "with" or "given"
- For both
contextstatements anditstatements, make sure you can easily identify the purpose of the spec, and that it describes the behavior desired, and not simply the code being tested - When testing a method with a conditional, the test should exercise the conditional
- Each
Scenariohas its own setup and teardown, so it's acceptable to test multiple user actions that follow one another within a scenario - If a
Scenariois too long or complicated, then break it up - Use
Given,When, andThenmeaningfully - Do not use any instance variables except @user (for the current logged in user)
- Use
"([^"]*)"in the body to allow specifying things like Program titles, Course names, etc.
vhl/docs/code_quality/refactoring_guidelines.docx (these links suck)
- Keep methods to < 6 LOC, for reals. (You can't just hide the other lines in a private.)
- No business logic
- Keep presentation separate from data
- Use a Presenter for complex logic
- Use Helpers only for presentation (not logic)
- No data structure manipulation (looping is ok)
- No variable assignment
- Keep methods to < 6 LOC
- Leverage built-in ActiveRecord capabilities properly
- Using named_scope for composable queries
- Single Responsibility Principle
- Law of Demeter
- Keep
beforeblocks to < 8-10 LOC on unit tests. Integration setup may be longer.
See Mike's new doc.
Inclusion order:
- modules should be included first, so we know what behavior we are adding to the class.
- default_scopes
- associations (in this order):
- has_many
- has_one
- has_and_belongs_to_many
- belongs_to
- named scopes
- validations
- callbacks
- class-level macros (delegate, accepts_nested_attributes, etc)
- DRYness
- Refactor cycles (vs just moving things around)
- Repo management strategy
- cyclomatic complexity
More than one Enumerable method in a method ramps up complexity exponentially. Break these down into smaller methods. Then, make sure you’re using the correct Enumerable method. If you are aggregating results into an array or hash, use inject; don’t use an external variable and an each loop. If you need to transform elements, use map/collect. Use count instead of select { block }.size. Use any? rather than select { block }.size > 0. Use none? Instead of select { block }.size == 0. Since we use Enumerable every day, we should use it properly. There are analogues for some of these methods in AR that generate SQL statements; these can be very helpful as well!
Maintain the same level of abstraction in a method. That is, don’t mix high- and low-level calls in the same context. This is good:
def some_method
something_valid? && things_have_some_value?
end
This is bad:
def some_method
something_valid && things.any? { |thing| thing == @some_instance_var || thing > @some_other_var }
end
That last enumerable should be moved into its own method, tested, and the method it was extracted from can now be composed of smaller methods with meaningful names.