15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Objective-C の循環的複雑度を計測する

Last updated at Posted at 2016-12-27

諸般の事情があり Objective-C のコードをレビューしているが、if else のネストが多く循環的複雑度を計測したくなったので計測してみた。

循環的複雑度(CCN)って?

循環的複雑度は英語で cyclomatic complexity number であり、 CCN と略される。

ざっくり言うと、if や switch が多いコードは分岐が多くなるので、その分岐を数字で表したもの。
CCN が 10 以下なのは良い構造であり、それ以上はよろしくないとされている。
(指標なので、絶対的にそうだというわけではない)

が、個人的に CCN が 5 を超えるとコードを追うのが辛くなってくる。(コードにもよるが)

計測してみる

OCLint で開発しながら計測するのがよさそうだが、今回はとりあえず計測だけしたかったので OCLint は使っていない。

terryyin/lizard で ObjC の CCN を計測

他にも色々とあるようだが、 GitHub で検索して出てきた terryyin/lizard を使ってみる。

Mac なら python 入っていると思うので、 pip で install できる。

$ pip install lizard

実際に計測

Pods や gem なども計測対象になるので、計測したいコードがあるディレクトリに移動して lizard コマンドを実行する。

$ cd PROJECT_ROOT/PROJECT
$ lizard -Tcyclomatic_complexity=10
================================================
  NLOC    CCN   token  PARAM  length  location
------------------------------------------------
       3      1     19      0       4 application: didFinishLaunchingWithOptions:@18-21@./AppDelegate.m
       2      1      9      0       4 applicationWillResignActive:@24-27@./AppDelegate.m
       2      1      9      0       4 applicationDidEnterBackground:@30-33@./AppDelegate.m
       2      1      9      0       3 applicationWillEnterForeground:@36-38@./AppDelegate.m
       2      1      9      0       3 applicationDidBecomeActive:@41-43@./AppDelegate.m
       2      1      9      0       3 applicationWillTerminate:@46-48@./AppDelegate.m
       5      1     35      2       5 main@12-16@./main.m
       3      1      8      0       4 viewDidLoad@17-20@./ViewController.m
       3      1      8      0       4 didReceiveMemoryWarning@23-26@./ViewController.m
5 file analyzed.
==============================================================
NLOC    Avg.NLOC  AvgCCN  Avg.token  function_cnt    file
--------------------------------------------------------------
      3       0.0     0.0        0.0         0     ./AppDelegate.h
     17       2.2     1.0       10.7         6     ./AppDelegate.m
      5       5.0     1.0       35.0         1     ./main.m
      2       0.0     0.0        0.0         0     ./ViewController.h
     10       3.0     1.0        8.0         2     ./ViewController.m

=============================================================================================
No thresholds exceeded (cyclomatic_complexity > 10 or length > 1000 or parameter_count > 100)
==========================================================================================
Total nloc   Avg.NLOC  AvgCCN  Avg.token   Fun Cnt  Warning cnt   Fun Rt   nloc Rt
------------------------------------------------------------------------------------------
        37       2.7     1.0       12.8        9            0      0.00    0.00

作成して何もしていない Project なので問題のあるコードはないと出ている。

if 文を大量に置いて計測

精神が不安定になるコード:

- (void)viewDidLoad {
    [super viewDidLoad];
    if (true) {
        if (true) {
            if (true) {
                if (true){
                    if (true){
                        if (true){ }
                    }
                }
            }
        }
    } else {
        if (true) { }
    }
    if (true) { }
    if (true) { }
    if (true) { }
    if (true) { }
}

lizard を実行

$ lizard -Tcyclomatic_complexity=10
... 略 ...

=========================================================================================
!!!! Warnings (cyclomatic_complexity > 10 or length > 1000 or parameter_count > 100) !!!!
================================================
  NLOC    CCN   token  PARAM  length  location
------------------------------------------------
      21     12     77      0      22 viewDidLoad@17-38@./ViewController.m

CCN が 12 になりました、Warning で教えてくれています。

コードの品質を計測することができました :tada:
(ただし、 CCN はあくまで一つの指標です)

こうならないために

早期リターンをしたり、メソッドの分割をしてネストを浅くしていきましょう :muscle:

おまけ

本当に 10 以下なら問題ないと言えるのか?

このコードで CNN は 7 、だがどう見てもこれは... :scream:

- (void)viewDidLoad {
    [super viewDidLoad];
    if (true) {
        if (true) {
            if (true) {
                if (true){
                    if (true){
                        if (true){ }
                    }
                }
            }
        }
    }
}

Swift も計測できる

いま仕事で書いているコード。
SwiftLint で設定しているのでそれと同じ結果だが、 Swift の場合 enum の switch case 増えるしそこで CCN 高くなると思うのだが皆どうしているんだろう。

========================================================================================
!!!! Warnings (cyclomatic_complexity > 5 or length > 1000 or parameter_count > 100) !!!!
================================================
  NLOC    CCN   token  PARAM  length  location
------------------------------------------------
      18     15    127      1      18 hoge@134-151@./Hoge/Error.swift
      30      8    142      1      31 hoge@28-58@./Hoge/Message.swift
      11      6    117      0      11 hoge@59-69@./Hoge/Controller.swift
15
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?