2019-09-26に更新

Haskellで複雑度測定

※ この記事はHaskellで複雑度測定からの転載です。

自分で書いているブログのPVが増えなくて悲しいので、こういうところにも載せて見たら多少増えるんじゃないかと思って試しに載せて見ます。


Haskellでサイクロマティック複雑度(循環的複雑度)を測定する場合、2つツールがあるようです。

githubのスター数はargonの方が多いのですが、コミット履歴を見るとhomplexityの方が今もメンテナンスされているようなのでhomplexityがオススメです。機能的な違いは特に調べていません。

homplexityの機能

公式サイトによれば、以下の統計値を出してくれるようです。

  • Cyclomatic complexity
  • Code metric
  • Lines of code
  • Branching depth
  • Type metric
  • Comment metric
  • Code to comments ratio
  • Type tree nodes
  • Number of function arguments

本題から外れますがBranching depthってなんでしょうか。説明には

Branching is used with conditionals and has been used as a criterion for both software complexity and logic.

と書いてあります。分岐の数のことなんでしょうか。ちょっと試して見たところ、if分岐がある場合でも0でしたが、ifの中にifをネストさせると1になり、ifの中にifの中にifとネストさせると2になりました。だから分岐の深さってことか。なんかサイクロマティック複雑度と似ていますね。

homplexityのインストール

stackが入っていれば簡単です。クローンしてstack installするだけです。

git clone https://github.com/mgajda/homplexity.git
cd homplexity
stack install

で、~/.local/binhomplexity-cliができるはずです。パスを通すなら、~/.bashrc~/.bash_profileなどに

PATH=$PATH:~/.local/bin

を追記すれば良いです。

これで簡単にインストールできるのは良いのですが、このリポジトリで指定しているGHCバージョンが入っていない場合、そのインストールと依存パッケージのインストールから始めるので結構時間がかかるかもしれません。これがstackのデメリットですよね(メリットなのか?cabal hellという言葉を思い出した、そしてWhat is Cabal Hell?というStackoverflowを見つけたw)。

使い方

githubリポにも書いてありますが、以下のようにメインモジュールファイルと依存モジュールのルートディレクトリを指定します。

# プロジェクトディレクトリ構成がこのようになっている場合
root --- app --- Main.hs
      |
      |- src --- Lib.hs
              |- ...

homplexity-cli app/Main.hs src/

これで、メインモジュールと依存モジュールファイル群を見つけて各メソッドの複雑度を測定してくれます。出力は、

Warning:src/InterfaceAdapter/Presenter/StockAPIHandler.hs:SrcLoc "src/InterfaceAdapter/Presenter/StockAPIHandler.hs" 34 1:function stockServer has 48 lines of code should be kept below 20 lines of code.
Correctly parsed 16 out of 16 input files.

こんなのが出てきます。このファイルのこのメソッドが48行もあるから20行未満に抑えた方が良いよ、と言っています。これは複雑度ではありませんが。

もっと詳細な情報を出して欲しい場合は--severityというオプションを使います。ログレベルの設定のような感じです。homplexity -hを見てもらえばわかりますが、

# ヘルプの説明
 --severity={Debug|Info|Warning|Critical}  level of output verbosity (Debug Info Warning Critical) (default: Warning, from module: Main)

とのことなのでデフォルトはWarningですがInfoにすればもっと色々出てきます。以下はInfoで解析した時の出力の一部です。

homplexity-cli --severity=Info app/Main.hs src/
Info:app/Main.hs:SrcLoc "app/Main.hs" 1 1:module Main has 14 lines of code
Info:app/Main.hs:SrcLoc "app/Main.hs" 8 1:type signature for main has type constructor nesting of 1
Info:app/Main.hs:SrcLoc "app/Main.hs" 8 1:type signature for main has 1 arguments
Info:app/Main.hs:SrcLoc "app/Main.hs" 9 1:function main has 8 lines of code
Info:app/Main.hs:SrcLoc "app/Main.hs" 9 1:function main has cyclomatic complexity of 1
Info:app/Main.hs:SrcLoc "app/Main.hs" 9 1:function main has branching depth of 0
  • メソッドの行数
  • コンストラクタのネスト数
  • 引数の数(+1された数字が出ている?Haskellの関数には暗黙的な引数が一つあるのかな?それか単に型一つにつき1とカウントしているのかな?)
  • サイクロマティック複雑度
  • Branching depth
    が出てきました。

これは、Makefileなどに書いておいて、毎回ビルドの時に一緒に測定してもらうなどが良さそうですね。それかIDEでファイル保存のトリガーで実行してくれる方が良いのかな。そこで警告などが出てくれればソースコードを見直そうという気になるかもしれません。

Originally published at www.leo-leo.uno

reouno

Crieitは個人で開発中です。 興味がある方は是非記事の投稿をお願いします! どんな軽い内容でも嬉しいです。
なぜCrieitを作ろうと思ったか

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください!

ボードとは?

関連記事

コメント