Python | テスト・設計・品質:ruff

Python Python
スポンサーリンク

ruffって何?一言でいうと「超高速オールインワンLint&フォーマッタ」

ruff は、Python のコードをチェックするための「超高速リンター兼フォーマッタ」です。
flake8 や isort、部分的には pylint や pyupgrade など、いろんなツールがやっていたことを「ほぼ全部まとめて一つでやる」イメージのツールです。

しかも、とにかく速いです。
小さなプロジェクトだと「実行したのか分からないくらい一瞬」で終わります。
だからこそ、「保存のたびに ruff を走らせる」「CI で毎回 ruff を回す」が現実的にできます。

ざっくり言うと、

コードスタイルチェック(flake8 的なこと)
未使用 import・未使用変数の検出
import の並び替え(isort 的なこと)
一部の自動修正(black ほどではないが、かなり直せる)

を、ruff 一つでこなせます。


まずは「ダメなコード」をruffに見てもらうイメージ

わざと雑なコードを書く

例として、こんなファイルを用意します。

# sample.py

import os, sys

def add(a,b):
  x = 1
  return a+b
Python

このコードには、典型的な問題がいくつかあります。

未使用の import(os, sys
未使用の変数 x
スペースやインデントがバラバラ

ruff を実行すると、例えばこんな感じの指摘が出ます(イメージ):

sample.py:3:1: F401 `os` imported but unused
sample.py:3:5: F401 `sys` imported but unused
sample.py:5:3: F841 Local variable `x` is assigned to but never used
sample.py:3:12: E401 multiple imports on one line
sample.py:5:12: E231 missing whitespace after `,`
sample.py:4:1: E302 expected 2 blank lines, found 1

flake8 っぽいコード(F401, E231 など)が並んでいますが、
これを「ruff 一つ」で出してくれます。

さらに、ruff は多くの問題を自動修正できます。

ruff check . --fix

のように --fix を付けると、
未使用 import の削除や、カンマ後のスペース挿入などを自動で直してくれます。


ruffが「ただのflake8互換」じゃないところ

複数ツールの役割をまとめてくれる

ruff の強みは、「いろんなツールのルールセットを取り込んでいる」ことです。

flake8 系のルール(E, F など)
isort 的な import 並び替え(I 系)
pyupgrade 的な「古い書き方を新しい書き方に」するルール
バグっぽいコードを検出するルール(例えば == Noneis None に、など)

これらを、設定でオン・オフしながら一つのコマンドでチェックできます。

例えば、import の並び替えも ruff に任せられます。

ruff check . --select I --fix

のようにすると、「import の順番・グルーピング」を isort 的なルールで自動整形してくれます。

「flake8 + isort + いろいろ」をバラバラに入れる代わりに、
「ruff 一つ入れておけばだいたい済む」という世界観です。

とにかく速いから「常に回す」が現実的

ruff は Rust で書かれていて、とにかく高速です。
Python 製のリンターと比べると、体感で「桁が違う」ことも多いです。

この速さのおかげで、

保存のたびに ruff を走らせる
pre-commit フックで毎回 ruff を回す
CI で全ファイルに ruff をかける

といった運用がストレスなくできます。

「遅いから後回し」にならないのが、品質的にはかなり大きいです。


ruffとblackの関係:「役割がかぶるところ」と「分けるところ」

ruffもフォーマットを少しやる、でも「全部」ではない

ruff も --fix でかなりの自動修正をしてくれますが、
black ほど「全面的なフォーマット」はしません。

ruff
未使用 import の削除
未使用変数の削除(安全な範囲)
簡単なスタイル修正(スペース、簡単な改行など)
import 並び替え(isort 的)

black
行の折り返し
クォートの統一
辞書・引数の縦並びなど、見た目全体の整形

というイメージです。

実務では、

black で「見た目」を整える
ruff で「ルール違反・バグの匂い」をチェック&一部修正

という組み合わせがかなり多いです。

「ruff だけでフォーマットも全部やる」運用もありますが、
現時点では「フォーマットは black、lint は ruff」という分担が分かりやすいです。


もう少し実践的な例:ruffで「危ない書き方」を直す

古い書き方を新しい書き方にする(pyupgrade 的なこと)

例えば、こんなコードがあったとします。

# old_style.py

x = 1
if x == None:
    print("None")
Python

Python 的には x is None の方が良い書き方です。
ruff のルールセットを有効にしておくと、こういう書き方も指摘してくれます。

old_style.py:3:4: E711 Comparison to `None` should be `is None`

--fix を付けて実行すると、自動でこう直してくれます。

if x is None:
    print("None")
Python

こういう「バグの温床になりやすい書き方」を、
機械的にあぶり出して直してくれるのが、ruff のおいしいところです。

未使用変数をあぶり出す

例えば、こんなコード。

def process(items):
    count = 0
    for i, item in enumerate(items):
        count += 1
    return len(items)
Python

ここでは count が実質使われていません。
ruff はこれも指摘してくれます。

F841 Local variable `count` is assigned to but never used

これをきっかけに、

「この変数、本当に必要?」
「ロジックを整理できない?」

と自分に問い直すことができます。

ruff は「ただ怒る」のではなく、
「設計を見直すきっかけ」をくれるツールでもあります。


ruffの設定と「うるささ」の調整

すべてのルールをオンにすると、最初はだいたいうるさい

ruff は、かなり多くのルールセットをサポートしています。
全部オンにすると、警告だらけになります。

現実的には、

最初は基本的なルール(E, F, I など)だけ有効にする
慣れてきたら、徐々に追加のルールをオンにしていく

というステップがオススメです。

設定ファイル(pyproject.toml など)で、
有効にするルールや無視するルールを細かく調整できます。

例えば、行の長さを少し緩めたいなら、こんな感じです。

[tool.ruff]
line-length = 100

特定のルールを無視したい場合も、設定で ignore に追加できます。

「全部守る」より「なぜ無視するかを説明できる」ことが大事

ruff のルールは、どれもそれなりの理由があって存在します。
でも、プロジェクトによっては「このルールは現実的じゃない」ということもあります。

そういうときは、

チームで「このルールは無視しよう」と合意する
設定ファイルに「なぜ無視しているか」をコメントで残す

という形にすると、
「考えたうえで無視している」状態になります。

「うるさいから全部オフ」ではなく、
「どこまで厳しくするかを自分たちで決める」感覚が大事です。


初心者がruffから何を学べるか

「良くない書き方」を機械に教えてもらう

ruff のメッセージは、
そのまま「Python のアンチパターン集」みたいなものです。

未使用の import・変数
危険な比較(== None など)
無駄な条件式
古い構文

こういうものを、ruff が全部拾ってくれます。

最初は「なんでこれダメなんだろう?」と思ったら、
エラーコードで検索してみると、
理由や改善例がたくさん出てきます。

それを繰り返すうちに、

「Python らしい書き方」
「バグを生みにくい書き方」

が、自然と体に染み込んでいきます。

「機械に任せるところ」と「自分で考えるところ」を分ける感覚

ruff や black を使うと、

インデント・空白・import の順番・簡単なアンチパターン検出
→ 機械に任せる

設計・責務の分割・テストの観点・仕様の妥当性
→ 自分で(チームで)考える

という分担がはっきりします。

これは、エンジニアとして長くやっていくうえで、かなり重要な感覚です。

「機械でできることは機械に任せて、
人間にしかできないところに集中する」

ruff は、その「境界線」を分かりやすく引いてくれるツールでもあります。


まとめ(ruffは「速くて賢い、lintの総合格闘家」)

ruff を初心者目線で整理すると、こうなります。

ruff は、flake8 や isort などの役割をまとめて担える、超高速なリンター兼フォーマッタで、未使用 import・変数、スタイル違反、古い書き方などを一気にチェックしてくれる。
多くの問題を --fix で自動修正できるので、「指摘して終わり」ではなく「直すところまで」かなり任せられる。
black と組み合わせると、「見た目の整形は black、ルールチェックと軽い修正は ruff」という分担で、コードの品質と一貫性を高いレベルで保てる。
ruff の警告一つひとつが「Python の良くない書き方のレッスン」になり、何度も触るうちに「lint に怒られない=より良いコード」が自然と書けるようになっていく。

もしあなたが今書いているファイルの一部(10〜30行くらい)を貼ってくれたら、
「ruff がどう指摘しそうか」「それをどう直すと設計・可読性の面でも良くなるか」を、具体的なコードを使って一緒に見ていきましょう。

タイトルとURLをコピーしました