💭

Prettierを使わない理由

2024/03/30に公開
18

はじめに

Prettierはコードフォーマッターとして広く使われているツールです。
コードスタイルに関する議論をなくすことを目的としており、ESLintとは異なりデフォルト設定のままですぐに使えるのが特徴です。
さらに、PrettierはJS以外にもHTMLやCSS、Markdownなどのフォーマットにも対応しています。
そして、ESLintでは自動修正が難しい部分(max-len等)もPrettierを使えば自動で修正できるため、ESLintよりも優れた点が多くあります。

そんなPrettierの利点を紹介しましたが、正直なところ私はPrettierをあまり好きではありません。
この記事では、私がPrettierを使わない理由を説明したいと思います。

printWidthが強すぎる

Prettierはデフォルトで80文字で折り返しを行います。
これはコードを読みやすくするための設定ですが、読みやすさのためにあえて改行していない所も強制的に改行されます。(逆も然り)
// prettier-ignoreとコメントする事で、Prettierのフォーマットを無効に出来ますが、ignoreするかどうかは実装者次第です。
実装者によってはignoreして読みやすく書く人もいれば、ignoreしないでPrettierに任せてしまう人もいるかもしれません。
これでは、Prettierの利点であるコードスタイルの一貫性が失われてしまいます。

配列定義

将来的に要素が増える可能性がある配列を定義する場合、下記のようにPRのDiffが見やすくなるように改行しておくことがあります。

const arr = [
  elment1,
  elelment2,
  elment3,
+ element4,
];

しかし、Prettierを通すと下記のように置き換えられてしまいます。

const arr = [elment1, elelment2, elment3];

関数呼び出し

関数呼び出しの引数が多い場合、可読性の為に下記のように改行しておくことがあります。

func(
  arg1,
  arg2,
  arg3,
);

しかし、こちらも関数定義と同様にPrettierを通すと下記のように置き換えられてしまいます。

func(arg1, arg2, arg3);

メソッドチェーン

メソッドチェーンを行う場合、下記のように改行しておくことがあります。

const test1 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod();

const test2 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod();

const test3 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod();

しかし、Prettierを通すと下記のように置き換えられてしまいます。

const test1 = func().chainMethod().chainMethod().chainMethod().chainMethod();

const test2 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod();

const test3 = func().chainMethod().chainMethod().chainMethod();

改行されるかどうかは、PrettierのprintWidthに依存し、読みやすさの為の改行は全て無視されます。
読みやすさを優先したいのであれば、下記のように// prettier-ignoreを付けるしかありません。

// prettier-ignore
const test1 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod();

// prettier-ignore
const test2 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod()
  .chainMethod();

// prettier-ignore
const test3 = func()
  .chainMethod()
  .chainMethod()
  .chainMethod();

ESLintと被る部分が多い

Prettierを使う場合、ESLintと併用して使う方は多いと思います。
ESLintはLinterとFormatterの両方の機能を備えている為、Prettierと併用する場合には幾つかのルールが重複してしまいます。
そのため、eslint-config-prettierを使ってESLintのフォーマット関連のルールを無効にすることが推奨されています。

以下は、eslint-config-prettierが実際に無効にするルールの一覧です。
これだけ多くのルールを無効にするのであれば、ESLintのみを使用してコードフォーマットを行う方がよりシンプルではないでしょうか。
https://github.com/prettier/eslint-config-prettier/blob/main/index.js

また、ESLintにはデフォルトの設定はありませんが、recommendedという推奨されるルールのプリセットが用意されています。
コードスタイルに関する議論をなくすことを目的とするならば、ESLintのrecommendedを使用するだけで十分ではないでしょうか。
ESLintのPluginの選定ですら面倒なのであれば、eslint-config-airbnb@antfu/eslint-configのようなプリセットを使うこともできます。

実際に、私が所属するチームではESLintのみを使用していますが、コードスタイルに関する議論はほとんど発生していません。
ESLintと競合するルールを無効化する必要があるという複雑さが増えることが、私がPrettierを使用しない理由の一つです。

まとめ

Prettierには、全員に同じコードスタイルを強制できるという利点がありますが、場合によっては好ましくないスタイルも強制されることがあります。
ESLintだけでもコードのフォーマットは十分可能ですし、今のところPrettierを使用していれば良かった等と困ったこともありません。

