パルカワ2

最近はFlutterをやっています

最近のLinter事情

analyzer 9.x.xにアップデート出来た*1ので、元々custom_lintで書いてたものに加えて新たにカスタムルールを書いたりしている。

なぜLinterが必要なのか

  • AIは確率論的に動くため人間と同様に抜け漏れがある。逆にLinterは、抜け漏れが*2ない
  • Linterはルールのテストが書けるというのも自分的には大事
  • 基本的に自分が扱うリポジトリは、Claude Codeを前提にしてルールなどを書いているが、チームメンバーがそれ以外を使って開発することは止めることは出来ないし、プルリクエストが必ずAIを通しているとは限らない

すべてをAIで解決するのではなく、適材適所いい感じに使いたい。プログラムで問題発見出来るものを都度AIで発見するのではなく、問題発見するためのプログラムをAIで書く。手動テストせずに自動テスト書くみたいな感じ。

どういうルールを書くのか

プロジェクト特有のルールやライブラリ特有のルールを書く。 例えば、以下のようなのを書いて設定している。

  • このレイヤーからこのレイヤーは逆流してはいけない
  • このファイルは、こういう命名規則のクラスでなければならない
  • Widgetは1ファイルにつきpublic classは1つでなければならない
  • sealed classは、freezedを利用しなければならない
  • RiverpodのRefをProvider以外に引数として渡してはいけない

どういうルールを作るべきか?もAIと話して見つけることがある。また元々custom_lintを使っていた時からこういうルールがあると良さそうというのを溜めていたのでそこからちまちま作っている。

その他、考えていること

コードレビューをAIに任せようという話があり、自分も任せているし有益である。一方で、Linter、テストカバレッジ、循環的複雑度認知的複雑度Code smellsなどを機械的に示すことで解決できることも多くあり、まずはそっちを頑張ろうかとぼんやり思っている。

*1:アップデートした日に13.0.0が出ましたが...

*2:ルールにバグがない限り

プルリクエスト作成時のAIによるコードレビューの所感

プルリクエストを出す流れが結構決まった流れになってきたのでスキル化した。今のところ、Github Copilotを前提とした流れになっている。

  1. Claude Code) /create-pr
    1. Draftでプルリクエスト作成
    2. Github Copilotへのアサイン
    3. テンプレートを元にbodyを作成
  2. Github Copilot) アサインされたらレビューする
  3. 自分) Github Copilotからのレビューを対応する/しないを決めてGithub上でコメントする
  4. Claude Code) /respond-to-review
    1. コメントされた内容を本当にやるべきかも改めて確認する
    2. Github Copilotに指摘された内容を修正
    3. 変更 -> commit -> push -> Github上での対応しましたコメントまで行う
  5. 自分) Github上の対応しましたコメントを確認して、解決していたらResolvedに変更
  6. 自分) Github上のUIで変更を眺めてOKならReady to reviewに変更
  7. 同僚) レビュー + Approveする(AIを使うかもしれないが自分は認知しない)

Github Copilotによるコードレビューは、大きく変更しない限り基本的に1回しか行わない。変更をpushするたびに再度全体を人間にレビューしてもらうことはしないと思うのだが、それと同様にAIもしなくていいという気持ちに今はなっている。


プルリクエスト作成時のAIによるコードレビューの目的は、人間レビュアーの負荷軽減だと自分は思っていて、人間レビュアーが指摘しそうなことを先に潰しておいてレビュアーがわざわざ指摘しなくてもいいようにしたい。

なので、Draft状態でAIによるコードレビューを先んじて行い、レビュイーがすべて対応してから人間にレビュー依頼を行うという形にしている。

自分は、レビュアーとしてアサインされたプルリクエストにAIによるコードレビューが大量に残ってると「これは対応するのか?対応したのか?対応を待ったほうがよいのか?」など考えることが増えてだるいな〜と思うので。


コードレビューには、レビュイーが持つコストとレビュアーが持つコストがあって、AIによってレビュイーのコストは自然と減っていく気はするが、レビュアーのコストはレビュイーが意識しないと減らない気がするので、減らしていきたい。

プルリクエスト作成時のコードレビュー

最近はClaude Codeでしかコードを書いていない。1月に対して2月は自分が関わったプルリクエストの量は3倍になったらしい。

コードを出力するスピードが上がっているのであれば、コードレビューがネックになるでしょう!と思って、Claude Code ActionによるAIレビューを導入してみたのだがあまりしっくりきていない。

考えてみると、コードレビューの何をAIに期待しているのかを自分の中で整理できておらず、期待しすぎてるかもと思ったので整理してみる。

コードレビューの目的と役割分担

コードレビューの目的はかなり多いし、人や組織やプロダクトによっても異なりそう。例えば、検査の観点でいえばバグ発見、コードの質、テストの質などがあるし、チームメンバーと話して疑問をはっきりさせたり、共通認識にしたりする場でもあるみたいな話もあるだろう。

Coding Agent登場以前は、これらすべてを人間がやっていたのかでいえばそうではなくLinterに頼ってもいた。Linterは、答えが明確になっているルールに沿って警告やエラーを出す。

