0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Qlty によるコードの品質チェック

0
Posted at

Qlty

Qlty は Code Climate Quality の次世代版のオープンソースの静的解析コードツールセットで、各種プログラミング言語に対応している。
ここでは、コード品質の指標を試してみる。
指標は以下の通り。

  • classes: クラス数

  • funcs: 関数(メソッド)の数

  • fields: クラスのフィールド (メンバ変数・プロパティ) の数

  • cyclo (Cyclomatic Complexity): 循環複雑度

    • if、for などの制御構文による分岐の数
  • cognitive (Cognitive Complexity): 認知複雑度

    • if、for などのネストの深さ
  • LCOM (Lackoh of Cohesion in Metrics): 凝集度の欠如

    • クラス内のメソッドとフィールドの関係性の薄さを表す指標で、クラス内の各メソッドがどれくらい同じフィールド(変数)をしようしているか
  • lines (Total Lines): プログラムの全行数

  • LOC (Lines of Code)

    • 空行やコメント行を除いた、実行可能な実質的なコードの行数

インストール

curl -fsSL https://qlty.sh | bash
source ~/.bashrc

使い方

qlty は docker コンテナ内の各種プログラミング言語の静的アナライザを呼び出す。
そのため、qlty を実行するには、まず docker を起動する。

sudo systemctl start docker

初期化

ソースコードがあるディレクトリに移動する。

cd test1

qlty は git リポジトリ内での動作を前提としているため、非 git ディレクトリでは動作しない。
ここでは qlty の動作検証を行うために git init でリポジトリ化する。

git init

qlty init を実行すると、qlty で解析を行えるようになる。

qlty init

指標の出力

qlty metrics で指標を表示することができる。

qlty metrics -a

ここでは、以下のプログラム (test1.py ) を対象とする。

test1/test1.py
def main():
    print('test')
    return 0

if __name__ == '__main__':
    main()

解析結果は以下の通り。

 name     | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
----------+---------+-------+--------+-------+---------+------+-------+-----
 test1.py |       0 |     1 |      0 |     2 |       1 |    0 |     6 |   5
 TOTAL    |       0 |     1 |      0 |     2 |       1 |    0 |     6 |   5

比較

プログラムを変更して、各指標がどのように変化するかを比較してみる。

比較1. classes/fields

以下のプログラム (test2.py) ではクラスを定義している。
test1.py と評価結果を比較してみる。

test1/test2.py
class Test:
    def __init__(self, msg1, msg2):
        self.msg1 = msg1
        self.msg2 = msg2

    def show_3(self):
        print(self.msg1, self.msg2)
        print(self.msg1, self.msg2)
        print(self.msg1, self.msg2)

if __name__ == '__main__':
    test = Test('hello')
    test.show_3()
 name     | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
----------+---------+-------+--------+-------+---------+------+-------+-----
 test1.py |       0 |     1 |      0 |     2 |       1 |    0 |     6 |   5
 test2.py |       1 |     2 |      2 |     2 |       1 |    1 |    13 |  11

test1.py では classes=0 だったが、test2.py ではクラスを定義したたため、classes=1 となっている。
また、fields はメンバ変数の数のため、test1.py では fields=0 だが、test2.py では fields=2 となっている。

比較2. cyclo (循環複雑度)

以下のプログラム (test3.py) では for 文を使用している。
test2.py と評価結果を比較してみる。

test1/test3.py
class Test:
    def __init__(self, msg):
        self.msg = msg

    def show_n(self, n):
        for i in n:
            print(self.msg)

if __name__ == '__main__':
    test = Test('hello')
    test.show_n(10)
 name     | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
----------+---------+-------+--------+-------+---------+------+-------+-----
 test2.py |       1 |     2 |      2 |     2 |       1 |    1 |    13 |  11
 test3.py |       1 |     2 |      1 |     3 |       2 |    1 |    11 |   9

test3.py では for を使用したため、cyclo の値が 1 増えている。

比較3. complex

complex を比較するために、if 文を並列に実行する場合 (test4.py)と、if 文をネストさせた場合 (test5.py) を比べてみる。

test1/test4.py
class Test:
    def __init__(self, msg):
        self.msg = msg

    def show_n(self, n):
        for i in n:
            if i % 2 == 0:
                print(self.msg)
            if i % 3 == 0:
                print(self.msg)

if __name__ == '__main__':
    test = Test('hello')
    test.show_n(10)
test1/test5.py
class Test:
    def __init__(self, msg):
        self.msg = msg

    def show_n(self, n):
        for i in n:
            if i % 2 == 0:
                print(self.msg)
                if i % 3 == 0:
                    print(self.msg)

if __name__ == '__main__':
    test = Test('hello')
    test.show_n(10)

指標は以下の通り。

 name     | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
----------+---------+-------+--------+-------+---------+------+-------+-----
 test3.py |       1 |     2 |      1 |     3 |       2 |    1 |    11 |   9
 test4.py |       1 |     2 |      1 |     5 |       6 |    1 |    14 |  12
 test5.py |       1 |     2 |      1 |     5 |       7 |    1 |    14 |  12

test3.py と比べて test4.py、test5.py は if 文が 2 つ増えたため、cyclo が 3 から 5 に増えている。
一方、complex は test4.py では complex=6、test5.py では complex=7 となっていて、ネストしている方が complex の値が大きくなっていることがわかる。

qlty metrics のオプション

  • -a/--all: ディレクトリ配下の全プログラムを対象として指標を出力する。

  • --functions: 関数単位で指標を出力する。cognitive が出力される。

    qlty metrics --functions test5.py
    
     function | fields | cyclo | cognitive | lines | loc
    ----------+--------+-------+-----------+-------+-----
     __init__ |      1 |     1 |         0 |     2 |   2
     show_n   |      1 |     4 |         6 |     6 |   6
    
  • --sort: ソートのキー。例えば、--sort lines で行数の降順にソート。

    qlty metrics -a --sort lines
    
     name     | classes | funcs | fields | cyclo | complex | LCOM | lines | LOC
    ----------+---------+-------+--------+-------+---------+------+-------+-----
     test5.py |       1 |     2 |      1 |     5 |       7 |    1 |    14 |  12
     test4.py |       1 |     2 |      1 |     5 |       6 |    1 |    14 |  12
     test2.py |       1 |     2 |      2 |     2 |       1 |    1 |    13 |  11
     test3.py |       1 |     2 |      1 |     3 |       2 |    1 |    11 |   9
     test1.py |       0 |     1 |      0 |     2 |       1 |    0 |     6 |   5
     TOTAL    |       4 |     9 |      5 |    17 |      17 |    4 |    58 |  49
    
  • --exclude-tests: テストコードを除外。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?