Prettierに限らず、ツールを導入する際はメリットとデメリットをしっかり理解し、自分たちのチームに最適なツールを選択することが重要だと思います。

PrAha

Discussion

Honey32Honey32

失礼します。ご存知だったら恐縮ですが、

僕は、prettier (および biome) に潰されてほしくない改行は、// コメントを使って固定しています。これなら、改行以外のルールを無効にせず改行の位置のみをコントロールできます。

三項演算子以外は、これで何とかなっています。

  const {
    watch, //
    register,
    handleSubmit,
  } = useForm<ProfileFormValues>({
    defaultValues: { familyName: "", personalName: "" },
  });
KaribashKaribash

prettier (および biome) に潰されてほしくない改行は、// コメントを使って固定しています。

その手段も知っていますが、// prettier-ignoreと同様に//を使用するかどうかは実装者次第だと思います。
この方法ではPrettierの利点であるコードスタイルの一貫性が失われてしまうため、それであればESLintのみで運用する方が良いのではないかというのが私の考えです。

(そもそも//ってhackyな感じがするけどPrettierが公式にサポートしている機能なのかな・・・)

Honey32Honey32

ご存知だったんですね💦 失礼しました

あと、僕は prettier にまかせて、eslint にフォーマットをさせないのが当たり前でやってきたので、eslint に寄せるとどうなるのかよく考えてなかったです

KaribashKaribash

ESLintのフォーマットが過小評価されていると感じたのがこの記事を書き始めたキッカケでした。
なので、この記事を通して「ESLintでもフォーマット出来るんだ」と考え直す機会になる事ができて嬉しく思います。

makoto-developermakoto-developer

eslintのフォーマッターは最新のバージョンでdeprecatedされてます。
https://eslint.org/blog/2023/10/deprecating-formatting-rules/

個人的にはdprintが好きです。
https://dprint.dev/

KaribashKaribash

eslintのフォーマッターは最新のバージョンでdeprecatedされてます。

そちらの記事でも言及されていますが、フォーマット関連のルールはESLint Stylisticという形でPluginとして切り出され、Anthony Fu氏がメンテナンスを行っています。
Anthony Fu氏はVitestSlidev等の有名なOSSの作成者であり、今後も継続的なメンテナンスが期待できるでしょう。

MS-DDDMS-DDD

karibashさんのこの記事を見たときに真っ先に思い浮かんだのはAnthony Fuさんの「Why I don't use Prettier」という記事でした。
Karibashさんはご存じのことかと思いますが、この記事を見た方向けに紹介させていただきます。

Hidden comment
intet1234intet1234

いつ別の人に引き継ぐかもしれない企業コードでオリジナリティだす勇気。
こういう人がやめてった後のコードは大変じゃないです?
そう思うとprettierは確かにアレな部分もあるけど一般化してしまった以上、
他の人の気持ちを考えれば別の手段は取れない…

KaribashKaribash

そう思うとprettierは確かにアレな部分もあるけど一般化してしまった以上、
他の人の気持ちを考えれば別の手段は取れない…

何をもってESLint + Prettierの組み合わせが一般化していると定義するのかが難しい所ですね。

正確な値は導き出せないかもしれませんが、npmの週間ダウンロード数から推測してみましょう。
ESLint及び、ESLintPrettierを組み合わせる場合に使用する事が多いeslint-config-prettierの週間ダウンロード数を調べてみたところ下記の通りでした。

ESLint: 33,489,452件
eslint-config-prettier: 17,964,938件

ESLint + Prettierの割合: 17,964,938 / 33,489,452 = 0.53 = 53%

この事から、ESLintを利用している方の約53%がPrettierと組み合わせている可能性があるという事が推測できます。
ESLintのみを使用している方は約47%存在するという点から、Prettierを使わないという選択肢は必ずしも異端という訳では無さそうに思えます。

いつ別の人に引き継ぐかもしれない企業コードでオリジナリティだす勇気。

前述の事から、ESLintのみを使用しているユーザーは約47%という事が分かるので、これをオリジナリティと表現するのもあまり適切では無いかなと思います。

Naoki FujitaNaoki Fujita

コード実装者がフォーマットについて思考する必要がないということと
コード実装者が実装意図をフォーマットとして表現する機会を喪失することを天秤に掛ければいいのかなと思いました。
個人的にはコードレビューの観点も含めるといい意思決定ができるのかなと思います。
実装意図がかき消されたコードレビューはかなりきついと思っています。

HTMLGOHTMLGO

printWidthが強すぎる
Prettierはデフォルトで80文字で折り返しを行います。
これはコードを読みやすくするための設定ですが、読みやすさのためにあえて改行していない所も強制的に改行されます。

これわかります。
機械的に長さを制限するメリットが
読みやすさを破壊するデメリットを下回る事が多々あって、それを毎回ignoreするのも違うなぁと。

ESLintも試してみて、今後どうするかまた判断しようと思います!
ありがとうございました。

Hidden comment
ふーふー

Prettierはデフォルトで80文字で折り返しを行います。
これはコードを読みやすくするための設定ですが、読みやすさのためにあえて改行していない所も強制的に改行されます。(逆も然り)
// prettier-ignoreとコメントする事で、Prettierのフォーマットを無効に出来ますが、ignoreするかどうかは実装者次第です。

それを言ってしまうと読みやすさのためにあえて改行を入れるかどうかも実装者次第では...
あえて改行を入れたり入れなかったりしているとき、Prettierを導入していないときは修正し忘れなのか意図的なのかわかりませんが、導入していると // prettier-ignore があるので意図的であることがわかるというメリットもある気がします。

KaribashKaribash

それを言ってしまうと読みやすさのためにあえて改行を入れるかどうかも実装者次第では...

おっしゃる通り、それも実装者次第だと思います。
ですが、ESLintの場合はわざわざ// prettier-ignore//を入れなくて良いメリットがあります。
まとめの項にも記載していますが、Prettierを使用すると全員のコードスタイルを強制できますが、場合によっては好ましくないスタイルも強制されてしまい、それを無視するためにはignoreしないといけないのがPrettierを使わない理由です。
ESLintだけでも十分にフォーマット可能ですし、フォーマットに従いつつ必要があればより良い書き方をすることもできます。

あえて改行を入れたり入れなかったりしているとき、Prettierを導入していないときは修正し忘れなのか意図的なのかわかりませんが、導入していると // prettier-ignore があるので意図的であることがわかるというメリットもある気がします。

気持ち的にフォーマッターは可能な限りignoreしたくないという所があったので、その観点は私も抜けていました。
貴重な意見を頂きありがとうございます!

michiharumichiharu

複数の似たようなコードを書いているのに、改行有無で似たように見えなくなってしまうのはかなりストレスを感じます。

慣れというのはいろいろなことを見えなくしてしまうもので、ストレスを感じるたびに//を使うプラクティスで直すところまでが当たり前になっていました。だけど「なんかきれいじゃない」という感覚はありました。

Prettier を使わない設定、試してみます!

achamaroachamaro

各所に読みやすさの為というワードが出てくるけど、冒頭にもある通りコードスタイルに関する議論(誰かの主観である読みやすさについての議論)をなくすことを目的に入れているので、使わない理由としては正しいと思う。

Prettierに限らず、何かのツールをただ周囲のエンジニアが使っているからという理由だけで導入するのは適切ではありません。

ただ、最後の最後で「Prettierを使う人は周囲のエンジニアが使っているからという理由だけで導入している」というディスともとれるようなことを書かれると反論したくなる。

その「誰かの読みやすさ」とかいうこだわりに付き合いたくないから入れてます。

KaribashKaribash

ただ、最後の最後で「Prettierを使う人は周囲のエンジニアが使っているからという理由だけで導入している」というディスともとれるようなことを書かれると反論したくなる。

改めて見返してみると、確かにディスと受け取ってしまいかねない表現だなと思いました。
文言修正しておきます。貴重な意見を頂きありがとうございます!

neco3coffeeneco3coffee

こういう部分もあるよっていうの共有してくれたのありがたいです。

たしかに必要になったらprettier導入とかでもいいのかも、

アルファベット順にimport並び替える設定と
typeの前にこれをimportしなきゃダメだよってルールが競合してコンパイルできなくなったことあるから、

そしてprettierとeslintどっちがどのルールを適用してるとかもちゃんと把握してなかったから問題の修正が大変だった記憶がある、、

しかもvscodeのformat on saveでimportの順序が最終的には入れ替わってないのに一瞬ちらっと入れ替わってるような動作してたし、
まずeslintとか使って、こういう風にしたいけどeslintじゃできないっていうのが出てきたら導入してみたいと思います!