dart_code_metricsを試してみた

image_1

はじめに

2023年はコード品質の向上に積極的に取り組んでいきたいと思っており、前から気になっていた dart_code_metrics パッケージを試してみた。

これは文字通りDartのコードを静的解析して、改善点を提示してくれるツール系のパッケージ。

所感を言うと使いやすい。解析したいケースも複数 (未使用コード, 未使用ファイル, 不要Null許容パラメータ検出) 揃っていて、丁寧なドキュメントコードも揃っているし、カスタマイズもできる、メンテナンスもよくなされている印象を受ける。

他言語の静的解析ツールを使い倒した経験がないため、この標準機能群がどれほど整っているのか、優れているのかは判断しかねるが、デファクトスタンダードに則った環境で使えば、普通に良いツールだと思った。

自分は普段巨大なDartプロジェクトの開発をしている。

image_2

(JsonSerializable系の自動生成コードが一部入っているが、ほぼ純粋な実装コード)

以下では、この巨大なDartコード群の中で静的解析を試した結果とそこで感じた手触り感を紹介してみる。※ 詳細なコード情報などは出てきません

なお、ここでは詳細なツールの使い方などには触れません。公式ドキュメントが非常に丁寧に整備されているため、そちらを参考にしてください。

目次

解析結果の確認

dart_code_metrics ではCLI操作でコマンド実行することで解析を行い、結果を確認することができる。解析結果はコマンド実行後のConsoleに表示される or HTMLコードが吐き出されて、ブラウザ上からも確認できる。

image_8

(CLI上ではSTYLEやWARNINGの問題をハイライトで示される)

巨大なコード群の解析を俯瞰して確認したい場合はConsoleよりもHTMLコードを確認した方が良いなという印象。解析先のコードを表示した上で、どこに何の問題があるのかを指摘してくる。さらに、ディレクトリ単位で見ることもでき、ファイルごとに解析のサマリーも見れる。

解析結果とフィードバック

Analyze

特に追加で制約は設けずにプリセットで実行し、いくつかフィードバックを受け取った。

チームとしても厳密に定義してこなかった重箱の隅のようなコーディングルールに対してのコメントだったので、”まぁそうだね” という印象。Dart Code Formatterを使えば、一気に変更を適用できるし、Lint Ruleを追加すれば、以後ファイルをセーブするタイミングで自動でFormatを効かせてくれたりもするので、いくつかのフィードバックコメントはチームに確認した上で適応させていこうと思う。

newline-before-return のreturn手前にワンライン空けるものや、prefer-moving-to-variable などは導入したい。逆に avoid-ignoring-return-valuesavoid-non-ascii-symbols は検討して導入を見送りそう。

image_3

(ファイルごとのカルテが示される)

Cyclomatic complexitySource lines of codeMaximum Nestingといったコードの指標に関しても評価してくれる。これも評価結果がHTMLで確認できるのが良い。

マルチテナントプロダクトであるが故にswitch文が増え、cycloが増加してしまい解析結果としては厳しい内容なっていたりする。Technical Debtは1つもなかった。引数の過剰渡しや地獄のようなネストもない(確認した限りでは最大でも4階層)。

コード上の評価でどこが複雑性の要因となる箇所なのか、どう評価されるのかがわかるので、リファクタリング箇所を発見する手助けにもなりそう。これ自体がコードの可読性向上を支える適応度関数として見ることができる。

解析結果でアラート表記に変える基準はカスタマイズ可能なので、自分たちの目指したい品質水準に合わせて設定を調整するのが良い。

image_4

(cycloのカウントがなされる箇所が示される)

Check unnecessary nullable parameters

メソッドのパラメータに対して、不必要なnullable対応が含まれているかを教えてくれる。

この解析はよく理解できなかった。nullableなフィールド宣言に対して、constructorでnamed parameterを要求すると、不必要なnullable parametersと認識されてしまう。

確かにnullableならparameter宣言をやめてsetterを使って対応でも良いかもしれないが、constructor時点で値 (null値を含めて) をセットしたいこともあるし、することで問題が起きうる理由がわからなかった。今後改修予定かもしれない。もしくは自身の見方が間違っているかも。

例えば、以下の例は不必要なnullable対応であると指摘される。

class Ticket {
  String name;
  String? subject;
  String? comment;

  Ticket({
    required this.name,
	this.subject, // こことか
	this.comment, // これも
  })
}

Check unused files

unused filesを試すと、いくつか未使用のファイルが見つかった。