人間とAIは同じ入力に対して異なる結果を返す可能性があるが、LinterやTestは同じ入力に対して常に同じ結果を返す。それを踏まえると以下のような役割分担になるのではないか。

  • 答えが明確でルール化できる → 主にLinter / Test
  • まだ答えがないので人間の判断が必要 → 主にAI
  • 判断・確定 → 主に人間

Linterによるレビュー

スタイル・フォーマット・命名規則みたいなのは当然として、依存方向の違反や禁止されたimportのようなアーキテクチャルールも明文化できるならLinterに寄せられる。

言語イディオムレベルの冗長なコードもLinterが得意。Dartは、関数参照(tear-off)で書けるのにラムダ式を使っている箇所を検出するルール のunnecessary_lambdas とかそういうのがある。コードの質でいえばDart Code Metricsとかもある。

テストの質も頑張ればいける気がする。ミューテーションテストは、ソースコードを自動的に壊して(a > ba < b など)テストを実行し、壊したのにテストが通ったらアサーションが甘いのでテストの質が低いねというのがわかる。*1

ルールとして明文化できるなら、まずLinterに寄せるのがよさそう。

AIによるレビュー

AIが扱うのは、Linterではルール化できないが人間に「確認してほしい」箇所。例えば

  • 既存のコードと異なるパターンで書かれているがLinterは指摘していない
  • テストが書かれていないが書かなくていいのか判断つかない

一方で、AIはAIが持つわずかなコンテキストを元に「このコードは怪しい」という確度を出しているだけなので、AIはバグや間違いっぽいものを検出するが「ここが間違いです」とは断定できない。加えて、人間の方がいろんな情報にアクセス出来るため、コンテキストを多く持っていて「あえてそうやっている」とか「別にそこまでやる必要ない」とかすでに判断していることが多い気がする。

AIがアクセス出来る場所にコード以外のコンテキストも含めていくのが必要で、難しければAIには暗黙知っぽいところを指摘してもらうくらいしか出来ないのではなかろうか。

人間によるレビュー

AIによるレビューで書いたことは、人間によるレビューにも言えるが、人間にしか出来ないことは、以下のようなものがある。

  • 設計の妥当性の判断
  • ビジネスロジックの正しさの判断
  • AIの指摘に対する判断
  • 知識共有の会話

判断するのは人間で決定したことをLinterで気付けるようにしていくみたいなのをAIに指示するのも人間ですね。

まとめ

Claude Code Actionでのコードレビューは、Linterでやるべきことも指摘しようとしていたからしっくりこなかったんだとおもう。

今まであんまりやりきれてなかったLinterカスタムルールなどを色々整備していくことが今後重要になっていくだろうし、Coding Agentによってそれがしやすい環境になってきた。加えて、AIは答えが不確定で、チューニングや期待値の調整が必要なため効果が読みにくい。Linterで地盤を固めたりリポジトリ内にコンテキストを持てるようになった上でAIによるレビューを導入するか、さくっと使えるGithub Copilotでレビューしたりするほうがよさそうではある。

いま悩ましいのは、custom_lintを使わずにカスタムルールを書くにはanalyzerのアップデートが必要で、そのためにはRiverpodのアップデートやcustom_lintからの移行を真面目に考える必要があるということ!やるしかねえ

*1:もちろんそれだけでテストの質が高い!とは言い切れないとは思うんだけど…

諦めない

仕事をしていると実装に対して「もっとこうしたほうがいいな!」と思うことはある。一方同時にたくさん積み上げられたタスク、期待されているであろうことを踏まえると「今じゃない…」とも思う。

「今じゃない」と言って諦めるのは簡単だし、コストもかからない。でも、「今じゃない」を重ねていくと「こうしたほうがいいな!」は忘れて、保守性は下がったまま。もしくはもっと下がる。

自分も「今じゃない」と思いがちなのだが、「今じゃない」で済ませないこと、つまり諦めないことが重要なんじゃないかと最近よく思う。全部やるのは今すぐじゃないとしても、今できる最小のことはなにかを考えてやる。

最小のことは、例えばコードにコメントを書くことかもしれないし、Coding Agentにクラスを分けさせることなのかもしれない。

最近はAIのおかげで諦めないことが容易になってきた。諦めずにやっていきたいですね。

モバイルアプリの開発をしているとターミナルを使うのは、gitやadbを操作するときくらいであんまり使わないので、panelを複数出すこともそんなになかったのだが、最近はClaude Codeでコードを書いており、ターミナルに滞在することが多いので、画面分割をよくしている。画面分割をしたあとにブラウザとかVSCodeを見てターミナルに戻ってくるとカーソルがどこにいったのかわからなくなることが多々あったので、tmuxの設定を見直した。

元々はこんな感じでカーソルを探すか真ん中の線の色表示で見分けてた。

panelのtopに線を表示して、フォーカスが合っていると色が変わるようにした。全体をぼんやり見れば、どこにフォーカスが当たっているのかわかるし、位置が固定されているので目の移動が少なくなったので便利

set -g pane-border-status top
set -g pane-border-format "#{?pane_active,#[reverse] #P #[noreverse], #P }"

見た目的には前のほうがすきだけど、めんどくささには勝てなかった