社内で行なった Ruby Style Guide勉強会について

## 背景
私たちの会社(エイチーム引越し侍)では、長らくバックエンドでPHPを使ってきた歴史がありますが、
最近はRubyを使うことも多くなってきました。
でも、`Rubocop`さんに怒られる日々。
これじゃあいけない。
ということで、社内でRubyのStyle Guideを勉強しようという話になりました。
数名を集め、議論をしながらスタイルガイドを作成していきました。

## ゴール
https://github.com/rubocop-hq/ruby-style-guide
https://github.com/airbnb/ruby
https://github.com/cookpad/styleguide
この辺りを教材として、引越し侍 `Ruby Style Guide`を作成するところまで

## 注意事項

本記事は**まだ未完成**となっております。（ので、**これが完全に良い書き方だ！というつもりはございません。**）
ノウハウがたまるごとにアップデートを行います。
ご意見等ある方はコメント欄に記載していただけると、勉強になるので、是非お願いいたします。

# 引越し侍 `Ruby Style Guide`

## インデント系
### 【MUST】 メソッドのインデントには2つのスペースで統一
コードが右に長くなりすぎず見えやすい

```ruby
# Bad
def sample_method
    do_something
end

# Good
def sample_method
  do_something
end
```

【議論】
異論なし
見やすい & Ruby規約なのでという理由で1秒で決定

### 【MUST】 `case ~ when`文には、スペースを入れない
`case ~ when`は`if ~ else`と同じ扱いなので、入れないのが良い

```ruby
# Bad
case
  when song.name == 'Misty'
    puts 'Not again!'
  when song.duration > 120
    puts 'Too long!'
  when Time.now.hour > 21
    puts "It's too late"
  else
    song.play
end

# Good
case
when song.name == 'Misty'
  puts 'Not again!'
when song.duration > 120
  puts 'Too long!'
when Time.now.hour > 21
  puts "It's too late"
else
  song.play
end
```

【議論】
冒頭に話した通り我々はPHP脳の人間なので、`switch ~ case`文同様、1つめがいいという議論が生まれました。
ただ、`if ~ else`と同じ扱いという事には納得。
rubyの文化に慣れようという結論になりました。

### 【MUST】 複数行にメソッドが連なる場合はドットの位置を合わせる
まだメソッドが続いているということがわかり、かつドットが揃っていて見やすいため

```ruby
# Bad
User.active
.some_scope(foo)

# Bad
User.active
  .some_scope(foo)

# Good
User.active
    .some_scope(foo)
```

※ ドットが上か下かという議論は改行の項目を参照

【議論】
2つめの方が`.`の位置を合わせるために、スペースを合わせなくていいのでいいという意見もありました。
**1人がスペースを合わせるだけで見やすくなり、のちにそのコードを見る10人の人の時間を削減できたならそれがいい！**という結論で終わりました。

### 【MUST】 複数行に連なるBooleanの改行は2スペース開ける
Booleanの判定がまだ続いていることを判別しやすいため

```ruby
# Bad
def eligible?(user)
  Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) &&
  is_in_program?(user) &&
  program_not_expired
end

# Good
def eligible?(user)
  Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) &&
    is_in_program?(user) &&
    program_not_expired
end
```

【議論】
異論なし
Rubyでは`&&`も下に下ろせないため、これが最適だろうという結論

## インラインスペース系

### 【MUST】 インラインコメントは半角スペースを開ける
その方がとても見やすいため

```ruby
# Bad
result = func(a, b)# we might want to change b to c

# Good
result = func(a, b) # we might want to change b to c
```
【議論】
満場一致で合意
ただ、右に長くなってしまうため、基本的にコメントは上に書いて欲しいという議論が生まれました

### 【MUST】 オペレーター、コンマ、コロン、セミコロン、`{}`の後には半角スペースをいれる
その方が見やすいため

```ruby
# Good
sum = 1 + 2
a, b = 1, 2
1 > 2 ? true : false
[1, 2, 3].each { |e| puts e }
```
【議論】
異論なし
ただ、eachを`do ~ end`で書かないのかという論争に発展
こちらについては、下で別途議論しました

### 【MUST】 コンマの前にはスペースをいれない
英語では`,`の前にスペースを入れないためそちらの方が見やすいため

```ruby
# Bad
result = func(a , b)

# Good
result = func(a, b)
```

【議論】
異論なし
どの言語も共通して、コンマの前にスペースは入れないが、
なぜここだけ入れないのかという議論がありました。
そこで考えたものがこちらです
> 英語では`,`の前にスペースを入れないためそちらの方が見やすいため

