コーディング規約

コーディング規約の意味

チームで開発を行う場合、複数のメンバーで同一のプログラムコードを共有する事になります。
コーディング規約とは、あらかじめプログラムコードを書く際のルールをチーム内で決めておき、メンバー間での認識の齟齬を極力減らすことでメンテナンスしやすくするために存在します。

例えば、以下のコードを見てみましょう。

1
2
3
4
5
6
7
8
9
def func a
if a.length==0
return nil
end
b=0
a.each{|c|b+=c;puts "data=#{c}"}
return b
end
p func [1,2,3]

上記のプログラムは実際に実行することができますし、正しい結果が得られます。
しかし、プログラムが非常に読みづらく、「どんな処理がされているのか」も実行してみるまで予想しづらいと思います。
これがより業務で扱うさらに大規模なコードだったら…
このように、コードが分かりづらいものになっていると、初めてコード見る人にとっては理解に時間がかかったり、間違った解釈をしてしまったりします。
また、いざ修正しようとすると大変なことがわかるでしょう。

では、先ほどのコードが次のようになっていたらどうでしょうか。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 数値の配列を引数として受け取り、その合計値を返却するメソッド
def sum(nums)
  # 配列の要素が空の場合
  if nums.length == 0
    # nilを返却して終了
    return nil
  end

  # 合計値を格納する変数
  result = 0

  nums.each do |num|
    # 配列から数値を一つずつ取り出しresultに加算
    result += num

    # 現在参照している数値を画面に出力
    puts "data=#{num}"
  end

  return result
end

# sum メソッドに配列を渡して実行
p sum([1,2,3])

処理の内容は先程のコードと全く同じですが、何をしているのか分かりやすくなったのではないでしょうか。
コードを書く際のルールがあらかじめ決まっていれば、コード全体に一貫性が生まれ、他のメンバーが書いたコードでも理解がしやすくなります。

部署配属後では、チームで決められたコーディング規約を守る事になると思いますが、
本研修中でも、なるべく他の人が見てもわかりやすいコードを書くという気配りを意識したコーディングを心がけましょう。

以下では、新人研修中にRubyでコーディングを行う際に意識してもらいたいことをまとめています。
はじめはわからない部分もあると思いますが、都度見返して徐々に意識できるようになってください。

心得12ケ条

一覧

心がけてほしいことを一覧にしています。
分類は以下のようにしてあります。

  • 慣習: Rubyの慣習として、一般に統一されているものです。Rubyを使ったフレームワークには、この慣習を前提に実装されているものもあるので注意しましょう。
  • 規約: 研修中に遵守してほしい部分です。可読性が損なわれたり意図しないバグが発生しないために意識しましょう。
  • 心得: 研修中に推奨する記法などです。Rubyでは同じ処理にいくつかの書き方が存在しますが、他の人が見てもわからなくならないように心がけましょう。

詳細は各項目のリンクから飛べます。

分類 項目 内容
慣習 命名規則 リンク先の表を参照
慣習 モジュール・クラスのファイル名 モジュール名、クラス名をlower_snake_caseで記述
規約 文字コード UTF-8に統一
規約 インデント 半角スペース2つ
規約 空行の挿入 メソッドの区切り / 処理のまとまりごと
規約 コメント 他の人が読んで流れがわかるレベルで
規約 グローバル変数 使用しない
規約 ifとunless unless ~ else ~ endif ~ else ~ end にする
心得 変数名の付け方 わかりやすさを重視する(a, bなどの安易な変数名は避ける)
配列は基本的に複数形にする
心得 returnの指定 基本的につける(MUSTではない)
心得 三項演算子 処理がシンプルかつ明確な場合に限り使用可
心得 ブロック 1行の場合: { || ...}
複数行の場合: do || ... end
心得 一行あたりの文字数 長くなる場合は適切に改行を入れる

命名規則

オブジェクト 規則   例 
モジュール・クラス アッパーキャメルケース UpperCammelCase
メソッド ローワースネークケース lower_snake_case
変数 ローワースネークケース lower_snake_case
定数 すべて大文字のスネークケース CONSTANT_VARIABLE

Note : キャメルケースとスネークケース

  • キャメルケース:複数の単語をつなげて一つの変数名とする場合に、単語の先頭を大文字にしてつなげる記法です。その形が「ラクダのコブ」に似ていることから名付けられました。下のような二種類の書き方が存在します。
    • アッパーキャメルケース:先頭が大文字 (例:UpperCammelCase)
    • ローワーキャメルケース:先頭が小文字 (例:lowerCammelCase)
  • スネークケース:複数の単語をつなげて一つの変数名とする場合に、単語と単語をアンダースコア_でつなげる記法です。その形が「ヘビ」に見えることから名付けられました。一般に、「全て大文字」か「全て小文字」にします。

この他にも、ハイフン-つなぎで記述するチェインケース(例:chain-case)という記法もあります。

一部の言語では変数名の先頭にアンダースコアをつける慣習がありますが、Rubyでは基本的につけません。
このように、他の言語と命名規則が異なる場合があるので混同しないように注意しましょう。

1
_name = "Taro"

モジュール・クラスのファイル名

自作のモジュール/クラスを記述したファイル名には、そのモジュール/クラス名と同じ名称をつけましょう。

1
例:自作の`MyModule`クラスを記述した.rbファイルの場合 “my_module.rb”

文字コード

同じコードを見ていても、エディタの仕様や設定によっては文字化けしてしまう場合があります。
チーム内でコードの共有を行う際には、あらかじめどの文字コードで書くかを統一しておくよいでしょう。
研修中ではUTF-8で保存するようにしましょう。

インデント

インデントの幅は、タブではなく半角スペース2つに統一しましょう
Atomの設定で、タブキーを押した場合に半角スペース2つを入力することが可能です。
エディタ上でスペースやタブを可視化しておくとよりわかりやすいです。

