Flutter解析ツールのDCMを使ってみた（無料版）

# はじめに
先日[FlutterNinjas2025](https://flutterninjas.dev/)に参加し、そこで紹介された[DCM](https://dcm.dev/)(Dart Code Metrics)というDart&Flutter解析ツールが紹介されました。
最近コードの品質を保つのに少し悩んでいたこともあり、興味が湧いたので実際に使ってみました。

この記事では、DCMの導入から解析結果を軽く解説します。コードを綺麗に保ちたい、現在のコードを評価してみたい方は試していただければとおもいま
DCMは無料で使えるライセンスがあるため、今回は無料版を使ってみます。
# 導入
### ライセンスキーの取得
[こちら](https://dcm.dev/pricing/)からStart for Freeを選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/9e33e5af-a38a-4f1b-a0f5-9f75a19e4c47.png)
メールアドレスを入力しSubmit order
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/dda98276-55b9-4b8c-b50c-a14f036394a4.png)
License Keyと手順が記載されたメールが届きます。

## DCMのインストール
https://dcm.dev/docs/getting-started/installation/macos/
### Homebrewのインストール
すでに開発を行っている方は入っていると思いますが一応
[Homebrew](https://brew.sh/)
```
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
### DCMのインストール
Homebrewインストールに以下のコマンドを実施
```
brew tap CQLabs/dcm
brew install dcm
```

これで完了です。

## エディタへの適用
今回はVS Codeに入れていきます。
いつも通りExtensionsにてDCMを検索しインストール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/03b72d25-1b4f-4839-80ed-3d9513d4a181.png)

チーム内で拡張機能を合わせる必要があれば`.vscode/extensions.json`に以下を追記。
```
{
  "recommendations": ["publisher.dcm"]
}
```

### ライセンスをアクティベート
ライセンスはデバイスに紐づかれるため共有などはできません。

以下のコマンドでメールに届いたライセンスキーをアクティベートします。
```
dcm activate --license-key={ここにライセンスキーを入力}
```
以下のコマンドでDCM License: Free  Version: x.xx.xと表示されたらOKです。
```
dcm license
```

有料版のみになりますがCI/CD環境でDCMを自動的に実行して品質をチェックできます。

## プロジェクトに統合
DCMのルールを追加していきます。
有料版であれば recommended を設定するだけで、いい感じにルールを適用してくれるのですが、無料版ではルールを一つずつ追加していく必要があります。

とりあえず以下のページから無料のルールを詰め込みましょう。有料版だとあったら嬉しいルールがちらほら見受けられます。
https://dcm.dev/docs/rules/

今回は無料以下のFlutterのルールを追加してみます。以下を`analysis_options.yaml`に追記します。
``` analysis_options.yaml
dart_code_metrics:
  rules:
    - always-remove-listener
    - avoid-expanded-as-spacer
    - avoid-returning-widgets
    - avoid-shrink-wrap-in-lists
    - avoid-wrapping-in-padding
    - check-for-equals-in-render-object-setters
    - prefer-const-border-radius
    - prefer-correct-edge-insets-constructor
    - prefer-text-rich
```

| ルール名 | 説明 |
|----------|------|
| always-remove-listener | イベントリスナーを追加したが、削除していない場合に警告します。 |
| avoid-expanded-as-spacer | 空の SizedBox/Container ウィジェットを含む Expanded ウィジェットの代わりに Spacer ウィジェットを使用することを提案します。 |
| avoid-returning-widgets | メソッドや関数が Widget または Widget のサブクラスを返す場合に警告します。 |
| avoid-shrink-wrap-in-lists | shrinkWrap パラメータを持つ ListView ウィジェットが Column、Row、または別の ListView ウィジェットにラップされている場合に警告します。 |
| avoid-wrapping-in-padding | ウィジェットが Padding ウィジェットにラップされているが、自身に padding 設定がある場合に警告します。 |
| check-for-equals-in-render-object-setters | RenderObject のセッターで、新しい値に対する等価性チェックがない場合に警告します。 |
| prefer-const-border-radius | BorderRadius.circular コンストラクタの代わりに const BorderRadius.all コンストラクタを使用することを提案します。 |
| prefer-correct-edge-insets-constructor | 正しい EdgeInsets コンストラクタを使用することを提案します。 |
| prefer-text-rich | RichText ウィジェットの代わりに Text.rich を使用する場合に警告します。 |

ルールが多すぎてよく分からないという方は、まず以下のコマンドを使って、dcmで利用可能なすべてのLintルールで解析してみましょう。
どのルールに引っかかっているのかを確認したうえで、必要なものだけを追加するかどうかを判断できます。
```
dcm init preview lib
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/801db58c-ff27-4064-82f6-e69adcc99940.png)
それぞれのルールに対してのissue数を確認できます。

ルールを設定したら解析をしていきましょう。

## コード解析
コマンドは基本的に`dcm [解析種類] <解析したい場所>`になります。
今回はlibフォルダに対して様々な解析を行っていきます。

まずは以下のコマンドでLintルールに基づいて分析し、問題を見つけてくれます。
```
dcm analyze lib --reporter=console
```
たくさんの issues が出てきました。
`--reporter=console`オプションをつけることで、どのファイルでどんな警告が出ているのかを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/5aa35b7b-b9e1-4c84-9248-b999f270c7c0.png)