### 【MUST】 文字列中の変数展開にスペースを入れない
展開する場所の前後にスペースがある場合、展開の中にもスペースがなく、可読性が高いため

```ruby
# Bad
var = "This #{ foobar } is interpolated."

# Good
var = "This #{foobar} is interpolated."
```
【議論】
こちらの方が見やすいため

### 【MUST】 rangeの`...`の前後にスペースを開けない
こちらの方が可読性が高いため

```ruby
# Bad
(0 ... coll).each do |item|

# Good
(0...coll).each do |item|
```

【議論】
異論なし
終端を含む`...`と終端を含まない`..`共にGoodの方が見やすいよねということで決着

## 改行系

### 【MUST】 区切り文字は`;`ではなく、改行する
無駄に右側にコードが長くならずに綺麗に見えるため

```ruby
# Bad
puts 'foo';

# Bad
puts 'foo'; puts 'bar';

# Good
puts 'foo'
puts 'bar'
```

【議論】
異論なし
そもそもRubyで`;`使えるんだ、、、意見も

### 【MUST】 メソッドのパラメーターが多い場合、一行ごとに改行する
その方が見やすいため

```ruby
# Bad
def create_translation(phrase_id, phrase_key, target_locale,
                            value, user_id, do_xss_check, allow_verification)
...
end

# Bad for samurai
def create_translation(
  phrase_id,
  phrase_key,
  target_locale,
  value,
  user_id,
  do_xss_check,
  allow_verification
)
...
end

# Good for samurai
def create_translation(phrase_id,
                       phrase_key,
                       target_locale,
                       value,
                       user_id,
                       do_xss_check,
                       allow_verification)
...
end
```

【議論】
ここはすごくもめました
決めの問題かとは思いますが、2つめのものだと、`def`の下に処理を記述して言った時に、
パラメータのインデントと処理のインデントが同じになるため、見にくいということで3つめのもので決着しました。

### 【MUST】 複数行にメソッドが連なる場合は`.`を下におろす
我々は、PHPでも`->`を下におろしており、慣れしたしんでいて、見やすいため
※ Rubyコミュニティではどちらで見やすいため、OKという見解

```ruby
# Bad for samurai
User.active.
  first_scope(foo).
  second_scope(bar)

# Good for samurai
User.active
    .first_scope(foo)
    .second_scope(bar)
```
※ インデントに関してはインデントを参照

【議論】
`Airbnb`さんや`Cookpad`さんは1つめのものを推奨しています。
ドットを下ろし、かつインデントを2つに統一しようとすると

```ruby
User.active
  .some_scope(foo)
```
となり、ドットの位置が微妙になるため、彼らの定義には納得です
ただ、ドットをあげたものがどうしても我々には見にくいため、ドットの位置も合わせてやることで決着

## Collection

### 【MUST】 配列やハッシュから要素を取り出したい場合は、`find`を使わずに`detect`を使う
`ActiveRecord`の`find`メソッドと混同せずに、それが`collection`だということがわかるため

【議論】
本当に混同するかどうかを議論しましたが、実際に混同してしまったという人がいたため、採用しました。

### 【MUST】 `collect`よりも`map`を使用してください
jsなどでも使える`map`の方が、親しみやすいため
※ どちらも同じ動きをする

【議論】
満場一致で`map`の方が親しみやすいとのことで異論なし

### 【MUST】 `inject`ではなく、`reduce`を使ってください
同じ動きをしますが、"配列を折り畳む"という意味が伝わりやすい`reduce`を使ってください
また、PHPやSwiftなど他の言語でも実装されている`reduce`の方が親しみやすいです

```ruby
numbers = [4, 3, 9, 8, 5, 6, 1, 7, 2]
puts numbers.reduce {|sum, n| sum + n }
> 45
# ブロックの第一引数である初期値は以下のように定義できます
puts numbers.reduce(100) {|diff, n| diff - n }
> 55
```

【議論】
異論なし
そんなに使うことがないため、白熱もせず、、

### 【MUST】 `count`や`length`よりも`size`を使うようにする
`size`の方速いため

【議論】
え、、全然`count`とか使ってるわ、、
本当に遅いの？という議論
TODO: 本当に遅いか調べる（知っている方はコメントお待ちしております。）

### 【MUST】 中身のない`Array`、`Hash`は`[]`、`{}`で初期化
こっちの方がわかりやすいし、シンプルだから

```ruby
# Bad
arr = Array.new
hash = Hash.new

# Good
arr = []
hash = {}
```

【議論】
異論なし


## `%`リテラル

### 【MUST】 `%()`による文字列宣言を使う場合は、1行かつ挿入変数があるかつダブルクウォートを使っているもののみに限り使う
それ以外は適切な宣言方法があるため

