このエントリで書いてないこと
- Rubocopというgem名について
このエントリを読んでその点について議論したくなるかもしれないけど、筆者が書きたいわけではないこと
- プロジェクトにRubocopを導入するかどうか
このエントリで書くこと
このツイートに至った経緯と、その上での自分の考えを書く。
「Rubocopを採用しない」と決めたプロジェクトなら「Rubocopが指摘することは(少なくともStyleレベルの話なら)人間が指摘するべきでない」って思ってたんだけど、結局この考え方に従う限りメンバーは「どういうことをRubocopが指摘するか」を知っている必要があるので、僕が理不尽なのかもしれない。
— うちやま (@highwide) 2020年6月24日
現職での前提
基本的にRubocopを採用しないプロジェクトが多い。 理由はいくつかあるんだろうけれど、基本的にはこういう話なのかなって思っている。
たとえばですが...
— うちやま (@highwide) 2020年6月24日
「Rubyのように多彩な書き方を良しとする文化がある言語において、"さすがにこれは実害がある"という書き方を自然と避けられる程度に習熟したメンバーが集まったチームなので、画一的な書き方を強制されるよりは、個々人の書き味を優先したいから」
だったらどうですか?
あるいは「Rubocopが指摘するような事柄の中には画一的に決められるものだけでなく、都度どのような選択をとるべきか考えることに心血を注ぐべきだから」といった考え方があったという話も耳に挟んだ。
これらのスタンスに対する自分の意見としては、
- これらの考え方は、基本的には自転車置き場の議論になりやすいCop、特にStyleやLayoutに対するものが多いと思っている
- それらのCopを全てdisableにしたとしても、Rubocopで得られるものはそれなりにあるのではないか(SecurityやLintのCopなど)
- ただし「じゃあどのCopをdisableにして、どのCopをenableにするのか」のメンテや、メンバーの考え方のすり合わせにコストがかかるのは理解できるので、一律で導入しない選択も全否定しない
- 特にOwnershipがあいまいになりがちな共通ライブラリであれば、関わる人数の多さからそのコストが大きくなってしまうことは想像に易い
前職では厳し目のconfigによるRubocopに馴らされていたこともあり、導入したくないメンバーが多い現職に戸惑っていたのも正直な本音としてあるのだが、それでも導入するコスト/リターンと、導入しないそれとを勘案したときに、現状の結論に至っていることについての一定の理解はあったつもりだ。 少なくとも、現状の採用していないプロジェクトに後から導入するコストは大きいだろうなと思っていた。(rubocop_todo.ymlみたいなテクニカルな解決ができる話というよりは、メンバーの心理的な話が大きい)
というか、前職ではRubocopの推奨するStyleに異論唱えがちだったのは僕だったんだよな。
本題: 今日あったこと
Railsで書かれたコードのちょっとした修正をするのに Time.current
という書き方をした。 ActiveSupport::TimeWithZone
を利用した現在時刻の取得だが、この書き方についてはほぼ手癖だったと言っていい。
このPRにおいて、同僚から Time.zone.now
に変更するCommit Suggestionをもらった。
自分の理解ではこれらのメソッドは等価だと思っていたので、単なるStyleの違いをどちらかに揃えるよう指摘されたのか聞き返した。
...いや、もっと正直に言います。 「Rubocopを導入しない」ということは「Styleの違いを許容する」だと思っていたので「そういうことの指摘はしないでほしい」っていう態度を示しました。ごめんなさい。
それに対する同僚からのレスとして、自分が入社する前に書かれた「時間に関する緩やかな指針」という社内ドキュメントを提示してもらった。曰く、
Time.current
は使わないようにした方がいいTime.current
は内部で「Time.zone
がなければTime.now
を使う」という挙動をとる- Railsアプリケーションを書いている限り間違いは怒らないが、時間ほど重要なものであれば、念を入れるに越したことはない
といったことが書いてあった。
このことについて僕は知らなかったので、できる限り Time.zone.now
を使うべきという指針は一理あるように思えた。(とはいえ、明らかにRailsってわかってるならどっちでもよいんじゃないかなって気持ちも、正直ちょっとはある)
ただ、New Joinerが目につきにくい場所に"指針"があるのは望ましくないように思えるし、今後は自分も含めて Time.current
って使われてるの見たら都度コメントしなきゃいけないのかな?みたいなことが頭をよぎって、当初は素直に受け入れにくかった。
あるいは「だったらRubocop導入すればいいんじゃないかな」って気持ちになったのも事実なんだけど、冒頭書いたように、このエントリで「Rubocopを導入すべきか」を議論したいわけではない。
今思えば、これは「Rubocop導入しないことで発生したコスト」なので、「このコストを払うくらいなら、Rubocop導入するコストを払ったほうがいい!」「なんなら、俺が頑張ってそのコストを引き受けるから導入しよう!」って言うんだったら誠実だよなーと思っている。
はい、そのとおりですよね...↓
ああ、でも想像すると、その次に出てくる言葉は「いやでもLinter入れるほどの話ではないよね」な気もしました。多彩さの保守というよりコスパの観点強めですが
— アルミ軽量物干しシンプルタイプ (@terrierscript) 2020年6月24日
で、このツイートに至る
「Rubocopを採用しない」と決めたプロジェクトなら「Rubocopが指摘することは(少なくともStyleレベルの話なら)人間が指摘するべきでない」って思ってたんだけど、結局この考え方に従う限りメンバーは「どういうことをRubocopが指摘するか」を知っている必要があるので、僕が理不尽なのかもしれない。
— うちやま (@highwide) 2020年6月24日
たとえば、僕はなんとなく今回の件は「きっとCopでなんとかなるだろうな」っていう感覚があったから、それならRubocop使えばいいのではって考え方に走るのだが、指摘をしてくれた同僚は知らなかった。
参考までに、rubocop-railsのこのCopで対応できる。
https://docs.rubocop.org/rubocop-rails/cops_rails.html#railstimezone
もちろん「知ってるべき」という考えはあんまりなくて、どっちかというと Time.current
の内部挙動について知ってた方がうれしい気がする。
...というわけで結局、ここで長々と書いているのは
「Rubocopを導入しない」ということは「Styleの違いを許容する」だと思っていたので「そういうことは指摘しないでほしい」っていう態度を示しました。
についての反省文なのかもしれない。
じゃあRubocopを導入しない世界ですべき振る舞いとは?
自戒をこめて言語化してみる。
- 前提として、実利のない(と各々が信じる)議論は避ける
- その上で、レビュアーやレビューイに「Rubocopがどんなことを指摘できるか」の知識を求めない
- 結果として、自分がレビューされるときはRubocopのような指摘をもらうこともあるし、自分がレビューするときはRubocopがしてくれるような指摘をすることもある
- 同じような指摘が何度か続いて、それらのコストとリターンが釣り合わないと思ったら、Rubocop導入を提言する
- 別途コードガイドラインにしておきたい事項があるなら見えやすいところに置いておく
というわけで、チームにそれなりの習熟度を必要とするんだけど、そこまで無理な世界だとは思わない。
あと、このあたりについて他の人の考えを知れたらうれしいという気持ちもある。
ちなみに
社内の他の言語のプロジェクトではLinter(Formatter)が使われることが多い。 js/tsのプロジェクトではESLint+Prettier、Goのプロジェクトではもちろんgofmt、Elixrプロジェクトではmix formatというものが使われているらしい。SwiftとKotlinはどうしてるんだろう。
あと、Rubocopとは別のアプローチとして、Dangerってツールがあることを知った。(これは社内で使われている)