コードレビューはしたはずなのに

ヴォラーレのCTOのSouki.Tです。

ヴォラーレの開発室では全コミットに対してコードレビューを入れているので、同僚のコードを読むという機会がかなり多くあります。そんな中、なんでここにコピペコードがあるのかと不思議に思うコードと出くわすことが結構あります。コードレビューの際に指摘が入らなかったのか不思議に思いながらも、動いてるし手を付けないで放置してしまうことが多いです。こういったことは発生の時点で叩くのが正解なので、リリースされてしまった時点で後の祭りです。今後のために原因を考えてみたのが今回の記事です。

これらのコピペコードはコピペは出来る限りない方がいいというコンセンサスは取れているにもかかわらず発生しています。それならば何かしら理由があるはずと考えて調べてみたら、「一定のルールがあった」というのが今回の結論です。センスで片付けられることの多い領域ではありますが、自分自身が書いてしまっていることもあって、自戒の念もこめてまとめてみました。

実際の現象

具体的にどのような場合かを簡単に説明しましょう。

要求1
九九の表を返す関数を作れ

最初に出された要求は上のようなものだとします。プログラミングの初心者であっても大抵は作れるでしょう。1から9までのforループを二重に回せば難なく作れるのではないでしょうか。Cライクの適当な言語があるとして実際に書いてみると

こんな感じです。ここで次に、

要求2
1の要求から追加で、1から9に限定せず任意の場所を切り取った掛算表を返す関数を作れ

という要求が出たとすると、これも難しい話ではなく多くの人は難なく作れることでしょう。

難しいことは特にありません。

では、次のような要求であればどうするでしょうか。

要求3
2の要求から追加で、掛け算に限らず任意の演算結果の表を返す関数を作れ

コールバックを何かしらの方法で実装すればそう難しい話ではありません。それこそJavaScriptの様に関数を代入してしまえれば簡単な話です。Javaなら無名クラスを作ってもいいし、どんな言語でもだいたい実装は可能です。

調べてみると、このタイプの処理にコピペは発生します。コピペで関数を複製しcallbackのロジックを差し替えている事例が多数見つかりました。難しい実装ではないはずなのにおかしいなと感じるポイントです。

なぜコピペが発生するのか

コピペが発生するタイミングと言うものが存在しています。過去のログを遡って行くと、ここにも一定のパターンがあります。3の要求は最初から3の要求の体裁をしているわけではないのが大きな要因です。

要求3′
2の要求から追加で、掛け算か足し算どちらか指定して、その表を返す関数を作れ

最初は任意のなんてことは言わず、フラグで管理すればよいという要求であることが多いです。

これで済めば問題ないのですが、追加の要望が大量にされた時にこの方法は崩壊します。最終的に多数のロジックを組み込もうとして、switchでは収集がつかず、複雑なif分の連続による複雑な内容になってしまいます。そこにさらに追加の要件を追加しようとすると、既存の関数は触らずコピペで増やすという行動に結びつきます。これがコピペが発生する原因です。その結果、ソースは荒れていくことになります。

ロジックの抽象化

ソースコードを修整する上で、関数の引数を追加することは多くの人が出来ることだと思います。しかし、外部からロジックを注入する形に書き換えることを発想として持っているメンバーは多くはないようです。無理して書き換えなくてもどうにかなることが多いのも事実で、今までにやったことがないメンバーも居るのではないかと思います。

何らかの方法でロジックを注入する構造に変えるには、ロジックの捉え方の抽象度を一段階上げる必要があります。つまりは、ロジック自体も変数の中身や、引数の値のように交換されうるものだと考えてロジックを組み上げる必要がでてきます。

OOPではこのロジックの交換をクラスの継承によるオーバーライドで仕様レベルに組み込まれていることが殆どだと思います。オーバーライドを使わないとクラスの継承をする意味はあまりないので、OOPを勉強してつまずくのも仕方ないことかもしれません。

センスのありなしではなく上達を目指す

ロジックの一部を交換可能なものとして考えるのは一種の発想の飛躍が必要になります。そこにプログラミングの上達を妨げる壁がある気がしてならなりません。出来るようになったからといって上達に結びつくとは限りませんが、プログラマーの成長の上で必要となる能力ではあります。

立場上、人にプログラミングを教えることも多いのですが、こういった領域は「センス」という言葉で片付けて来てしまいました。今後は「センス」で片付けられる領域もパターンを整理し、上達を目指すべきだと考えています。こういった領域の話が語れるなら、もっと語られるべきなんじゃないかと思います。