```ruby
# Bad
%(<div class="text">Some text</div>)
# Good
# '<div class="text">Some text</div>'

# Bad
%(This is #{quality} style)
# ダブルクォート使った方がスマート "This is #{quality} style"

# Bad
%(<div>\n<span class="big">#{exclamation}</span>\n</div>)
# heredocの方がスマート<<EOS
# <div>
# <span class="big">
# #{exclamation}
# </div>
# EOS

# Good
%(<tr><td class="name">#{name}</td>)
```

【議論】
`%()`は便利だし、綺麗にかけるからGood!という結論に
異論なし

### 【MUST】 文字列の配列は`['sample', 'today']`ではなく`%w`の形で初期化
`%w`の方が新しく追加された構文で、タイプ数が少なくて済むため
ただし、スペースを含む場合は`['1st day', 'today']`という形で初期化する

```ruby
# Bad for samurai
STATES = ['draft', 'open', 'closed']

# Good for samurai
STATES = %w(draft open closed)

# Good
STATES = ['draft', 'open', 'closed', 'already deleted']
```

【議論】
いつも`rubocop`怒ってくるけど、`%w`って本当に必要？
という議論が生まれました
`%w`とか`%i`は`ruby`でしか使わない構文で直感的ではないのでは？という意見がでました
調べて見たところ、
1. 速くかける
2. `%w`という構文を知ってさえいれば、無駄なものを書かなくても`String`型の配列であることがわかる
というメリットがありました
ただ、確かに多く書くときは便利だし、これが文字列の配列であることは慣れの問題だけなので、時代の流れにそって採用という結論に

### 【MUST】 リテラルの配列は`[:sample, :today]`ではなく`%i`の形で初期化
`%i`の方が新しく追加された構文で、タイプ数が少なくて済むため

```ruby
# Bad for samurai
STATES = %i(draft open closed)

# Good for samurai
STATES = [:draft, :open, :closed]
```

【議論】
上と同様の議論をしました

### 【MUST】 スペースを含むシンボルの初期化は`%s`ではなく、`:"sample symbol"`の形で初期化
ほぼ使うことのない`%s`があると、次見た人がわざわざ調べないといけないが、`:"sample symbol"`の形で書かれて入れば、それが何か一目でわかるため
※ `ruby`コミュニティでも`%s`は使わない方針に変更

```ruby
# Bad
%s(Hello World) 

# Good
:"Hello World"
```

【議論】
異論なし
ほとんど使うことないと思うけど、確かにハイフン`-`は使ったことあるので、採用

## メソッド系

### 【MUST】 必要ない時は、`class << self`を使わず、`self.`を使う
`self.`を使っていた場合はそのメソッドを見ればすぐにselfメソッドであることがわかる。
ブロックで定義すると、（ブロックの中が肥大化しているなどの理由で）すぐにselfメソッドであるかどうかがわからない

```ruby

class TestClass
  # Bad
  class << self
    def first_method
      ...
    end

    def second_method
      ...
    end
  end

  # Good
  class << self
    attr_accessor :per_page
    alias_method :nwo, :find_by_name_with_owner
  end

  def self.first_method
    ...
  end

  def self.second_method_etc
    ...
  end
end
```

【議論】
異論なし

### 【MUST】 引数なしのメソッドは`()`を省略、引数があるときは必ず`()`を書く
パラメータの有無を明示的に分けることができるから

```ruby
# Bad
def some_method()
  # body omitted
end

# Good
def some_method
  # body omitted
end

# Bad
def some_method_with_parameters param1, param2
  # body omitted
end

# Good
def some_method_with_parameters(param1, param2)
  # body omitted
end
```
【議論】
異論なし

### 【MUST】 引数のあるメソッド呼び出しは、メソッドの後にスペースを入れずに`f(params1, params2)`の形で書く
メソッドの定義と同じ形式でかけるようにするため

```ruby
# Bad
some_method (params1, params2)

# Good
some_method(params1, params2)
```

【議論】
異論なし

## その他

### 【MUST】 一行の長さは100文字以内
一行が右によりすぎずエディタに表示できる範囲内だから

【議論】
なぜ100文字なのかという議論がありましたが、エディタに表示できる限界がこれぐらいだろうということと、
これ以上長くしていい事なんかないと言うことで決着

## 最後に

最初にも記載させていただいた通り、本記事はまだ未完成となっており、内容をアップデートする可能性がございます。
この書き方が万人に良いというものではなく、自分たちに合った書き方を模索している状態になります。
ご意見等ある方はコメントに記載していただけると幸いです。（勉強させていただきます！！）