ソフトの開発中にバグの発生数が大きくなりすぎたり、開発速度があまりに遅すぎたりしてもらっては困るわけです。
じゃあ、それらを改善するためには何をすればいいんだろう?ってことで、「サイクロマティック複雑度」を測って、その数値が大きすぎたら機能を分けたらいいんじゃない?って考え方をMcCabeという方が提唱していたということを、前回記事では書きました。
その中でも、こんな条件分岐はスパゲッティプログラムを作りやすいから注意しなさいよーってことも書かれていましたので、今回の記事ではそのあたりについて書いていきます。
それと、ちょっと時間が経って改めて考え直してみたら、サイクロマティック複雑度って本当に使えるのかな?って思うようなところも出てきたので、そのあたりの考察もしていきます。
※スパゲッティプログラムってのは、処理が色んな所に飛んでて、解読がめちゃくちゃ難しいプログラマ泣かせのプログラムのことです。
問題になる条件分岐
結論から先に言っちゃいますと、論文の中で問題視されている条件分岐は4種類ありまして、次の4つになります。
- ループ内への分岐
- ifブロック内への分岐
- ループ外への分岐
- ifブロック外への分岐
これら4つの分岐には特徴がありまして、どれもソースコードを読みにくくする原因になりやすいんです。もしかしたら、「分岐」と言うよりも「ジャンプ」と書いた方が分かりやすかったかもしれません。
というのも、これらを実現するにはgoto文が必要になってきてしまうんですな。「goto文」で勘のいい方なら気づいたかもしれませんが、要するにスパゲッティプログラムの話です。
不用意にgoto文を使うと処理とか変数の状態とかを追いかけるのが大変になって、プログラムの理解に時間がかかるようになってしまうんですな。
逆に言えば、上記4種類の分岐はgoto文を使わない限り発生しないので、goto文は極力使わないようにしましょうという話になるでしょうな。
とは言え、goto文が絶対的な悪者かといえばそんなことも無くて、2重ループから一気に抜け出したいときとか、エラー処理を関数の後半部分にまとめて書いておきたいときとかには結構便利だったりします。
あくまで、上記4種類の分岐はプログラムの可読性を悪くするから、特別な理由がない限りgoto文を使うのは避けようね、って感じの話に落ち着くかと思います。
サイクロマティック複雑度って本当に使えるの?
さて、ざっくりと論文を紹介してきましたが、この論文にはいくつか疑問の余地があるんですな。それは、
- 本当に効果があるのか?
- 仮に効果があるとして、現在でも効果があるのか?
っていう2つです。
本当に効果があるの?
ソースコードの複雑さを測る最終目的はテストをやりやすくする(テスト条件が簡単に分かるようなプログラムにしておく)、保守性を高める(バグを取りやすくする)といった辺りになるかと思います。
この論文ではあくまで、こんな考え方があるよーってのが示されただけで、本当にサイクロマティック複雑度を調整すればプログラムを改善できるのか?って辺りはこの論文では示されてないんですな。
なので、実際にサイクロマティック複雑度を測ってソースコードのテスト性を良くしたり、保守性を高めたりできるのか?できるのだとすれば、どんな条件のときに出来るのか?(どんなときでもサイクロマティック複雑度を測ればいいのか?)etc.って辺りについては、「実際にやってみないと分からない」とか「(あれば)サイクロマティック複雑度の効果を調査した論文を読まないと分からない」が結論になってしまいます。
要するに、複雑度を測ることが出来ても、ソフトウェア開発の役に立たなかったら意味ないよねーって話です。
現在でも効果あるの?
こちらも、先ほどの開発の役に立たなかったら意味ないよねーって話と似たような話なんですが、論文が書かれた当時から環境が大きく変わっているわけです。それでも、本当に効果があるの?って話です。
というのも、当時はPythonとかC++とかがまだ登場していない時代で、FortranとかCOBOLなんかが普及してた時代なんです。
で、そのFortranとかCOBOLとかでは構造化プログラミングの概念が取り入れられてなかったんです。ざっくりと言うと、めちゃくちゃ注意深く書かないとスパゲッティプログラムになってしまう言語のことです。
要するに、この論文はスパゲッティプログラムになってしまう問題が前提にある状態で書かれたようなものなので、この論文が、現在のC++とかPython、Javaみたいなオブジェクト指向言語にも適用できるのかどうかは不明なんです。
今ではそんなにgoto文を使う機会も無いし、if文ブロック内に飛ぶような処理も書かないし、この指標は果たしてどこまで使えるんだろう?ってことですな。
まとめ
結局、この論文から得られることは、goto文は特別な理由がない限りは極力使わないようにしましょうっていうごくありきたりな警告くらいになりそうです。
それと、サイクロマティック複雑度と論文について色々と問題点を書きはしましたが、ソフトウェアの規模が大きくなればなるほど分岐とかループの数も増えてくるので、サイクロマティック複雑度がコードの規模のとある側面を示していることは間違いないと思います。
なので、構造化プログラミング言語(C言語とか)とかオブジェクト指向言語を使われている方向けには、「コード行数はそんなに多くないのに、サイクロマティック複雑度がやけに大きいな。どこかの機能を別の関数として定義した方が良いかもな」みたいな感じで、機能を分割するかどうかの客観的な判断材料として使えるかも?ってくらいのことは言えるかと思います。