1
2
3
4
5
6
7
8
9
10
x = 20
y = 0

if x > 0
  if y > 0
    puts "xもyも0より大きいです"
  else
    puts "xは0より大きいですが、yは0以下です"
  end
end

空行の挿入

メソッドの区切りや処理のまとまりなど、適切に空行を挿入して区切りをわかりやすくましょう。

1
2
3
4
5
6
7
def func1
  ...
end

def func2
  ...
end

コメント

メソッドやループ処理、条件分岐などといった処理が複雑になる場合には、他の人がコードを読んでも流れが理解できるように、どこでどんなことをしているかを処理の前にコメントとして簡潔に残しておきましょう。
また、メソッドの説明に関するコメントについては、研修中はメソッド定義の上に統一しておきましょう

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# bad: コメントがない
def add_tax(price)
  ...
end

# bad: メソッド定義の下
def add_tax(price)
# 引数に税抜き価格を与えると、税込み価格を返すメソッド
  ...
end

# good: メソッド定義の上
# 引数に税抜き価格を与えると、税込み価格を返すメソッド
def add_tax(price)
  ...
end

グローバル変数

グローバル変数は、変数名が同一であればプログラム中のどこであっても必ず同じ変数として扱われます。
グローバル変数は便利である一方、その性質上プログラムが大きくなるほど意図しない場所で改変されてしまったり、修正しなければならない部分が増えたりと、保守も難しくなります。
研修中では、グローバル変数は使わないようにしましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# グローバル変数として扱う場合は、変数名の前に$をつける
[1,2,3,4,5].each do |a|
  $x = a
  puts "loop_x: #{$x}"
end

puts "x: #{$x}"

#=> loop_x: 1
#=> loop_x: 2
#=> loop_x: 3
#=> loop_x: 4
#=> loop_x: 5
#=> x: 5

ifとunless

unless A else B end はあまり推奨されていません。
順番変えればif B else A end で書けるためです。
unless ~ else ~ end となる場合には、if ~ else ~ endで置換しましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
# bad: unless ~ else ~ end
unless success?
  puts 'failure'
else
  puts 'success'
end

# good: if ~ else ~ end
if success?
  puts 'success'
else
  puts 'failure'
end

変数名の付け方

大きなプログラムになるほど、変数名は重要になります。
変数名がabというった安易なものだと、どの変数がプログラムのどの部分に関連するのかわからなくなってしまいます。
できる限り他の人がその変数をみたときに中身が何であるか想像しやすい命名を心がけましょう。

また、Rubyでは配列名は複数形で書く場合が多いです(ただし、集合のような単数形で複数を表すようなものはその限りではありません)。
意識して変数名をつけてみましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
# bad: わかりづらい変数名
a = 1
hoge = '太郎'

# good: 内容がイメージしやすい変数名
member_id = 1
member_name = '太郎'

# bad: 単数形の配列名
member = ['太郎', '二郎', '三郎']

# good: 複数形の配列名
members = ['太郎', '二郎', '三郎']

returnの指定

Rubyのメソッドでは、returnの記述がない場合は最後に評価された値が戻り値になります。
ただし、省略すると意図しない値が戻り値になる場合があります。
研修中はなるべく混乱を避けるために、基本的にはreturnをつけた方がよいでしょう(ただし強制はしません)。

1
2
3
4
5
6
#どの値が返却されるかが明確な場合
def hello_world
  "Hello World"   #最後の処理の場合、returnは省いてもよい
end

puts hello_world  #=> Hello World!

三項演算子

三項演算子を用いることでシンプルに書ける場合は使用しても構いません。
しかし、複雑な分岐になるほど三項演算子は可読性が低くなってしまいます。
三項演算子を入れ子にすることは、可読性を著しく損なうためやめましょう

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 三項演算子を用いることでシンプルに書ける場合
a = 10

# good: 三項演算子を用いた例
puts (a >= 0) ? a : -a  #=> 10

# if ~ elseを用いた例
if(a >= 0)
  puts a
else
  puts -a
end
#=> 10

# bad: 三項演算子が入れ子になる場合はNG!
puts (a >= 0) ? (a < 10) ? a : -a : -a

ブロック

ブロックを使う場合、{ || ~ }を使用する書き方は一般的に一行で表現する際に使うとされています。
人やプロジェクトによって全てこの形で使用しているところもあるため、実際のチームで作業をする場合などは、事前にルールの確認が必要です。
研修の間は、処理が複数行に渡る場合は前者、一行で表現する場合には後者を使用しましょう。

1
2
3
4
5
6
7
8
9
10
11
# 一行の場合
array.each { |value| puts value }

# 複数行の場合
array.each do |value|
  if value > 10
    puts 'valueの値は10より大きいです。'
  else
    puts 'valueの値は10以下です。'
  end
end

一行あたりの文字数

要素が多い配列やハッシュ、引数が多いメソッドなどは、一行が長くなりがちです。
一行の文字数が長くなると、コードが画面内に収まらず非常に見づらくなります。
その場合、適切に改行を入れて読みやすくすることを心がけましょう。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# bad
hash = {key1: "foo", key2: "bar", key3: "baz", key4: "qux", key5: "quux", key6: "corge", key7: "grault", key8: "garply", key9: "waldo", key10: "fred", key11: "plugh", key12: "xyzzy", key13: "thud"}

# good
hash = {
  key1: "foo",
  key2: "bar",
  key3: "baz",
  key4: "qux",
  key5: "quux",
  key6: "corge",
  key7: "grault",
  key8: "garply",
  key9: "waldo",
  key10: "fred",
  key11: "plugh",
  key12: "xyzzy",
  key13: "thud"
}