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おじさんの話題が出てきたので勢いで書いてしまったらこうなった。

ジョギングを始めた。700mほど。

そういえば、去年から雑なジョギングを始めている。
バスが間に合わなそうで走ったときに、ちょっと走れなすぎてヤバいなと思ったので、走るという行為をたまにやっとこうと思ったのがきっかけ。 その程度のモチベーションなので、何キロも走ったりとかせず、家のまわりのブロックを一周するくらいにした。

そうすると、距離にして700m弱で、準備をして部屋からでて走って戻っても10分かからない。
テキパキやれば5分ちょいくらい。
数キロ走ろうとして30分とかかかってしまうと走るタイミングを考えてしまうけど、5分で終わるとなると思いついたときに走ってくればいいのでやりやすい。ぼくでもできる。
やはり、継続したいことは5分で終わるようにするべき。

ということで週に1-2回くらい思い出したように走ってる。
やらないよりはマシという程度に健康になった気がする。やらないよりはマシなのでいいのだ。

報道ヘリがうるさくて救助の邪魔になるという話はどう広まったのか

報道ヘリがうるさくて救助の邪魔になるという話はどう広まったのか、というのを調べてみていたのでメモ

そもそもとして「報道ヘリがうるさくて救助の邪魔になる」ということなんてあるのか、という話は、1995年1月17日の阪神淡路大震災にさかのぼる。
震災後6日後に収録されたと言われる1月27日放送の「パペポTV」で上岡龍太郎が次のような発言をしていた。

取材陣のヘリコプターがあの被災地の上を飛び回るでしょう。あの爆音のために、生き埋めになってる人に外からどんなに声かけても、その人たちの声が爆音のために聞こえない

救助の邪魔になるという話 以外にも、被災者から「自分が見せ物にされている」というような苦情もあったようだ。救助ヘリの邪魔になる高度を飛ぶようなこともあったらしい。

これは実際に問題だったようで、その後1997年に日本民間放送連盟から「航空取材ガイドライン」が出されて、報道ヘリがある程度の高度を保つようになっている。
よりよい放送のために | 一般社団法人 日本民間放送連盟

なので、現在ではマスコミのヘリはそこまで邪魔になるような高度を飛んでないはず。

にもかかわらず、いまネットでそういう話が流れるのは、2016年に上記の番組がYouTubeにあげられて、その書き起こしがネットに広がったというのが影響していそう。
もちろんそこには航空取材ガイドラインの話は出てこないので、「今でも邪魔な報道ヘリの飛ばし方をしている」というような印象をもって広まった。

それがいまだにTwitterで語り継がれてる、というそういう状況だと思われる。

※ 追記 2024/1/6 長崎県の轟峡遊歩道での件が「反例」として貼られてるけど、ガイドラインで報道ヘリの基準高度が600-700m以上くらいに決まってるものの(具体的な数字は見当たらず)、標高200mということで報道ヘリとの距離が平地より近くなったんじゃなかろうか。 あと、ドローンは電波がそれほど届かないので操縦者が直下まで出向かなければならず、災害時に飛ばすのには向いてないですね。

今年おもしろかったマンガ2023

今年読んで面白かったマンガをまとめておきます。

葬送のフリーレン

アニメがヒットしてるフリーレン、最近やってた黄金郷編がめちゃよかった。

転生してハイエルフになりましたが、スローライフは120年で飽きました

フリーレンはエルフを主軸にしたマンガではあるけど、基本的にはフェルンの物語なので、人間の時間軸で話が進みます。
一方で「転生してハイエルフ」はエルフの時間軸で話が進むので、宿屋の女の子が、次に会う時には大きくなっているということが当然のようにあります。
エルフのように生きるのがどんなことかということを書こうとしてる感じ。

ヘルモード

貧しい農村に生まれて召喚スキルを使ってちょっとずつ認められていくという話。
召喚獣がかわいい。
最初のちょっとしたエピソードもぜんぶ伏線になっていて、そういうことだったのかとなっていくのがいいです。

落ちこぼれ国を出る

貴族の家を追い出されるけど、付与術で無双していくという追放もの。
追放した貴族が没落していくざまぁものでもあるのだけど、その没落しかたが他にない感じでおもしろい。
ニーナがかわいい。

