tag:crieit.net,2005:https://crieit.net/tags/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6/feed 「循環的複雑度」の記事 - Crieit Crieitでタグ「循環的複雑度」に投稿された最近の記事 2019-09-26T13:00:18+09:00 https://crieit.net/tags/%E5%BE%AA%E7%92%B0%E7%9A%84%E8%A4%87%E9%9B%91%E5%BA%A6/feed tag:crieit.net,2005:PublicArticle/15415 2019-09-23T09:59:26+09:00 2019-09-26T13:00:18+09:00 https://crieit.net/posts/Haskell Haskellで複雑度測定 <p>※ この記事は<a target="_blank" rel="nofollow noopener" href="https://www.leo-leo.uno/2019/09/23/1050/">Haskellで複雑度測定</a>からの転載です。</p> <p>自分で書いているブログのPVが増えなくて悲しいので、こういうところにも載せて見たら多少増えるんじゃないかと思って試しに載せて見ます。</p> <hr /> <p>Haskellでサイクロマティック複雑度(循環的複雑度)を測定する場合、2つツールがあるようです。</p> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/mgajda/homplexity">homplexity</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/rubik/argon">argon</a></li> </ul> <p>githubのスター数はargonの方が多いのですが、コミット履歴を見るとhomplexityの方が今もメンテナンスされているようなのでhomplexityがオススメです。機能的な違いは特に調べていません。</p> <h3 id="homplexityの機能"><a href="#homplexity%E3%81%AE%E6%A9%9F%E8%83%BD">homplexityの機能</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://www.migamake.com/projects/homplexity.html">公式サイト</a>によれば、以下の統計値を出してくれるようです。</p> <ul> <li>Cyclomatic complexity</li> <li>Code metric</li> <li>Lines of code</li> <li>Branching depth</li> <li>Type metric</li> <li>Comment metric</li> <li>Code to comments ratio</li> <li>Type tree nodes</li> <li>Number of function arguments</li> </ul> <p>本題から外れますがBranching depthってなんでしょうか。説明には</p> <pre><code>Branching is used with conditionals and has been used as a criterion for both software complexity and logic. </code></pre> <p>と書いてあります。分岐の数のことなんでしょうか。ちょっと試して見たところ、if分岐がある場合でも0でしたが、ifの中にifをネストさせると1になり、ifの中にifの中にifとネストさせると2になりました。だから分岐の深さってことか。なんかサイクロマティック複雑度と似ていますね。</p> <h3 id="homplexityのインストール"><a href="#homplexity%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB">homplexityのインストール</a></h3> <p><a target="_blank" rel="nofollow noopener" href="https://docs.haskellstack.org/en/stable/README/">stack</a>が入っていれば簡単です。クローンしてstack installするだけです。</p> <pre><code class="bash">git clone https://github.com/mgajda/homplexity.git cd homplexity stack install </code></pre> <p>で、<code>~/.local/bin</code>に<code>homplexity-cli</code>ができるはずです。パスを通すなら、<code>~/.bashrc</code>や<code>~/.bash_profile</code>などに</p> <pre><code class="bash">PATH=$PATH:~/.local/bin </code></pre> <p>を追記すれば良いです。</p> <p>これで簡単にインストールできるのは良いのですが、このリポジトリで指定しているGHCバージョンが入っていない場合、そのインストールと依存パッケージのインストールから始めるので<strong>結構時間がかかる</strong>かもしれません。これがstackのデメリットですよね(メリットなのか?cabal hellという言葉を思い出した、そして<a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/50925938/what-is-cabal-hell">What is Cabal Hell?</a>というStackoverflowを見つけたw)。</p> <h3 id="使い方"><a href="#%E4%BD%BF%E3%81%84%E6%96%B9">使い方</a></h3> <p>githubリポにも書いてありますが、以下のようにメインモジュールファイルと依存モジュールのルートディレクトリを指定します。</p> <pre><code class="bash"># プロジェクトディレクトリ構成がこのようになっている場合 root --- app --- Main.hs | |- src --- Lib.hs |- ... homplexity-cli app/Main.hs src/ </code></pre> <p>これで、メインモジュールと依存モジュールファイル群を見つけて各メソッドの複雑度を測定してくれます。出力は、</p> <pre><code class="bash">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. </code></pre> <p>こんなのが出てきます。このファイルのこのメソッドが48行もあるから20行未満に抑えた方が良いよ、と言っています。これは複雑度ではありませんが。</p> <p>もっと詳細な情報を出して欲しい場合は<code>--severity</code>というオプションを使います。ログレベルの設定のような感じです。<code>homplexity -h</code>を見てもらえばわかりますが、</p> <pre><code># ヘルプの説明 --severity={Debug|Info|Warning|Critical} level of output verbosity (Debug Info Warning Critical) (default: Warning, from module: Main) </code></pre> <p>とのことなのでデフォルトはWarningですがInfoにすればもっと色々出てきます。以下はInfoで解析した時の出力の一部です。</p> <pre><code>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 </code></pre> <ul> <li>メソッドの行数</li> <li>コンストラクタのネスト数</li> <li>引数の数(+1された数字が出ている?Haskellの関数には暗黙的な引数が一つあるのかな?それか単に型一つにつき1とカウントしているのかな?)</li> <li>サイクロマティック複雑度</li> <li>Branching depth<br /> が出てきました。</li> </ul> <p>これは、Makefileなどに書いておいて、毎回ビルドの時に一緒に測定してもらうなどが良さそうですね。それかIDEでファイル保存のトリガーで実行してくれる方が良いのかな。そこで警告などが出てくれればソースコードを見直そうという気になるかもしれません。</p> reouno