注: 記述する上で面倒なので、以下で「関数」と単に書いてある場合、メソッドやプロシージャといったものをまとめて指すこととする。
TL;DR
「分割」しようとするな。一つ一つ、別の処理に「分解」しろ。
そもそもなぜ「分割」しろといわれるのか
短くしたいから。
人間、長い文章は途中で混乱するものだ。
そしてプログラムも結局は文章である。
多くの日本人が英語の本を読んだら混乱するように、人類は長いプログラムを読むと混乱する。これは当然だ。
なにしろプログラムは「プログラミング言語」という言語で記述されている。この言語は困ったことに、なんと外国人どころかコンピュータと対話するための言語である。
そりゃあ、慣れないうちは(あるいは慣れたとしても)混乱して当然だ。
重要なのは「短い」ことではない
「This is a pen」は日本人を混乱させるだろうか。
もちろん、させないだろう。「これはペンです」。簡単だ。
では「Er ist wieder da」はどうだろう (いや、これは人によっては通じると思うが) 。
答えは「彼、再び」といった具合になるらしい。ちなみにドイツ語で、小説のタイトルである。彼再び!って、なんのこっちゃ?1
そう、仮に十分に短い場合であっても、それ単独で意味が通じなければ、結局多方面を調べ回るハメになる。当然時間がかかる。
重要なのは、わかりやすいことだ。もし混乱しないのであれば、長くてもその方がよい。
短くしろと言われるのは、短ければ「マシ」になりやすいからであって、短くすることそれ自体は解決策たり得ない。
例
ここにクソ長いメソッドがあり、これを短くしろと命じられたとする。
public void hoge(List<Hoge> h, List<Fuga> f){
...(なんかいっぱい)...
}
駄目な例
「切り離しました!」
public void hoge(List<Hoge> h, List<Fuga> f){
part1(h, f);
part2(h, f);
part3(h, f);
}
private void part1(List<Hoge> h, List<Fuga> f){
...(なんか)...
}
(以下略)
ぶん殴られても文句言えない。
何が駄目か
単純に、結果どうなるのかを見通すためには全部読まなければならない。
part1, part2, part3 はそれぞれ独立していないので、本当にただ切り離しただけなのだ。
こうなってくると単に連続した処理が別の場所に書かれただけで、いろいろなところを読まなければならない分却ってめんどくさい。
どうすべきか
こうすると少し改善する。
(他にもいろいろやるべきことはあるが、今回の記事でいいたいのはここ)
public void hoge(List<Hoge> h, List<Fuga> f){
List<Pair<Hoge, Fuga>> result1 = part1(h, f);
List<Pair<Hoge, Fuga>> result2 = part2(result1);
List<Pair<Hoge, Fuga>> result3 = part3(result2);
}
protected List<Pair<Hoge, Fuga>> part1(List<Hoge> h, List<Fuga> f){
...(なんか)...
}
protected List<Pair<Hoge, Fuga>> part2(List<Pair<Hoge, Fuga>> result1){
...(なんか)...
}
(以下略)
どう違うのか
先ほどと違い、part1, part2, part3 はそれぞれ「結果」を返している。
乱暴な言い方だが、結果が出るということは、その処理一つだけでも意味が通り、検証が可能だということである。
このため、自動ユニットテストも掛けやすくなる。手動のテストもいくらかやりやすくなるだろう。
(protected になっていることに気づいたらなかなか鋭い。普段ならリフレクションで private を触らせるが、今回はそういう意味合いも込めて protected にした)
-
結構面白かった。日本語訳も出てるので興味があれば調べるとよい。そう、調べないとわからんだろ。 ↩