linterのruleのドキュメントから学びを得る(Biomeを例に)

2024/07/01に公開

はじめに

linter(リンター)とは、ソースコードを静的解析し、潜在的なバグや、パフォーマンスに関わる問題などを、指摘・修正してくれるツールです。Rustならclippy、Kotlinならktlint、JavaScriptならESLint、というように言語毎に様々なlinterが存在します。

linterには「xxxという構文はyyyという構文に置き換えられるべきだ」、「xxxしてはいけない」というようなruleと呼ばれるものがあり、複数のruleを静的解析によりチェックする仕組みとなっていますが、こういったruleには当然導入に至った背景・理由があり、公式ドキュメントにまとめられていたりします。

普段そのlinterを使っていたとしても、使っていなかったとしても、linterのruleのドキュメントや解説から学べる点はそれなりにあるなと感じたため、この記事を執筆させていただきました。

Biomeのlint ruleのドキュメントを眺めてみる

Biomeとは

https://biomejs.dev
Biomeとは主にJavaScriptのためのlinter兼formatterで、以下のような特徴があります:

  • JavaScriptではformatterにPrettier、linterにESLintを使うのが主流だが、Biomeだけでformatter・linterの両方を兼ね備える
  • Prettierとの97%の互換性があるが、Prettierと比べて実行速度が高速
  • TypeScriptを標準でサポート
  • ESLintやTypeScript ESLintなどのruleを含む、254(執筆当時)のlint ruleを実装
  • Rust製

典型的なPrettier + ESLintの構成と比較して、設定ファイルが減り、必要なplugin・依存パッケージ(eslint-plugin-importなど)も減るため、個人的にはかなり注目しているツールです。

Biomeのlint rule

公式サイトではlinterのruleが役割・目的別(Accessibility/Performance/Securityなど)に分類された上で一覧化されています。
https://biomejs.dev/linter/rules/
それとは別のページでは、ruleのアイデアのソースとなったものがあれば、そのソース別に分類されて一覧化されています。Biome exclusive rulesはBiome独自のルールです。
https://biomejs.dev/linter/rules-sources/

実際にこの記事では2つのlint ruleを紹介します。

noDelete

https://biomejs.dev/linter/rules/no-delete/
deleteを使ってはいけないというruleです。下記のようなコードが該当します。

const arr = [1, 2, 3];
delete arr[0]; // Avoid the delete operator which can impact performance.

deleteを使ってはいけない理由として、JavaScriptエンジンの最適化を妨げる危険性がある(参考:https://webkit.org/blog/10298/inline-caching-delete/ )ことや、配列の要素をdeleteしても実は配列の長さは変わらないなど、予期せぬ動作をする危険性があることが挙げられています。
個人的には、deleteは機能としては知っていたものの実際に使ったことはなく、最適化を妨げる可能性があるという話は知らなかったのでためになりました。

noAccumulatingSpread

https://biomejs.dev/linter/rules/no-accumulating-spread/
スプレッド構文をArray.prototype.reduceなどのaccumulator内で使ってはいけないというルールで、下記のようなコードが該当します。

const a = ['a', 'b', 'c'];
a.reduce((acc, val) => [...acc, val], []); //A void the use of spread (`...`) syntax on accumulators.

理由として、パフォーマンス面の問題が挙げられています。
例えば上記のようなコードで配列aの長さをNとした時、時間計算量がO(N^2)となってしまいます。代わりにpushを利用したコードにすることで計算量をO(N)に改善できます。

const a = ['a', 'b', 'c'];
a.reduce((acc, val) => {acc.push(val); return acc}, []);

Biomeのドキュメントからは、参考文献として
https://prateeksurana.me/blog/why-using-object-spread-with-reduce-bad-idea/
が挙げられており、よくわからなかった方はこの記事も読んでみてください。

私自身は、競技プログラミングをやっていたこともあり、普段から計算量を意識してコードを書いているため、特に指摘されるようなruleではないかなと感じました。
しかし、こういった計算量の話は全く意識していない・知らないという人もそれなりにいると感じているため、こういったruleの存在や公式ドキュメント上での解説は有益だと感じました。

最後に

今回はBiomeを例に紹介しましたが、例えばESLintやclippyでも各ruleに対する説明が公式ドキュメントにまとめられています。

ツールにもよりますが、linterのruleは量が多く、全てを読むのはかなり時間がかかると思いますが、興味のあるものを隙間時間に読むだけでもかなり良さそうだと感じています。
皆さんもlinterのruleのドキュメントを通じて新たな学びを得たり、コード品質を高めたりしていきましょう!

参考サイトなど

Discussion