一部からアンチパターンと切り捨てられて不本意だったお話 — お気持ち編

技術的な話はおまけですが、出てくるコードはFlutter/Dart前提です

mono 
Aug 26, 2021
Photo by Paola Chaaya on Unsplash

以前したこのツイートに対して、

次のような引用RTとそれへのリプライがあり、前者の引用RTは主旨と違うことに注目して論じていることに違和感はありつつも受け手に対する配慮は感じられた言い回しなので読み流す程度でしたが、それに対してのリプライは不快かつ不本意に感じずにはいられませんでした。

技術的観点でもその是非についていつか書きたいなとも思いつつ、その前に今回は技術的観点ほぼ抜きにそもそも今回僕がこのような反応についてうんざりしたこととその理由について述べていきます。

もちろん表現の自由はあるのでどういうツイートをするかどうかは自由ではありつつも、不本意に感じる批判をされた立場としての気持ち表明やどういうやり取りが望ましいと思うかなどについて以下述べていきます。

そもそも議論の対象がすり替わっている

僕のツイート内容そのまま繰り返しになりますが、元々は「コンストラクター内でasync/await使いたい時」という前提条件の上で、その手法について述べたもので、「そういえば以下のように無名関数即時実行で簡単にできる」と気付いた時のツイートでした(言われてみれば簡単に見えますがそれまで意外と思い浮かばずでした)。

class Foo {
Foo() {
() async {
await Future<void>.delayed(const Duration(seconds: 100));
// ...
}();
}
}

理想的な反応例

それに対して、Remiさん(お馴染みのProvider/Riverpodの作者)からは以下のように Future<T> constructor を用いた別解を教えてもらい、こちらの方が明示的で良さそうとのことで、確かに同意でき、建設的なフィードバックをいただけて大変ありがたいと思いました🙏(母国語が違ってもきちんと伝わるのだなと思う一方、母国語が同じでも主旨を汲み取ってもらえない虚しさ)

class Foo {
Foo() {
Future(() async {
await Future<void>.delayed(const Duration(seconds: 100));
// ...
});
}
}

ちなみに、前者の無名関数即時実行はその中の処理が即座に同期的に呼び出される一方、後者のFutureコンストラクター内の処理は1つ後のイベントループ後に呼び出される違いがあります。理想的には、周辺コードはそういう些細な違いによらずどちらでも動くのが望ましいですが、現実的にはそのどちらかが都合の良いこともたまにありますね。

この反応に限らず、割合としてはポジティブな反応が多数派ではありました🙏
(以下でも触れてますが、ポジティブな反応だけを求めているわけではなく、真っ当な指摘なら歓迎です。)

今回、不快に感じた反応

「コンストラクター内でasync/await使いたい時」という前提条件自体についての議論にすり替えて、さらにそれに対して「アンチパターン」と切り捨てられました。さらに「地獄」という強い言葉も添えながら皮肉めいた批判もされています。

ソフトウェア開発におけるアンチパターン (英: anti-pattern) とは、必ず否定的な結果に導く、しかも一般的に良く見られる開発方式を記述する文献形式を言う[1]。その内容は、基本的には、否定的な開発方式の一般的な形、主原因、症状、重症化した時の結果、そしてその対策の記述からなる[2]。

https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3

おそらく、 async/await さえ関係なく、以下のような非同期処理投げっぱなしのままコンストラクタから抜けてしまうようなコードを、アンチパターンだと主張したかったようです。

class Foo {
Foo() {
someFuture();

// あるいはこういう処理?
someFuture().then((value) {
// ...
});
}
Future<void> someFuture() async {
// ...
}
}

僕の元ツイートの主旨とは全く違う枝葉の部分に対しての話になってしまっています。

何が問題だと思うのか

そもそも主旨と違う前提条件に対して強めの言葉でケチを付けていること、およびその明確な理由が欠けていることが問題に感じました。

たとえ主旨と違う内容に対してでも、「この部分はXXという問題があってまずいのでは?」のように普通に指摘されれば、「場合によってはXXという問題があるのは把握している上で、こう組み合わせて使う分にはそれは問題にならずその範囲で普通に常用できるパターンだと解釈している」などのような建設的なやり取りも可能ですが。

また、それを見た第三者はその人への信頼度に応じて僕がトンチンカンなことを言っていると印象を持つ可能性も高く、今回のように主旨などを誤解した上で論じられている場合はとても不本意です。それを挽回するためには、無駄な説明コストなどがかかり、すごく疲れます。

そして、少し個人的な感情の話になりますが、普段ポジティブな言及は全くしてこない相手からネガティブな点だけに限定して指摘されるともちろんイヤな気分の方が勝ります。この場合、ブロックして一切関係を断つのが得策だろうという判断に繋がったりします。

