株式会社クリアコード > ククログ

ククログ


クリアなコードの作り方: 同じことは同じように書く

「同じことは同じように書く」ことがどうして大事かを説明します。

具体例: returnの有無

先日、DevLOVE運営チーム主催のリーダブルコードイベントが開催されました。イベントの前半はリーダブルコードの訳者である角さんによるリーダブルコードの紹介で、後半は参加者が「リーダブルコードとはどういうコードか」をディスカッションしました。ディスカッションでは実際に参加者が書いたコードを読みながら「ここはリーダブルだね」「ここはこうした方がもっとリーダブルじゃないか」といったことを考えました。

さて、その中で使ったコードを見ながら「同じことは同じように書く」ことがどうして大事かを説明します。ここで使うコードはdproject21/yaruo_tdd_triangleのtriangle.rbです*1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Triangle
  attr_accessor :a, :b, :c
  def is_equilteral_triangle?
   not_nil? && preCondition? && @a == @b && @b== @c && @c == @a
  end
  def is_isoscales_triangle?
   not_nil? && preCondition? && (@a == @b || @b == @c || @c == @a)
  end
  def is_triangle?
   not_nil? && preCondition? && (a < b + c) && (b < a + c) && ( c < a + b) 
  end
  def is_scalene_triangle?
    return is_triangle? && !is_isoscales_triangle?
  end
  def preCondition?
    unless [@a,@b,@c].find{|n| n.is_a?(Numeric) && n > 0} 
      false
    else
      true
    end
  end

  def not_nil?
    if (@a.nil? || @b.nil? || @c.nil?) 
      false
    else
      true
    end
  end

end

ディスカッションのときは以下のreturnに注目しました。

1
2
3
def is_scalene_triangle?
  return is_triangle? && !is_isoscales_triangle?
end

このコードはRubyのコードなので最後に評価した式がメソッドの返り値になります。そのため、この場合はreturnを書いても書かなくても動作は変わりません。では、どのような観点でreturnに注目したかというと、他のメソッドではreturnを使っていないのにこのメソッドでは使っているという観点です。コード全体を見れば、特にreturnを使うかどうかを使い分けていないだけという雰囲気を感じますが、通常はここで「何か意図があるのではないか」と考えます。それではどのように考えるかを説明します。

推測

まず、書かなくてもよいreturnを明示的に書いているということは、returnを強調しているのではないかと考えます。つまり、「このメソッドだけは返り値が重要」で、他のメソッドでは「Rubyなので必ず値を返すけど、その値は重要ではない」という意図があるのではないかと考えます。それでは、returnがない他のメソッドも見てみましょう。

1
2
3
def is_triangle?
 not_nil? && preCondition? && (a < b + c) && (b < a + c) && ( c < a + b) 
end

メソッド名に?がついていることに注目します。RubyではSchemeなどと同じように、真偽値を返すメソッドの名前の最後を?にする習慣があります。これを考慮すると、このメソッドは「真偽値を返す」ということが重要だと考えられます。しかし、明示的なreturnがないため、「returnは返り値が重要であるということを示す意図がある」という考えと両立しません。よって、明示的なreturnは「返り値が重要」ということを示すためのものではなく、使っても使わなくてもどちらでもよいからたまたまついていただけなのだろうと考えます。

このように、周囲のコードとあわせて読めばreturnの意図を推測できますが読む人が大変です。しかし、すべてにreturnを書く、一切returnを書かない、一定のルールでreturnを使う*2、など全体として統一された使い方になっていれば読む人が読みやすくなります。できるだけ読みやすいコードにしたいですね。

まとめ

リーダブルコードのイベントのときに使ったコードを例にして、同じことが同じように書かれていない場合は読む人が大変という事を説明しました。自分がコードを書くときは同じことをするときは同じように書いて、どういう意図でこのコードを書いたかが読めばすぐにわかるコードを書きましょう。

なお、ここではreturnを例にしましたが、他のコードや技術的な文書でも同じことが言えます。通常の文章では、同じことを何度か言う場合は同じ言い回しを避けます。これは読む人が飽きて読みづらくなることを避けるためです。一方、プログラミングや技術的な文書では「同じことは同じように書く」ことで、読む人がすぐに「同じこと」であると認識できるようにします。これにより、読む人が書いた人の意図を理解しやすくなります。

あわせて読みたい:

*1 このコードはディスカッションの練習用に選んだもので、小さいスクリプトだったのが選んだ理由の1つ。他の理由はイベントでは紹介したので省略。また、他にディスカッションに使ったコードについても省略。

*2 例えば、基本はreturnを使わないで、特別なケースを処理するとき(ガード節とか)だけ使うとか。

2012-07-18

«前の記事: 思い出せるチケットの書き方: 「動機」、「ゴール」、「実現案」 最新記事 次の記事: Firefox/Thunderbird用アドオン開発者向けテスティングフレームワーク UxU 1.0.0をリリースしました»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|