📜 ⬆️ ⬇️

Rules for developers from Sandi Metz

In January of this year, Sandi Metz presented its rules for developers on the Ruby Rogues podcast. Around this time, my team and I started a new project. This article describes the experience we gained by applying these rules to our new project.

rules


  1. Classes cannot contain more than 100 lines of code.
  2. Methods can not be longer than 5 lines of code.
  3. You cannot pass more than 4 parameters to a method. Hash values ​​are also considered parameters.
  4. Controllers can instantiate only one object. Therefore, the view can know only about one instance variable and should only send messages to this object ( @object.collaborator.value not valid).



When to break the rules


To paraphrase Sandi, “You can break the rules only if you have good reasons for that, or your programming partner approves of this.” You should get permission from your programming partner or the person who is reviewing your code.

Let this be the unchanged rule number 0.
')

100 line classes


Despite the fact that we had a large number of private methods, it was easy enough to keep the classes short. This prompted us to determine the very common responsibility of our classes and to understand what code should be rendered.

This also applies to speck. There was a case when we found a spec file exceeding this limit. He helped us realize that we are testing too many features. It was decided to split this file into several, more focused on features, specs.

We came to the conclusion that git diff doesn’t necessarily show us when we exceeded the limit of 100 lines.

5 lines of code per method


Limiting the method to five lines is the most interesting rule.
We agreed that 'if', 'else', 'end' are also considered. In the 'if' block with two branches, each branch must fit into one line.

For example:

 def validate_actor if actor_type == 'Group' user_must_belong_to_group elsif actor_type == 'User' user_must_be_the_same_as_actor end end 

5 lines guarantee that we will never use 'else' with 'elsif'.

A one-line restriction on a branch prompted us to use private methods with well-thought-out names to achieve the desired result. Private methods are excellent documentation. They need very clear names, which made us think about which code should be highlighted.

Maximum 4 arguments per method


Using this rule in Rails has become a big challenge for us, especially in views.

View helpers, such as 'link_to' or 'form_for', may require many parameters to work correctly. Of course, we made efforts to limit the number of arguments passed, but sometimes we returned to rule 0 and left them if we could not find a better way.

Instantiate a maximum of one object in the controller


This rule surprised us the most before we embarked on a new project. Often we needed more than one type of object on a page. For example, on the home page we needed an activity feed and a notification counter.

We solved this problem through the Facade design pattern . And it looked like this:

app / facades / dashboard.rb:

 class Dashboard def initialize(user) @user = user end def new_status @new_status ||= Status.new end def statuses Status.for(user) end def notifications @notifications ||= user.notifications end private attr_reader :user end 

app / controllers / dashboards_controller.rb:

 class DashboardsController < ApplicationController before_filter :authorize def show @dashboard = Dashboard.new(current_user) end end 

app / views / dashboards / show.html.erb:

 <%= render 'profile' %> <%= render 'groups', groups: @dashboard.group %> <%= render 'statuses/form', status: @dashboard.new_status %> <%= render 'statuses', statuses: @dashboard.statuses %> 

The 'Dashboard' class provides a common interface for placing user interacting objects, and we are already passing its object into the presentation templates.

We agreed that the memorization of variables in the controller does not affect this restriction. And we agreed to add the prefix in the form of an underscore to the unused variables to reflect the fact that they are intended for use in the template:

 def calculate @_result_of_expensive_calculation ||= SuperCalculator.get_started(thing) end 

Unprecedented success!


We recently recognized our experiment as successful, published it on our research list, and included these rules in our best practice guide .

Source: https://habr.com/ru/post/181434/


All Articles