セールで1000円くらい安くなってて、前からちょっと欲しいなぁと思ってたので購入。
ディスプレイ1台、キーボードとマウスとUSB PDがノートPCに繋がればまぁいいやってレベルにはちょうどいい感じ。
USB PDの給電が60Wに達していないので使えるPCを選ぶけど、それを割り切れればいいかな。
データ構造をimmutableにしたい、イベントは起きたことをそのまま記録したい、更には監査の観点から修正させたくない、という人類の夢と希望に対して、「だってそれじゃあ現場は回らないんだよ」という例外運用のバランスをどこで取っていくか?というのは昨日・今日出てきた話ではないんですよ
— magnoliak🍧 (@magnolia_k_) 2021年11月28日
所謂、業務システムの設計の一番肝心なところって、「起きた事実をありのまま記録する」っていう要件と、実際の運用がそうなっていない現実との戦いなんじゃないかって
— magnoliak🍧 (@magnolia_k_) 2021年11月28日
みんなそうしたいんだよ、でもできないんだよっていう
「データを活用しよう」って言い出しても、「活用できるように維持していましたっけ?」みたいな話も同じなんだけど、とにかく例外との戦いなんですよ
— magnoliak🍧 (@magnolia_k_) 2021年11月28日
その時はそれで回るからいいじゃん!って積み重ねで、性別「男」「女」「1」「2」「その他」みたいなのが発生するんですよ
— magnoliak🍧 (@magnolia_k_) 2021年11月28日
でも、ここまでわかりやすい事例はまずなくて、不整合を検知するのは難しいんだ
最近のimmutableデータにしようって話、メモリやディスクが貴重だった時代の、「イベントと、何でも状態フラグ」が混在しているテーブル設計からの呪いみたいな話で、それからは脱出できると思うけど、その先の業務の本質と向き合うフェーズがすぐに来るんですよ
— magnoliak🍧 (@magnolia_k_) 2021年11月28日
汎用性を持たせようとしたり、一定のルールに基づいて設計しようとすると「無駄じゃない?」みたいな話が出てくるんだけど、データを活用する時代に異なる要件は分離しておかないといけないっていうのを浸透させていかないと
— magnoliak🍧 (@magnolia_k_) 2021年11月28日
ほんとシステム開発の原理原則は、「混ぜるな危険!」なんですよ
たぶんこの辺ももっと言語化されても良い領域なんじゃないかなと。
システムと運用の境目をどこに置くのかによって設計の複雑さは大きく変わっていって、immutableにしたい気持ちと、どんどんmutableな要望が出てきた時、それは実はそもそも境目の前提が合っていないんじゃないかとか何とか。
今まで簡単なコードリーディングくらいはしてきたけど、自分でちゃんとGoのコードを書いてこなかったなーと思って、とりあえず『Learning Go』を買ってみた。
ざっと一通り書けるようにトピックが網羅されている気がする。
O’ReillyのScala関係の本がScala3に対応して改版されました。
Scala3で大きな文法や言語機能に大きな変化が有った一方で、ライブラリは必ずしもScala3に対応しきれてはいない、という状況ですが、書籍類は続々とScala3対応版になっていますね。
まだメンテされ続けるScala2のコードも当然残るので、『Programming Scala』はかなり意識的にScala2と、Scala3で異なる部分を丁寧に説明しています(Scala3対応の機能のところには「3」のマークが付いています)。
『Scala Cookbook』は言語機能周りはScala3にアップデートされているので、OPTIONAL BRACES形式の文法で書かれている(つまり明示的にブロックのための括弧を書かない)一方で、ライブラリ関係はScala2に合わせているのでブロックのための括弧が書かれています。
データモデルを作るっていうのは、別にデータベース設計をするだけじゃなくて、アプリケーションコードの中でどんな処理フローになるかを考えて、それに適したモデルと、その引き回しの指針を決めることなんだよね
— magnoliak🍧 (@magnolia_k_) 2021年11月20日
そうしないと知らないオブジェクトがどんどん増えていく
「必要だから作った」データ構造のためのオブジェクトがそこらじゅうに溢れかえると、コードはデータ構造の詰め替えばかりになってしまう
— magnoliak🍧 (@magnolia_k_) 2021年11月20日
その場その場で最小のコード量にしようと思ってボトムアップ的に作り上げていくとそんなことが起きる
モデルを作ることで…
— magnoliak🍧 (@magnolia_k_) 2021年11月20日
1. ギョームヨーケンと実装詳細を”なるべく”引き離すことができる
2. 場当たり的なデータ構造が散らかるのを防ぐ
3. 作る過程においてギョームヨーケンへの理解が深まる
データ構造を詰め替えるためのコードが大部分を占めた時、何かがおかしいんだよね
— magnoliak🍧 (@magnolia_k_) 2021年11月20日
場当たり的なコードを書き続けると、そこら中に個別最適なデータ構造が作られてしまって、気がつくとコードの大部分がデータ構造間の形式に合わせるための詰め替えになっていたりしませんか。
コードからビジネスロジックを読み取りたい時...
あたりを読み取りたいので、単なるデータ構造の変換のためのコードが増えてくると上記のようなコードが埋没して読み取りづらくなっていきませんか。
特にデータベースのカラム、不用意にお作法を守らずに参照しているコードが思ってもみなかった影響を与えることが有るので、素早く読み取りたいけど、全カラムを取得して変換して、フィルタして...みたいなコードが続くと実際に影響のあるコードを特定するのにすごく時間がかかってしまう。
ひょっとして我々が今求めているのは、そのデータがどこから来て、どこへ行くのか、出自が追跡可能なデータモデル・機能なのかもしれない(今、思い付いた)。
Rustの所有権という概念もいいけど、エンタープライズ用途だと、追跡可能性(トレーサビリティ)という概念を導入した方がいいのかもしれない。
色んなJavaのディストリビューションのバージョン表記を集めてみました
1行目のダブルクォーテーションに囲まれた数字を見ておけばOKですね
java version "17.0.1" 2021-10-19 LTS Java(TM) SE Runtime Environment (build 17.0.1+12-LTS-39) Java HotSpot(TM) 64-Bit Server VM (build 17.0.1+12-LTS-39, mixed mode, sharing)
openjdk version "11.0.13" 2021-10-19 OpenJDK Runtime Environment Temurin-11.0.13+8 (build 11.0.13+8) OpenJDK 64-Bit Server VM Temurin-11.0.13+8 (build 11.0.13+8, mixed mode)
openjdk version "11.0.11" 2021-04-20 OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.18.04) OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.18.04, mixed mode, sharing)
openjdk version "17.0.1" 2021-10-19 LTS OpenJDK Runtime Environment Microsoft-28056 (build 17.0.1+12-LTS) OpenJDK 64-Bit Server VM Microsoft-28056 (build 17.0.1+12-LTS, mixed mode, sharing)
openjdk version "17.0.1" 2021-10-19 LTS OpenJDK Runtime Environment Zulu17.30+15-CA (build 17.0.1+12-LTS) OpenJDK 64-Bit Server VM Zulu17.30+15-CA (build 17.0.1+12-LTS, mixed mode, sharing)
要約
u
の後ろの数字が一番大きなものが最新版-b
の後ろの数字はjdk自体のビルド番号であり、jdk自体の開発者向け情報...利用者側は無視してよいjava -version
でインストール済みのバージョンを確認すると、1行目に「1.8.0_312」とインストーラと異なる表記方法で出力されるu
に続く数字と一致する1.8.0
は固定で、今後JDK 8がアップデートされても変わることは無い(u
の後ろの数字だけがインクリメントされる)+
の前の数字を確認する+
の後ろの数字はjdk自体のビルド番号であり、jdk自体の開発者向け情報...利用者側は無視してよい17
はJDKのメジャーバージョン...JDK xxという表記と一致する0
のままjava -version
でインストール済みのバージョンを確認すると、1行目に「17.0.1」とインストーラのバージョン番号からビルド番号を除いたものが出力される上記二つと異なる表記ルールだが、LTSバージョンではないため割愛
詳細
Javaのバージョン番号の形式は典型的なセマンティックバージョニングでもないし、長い歴史の中で何度も変わっているので分かりづらいところがあります。
例えば2021年11月14日時点で最新バージョンのTemurinのJDK 8のバージョンはダウンロードサイトには「jdk8u312-b07」と表記されています。
実際にインストールして「java -version
」でバージョン番号を確認すると以下のように返ってきます。
openjdk version "1.8.0_312" OpenJDK Runtime Environment (Temurin)(build 1.8.0_312-b07) OpenJDK 64-Bit Server VM (Temurin)(build 25.312-b07, mixed mode)
まず、バージョン番号らしきものが3種類出てきて、どれ一つダウンロードサイトの表記と合っていません。
openJDKベースのでJDKであるTemurinをインストールしたのでおそらくopenjdk version
がJDKのバージョン情報のように見えます。しかし、「1.8.0_312」というバージョンの、セマンティックバーョニングでいうメジャーバージョンを示す位置にある「1」や、パッチバージョンを示す位置にある「0」はどこから登場したのでしょうか。
また、同じくTemurinのJDK 17のバージョンは「jdk-17.0.1+12」とダウンロードサイトに表記されています。
同じようにインストールして「java -version
」でバージョン番号を確認すると以下のように返ってきます。
openjdk version "17.0.1" 2021-10-19 OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)
少し表記が一致しましたが、今度は最後の「+12」はどこかへ消えてしまいました。JREのバージョン番号には含まれているし、完全一致しています。
この違いは何でしょうか?
OracleのJavaのサイトに残っているリリース情報を見てみるとバージョン番号の形式が色々と変わってきたことがわかります。
https://www.java.com/releases/
その最後にバージョン番号の変遷の歴史が載っていました。
ここに書かれている「JEP 223」と「JEP 322」がポイントになるようです。それぞれ提案を見てみましょう(JEPは、JDK Enhancement Proposalsの略で、機能拡張の提案文書のこと)。
JDK 9リリースに向けてバージョン番号の形式を変更する提案が、「JEP 223: New Version-String Scheme」でした。これは採択されてJDK 9から実際に適用されました。
Motivation
の項にこう書かれています。
What's the difference between releases named "JDK 7 Update 60", "1.7.0_60", and "JDK 7u60"?
These are just different names for the same release. These differences make it difficult to identify and verify equivalent releases. A simple pointwise comparison of sequences of parsed tokens does not suffice; instead, a fairly sophisticated algorithm is needed. The use of the lower-case 'u' is not an industry standard and is not language-neutral.
冒頭のJDK 8のバージョン番号の件でいえば、「1.8.0_312」と「JDK 8 8u312」は同じものを指すそうです(その後ろに続く「b07」は後述します)。
また、話は前後しますが、u
の後ろに続く数字は以下のようなルールで採番されているそうです。
Minor releases containing changes beyond security fixes are multiples of 20. Security releases based on the previous minor release are odd numbers incremented by five, or by six if necessary in order to keep the update number odd.
機能追加の時には20の倍数を付与し、セキュリティ修正をする時は、5か、6を足していく...よく分からないですね。とにかくJDK 8に更新が発生すると「u」に続く数字がインクリメントされ、リリースされることが分かります。とにかくこの数字が一番大きなものを使っておけば大丈夫、という訳です。
ただ、これでは分かりにくい、ということで「JEP 223: New Version-String Scheme」では「$MAJOR.$MINOR.$SECURITY」という一般的なバージョン番号の形式に変更することが提案されました。
メジャーバージョンが上がれば$MAJOR
がインクリメントされ、バグ修正や実装の改善(GCの拡張など)が有れば$MINOR
がインクリメントされ、セキュリティ修正が反映されれば$SECURITY
がインクリメントされます。ただし、$MINOR
がインクリメントされても$SECURITY
はリセットされずそのままインクリメントされ続けます。これはセキュリティパッチと機能追加を独立してチェックできるようにするための仕組みだそうです。
また、この時点でメジャーバージョンとJDKの番号が同期されるようになり、JDK 9のメジャーバージョンである$MAJOR
は「1」ではなく、「9」になりました。ここは分かりやすくなった点です。ただ、逆にちょっと分かりづらくなった点として、$SECURITY
がゼロになる時は、ゼロと表記するのではなく省略となり、更に$MINOR
と$SECURITY
の両方がゼロの場合は両方とも省略されます。そのため、最初にリリースされた「JDK 9」のバージョンは「9」で、その後にリリースされたセキュリティアップデートは、「9.0.1」というバージョンになりました。ちょっと分かりづらいですね...
しかし、openJDKが半年に一度のメジャーリリースとなり、それに対応した更に新しいバージョン番号の形式であるTime-Based Release Versioning
がJEP 322として提案されたため、この形式でのリリースはJDK 9のみとなってしまいました。$MINOR
はインクリメントされないまま終わりました。
ちなみに、4番目以降の数値はopenJDKの派生リリースを行うベンダが自由に付与して良い、という扱いになっています(JDKのディストリビューションベンダが独自のパッチを当てたバージョンをリリースする際に利用する)。
openJDKが半年に一度のリリースサイクルに変更されることに合わせて「JEP 322: Time-Based Release Versioning」という更に新しいバージョン番号の形式が提案され、JDK 10から実際に適用されました。
今度は、「$FEATURE.$INTERIM.$UPDATE.$PATCH」という形式に変わっています。
$FEATURE
は$MAJOR
と同じ...JDK 17であれば「17」...ただし、JDKが6ヶ月ごとのリリースモデルに変わったため、何が含まれているかに関わらずインクリメントされます$INTERIM
は$MINOR
と同じ...バグ修正や、互換性を破壊しない拡張が含まれると定義されています...ただし、6ヶ月ごとのリリースモデルではゼロに固定化されます...将来のリリースモデル変更のための予約となっています$UPDATE
は、互換性を破壊しないセキュリティ修正、バグ修正、リグレッション修正が含まれる...従来の$SECURITY
と$INTERIM
が混ざったような定義になっています$PATCH
は、緊急リリースのために使われます$FEATURE
は6ヶ月に一度インクリメントされますが、$UPDATE
も新しい$FEATURE
のリリース後1ヶ月時点、以降は3ヶ月に一度でインクリメントされてリリースが行われます。
また、ビルド番号を示す$BUILD
を「+」に続けて付加することができます。ビルド番号は開発中にインクリメントされる番号で、リリースされてしまえば気にする必要はありませんが、リポジトリのtagでは番号表記だったり「ga(general availability)」と表記されていたり、ちょっと分かりづらいですね。冒頭の、「17.0.1+12」であればJDK 17.0.1というところだけを注目しておけばOKです。
17.0.1はビルド番号12がGAリリースなので、17.0.1+12とが17.0.1+gaという表記は同じものを指しています...逆に17.0.1の後ろが11以下のバージョンのソースを開発目的以外で使うべきではない、ということが分かります。このビルド番号の考え方はJEP322が適用される前のJDK 8でも同様に運用されているようです(ただし、ビルドを示す「b」が付加されて「b07」という表記になっているので多少表記方法は異なる)。
あくまでビルド番号なので、バージョンコマンドでopenjdk自体のバージョン表記には含まれていないようです。
JEP 223の定義と変わらず、$PATCH
と$UPDATE
と$INTERIM
が全てゼロの場合は省略されるので、JDK 17の初期リリース時のバージョンは「17」となり、次のリリースのバージョンは「17.0.1」となりました(長期サポート版にはバージョン番号の後ろに、空白を一つ空けてLTS
を付ける...というルールも有るようですが、Oracleのリリース一覧では何故かそれぞれの初期リリースの時にしか付加していないようですね)。
冒頭で、バージョンコマンドは3つのバージョンを表示すると書きましたが、一つ目がJDKのバージョン、二つ目がJREとしてのバージョン、三つ目がJVMとしてのバージョンとなっていてビルド番号はJDK 8の頃よりJREとJVMにのみ表記する仕様が踏襲されているようです。
openjdk version "17.0.1" 2021-10-19 OpenJDK Runtime Environment Temurin-17.0.1+12 (build 17.0.1+12) OpenJDK 64-Bit Server VM Temurin-17.0.1+12 (build 17.0.1+12, mixed mode, sharing)
バイナリをリリースしているベンダが独自にパッチを充てた場合、上記のバージョン番号の後ろにディストリビューション独自のバージョン番号を付与して区別します。例えば、ubuntu 18.04のopenJDK 11のパッケージのアップデート情報は以下のように管理されていて、11.0.11+9-0ubuntu2~18.04
が、11.0.11+9をUbuntu 18.04へバックポートしたビルドであることが分かります。
バージョン番号の後ろに+に続いて付けられている番号の意味が分からなかったので調べ始めたら、色々なことがわかったのでメモにしてみました。簡単に言うと、無視しておいて良かった、ですね。
次回こそディストリビューションの話をします。