宇宙軍士官、冒険者になる

宇宙船が事故にあって地球型の惑星に不時着して冒険者になるという話。
かなり面白いのだけど、原作に追いついているようで、続きが出るのか心配。

片喰と黄金

イギリスの貧しい農家の女の子とその従者がアメリカにわたってゴールドラッシュに沸く西部を目指すという話。
なんかがんばったらどうにかなる感じがいい。

正反対な君と僕

ブコメ
だけどドタバタしてるだけじゃなくてみんないろいろ考えていてよい。
登場人物みんないい人。

今年買ってよかったもの2023

今年買ってよかったものまとめ

フライパン

テフロンのはがれたフライパンを惰性で使い続けていたのだけど、餃子やいてもはがれないし、タマゴを炒めるとくっつきまくりで気になっていた。
で、インターネッツぽちぽちやってるときに、なんとなく買ったら、やっぱり新しいフライパンはよかった。
オリーブオイルとニンニクと塩だけのパスタがおいしすぎてよく作っている。

電子レンジ

もらいものの電子レンジをずっと使ってたのが壊れたので買いなおし。
あっためれればいいので、一番やすいのを買った。
そしたら、キッチンタイマー機能があって、便利につかっている。
アナログのキッチンタイマーはあるのだけど、1分や2分は計りにくくて、電子レンジのタイマーを使うとちゃんと計れるので、紅茶を煎れるときの時間をちゃんと調節できるようになっておいしく紅茶が飲めている。
ただ、扉をあけると電源が入る仕様なのだけど、1秒弱ほどのラグがあって、そのラグの間にボタン操作するとフリーズして電源抜き差ししないと復帰しないというバグがあって「SHARPの開発りょく~」とか思ったりしている。

Positive Grid Spark GO

ちいさいギターアンプ
アンプもってなくてマルチエフェクタからPC用のオーディオインタフェースにつないでヘッドフォンで聞くというのをやってたのだけど、音を出したい、けどあまり音量も出したくないというので買ってみた。
スマホと接続していろいろエフェクトを調節できる。小さい割に出力が5Wなのでそれなりに大きい音も出るけど、小さい音がきれいに出るのがいいところだと思う。
ざつに机の上に置けるサイズなので、適当にギターをつないで弾いたりしてる。便利。

Google ColabでJavaを使う

Jupyter for JavaというのがInfoQで紹介されていたので試してみました。
Java News Roundup: JDK 22, Spring CVEs, Liberica JDK, JDKMon 21, Jupyter for Java, Gradle 8.5

Jupyter notebookでJavaを使うためのいろいろをまとめたGitHub organizationらしい。
https://github.com/jupyter-java

やってみたのがこれ。

まずGoogle Colabを開く
https://colab.research.google.com/

で、「ノートブックを新規作成」

ここで「ノートブックの設定」を見てみる。

「ランタイムのタイプ」にPython 3とRだけある。まだJavaは使えないことを確認。

とりあえずJavaのバージョン確認。11が入ってる。

17とか21が使いたければ、aptでインストールを。

Jupyter for Javaのページの「Installing in online Jupyter notebooks」の4行をコピー
https://github.com/jupyter-java

こんな感じになってる。

!pip install jbang
import jbang
jbang.exec("trust add https://github.com/jupyter-java")
jbang.exec("install-kernel@jupyter-java")

貼り付けて実行

30秒くらい待つと「ランタイムのタイプ」でJavaが選べるようになる。

そうするといろいろとJavaっぽいものが動かせるようになる。

%mavenMavenリポジトリからのライブラリインストールもできる。

%maven org.knowm.xchart:xchart:3.5.2

ので、こんなこともできる。

import org.knowm.xchart.*;

double[] xData = {0.0, 1.0, 2.0};
double[] yData = {2.0, 1.0, 0.0};

XYChart chart = QuickChart.getChart("Sample Chart", "X", "Y", "y(x)", xData, yData);

BitmapEncoder.getBufferedImage(chart);

こうなる。

実行環境としてはIJavaがインストールされるので、ノートブック上の使い方はこちらを。
https://github.com/SpencerPark/IJava