## プロジェクトのアーキテクチャを可視化する
ファイルの依存関係を可視化することができます。
dotファイルを生成しそれを可視化するためのGraphvizが必要であるため以下でインストールします。
※インストールに少し時間がかかります。
```
brew install graphviz
```
以下のコマンドでファイルの依存関係を可視化することができます。プロジェクトのルート直下にpng画像が生成されます。
```
dcm analyze-structure lib | dot -Tpng -Gdpi=200 -o example.png
```
実際の画像はお見せできませんが、以下のような図が出てきます。
今回解析したプロジェクトではかなりグチャグチャな図がでてきました。アーキテクチャを見直す必要があるようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/317d7195-8930-44e2-a53c-107c8ff4a05b.png)


## コードメトリクス解析
コードのメトリクス（品質、複雑さ、保守性など）を算出してくれます。
まずは`analysis_options.yaml`に以下からメトリクスの設定を選んで追加します。
https://dcm.dev/docs/metrics/

今回は以下で設定します。設定値に関しては様々な資料があるため調べて設定してみましょう。数値についてはデフォルトのものを使用しています。
```analysis_options.yaml
dart_code_metrics:
  metrics:
    # 循環的複雑度(分岐やループを調べて複雑さを測る)
    cyclomatic-complexity: 20
    # コード行数
    lines-of-code: 80
    # Halsteadボリューム(コードのサイズや記述労力を推定する)
    halstead-volume: 150
    # 保守性指数 (循環的複雑度や行数、Hslsteadボリュームから算出)
    maintainability-index: 50
    # 最大ネストレベル
    maximum-nesting-level: 5
    # パラメータ数
    number-of-parameters: 4
    # Widget数
    number-of-used-widgets: 20
```
設定できたら以下のコマンドで解析しましょう。
```
 dcm calculate-metrics lib
```
結果がでました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335560/1128bf1b-0f5e-45bc-855c-87ba240c1165.png)
それぞれどのような結果なのか見てみましょう。
今回は循環的複雑度（CYCLO）、Halsteadボリューム（HALVOL）、保守性指数（MI）の3つのメトリクスに注目してみます。

**CYCLO（循環的複雑度）**
コード内の分岐やループの数を数値化したもので、コードの複雑さを示す指標です。この数値が高いほど、コードの理解やテストが難しくなります。

**結果**
最小値：0
最大値：21
平均値：2.3

これは、分岐やループのない非常に単純なメソッドもあれば、最大で21もの分岐やループを含む複雑なメソッドも存在することが分かりました。
平均値は2.3で、複雑なメソッドが少ない良い数値と言えるでしょう。

**HALVOL（Halsteadボリューム）**
Halstead複雑度のボリュームはコード上にある演算子(`+`,`-`,`&`など)とオペランド(変数名や数字)の種類と出現数をもとに、コードの大きさや複雑さを測ります。
数値が高いほどコードが大きく複雑であるとされ、一般的に100~1000が標準的な範囲、1000~8000以上はかなり高いと見なされるようです。

**結果**
最小値：0
最大値：3687
平均値：148

最大値3687はやや高めな数値で、膨大で複雑な処理を行っているメソッドがあることを示しています。
平均値は148と比較的低いので全体としては問題なさそうですね。

**MI（保守性指数）**
循環的複雑度や行数、Hslsteadボリュームから算出される値で、保守性（理解しやすいか、修正や機能追加が容易か）を測ります。
デフォルト数値が50で、この数値が低いほど改善が必要になります。以下の評価基準を見ると20を切ったら気をつけたほうがいいようです。

**結果**
最小値：19
最大値：100
平均値：75

最小は19で20を下回っているため対象のコードは保守性の改善が必要そうですね。平均値は75で全体としては問題なさそうです。

## 無料版ではできない分析
widgetやassetsの解析、コード品質のチェックもできますが、無料版ではissueの数だけ表示されどのコードが問題かは表示されません。

また、dcm analyze や dcm check-unused-code で見つかった問題は dcm fix で自動修正できますが、これも有料版でのみ利用可能のようです。

社内で有料版の稟議を出して時間があるときに解析してみたいと思います。

## 使ってみての感想
コーディングスタイルの統一や潜在的なバグを発見するLinterとは別に、DCMがコードの循環的複雑度や保守性指数といった数値でコードの健全性を可視化できるのはかなり面白いし、リファクタリングが捗りそうだと感じました。

ただ、無料版ではDCMの強みであるWidgetの解析や詳細な品質チェック機能が制限されているため、大規模なプロジェクトで利用するには有料版の導入が必要そうですね。

## 参考文献

https://jp.mathworks.com/discovery/cyclomatic-complexity.html
https://learn.microsoft.com/ja-jp/visualstudio/code-quality/code-metrics-maintainability-index-range-and-meaning?view=vs-2019