はじめに
これはQiitaで開催されている「新人プログラマ応援 - みんなで新人を育てよう!」イベントの投稿記事です。
今回はメソッドの定義順に関する小ネタを書いてみようと思います。
なお、この記事はRuby版とJavaScript版の2部構成になっています。
JavaScriptを使ったコード例はRuby版のあとに載せています。
おことわり
この記事ではメソッドの定義順を変えてもエラーが出ないケースを議論の対象とします。
文法の制約上、特定の定義順で書かないと動かないケースは議論の対象としません。
Ruby版
メソッドの定義順は基本的に自由、だが・・・
メソッドの定義順は基本的に自由です。
class Foo
def a
end
def b
end
def c
end
end
と書いてもいいですし、
class Foo
def b
end
def c
end
def a
end
end
と書いてもエラーにはなりません。
しかし、コードを読むときは呼ぶメソッドを手前に、呼ばれるメソッドを後ろに定義した方が読みやすいです。
つまり、こういうことです。
# 呼ぶ側を手前に、呼ばれる側を後ろに定義した場合
class Foo
def a
b
end
def b
c
end
def c
end
end
これがバラバラになっていると、コードを読むときのリズムが崩れて読みづらくなります。
class Foo
def b
c
end
def c
end
def a
b
end
end
童謡を使って考えてみる
とはいえ、上のような意味のないコード例だといまいちピンとこないかもしれません。
そこで「あんたがたどこさ」という童謡の歌詞を拝借して、メソッドの定義順の良し悪しを考えてみることにします。
メソッドの定義順がバラバラの場合
最初はメソッドの定義順がバラバラになっているケースです。
以下のコードでplayer.play
を実行したときの実行結果がどうなるか、ぱっとわかるでしょうか?
play
メソッドから順に最後までメソッド呼び出しがどのように進むか、ぜひ目で追いかけてみてください。
class MusicPlayer
def play
あんたがたどこさ
end
private
def 肥後どこさ
熊本さ
end
def あんたがたどこさ
肥後さ
end
def 熊本さ
puts "熊本どこさ?"
end
def 肥後さ
肥後どこさ
end
end
player = MusicPlayer.new
player.play
どうですか?実行結果がわかりましたか?
はい、そうですね、play
メソッドを呼び出すと"熊本どこさ?"の文字列が出力されます。
player.play
#=> 熊本どこさ?
「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した場合
ですが、もしメソッドの定義順が次のようになっていたらどうでしょうか?
先ほどと同じようにplay
メソッドから順に最後までメソッド呼び出しがどのように進むか、目で追いかけてみてください。
class MusicPlayer
def play
あんたがたどこさ
end
private
def あんたがたどこさ
肥後さ
end
def 肥後さ
肥後どこさ
end
def 肥後どこさ
熊本さ
end
def 熊本さ
puts "熊本どこさ?"
end
end
player = MusicPlayer.new
player.play
play
メソッドを呼び出すと"熊本どこさ?"の文字列が出力されるのは先ほど同じですが、「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した方がコードが読みやすくなったのではないでしょうか?
Ruby版のまとめ
というわけで、この記事では「メソッドは呼ぶ側を手前に、呼ばれる側を後ろに定義しよう」という話を書いてみました。
もちろん、メソッドの定義順は絶対的な正解があるわけではないですし、読みやすさは主観によるので「ワシはメソッドの定義順なんて何でもかまわん!」という人も中にはいるでしょう。
とはいえ、僕の周りの熟練プログラマに話を聞くと、ほとんどの人が「呼ぶ側を手前に、呼ばれる側を後ろ」で書いた方がわかりやすいと答えています。
そもそもRubyだって普通はpublicメソッドを手前に、privateメソッドを後ろに定義にするので、これも「呼ぶ側を手前に、呼ばれる側を後ろ」のルールになっていますよね。
class MusicPlayer
# publicメソッドはprivateメソッドを呼ぶ(手前に定義)
def play
あんたがたどこさ
end
private
# privateメソッドはpublicメソッドに呼ばれる(後ろに定義)
def あんたがたどこさ
肥後さ
end
# 以下略
end
というわけで、新人プログラマの方で「メソッドってどういう順番で定義したらいいのかな〜?🤔」と悩んでいる人はとりあえず「呼ぶ側を手前に、呼ばれる側を後ろ」の順番で定義してみることをオススメします!
JavaScript版
メソッドの定義順は基本的に自由、だが・・・
メソッド(または関数)の定義順は基本的に自由です。
class Foo {
a() {
}
b() {
}
c() {
}
}
と書いてもいいですし、
class Foo {
b() {
}
c() {
}
a() {
}
}
と書いてもエラーにはなりません。
しかし、コードを読むときは呼ぶメソッドを手前に、呼ばれるメソッドを後ろに定義した方が読みやすいです。
つまり、こういうことです。
// 呼ぶ側を手前に、呼ばれる側を後ろに定義した場合
class Foo {
a() {
this.b()
}
b() {
this.c()
}
c() {
}
}
これがバラバラになっていると、コードを読むときのリズムが崩れて読みづらくなります。
class Foo {
b() {
this.c()
}
c() {
}
a() {
this.b()
}
}
童謡を使って考えてみる
とはいえ、上のような意味のないコード例だといまいちピンとこないかもしれません。
そこで「あんたがたどこさ」という童謡の歌詞を拝借して、メソッドの定義順の良し悪しを考えてみることにします。
メソッドの定義順がバラバラの場合
最初はメソッドの定義順がバラバラになっているケースです。
以下のコードでplayer.play()
を実行したときの実行結果がどうなるか、ぱっとわかるでしょうか?
play
メソッドから順に最後までメソッド呼び出しがどのように進むか、ぜひ目で追いかけてみてください。
class MusicPlayer {
play() {
this.あんたがたどこさ()
}
肥後どこさ() {
this.熊本さ()
}
あんたがたどこさ() {
this.肥後さ()
}
熊本さ() {
console.log("熊本どこさ?")
}
肥後さ() {
this.肥後どこさ()
}
}
const player = new MusicPlayer()
player.play()
どうですか?実行結果がわかりましたか?
はい、そうですね、play
メソッドを呼び出すと"熊本どこさ?"の文字列が出力されます。
player.play()
//=> 熊本どこさ?
「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した場合
ですが、もしメソッドの定義順が次のようになっていたらどうでしょうか?
先ほどと同じようにplay
メソッドから順に最後までメソッド呼び出しがどのように進むか、目で追いかけてみてください。
class MusicPlayer {
play() {
this.あんたがたどこさ()
}
あんたがたどこさ() {
this.肥後さ()
}
肥後さ() {
this.肥後どこさ()
}
肥後どこさ() {
this.熊本さ()
}
熊本さ() {
console.log("熊本どこさ?")
}
}
const player = new MusicPlayer()
player.play()
play
メソッドを呼び出すと"熊本どこさ?"の文字列が出力されるのは先ほど同じですが、「呼ぶ側を手前に、呼ばれる側を後ろ」のルールで定義した方がコードが読みやすくなったのではないでしょうか?
JavaScript版のまとめ
というわけで、この記事では「メソッドは呼ぶ側を手前に、呼ばれる側を後ろに定義しよう」という話を書いてみました。
もちろん、メソッドの定義順は絶対的な正解があるわけではないですし、読みやすさは主観によるので「ワシはメソッドの定義順なんて何でもかまわん!」という人も中にはいるでしょう。
とはいえ、僕の周りの熟練プログラマに話を聞くと、ほとんどの人が「呼ぶ側を手前に、呼ばれる側を後ろ」で書いた方がわかりやすいと答えています。
というわけで、新人プログラマの方で「メソッドってどういう順番で定義したらいいのかな〜?🤔」と悩んでいる人はとりあえず「呼ぶ側を手前に、呼ばれる側を後ろ」の順番で定義してみることをオススメします!