非同期処理投げっぱなしのままコンストラクタから抜けてしまうようなコードは実際問題ないのか?

技術的なことは別記事で書きたいと思いつつ、一応簡単に触れます。

まず、classのコンストラクタの扱いの基本としては、複雑な処理を書かずに同期的な最小限の簡単な処理にとどめることです。

コンストラクタで非同期処理したいというのは、その基本的な使い方に反するものだとは認識した上で、特にFlutterアプリの状態管理クラスの場合はそれが有効かつ基本的に実害ないという確信を得て使っています。また、僕独特の癖ではなくFlutterにおいての一般的な書き方の1つであるはずです(僕の場合は実際には非同期処理というよりStreamのlisten処理の方が多いですが、その場合も1つ目の値が流れてくる前にコンストラクタから抜けるため同様)。

仮に形式上避けようとしても、以下のようにせざるを得ないことが多いです(あるいは何か良い別解があれば純粋に知りたいです)。

特に一方向データフローになっていれば、「初期値含む何かしらあり得る値を受けてそれに応じて表示を変える」のような宣言的な処理になっていて、コンストラクタ抜けた時点の状態がどうであろうと関係ないことが多いはずです。アンチパターンと切り捨てた方も現在Flutterに取り組んでいるようですが、必然的に発生する不確定状態について一体どのように向き合っているのか気になります🤔

細かい是非の議論はともかく、少なくともケースバイケースであり、文脈抜きにコンストラクタで非同期処理を扱うことだけをもってアンチパターン扱いするのはさすがに雑過ぎるとは思います。

もちろん自分の主張が常に正しいとは思っているわけではなく、真っ当な指摘を受けてそちらが正しいと思えれば適宜撤回して考えを改めますが。

無配慮な表現のネガティブな言及は害だと思う

はてブの一部コメントなども同様ですが、受け手を傷付けてしまうような無配慮なネガティブな言及は害だと思います。もし裏で何度もこういう言及をされようなことが増えたらうんざりして情報発信シャットダウンしたくなってしまいますし、大抵の人はそう思うはずです。僕は今のところ幸いたまにしかないので、これまで通りマイペースに発信続けようと思っていますが。

「コンストラクター内でasync/await使いたい時」という前提条件の上で、その手法について述べた

特に今回の場合、少なくともこの観点で全く問題ないツイートだったと今振り返っても思うのに、主旨と異なるコード断片に絡めて「アンチパターン」「地獄」などと言われるのはとても不本意です。内容はともかく、せめて本人の目の前で言えるような表現になっているかなど配慮は最低限欲しいと思います。

自分が受け手の時はもちろん、他人がそういう言及されている場合も程度の差はあれ不快に感じます。

一応、失礼な形式でフィードバック受けた場合も真摯に受け止めるようにしてますが、その場合大半は的外れな内容で時間を無駄にするだけに終わりがちです。経験的には、真っ当な形でいただいた情報は有益なことが大半ですが、人の気持ちを害するような発言は内容関係なく完全に遮断してしまう方が期待値高いかもしれません。

もちろん、自分も気を付ける

僕もたまに批判的なことは言いますが、いつもそう判断した理由とセットにして丁寧に述べているつもりです。僕も過去そうなっていなかった時もあるかもしれず、その場合はすみません🙏

褒めるのはカジュアルに、批判は丁寧に、というのが大事だと思います。

あと、肯定できる部分があればそれも言及しつつ、否定部分にも触れるという形が好みです。これについては、僕自身もつい否定部分だけの言及になってしまうことはちょくちょくあると自覚しているので気を付けます🙏
(ネット上の振る舞いとしては個人的には、全体的に良いものの一部気になったことがあった場合はいいねボタンなど押して、否定部分だけの言及することがあります。これももしかしたら人によっては否定だけされた気分になるかもしれないですが、僕の気持ちとしては肯定もセットでしているつもりです🙏)

この記事自体、相手に対してかなり批判的だという自覚はありますが、そもそもネガティブな表現を見た受け手がどう感じるかの配慮が欠如した相手へのアンサー記事なので、このくらい書いても妥当だろうと判断しました。

[追記]

この記事を公開した後も、C#にてこういう明らかなNGなコード例をもってコンストラクタでの非同期処理をなしとみなすエアリプを目にしたりして、心底うんざりしています(´・︵・`)経験上、的外れな言及はその言語・フレームワークに対しての理解不足によるものが多いです。特定分野への理解不足自体は構いませんが、なぜそのような状態で自信満々に上から目線の批判的な発言をできるのか理解に苦しみます。

--

--