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

ククログ


クリアなコードの作り方: 専用の機能を使う

「やりたい処理もできる」機能ではなく「やりたい処理用」の機能を使うことで、書いた人の意図が伝わるコードになるという話です。「動く」コードは書けるけど「意図が伝わる」コードはまだ書けない、という初級者向けの話です。

「動く」だけだとどんな機能を使って実装しても同じですが、「意図が伝わる」という観点では使う機能によって違いがあります。これは読む人が期待することとコードが意図することが異なるからです。

繰り返し機能が必要なケースを考えます。ここでは次のように1から5まで出力したいとします。

% ruby output-numbers.rb
1
2
3
4
5

Rubyには繰り返し機能を提供するeachというメソッド*1があります。これを使って実装すると「繰り返して処理をしたい」という「意図」が伝わるコードになります。

1
2
3
4
numbers = [1, 2, 3, 4, 5]
numbers.each do |number|
  puts(number)
end

Rubyには「繰り返し」機能と「それぞれの繰り返しの結果を集める」機能を提供するmapというメソッド*2もあります。mapにも「繰り返し」機能があるので、mapを使っても「動く」コードを書けます。

1
2
3
4
numbers = [1, 2, 3, 4, 5]
numbers.map do |number|
  puts(number)
end

これら2つのコードは同じ「動き」になりますが、「意図が伝わる」という点では違います。

mapには「それぞれの繰り返しの結果を集める」機能があるので、プログラムを読む人は「mapで集めた結果をどう使うのだろう」と考えながら読みます。しかし、このプログラムではmapの「それぞれの繰り返しの結果を集める」機能を使っていないので、次のコードのようにmapの結果を代入していません。

1
2
3
converted_numbers = numbers.map do |number|
  puts(number)
end

今回のコードは単に結果を捨てています。

mapのことを知っている注意深く読む人*3ならここで次のように考えます。

「それぞれの繰り返しの結果を集める」機能を提供するmapの結果を使っていないということは…これは代入忘れのバグじゃないか?

しかし、コード全体を読んでみるとmapの「それぞれの繰り返しの結果を集める」機能は使っていなくて、単に「繰り返し」機能だけを使っていることがわかります。そしてこう思います。

なんだ、「それぞれの繰り返しの結果を集める」機能を使っていないのか。じゃあ、バグじゃないか。まぎらわしいな。。。

mapではなく「繰り返し」機能だけを提供するeachを使っていれば、読む人はまぎらわしく思わずに書いた人が何をしたかったかを理解できます。このようなコードが「意図が伝わる」コードです。

「意図が伝わる」コードは読む人が理解する時間が短くなりますし、間違って理解されにくくなります。これはコードの修正や改良に役に立ちます。多くのコードは一度書いたら終わりではなく、動くようになったあとにメンテナンスされます。そのため、修正や改良に役立つことは重要です。

「動く」コードを書けるようになったら「意図が伝わる」コードを目指してください。

まとめ

eachmapを例にして「動く」だけのコードと「意図が伝わる」コードの違いを説明しました。ちなみに、eachでよいところにmapを使っているコードはわりとよく見るコードです。いつもの癖でmapを使ったり、最初は「それぞれの繰り返しの結果を集める」機能が必要だったけど途中で必要なくなったのにmapを使い続けてしまっている、ということなのかもしれません。

「動く」コードを書けるようになったら、「動く」だけではなく「意図が伝わる」コードを目指してください。「意図が伝わる」コードは改良や修正などメンテナンスがしやすいからです。「とりあえず動くもの」の次を目指すときに参考にしてください。

あわせて読みたい:

お知らせ:

*1 JavaScriptならArray.prototype.forEach

*2 JavaScriptならArray.prototype.map

*3 まわりにいる「意図が伝わる」コードを書く人を思い浮かべてください。

2015-02-23

«前の記事: mrubyのVMのデバッグ方法 最新記事 次の記事: reportbugを使ってバグ報告をしてみよう»
タグ:
年・日ごとに見る
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|05|06|