掛算順序問題を学校という権威を叩くための棍棒として使う人がいる

掛算順序問題のやりとりや反応を見るときに、掛算順序否定派の人に攻撃的だったり侮蔑的な発言が目立つことが気になっていました。
また、借りてきた論拠をそのまま使ってるんではないかと感じることもあります。
これ、学校という権威を叩く棍棒として使ってる人も結構いるんじゃないだろうか。

こういうことを感じたのは、[https://nowokay.hatenablog.com/entry/2024/04/06/010143:title= 前のブログ]に「ルールでの順序はどちらでもいい」とわざわざ見出しにしているにも関わらず、ルールを固定しているのがダメだという論調で反論めいたやりとりがあって、「なんだか話が通じてないな」と思ったのがきっかけです。
書いてることを読んでないというのだけじゃなく、書いてないことへの批判のようなものもあったりします。

そして気になったのが「学習指導要領解説には法的拘束力はない」という、あまり意味のないことが異口同音に持ち出されてることです。
文部科学省の通知で「学習指導要領は大綱的な基準であることから,その記述の意味や解釈などの詳細については,文部科学省が作成・公表する学習指導要領解説において説明」という位置づけがされて「学習指導要領解説を活用して、教職員が学習指導要領についての理解を深められるよう周知・徹底を図ること」のように指示されているので、法的拘束力のある学習指導要領を運用するための強い指針であるので、法的拘束力がなくても無視していい文書ではありません。
そもそも、議論においては何が書かれているかが重要で、法的拘束力の有無はあまり関係ないように思います。

これ、だれかが「学習指導要領解説には法的拘束力はない」ということを言いだして、掛算順序を否定するときの材料として普及してそのまま使われてるんじゃないかと思います。

似たようなものに「数学者も言ってる」と数学者や物理学者を持ち出す人を見かけるというのもあります。
けど、数学者だからといって児童教育に詳しいとは限らないので、あまり意味がないように思います。 議論においては、誰が言ったかより何を言ったかのほうが大事なはずというのもあります。

ネットで目立つダメな例を使って全体を批判するというのも大きな傾向に思います。
そして、実際の教育の現場の人が、どのような必要性があってどのような意図で掛算順序を使っているか、どのように運用するべきであるか、現実的な問題として何があるかを説明しても、聞く耳もたないような反応を目にします。

小学二年生という発達段階の児童への教育は、大人への教育と比べると気をつけないといけない点が違うはずです。そこでは現場にいる人の知見は大事だと思いますが、尊重されずに批判を受けていることも見かけます。
数学者を持ち出す人がいると書きましたが、数学者でも児童教育の現場に立ち会った人、現場経験はなくても児童教育の心理学などを勉強した人というのは少ないと思います。

学校という権威を叩ける材料だとして、掛算順序の話に借り物の論拠で参加している人が議論をかきまぜてる面が結構あるんじゃないかというように思います。

目的を規定せずにモデリングを考えても意味がない

オブジェクト指向の本では「自転車をモデリングしてみましょう」「鳥をモデリングしてみましょう」ということが、どういうシステムで使うか規定せずによく書かれています。
けれども、モデリングではどういうシステムで使うかということが大事で、それを決めずにモデリングを考えても意味がありません。モデリングすべきはモノではなくシステムのプロセスです。

よく、オブジェクト指向では現実をモデリングするのようなことが言われますね。
例えば鳥が鳴くとして、その一種であるニワトリをどうモデリングするか、ということを考えるとします。
そうすると、まず

void 鳴く() {
  print("コケコッコー");
}

のようなメソッドを考えるのですけど、コケコッコーとうまく鳴けるのは鳴き慣れたニワトリです。そのため、鳴くメソッドにカウンターを用意してどんどんうまくコケコッコーになるようにしたくなります。
いや、そもそも、コケコッコーと鳴くようになる前、ヒヨコとしてピヨピヨ鳴いています。ヒヨコからニワトリへの遷移も必要になるのでは?
また、インフルエンザなどの病気にかかればうまく鳴けなくもなりそうですね。

「現実をモデリング」をやろうとすると、どんどんコーナーケースがでてきて、そのすべてのコーナーケースに対応しようとすると、結局は細胞モデルや分子モデルなど、微細要素まで分解してシミュレーションすることになっていきます。

そもそもモデリングというのは抽象化なので、現実のシミュレーションではないですね。
そして抽象化というのは、必要な要素を残して不要な細部を切り捨てる作業です。では何を残して何を切り捨てるかというのは、何に使うかということなしには決めれません。
モデリングでは「何に使うか」が重要です。
何に使うかということなしでは上記のニワトリモデリングのように、いろいろな条件をどんどん再現する必要がでてきます。そして、この作業は結構たのしいので、目的なくどんどんモデルを膨らませていくことになります。
目的が決まっていないモデリングは、モデリングのためのモデリングになってしまいます。

実際には、どのようなシステムで使うかということが、何をモデリングするかよりも大切です。
たとえばデータをメモリだけで扱うのか、ファイルに保存するのか、データベースに保存するか、データベースはMySQLかMongoDBか、そこでモデルの大きな方向性が決まります。

なにを目的にするのかも大切です。販売管理なのかゲームなのか動物百科事典なのか。

販売管理で、肉屋だとニワトリを仕入れてさばいて部位ごとにわけて、一部はミンチにして、という扱いが必要です。システム化のことを考えずにそういった解体可能なニワトリモデルを考えると、骨や肉、羽、そして細胞のモデルまでいきついてしまいますが、ほとんどは販売管理に不要な詳細になります。
現実をモデリングするのであれば、モモやムネの肉オブジェクトは仕入れたニワトリオブジェクトの一部である必要がありますが、実際には仕入れたニワトリと解体されたモモ肉は無関係なオブジェクトで構いません。

そして、このときのモデルを決めるのは、「ニワトリとはどういうものか」ではなく、「ニワトリの肉を売るとはどういうビジネスか」です。ニワトリとモモ肉は無関係でいいと書きましたが、トレーサビリティでモモ肉の生産業者わかるようにするとしても、大事なのはニワトリのモデリングよりも農水省のトレーサビリティ関連文書でしょう。

結局のところ、モデリングするべきは、モノではなくプロセスです。プロセスをモデリングしたあとで、そのプロセスを可能にするデータとしてモノをどうあらわすかというモデルが必要になるわけです。
オブジェクト指向が衰退した流れのひとつに1990年代後半に開発手法から開発プロセスに関心が移ったことを取り上げるのですけど、90年代後半にビジネスプロセス・リエンジニアリング(BPR)という言葉が流行りビジネスプロセスを分析設計することに関心が集まったこともオブジェクト指向の衰退に無関係ではないのかもしれません。

追記 2024/4/14
こういうモデリングはいつからあるんだろうというコメントありますが、オブジェクト指向モデリングの原典とも言える「オブジェクト指向方法論OMT」の最初に自転車の例があります。ただ、これはコンセプトを示すためで、実際の例としてはATMなどもっと実務に即した題材を使っています。意図せず広まってしまった感じ。
ランボーのOMT本はオブジェクトモデル→状態遷移→データフローと章が進んでいるけど、現実的には逆のほうが適切ですね。そこでヤコブソンのOOSEと組み合わさって、ユースケースを起点としたICONIXやRUPにつながっていきました。

AIがコードを書くようになるなら、AIだけに理解できる言語を作ればいい、のかな?

AIがコードを書くようになって、そしてその品質がどんどんあがってきて、人間がコードを書く必要性が薄れてきています。
であれば、プログラミング言語そもそも不要で日本語で命令与えるだけでいいのでは、とか、人間には読み書きできないAI専用言語を作るといいのでは、という話になりそうだけど、やっぱ今のプログラミングは残るんじゃないかな。

(画像は「創るJava」初版の挿絵です。初版のイラストは自分で描いてます)

大森さんと話をする機会があって、そこで話した内容が日経XTECHの記事で少し触れられていました。
生成AIは所詮は人間の亜種、企業のITシステムの置き換えにはならない | 日経クロステック(xTECH)

人の言葉を理解できるようになったのだから、プログラミング言語はもう不要なのではないか。
この考えをある著名なソフトウエアエンジニアに話してみたところ、意外なことに「プログラミング言語はなくならないと思う」という意見が返ってきた

このとき話した内容をもとに、すこしAI時代のプログラミング言語の必要性をまとめてみます。

AIがあるならプログラミング言語は不要?

AIが解釈してくれるのであれば日本語なり英語なりで命令与えればいいだけでは?と思ったりするけど、やはりなんらかの言語は必要だろうと思います。
システムにおいて大事なことは再現性と検証可能性、そして性能だからです。

再現性

システムでは、多数のユーザーに対して同じ動作を何回も提供する必要があります。そうすると、各実に同じ動作を何万回も繰り返せるよう、動作を規定できる必要があります。いまのAIのように、場合により少し動作が違ったり、うまくいかなかったりするというのではダメですね。
そのためには、なんなりか形式的な言語で動作をゆらぎなく記述する必要があります。プログラミング言語はそのための知見がつまって今の形になっているので、活用するほうがいいです。

もちろん、テストを十分に行えば動作保証できるのではという考え方もできますが、そのようなテストを行うのは困難です。まずは記述によって正確性を担保する必要があると思います。

検証可能性

同じ動作を何万回も繰り返せる必要があると書いたのだけど、やっぱり少しずつ条件が変わりますね。こういったブログの投稿を考えても、基本的には同じだけど書かれている内容や文字数、タイミングが違います。 そうすると、なんらか特殊な条件で動作がおかしいということが起きることがあります。
そのとき、どういう条件で動作がおかしいのか、なぜそのような動作になるのか検証できる必要があります。そして、その動作を修正したときに、他に影響がないのかも確認できる必要があります。

「なんかよくわからないけどいろいろ試してプロンプトに『よろしくお願いします』を付けたら治った」ではダメですね。
そうすると、確認できる可読性も必要になります。
いま広く使われている言語は、読み書きしやすいバランスが保たれているので、活用したほうがいいでしょう。

性能

そもそもAIは遅いし電気を食います。電気を食うということはコストがかかるということです。AIを動かすコストはかなり高いです。
サンプルプログラムレベルのTODOアプリを使うために月1000円の課金が必要になっても、だれも使わないですね。 システム構築では、いかにコンピュータを効率よく使ってコストを下げるかということも求められます。

では、AIに直接機械語を出力させればどうなのか、となります。けれども、効率のいい機械語を出力できるようAIを学習させるのは難しく、またそうやって出力した機械語が常に最適であるという保証もできません。
コンピュータには物理制約があり、その制約を回避するためにキャッシュやパイプラインといった複雑な仕組みをもっています。その仕組みをいかして性能を出すには、特性をいかしたコードを生成できる必要があります。AIにそのような特性を教え込ませるよりも、すでに存在するLLVMJVMといった最適化の仕組みを利用するほうが、効率が高く確実です。コードはプログラミング言語で記述して、そういった仕組みに高度な最適化を行ってもらうのが、一番効率がいいと思います。

AI専用のプログラミング言語でいいのでは?

プログラミング言語が必要というのはわかった、しかし人間に読み書きできることをあきらめてAI専用の言語にすれば、もっと高度なプログラミング言語ができるのでは」と思うかもしれません。
けど、それは難しそうだし、必要性もないんじゃないかなと思います。

どうやって作るのか

まず、どうやって作るのかという問題があります。結局のところその言語は人間が作る必要があります。 そうすると、人間には理解できないけどAIに理解できるということを想像しながら言語を作っていく必要があります。
そうやって作った言語が本当にAIに理解可能なのかを検証するために、言語を作って、その言語で書かれたコードを大量に作って、学習させて、理解度を確認する必要があります。
そしてAIに理解できていなさそうとなったとき、AIに本質的に理解できないのか、単に学習の量や質が足りないのかの判断は難しいですね。
そういった試行錯誤を行いながら言語を技術的に作れるか、現実的にそのような困難な作業をするモチベーションがあるかというと疑問があります。

必要なのか

人間じゃなくてAIが作ればいいんでは、となるかもしれませんね。じゃあなんなりかそのような言語が作れるとします。そうなると、そもそも必要かという話をする必要がでますね。

機械専用の言語を作るとしたときに、イメージとしては自然言語の単語で表しているものを記号にするというものがありますね。
たとえば、extendsと書いているところを:で表すような。これはJavaC++などの違いですけど。
けど、AIが扱うと考えたときにそのような記号化のメリットはほとんどありません。文字数は問題にならないからです。
また、いまのAIは自然言語で常識を学びつつプログラミング言語を学ぶという形になっています。自然言語がベースにあるのです。そうすると、AIにとっても記号より単語のほうが理解しやすいということになります。

では機能的なところはどうか、ということになりますね。AIだとより高度な言語機能を扱えるのではないかと。
言語機能といったとき、大事なのは型システムと並列性だと思います。ちょっと記述量が減らせるといったものは、AI専用としては不要です。いい感じに記述が減らせるなら、人間用の言語にも取り込めばいいですね。

まず並列性で、最近はコルーチンなど並列性の機能を取り込んだ言語も増えています。これをAIが扱うならさらに高度な並列機能が可能では、というのを考えたいところですが、並列性の難しさって本質的ではないかというのがあります。また、いまのAIの仕組みはトランスフォーマーからニューラルネットの階層に直列的に情報が流れるので、並列処理が人間に比べて得意になる要素がない気もします。
AIだからといって訓練された人間以上に並列処理の記述が得意になるとは思えないです。

型システムについては、人間よりちょっと複雑な型システムを扱えるかもしれないなという気はします。ただ、型システムを強くすると、広範囲に記述が面倒になりがちというのがあります。AIといえども、そういった面倒な記述は不得意で、不整合がでやすくなる型システムとの戦いが必要になる気がします。

そもそもとして、並列性も型システムも、いまある以上に高度なものが必要なのかという疑問があります。いま広く使われる実用言語で一番高度な型システムとしては、Rustの借用がありますが、ほとんどの人がそれを求めていないですね。求めている人も、コードのすべてでそれが必要とは思っていないはずです。
つまり、いま人間向けとしてある言語はすでに実用システムを書くために必要十分なんではないかということです。 いまプログラミング言語に採用されていない高度な型システムは、仕様記述言語のように用途限定して使うので十分な気がします。用途限定であれば人間にも扱えてるというのもありますね。

ということで、AI専用の言語というのは必要性が薄いなと思うし、そのような薄い必要性のためにコストと労力をかけて言語を作ることもないように思います。

今のプログラミング言語は1000年残る

10年以上前はITの世界はドッグイヤーだと言われて変化が速いと言われていましたが、最近は新しいものがでなくなっています。生成AIが久しぶりに話題になった感じ。
もう新しい言語は10年近く出てないです。また他の技術としてもAWS LambdaやKubernetesも10年近くたってますね。システム開発のためのIT技術の進化は一段落ついたように見えます。
いまあるプログラミング言語はある程度の淘汰や変化はあるとしても、漢字が2000年続いているように、それなりに今の形を保ったまま残っていくように思います。

なぜ掛算順序の話が混乱するのか

掛算順序について学習指導要領解説を見て整理したらいろいろ反論あって、結局のところ問題が三層構造になっていることと、表現という層が認識されていないことで混乱があるように見える。

前回のブログに書いたように「被乗数と乗数の順序が,この場面の表現 において本質的な役割を果たしている」と学習指導要領解説で説明されていて、表現の問題であると整理されています。
掛算の順序と学習指導要領 - きしだのHatena

というの書くと「解説だから・・」みたいな反応がつきますが、文部科学省の通知に「学習指導要領は大綱的な基準であることから,その記述の意味や解釈などの詳細については,文部科学省が作成・公表する学習指導要領解説において説明」とあるので、運用においては最重要な文書だと思います。

まあそれはそれとして、だいたい「交換則があるんだから」とか「ルールは固定されていない」とかが主な反論になっていて、交換則は計算のレイヤー、ルール固定は教育のレイヤーなので、表現として順序が大切かどうかということとはまた別の話になります。

表現の話なので、文化や文書の中で統一したほうが伝わりやすいということで、必要な範囲で統一されていれば、ルール自体はどうなっていてもいいですね。ただ、教えるときにはルールを決めておいたほうがやりやすいので、ルール固定になりやすい。

あと、順序を教えるのは教育の問題ですが、小学二年生の発達段階や理解の構造を考慮せず、できあがった大人と同じ理解力をしてる前提、もしくは理想の理解を前提に話す人も多いようにも思います。

ただ、学習指導要領解説での掛算順序の記述は2017年の改訂で加わったもので、それまでは学習指導要領解説にも掛算の式の表現をどのように教えるか具体的な記述がなく、掛算順序が表現のレイヤーの話であることが明確じゃなかったのだと思います。

表現のレイヤーが認識されていなくて、掛算順序肯定にしろ否定にしろ、教育か計算かどちらかに寄ってしまって、本来議論するべき内容から外れていくんではないかという気がします。

掛算の順序と学習指導要領

あいかわらず掛算の順序の話がもりあがってるようなのだけど、コーディングルールの話なんだから計算の定義の話をしても徒労だよなと思いながら見ていた。
で、ちょっと教育指導要領解説を見てみたのでまとめる。

学習指導要領解説の記述

「【算数編】小学校学習指導要領(平成29年告示)解説」では次のようになっています。順序は表現のときの問題で、計算では交換則を使っていいとなっています。

被乗数と乗数の順序は、「一つ分の大きさの幾つ分かに当たる大きさを求める」という日常生活などの問題の場面を式で表現する場合に大切にすべきことである。一方、乗法の計算の結果を求める場合には、交換法則を必要に応じて活用し、被乗数と乗数を逆にして計算してもよい。

このPDFの115ページ。
https://www.mext.go.jp/content/20211102-mxt_kyoiku02-100002607_04.pdf

ここからたどれます。
小学校学習指導要領解説:文部科学省

表現としての掛算式

数式というのは、左から計算するとか×を先に計算するとかの構文規則をもった言語です。「+より×を先に計算する」というのは乗算の性質ではなく乗算をあらわした式という言語の性質です。そして、言語であるからには人が読み書きするものなので、意図したとおりに伝わるかというのが大事になります。

指導要領解説には次のような文章があります。

「乗法の式から場面や問題をつくるような活動も,乗法についての理解を深め,式を用いる能力を伸ばすために大切」であり、式から場面をつくる際には「被乗数と乗数の順序が,この場面の表現 において本質的な役割を果たしている」ということです。
場面の表現としての式では順序が大切ということですね。

ルールでの順序はどちらでもいい

指導要領解説には「(一つ分の大きさ)×(幾つ分)=(幾つ 分かに当たる大きさ)」のように「一つ分の大きさ」が先に書いてありますが、文部科学省に問い合わせた人によると、これは例であって逆でもいいとのことです。
「表す順序を日本と逆にする言語圏があることに留意する」と書かれていることからも、「一つ分の大きさ」が先というルールに固執してるわけではないことがわかります。

ところで「リレーで4 x 100mと書くじゃないか」というのが頻出反論としてありますが、国際大会に合わせているように思います。つまりこれは順序が固定の例と言えます。

同じ処理に複数の表記があるなら統一したほうがいい

プログラミングのコーディングルールは、同じ実装に複数の表現があるからこそ必要になるわけですね。スペースをいくつ入れてもいいから「字下げのスペースは4つ」のようなルールがあるわけです。
add.list("foo")ではなくlist.add("foo")と書く」なんてコーディングルールはないですね。これはコーディングルールではなく文法です。

掛算も交換則でどちらを先に書いてもいいからこそ、コーディングルールがあったほうが解釈しやすくなるわけですね。分数で分母を上に書くか下に書くかという議論は出てこないわけです。
そして、字下げルールがスペース4つでもスペース8つでもいいように、ルールとしては一つ分の大きさでも幾つ分でもどちらが先でも構いません。

ただ、ある部分では4タブ、ある部分では8タブと混在するのがよくないように、掛け算で場面を表現するときもひとつの文章、ひとつのチームなどまとまった単位では順序を統一したほうが解釈しやすくなります。

気にしないけど統一されている

掛算の順序なんて日頃は気にしないのになんで学校でだけ気にするんだ、という話もあったけど、これは気にしなくても統一されてるからということもできます。
文化というのは、十分に浸透していれば気にする必要がなくなりますね。

「ポイント5倍キャンペーン」で画像検索すると、掛け算記号があるものはほぼすべて「x5」となっています。ひとつだけ「5x」がありました。増やしたいものが前、増やす倍数が後ろという習慣があらわれていると思います。

関係ないけど、広告がはさまってるように見えるな。広告じゃないです。

で、一方で、GPUなどの計算が2倍3倍に速くなったときのオフィシャルでの表記は2xとか3xとかになっていて、英語圏では逆ということがわかります。

この違いは「りんご4つ」「4 apples」という母語の語順に由来してるんじゃないかな。

出題や採点、教育姿勢の問題との混同

たとえば「りんごが5つ載った皿が4枚ある場合にりんごがいくつになるか計算せよ」という問題があるときに「4x5=20」と書いて「順序が違うからバツ~」ってされると「設問は『計算せよ』となってるじゃないか」となるわけですね。 式を書かせるための設問を小学二年生に理解できるように作るのは結構難しいんじゃないかと思いますが、採点基準は設問に含めるべきではないかと思います。
あと、「テストは教えたことの確認なんだから教えたとおりに書くべき」みたいなのは、それはそれで何を教え何を答えさせるべきかということから逃げていて教育姿勢としてよくないですね。

2024/4/9追記 数学者や物理学者の話

数学者や物理学者が実務で使ってないという話が出ますが、数学者や物理学者も、式を書くときになんなりかのルールで順序を決めたり、同じ分野では標準的な記述順序があったりするんじゃないでしょうか。 たとえばxについての多項式ではれば、xは項の最後に書くような文化がありますね。足し算についても次数が高いものを先に書きます。
人に見せる式としてxについての多項式 ax ^ 2 + bx + c を x ^ 2 a+xb+c とは書かないんじゃないでしょうか。
x ^ 2 y + x y ^ 2 = 0 という方程式も、xを求める方程式であれば y x ^ 2 + y ^ 2 x = 0 と書くし、yを求める方程式であれば x y ^ 2 + x ^ 2 y = 0 と書くんじゃないかと。そして、この場合に、掛算の順序はその式が何についての方程式なのかを表すのに重要、のような話になるんじゃないでしょうか。
可換な演算の記述順、結構気にしてるように思います。
ところで、tex記法がきかないのでy ^ 2 xがy ^ (2x)なのか(y ^ 2)xなのか見辛くなってますが、xについての方程式のルールに従えば読みときやすくなりますね。tex記法どうやるんだ。 [tex : y x2+y2 x=0] でいいはずだけど。

2024/4/10追記 学習指導要領解説であることについて

コメントを見ると、学習指導要領解説だから読む気なくす、法的拘束力はない、のようなものがあります。けど、文部科学省が学習指導要領の関連文書として告示しているものはそんなに軽い位置づけではないと思います。また、実作業者がだれであろうが、文部科学省として作成・公表しています。

改訂の際の通知に次のような記述があります。
https://www.mext.go.jp/content/1384661_1_1.pdf

法的拘束力のある決定には時間やコストがかかるので、行政を円滑的に運営するため、法的拘束力はないけど強い強制力のある文書を出すことがあります。わかりやすいところだと行政指導がありますね。
「【通達の意味・種類・法的性質(国民・企業・裁判所への法的拘束力)】 | 企業法務 | 東京・埼玉の理系弁護士」 https://www.mc-law.jp/kigyohomu/21524/

学習指導要領には「何を学ばせるか」が既定されていますが、それだけでは実際に教育の実務を行うことができません。なので「どのように学ばせるか」を学習指導要領解説として出しているのだと思います。どのように学ばせるかは臨機応変に対応できるほうがいいので軽い文書として学習指導要領解説を出していると考えれます。このように、指針を法的拘束力のある文書で規定して、運用を法的拘束力のないガイドラインなどで告示するということはよく見かけます。
上記の通知を見ると「学習指導要領解説を活用して、教職員が学習指導要領についての理解を深められるよう周知・徹底を図ること」のような記述があって、結構強い位置づけであることがわかります。

そもそも、掛算の順序がどのようなものかという議論をするべきで、法的拘束力があるとかないとかはあまり本質的ではないと思います。そして、掛算の順序を文部科学省としてどのようなものと考えているかが、学習指導要領解説に表されているので、この議論では重要な文書だと考えます。

まとめ

表現の問題なのだから、計算の性質の話ばっかりしても収束しないわけですね。
そして、表現のために規則が必要かという話には正しい答えなどはないので、正しい正しくないの話をしてもしょうがないです。適切かどうかではないかと。
たぶん、掛算順序が盛り上がったあとに改訂されていて、学習指導要領解説はよくまとまってると思うので、議論する際は目を通す方がいいと思います。

※追記2024-4-11 なぜ混乱するのかという話も書きました

JavaのDIコンテナは言語機能の補完でありinjectはimport

というブログを書こうとしたら、すでにあった。
Dependency Injectionでやりたいことはモジュールimport - きしだのHatena

依存性の注入って要するにimportなので。

まず、DIコンテナを実装してみるとどういうものかがわかりやすくなります。
このときの結論はこんな感じ。

DIコンテナというのは、Javaのリフレクションやバイトコード操作、ThreadLocalといった、あまり美しくない部分を覆い隠してきれいなコードでアプリケーションを構築するための仕組み
作って理解するDIコンテナ - きしだのHatena

言語機能の補完なので、他の言語で同様に便利とは限らないわけですね。
わかりやすい例として、DIコンテナの現実的に便利なのはAOPを利用した宣言的トランザクションやログです。これはAspectJのように言語機能としてAOPが用意されていれば不要になります。

あと、これらのブログで書いてないこととしては、DIでのクラス設計というのはオブジェクト指向は関係ないってことですね。
クラス分けを恣意的に行えるので、単に作業性の問題です。

たとえば次のようなコントローラクラスがあるとします。

@Path("/home")
@RestController
public class HomeController {
  @Path("/hello")
  public String hello() {
    return "hello";
  }
  @Path("/info")
  public String info() {
    return "test app";
  }
}

このようなクラスでメソッドが多くなったときなどに、次のように2つのクラスに分割することは簡単です。

@Path("/")
@RestController
public class HelloController {
  @Path("/home/hello")
  public String hello() {
    return "hello";
  }
}
@Path("/")
@RestController
public class InfoController {
  @Path("/home/info")
  public String info() {
    return "test app";
  }
}

逆に、コードの整理でメソッドが少なくなったり、必要と思ったらそれほどメソッドは必要なかったりで、メソッドが少なすぎる複数のクラスを統合することもあります。

単にどのメソッドをひとつのファイルにまとめておくと便利かという観点でクラスを定義することになりますね。グループ分けの問題であり線引きの問題です。

これがたとえば、ListのメソッドをMapにもっていくとか、ArrayListとLinkedListを統合しようとかいったことは簡単ではありません。そもそもとして「やろうとしたらできるかもしれないけどやるべきじゃないんでは?」となりますね。

ということで、DIでのインスタンスメソッドはAOPなどいろいろ仕込みたいときにstaticだと難しいので仕組み的にインスタンスメソッドを利用しているだけだし、そうするとimportが行えないので@Injectしている、というふうに考えるほうが利用しやすくなると思います。

時代がstaticおじさんに追いついてきた(追記あり)

この文章みてください。

オレはもう20年以上システム業界にいるけどな、その長い経験から言うと、オブジェクト指向なんてものは、理論としては面白いけど、およそ実用的とは言い難いものだな。まぁ、例えばGUIコンポーネントとかはオブジェクト指向に基づいて作られているようだから、そういうツールとかを作る人には必要なものなのかもしれない。しかし君たちがいずれ作ることになる業務アルゴリズムにはまったく無縁のものだと思ってもらって間違いない。どうもこの業界、オブジェクト指向でなければダメ、というような風潮がまかりとおっているけどな、オブジェクト指向なんか本当に使っている人はほとんどいないよ。オレも少し勉強してみたけど、カプセル化とかポリ何とかとか、どうにも利点が理解できなかったね。実際、実業務で使ったことなどないしな……

「またお前、オブジェクト指向の話をしてるのか」と思ったかもしれませんが、2010年の架空の開発現場での登場人物の話です。
高慢と偏見(1)隣は何をする人ぞ:Press Enter■:エンジニアライフ

この発言に主人公たちは眉をひそめるのですが、今みると全く当たり前のことを言っているように思います。カプセル化は理解してほしい気はしますが。

そしてstaticを勧める。

「staticを使えばインスタンス宣言などしなくてもいいんだよ。どっちが楽か分かるだろ? いちいちインスタンス宣言するなんておかしいよ」

「staticおじさん」という言葉があります。この物語に出てくる三浦マネージャーのような人をさして、staticだけではなく技術についていけていないことを揶揄するように使われます。

けど、ここでのコードは研修のサンプルコードの話で、例えばフィボナッチを次のように書いてた感じに思います。

public class Fib {
  public static void main(String[] args) {
    Fib f = new Fib();
    System.out.println(f.calc(5));
  }

  int calc(int n) {
    if (n <= 1) return n;
    return calc(n - 1) + calc(n - 2);
  }
}

calcをstaticにしてしまえば「インスタンス宣言」などしなくていいです。Fibのオブジェクトの必要性はないですね。

public class Fib {
  public static void main(String[] args) {
    System.out.println(calc(5));
  }

  static int calc(int n) {
    if (n <= 1) return n;
    return calc(n - 1) + calc(n - 2);
  }
}

Javaのstaticはクラスをネームスペースとして使う機能で、クラスを拡張版packageとして使う機能といえます。importも使えますね。

この時期、なぜかstaticではなく「インスタンス宣言」したほうがいいという風潮でした。「プロJava」の書評にも「著者が static 好きすぎ」と書かれてたりするので意味なくstaticを忌避する風潮は残ってるようですが。

この後も

「私の経験から言うとコードレビューはデバッグに非常に有効にもかかわらず、このプロジェクトでは月に1回も実施されていないようなので、ここらでビシッと引き締めたいね」

とコードレビューを勧めると

「ここのメンバーはコードレビューが必要なレベルではありません。全員が自分が書くコードの意味を理解しているし、それを実装する能力も十分です。また、それぞれ所属する会社としての文化も違うわけですし……」

と、主人公陣営から反論が来たりしています。
高慢と偏見(2)使徒襲来:Press Enter■:エンジニアライフ

2010年はGitHubもまだ会社ができたばかりで、プルリクエストによるコードレビューは知られておらず、紙ベースでみんなで集まってレビューしていますが、コードレビューについては今では常識になったことを言っています。
そのあとも、変なコード分割をするなとか、割とまっとうなことを言ってるはずですが、主人公たちからは受け入れられません。

GCバージョン管理システムを知らなかったり、方向性はいいけどツールに疎いという感じではありますが。あと態度が悪い。
けど、主人公たちも「今までやってたから」「良いと言われてるから」くらいしか理由を説明できないにも関わらず、三浦マネージャ不在のときに一気にコードを進めて既成事実化したり、あまりよくない。 主人公たちが「staticだからダメ」「オブジェクト指向じゃないからダメ」という「オブジェクト指向おじさん」になってるようにも見えますね。主人公は女性のようだけど。

「staticおじさん」三浦マネージャの、staticに関する話の元ネタはこれなのかもしれない。

「メンバー関数をstatic宣言すればインスタンス宣言をしなくてもいい」ということ知ってからは、メンバー関数を従来のファンクションのように使っている。共有変数も、pubulic static宣言していまう

実はオブジェクト指向ってしっくりこないんです!:気分はstatic!:エンジニアライフ

この内容も用語の使い方が甘い部分はあるものの、そこまで間違ってないように見える。

ようやく、オブジェクト指向だからよい、オブジェクト指向じゃないからよくない、というような空気が薄れて、時代がstaticおじさんに追いついてきた感じがある。

追記

三浦マネージャも主人公側も変なことを言ってる部分があってどっちもどっちなのに、三浦マネージャのいい部分、主人公側の悪い部分だけとりあげて、オブジェクト推進派への嫌悪感が表れているという指摘があったのだけど、まあ「static好きすぎ」という書評への嫌悪感が表れてしまってますね・・・

「プロになるJava」で例えばこんな感じで、サンプルで出てくるメソッドなどは、インスタンスが必要なければstaticメソッドとして定義しています。

public class Sample {
  public static void main(String[] args) {
    foo();
  }
  static void foo() {
    System.out.println("Hello");
  }
}

これ別に、Java 21に入った試用機能でmainを簡潔に書くとこう書けるんですね。staticかどうかはJavaコマンドの都合であって本質的ではない。

public class Sample {
  void main() {
    foo();
  }
  void foo() {
    System.out.println("Hello");
  }
}

既存の機能の範囲でも、無用にインスタンスを作って無理矢理インスタンスメソッドにしているサンプルをよくみかけます。

public class Sample {
  public static void main(String[] args) {
    Sample s = new Sample();
    s.foo();
  }
  void foo() {
    System.out.println("Hello");
  }
}

シングルトンにすると、フィールドもグローバル変数化するのでstaticと問題は変わらなくなるし、DIコンテナ使った場合もコンテナはグローバル変数置き場なので同様です。
そうやって、単に「staticロンダリング」のようなことをして実質はstaticのようなコードを書きつつ「staticじゃないからヨシ」みたいなことしてるんではと思ってたところにstaticおじさんの話題が出てきたので勢いで書いてしまったらこうなった。