どれも1年以上前に作られたファイルだが、途中実装方針の転換を受けて参照がなくなったもののようで、残骸のようなファイル。今後も使いそうなものでもないので削除していこうと思う。

プロジェクト自体が大きくなると人の目検でファイルの有効性を確認するのはどうしても難しくなる。そういう場合にこそ、この解析ケースを使うのは有用だと思った。

気になる課題点として、解析対象のディレクトリ内からの参照がないと未使用だと認識されてしまう点があった。

例えば、 root/lib/src 以下に主要な処理ファイルを置き、実行ファイルを root/bin/main.dart と置いたとする。 bin/main.dart から lib/src 以下のコードを参照している場合、 main.dart からのみ参照されているファイルは、解析範囲外になるため未使用に分類されてしまう。結果、不要な結果対象が表示されている事態に。

そりゃそうだろという感じだが、実行時に特定ファイルはignoreすることもできるので、調整すると綺麗に解析が行われそう。

Check unused code

この解析は微妙だった。残念ながらこの機能で期待通りの未使用なコードを解析して見つけることはできなかった。

先のCheck unused filesで触れた、「解析対象のディレクトリ内からの参照がないと未使用だと認識されてしまう」ケースが多々あり、toolのInterfaceから参照されているコードや、実行ファイルから参照されているコードは未使用認識されてしまう。

これはツールが悪いというより、自分たちのコード構成がデファクトスタンダード(lib/srcにまとめる)に則っていないが故に起きている問題。ツール自体は期待通りの振る舞いをしていると思う。

体裁を整えた上で実行すれば、きちんとした解析のもと未使用コードを検出してくれそう。

なお、デファクトスタンダードに則っている内製のパッケージ類ではきちんと機能しており、未使用のコードは見つからない判定をもらえている。(ヨカッタ)

image_5

Check unused l10n

localizationのアプローチは取っていないので、割愛。

可読性の向上に寄与するが効果は限定的

使ってみた感想としては、気づけた点がある時点で良かったと思っている。

大きな効果を生みそうかというと、そこまでのインパクトはなさそう。

これはもとからきちんとコード規約やフォーマッターの運用をやってきていれば、ある程度体裁が整ったコードに仕上がっているためで、厳しいフィードバックを受けそうにないから

都度静的解析の運用があっても損はないが、最悪なくても大丈夫かもしれないというのが自分の印象。

自分たちは解析での明らかになる課題よりも、そこに現れないコード構成やモデリングの表現、組織的な言葉の定義の方が課題感として強く、その課題解決の方が今は重要だということがわかった。

品質を底上げするには解析を運用フローに組み込んだ方が良いし、ここで取り組んだのは浅い実験内容なので、きちんと解析ルールをチューニングして整備すればもっとインパクトは出ると思う。自分たちはコードの静的解析でわかること以上に、モデリングの改善の方が課題感が大きいという感じ。

dart-code-metrics 自体のコードが綺麗

ツールを使ってみた話からは逸れるが、ツール自体のコードがめちゃくちゃ綺麗なので取り上げておきたい。

ツールを使ってみるのもおすすめしたいが、それ以上に自分は dart-code-metrics 自体のコードを読む方を薦めたい。(おい)

とても洗練されたモデリングから実装されており、初見で見てもどういった機能構成とデータ構造でツールが作られているのかが読み解ける。そこまで大きなツールでもないので、中級者レベルなら全部読み解けると思う。

image_6

(洗練された綺麗なコード構成で作られている)

Command, Reporter, Visitor, Analyzer, Config, Result Data Model, Constant Data Modelという整理がなされている。

image_7

(Factory Constructorsの理想の使い方)

ConstructorsやFactory方面のお作法( const を使うことや fromArg といったイディオム表現) もきちんと守られており、理想とするDartのコード表現になっている。前に書いた記事で自身が良いと考える書き方がそのまま反映されていて、やっぱりそうだよねという気持ちになった。

興味があればぜひ読んでみてほしい。

最後に

dart_code_metrics パッケージを試しに使ってみた感想を紹介してきた。

Dartはツールチェインのサポートも豊富で、開発者体験は非常に良いものが実現できているように思う。今回紹介した静的解析ツールもコードの品質向上に効果を発揮できそうな手応えを感じた。

最初期からきちんと整備した上で開発を進めている人にとってはツール導入の効果は薄いかもしれない。しかし、ツール自体は非常に優れているし、一度運用を整備してしまえばコスパが良いので、ぜひ導入を検討してみると良いかなと。

それでは、よいDartライフを! ;)

SHARES