Edited at

発表資料: sonarish で俺がお前を叱る

More than 1 year has passed since last update.


自己紹介


  • mizchi

  • フリーランス

  • リクルートでは yosuke_furukawa の元でR&Dみたいなことをしている



飛び入りLT用(発表ないかも)



yosuke_furukawa 「コードメトリクスツール作って」



コンテキスト


  • リクルート社内に膨大なJS含むプロジェクトがある

  • JSを(僕や yosuke_furukawa ぐらいに)真っ当に書ける人が少ない

  • いろんなプロダクトを串刺しでスコアリングして可視化したい



eslint は?


  • プロジェクトごとに運用のされ方が違う || そもそもない

  • 「1件でも落とすと exit-status = 1」 なので攻めたルールを採用しにくい



どうせだったらOSSにしようぜ => はい



※ 画面は開発中のものです



sonarish (仮)

$ npm i -g sonarish-cli

$ cd your-repo
$ sonarish src



実行例

$ cd sonarish

$ sonarish --detail
--- complexity
score: 96.4/100
┌──────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├──────────────────────┼───────┼──────────┼───────┤
│ no-shadow │ -2.6 │ 2 │ 2 │
├──────────────────────┼───────┼──────────┼───────┤
│ mutation/no-mutation │ -0.9 │ 1 │ 1 │
└──────────────────────┴───────┴──────────┴───────┘
--- best-practice
score: 92.9/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ import/no-extraneous-dependencies │ -2.5 │ 3 │ 4 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-console │ -2 │ 1 │ 22 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-unused-vars │ -1.8 │ 1 │ 18 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ compat/compat │ -0.6 │ 1 │ 2 │
└───────────────────────────────────┴───────┴──────────┴───────┘
--- meta-comments
score: 63.8/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-warning-comments │ -20.2 │ 4 │ 4 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-use │ -7.9 │ 1 │ 10 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-unused-disable │ -7.9 │ 1 │ 10 │
└───────────────────────────────────┴───────┴──────────┴───────┘



babel/babel

--- complexity

score: 61.1/100
┌──────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├──────────────────────┼───────┼──────────┼───────┤
│ no-param-reassign │ -15.7 │ 3 │ 106 │
├──────────────────────┼───────┼──────────┼───────┤
│ no-shadow │ -9.2 │ 2 │ 78 │
├──────────────────────┼───────┼──────────┼───────┤
│ max-lines │ -5.5 │ 2 │ 28 │
├──────────────────────┼───────┼──────────┼───────┤
│ mutation/no-mutation │ -5.2 │ 1 │ 601 │
├──────────────────────┼───────┼──────────┼───────┤
│ no-unreachable │ -2.9 │ 4 │ 2 │
└──────────────────────┴───────┴──────────┴───────┘
--- best-practice
score: 86.4/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ prefer-arrow-callback │ -4.8 │ 2 │ 503 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ import/no-extraneous-dependencies │ -3.6 │ 3 │ 25 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ promise/always-return │ -2 │ 2 │ 17 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-console │ -1.2 │ 1 │ 25 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eqeqeq │ -0.8 │ 1 │ 13 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ import/no-mutable-exports │ -0.6 │ 2 │ 2 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-unused-vars │ -0.2 │ 1 │ 1 │
└───────────────────────────────────┴───────┴──────────┴───────┘
--- meta-comments
score: 34.1/100
┌───────────────────────────────────┬───────┬──────────┬───────┐
│ rule │ score │ priority │ count │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ no-warning-comments │ -49.4 │ 4 │ 75 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-use │ -9.2 │ 1 │ 42 │
├───────────────────────────────────┼───────┼──────────┼───────┤
│ eslint-comments/no-unused-disable │ -7.1 │ 1 │ 25 │
└───────────────────────────────────┴───────┴──────────┴───────┘



オプション

$ sonarish [--root <root-path>] [--detail] 'src/**' 'subdir/**'



sonarish の 設計


  • 空白のスタイリングなどには関与しない(prettierでやれ)

  • ルールが落ちることを前提に、エラーカウント/合計ファイル数 で減点

  • 複数のカテゴリごとにeslintのルールセットを作る

  • カテゴリ内の priority を設定



「攻めたルール」の例


  • object-rest-spread あれば代入なんていらねーよな!

  • クラス以外で this なんてつかわねーよな!

  • 二重 if / switch はダサいよな!

  • 複雑な論理オペレータのネストはダサいよな!

  • TODOコメントなんて残んねーよな!



ダサいを可視化する


  • いわゆる codesmell の検出

  • 自分でそのためのeslintルールを書いてる(既存のものにそういうルール集はあんまりない)



スコアリングルール

そのルールの (エラー数/総ファイル数) * (priority/合計priority)

(実際は細かい正規化とスレッショルドがいっぱいあって調整中)



TODO


  • 自分でスコアルールを書けるようにする

  • ソースの公開

  • eslint 以外のツール対応


    • package.json の health check

    • コピペ検出

    • etc...





わかったこと


  • no-unused-vars は結構効く

  • TODO コメントはめっちゃ残ってる

  • eslintをまともに運用してるように見えてもeslint-disableを数えると結構やばい