Measure cyclical complexity of Objective-C
There are vaious articles about reviewing Objective-C code, but because of there are so many "if-else nest" inside the code so i wanted to measure the cyclical complexity of those nests For short, because if and switch blocks in our code create many logic branches, so CCN is a number implies to ...
There are vaious articles about reviewing Objective-C code, but because of there are so many "if-else nest" inside the code so i wanted to measure the cyclical complexity of those nests
For short, because if and switch blocks in our code create many logic branches, so CCN is a number implies to that logic branches.
If CCN is less than 10 then the code structure is good. The structure is not good if CCN is more than 10.
But for my personal point of view, it is harder and harder to follow the code that has a more-than-5 in terms of CCN (code becomes dark)
Related Articles
- https://en.wikipedia.org/wiki/Cyclomatic_complexity
It is ok if we measure by OCLint (http://oclint.org/) while developing, but this time I just wanted to measure so i did not use OCLint
Measure the CCN of Objective-C by terryyin/lizard (https://github.com/terryyin/lizard)
There are so many tools for us to try, but i did search on Github and decided to use terryyin/lizard this time
I think python is already installed on your Mac so we can install it by pip
$ pip install lizard
Actual Measurement
Pods and gem can also be measured, so that we have to navigate to the directory that we want to measure and run the lizard command
$ 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
This is the result for a brand new project with no code inside (no problem found)
Put a large amount of if blocks and measure
I put a really bad code like this:
- (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) { } }
Run 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 is calculated equals to 12, and a warning added too
We are able to measure the code quality now (if CNN is counted one of the criterias)
How to avoid this?
We can return sooner, and break method into smaller blocks to get rid of building a nest in our code
Does it really "not matter" if the code has CNN less than 10?
Following is the CNN-equals-7-code looks like:
- (void)viewDidLoad { [super viewDidLoad]; if (true) { if (true) { if (true) { if (true){ if (true){ if (true){ } } } } } } }
6 blocks of if makes the code looks like a mess...
We can get the same result if we set by SwiftLint
The CNN will be getting higher in Swift if we add more and more switch case of enum
======================================================================================== !!!! 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