Flutterって、フレームワーク自体の設計にけっこう粗が目立つ。
Dartのlintルールに「discarded_futures」「unawaited_futures」というものがある。これらは元々、Futureをawaitしなかったことによる意図しないバグを防ぐ目的のルールで、意図的に捨てていることをunawaited関数でラップして明示するか、大人しくawaitするかのどちらかに強制できる。
しかし、Flutter側の設計に目を向けると、大半のユースケースでFutureが捨てられることを想定した関数、つまり少数のユースケースのためにFutureを戻り値に設定している関数が大量に存在する。そのため、このルールに従おうと思うと、画面遷移のための大量の関数呼び出しをunawaitedでラップする必要がある。バグを防ぐためのlintが、大量のコードノイズを発生させるという状態である。2025年頃に「@awaitNotRequired」アノテーションがmetaパッケージに追加され、これがついている関数はFutureを捨てても怒られなくなった。現在のFlutterプロジェクトでは、急ピッチでNavigator.pushなどの関数にこのアノテーションを付ける作業が行われているが、苦肉の策感は否めない。
私が思うに、それぞれのユースケースで関数を分けるべきだったと思う。例えば、voidを返すNavigator.push、Futureを返すNavigator.pushReturningというように。そうすれば、静的解析に余計な負荷をかけずに済むし、awaitすべき関数とそうでない関数を簡単に区別できる。
ただこれは大規模API変更になるので、今更受け入れられるかは微妙なところ。シグネチャーも二重で定義が必要になり、ボイラープレートが増える。今までの慣習や記事が古くなる。結構影響はデカい。探してもメソッド分割に関する議論は全く見当たらなかったが、Issueを出すかはかなり悩むところ。すでに追加されてしまった@awaitNotRequiredとの兼ね合いも(分割の方針を取るとこのアノテーションの存在意義が行方不明に)。
ということを、私のプロジェクトにこの2つのlintルールを追加してみて思ったところ。lintの方向性は正しいのにその周辺がクソなので、このプロジェクトでは結局元に戻そうと思う。