日々常々

ふつうのプログラマがあたりまえにしたいこと。

DockerのアップデートしたらTestContainersが動かなくなったとかゆー

起こったこと

SpringBoot(3.5.7以前)でTestContainersを使っていて、Dockerをアップデートしたらテストが通らなくなった。

という状況のお話です。

環境を最新化するのは重要ですが、やると動かなくなるというのは困ったもの。 それを嫌ってアップデートを止めるというのも現実解としてはありますが、現在はどんどん更新していく方が主流かと思います。 動かなくなるというのも減りましたし。

対処

正道: SpringBootを更新する

リリースノートを読んでいればわかります。

Release v3.5.8 · spring-projects/spring-boot · GitHub 一番上にデカデカと書いています。

あとこういうのは雑にアップデートしてみたら動いたりします。 私は SpringBootを更新したら動いた→リリースノートを見た(教えてもらった) という順でした。 リリースノートを見るのは大事。順番はどっちでも。

SpringBoot3.5.8でもSpringBoot4.0.0でも対処されてます。

回避

とはいえアップデートができるとも限らない。

考えられる対応はこんな感じです。

  • Dockerのダウングレード
  • DockerのAPIバージョンを指定する(おすすめ)
  • Testcontainersを使用するテストをこの環境では諦める

回避するならAPIバージョン指定で対応するのがよいです。

Dockerのダウングレードはそれはそれで手間なのと、Dockerのセキュリティ対応などを見送るってことなのでよろしくない。 他の方法がない場合とか、全く手掛かりもない場合に切り分けのために試してみるなどでは有効なアプローチですが、なるべくなら取りたくない選択肢です。

諦めるのは、まぁ、諦められるならそれでも。 一部のテストでしか使ってないとか、CIでは動いてて自分の手元の環境だけだからーとかなら、まぁ、うん。(奥歯に物を挟みながら)

参考: https://github.com/testcontainers/testcontainers-java/issues/11212

個人レベルでの回避方法

ホームディレクトリに .docker-java.properties ファイルを作って以下を記述します。

api.version=1.44

プロジェクトごとに設定するとか実行時に指定するとかの方法もありますが、Dockerのアップデートなどの統制をとっていないということは環境が個々人に委ねられているということかと思います。 Testcontainersを使用しているプロジェクトが複数あるなら、環境問題としてHOMEに置いてしまうのがよかろうかと思います。

で、早くSpringBootのバージョンアップしよーぜーって言い続ける。 HOMEに置く場合、対象のバージョンアップが終わったら削除するの忘れないように……。 (ってのを気にするなら実行時にパラメタ渡すほうがいいのか?)

指定の方法は色々あって、詳しくは docker-java のREADMEをみるとよいですが、たとえば -D で渡したりもできます。

./mvnw -Dapi.version=1.44 clean test

ほんとの一時的な回避ならこんな感じで。(フォークしてるとかだと -D をテスト実行時に届くように細工がいった記憶あるけど、手元に手頃なのはなかった。)

チームレベルの回避ならテスト実行時のクラスパスに含まれるように docker-java.propertis を配置してしまうのがよかでしょう。 多人数で個々人が仕組みを理解せず「とにかく ~/.docker-java.properties を置く」とかやってしまうと、当面は動くでしょうがDockerやdocker-javaの更新でどちらかが指定したAPIバージョンに対応しなくなったら動かなくなっちゃうでしょうし。 それができるならSpringBootバージョンアップやっちゃえよ

仕組みと対処と選択の話

対応だけが知りたいならここまででOK。以下はどうやって調べるかとか、どうやって選ぶかとかの話です。

SpringBootTestがDockerを動かすにあたってはこういう構造になっています。

SpringBootTest -> Testcontainers -> docker-java -> DockerEngine

今回の動かなくなるのはDockerEngineのバージョンが 29.0.0 に更新されたことで、docker-javaとDockerEngine間がつながらなくなることによります。

SpringBootがDockerを動かすのに登場するライブラリにTestcontainersとdocker-javaの2つあるのがポイント。

Testcontainersもメジャーバージョンが上がっていて、こちらではDocker29.0.0の対応がされていることが謳われています。

「動きゃいいんだよ」という暫定対処をするなら、SpringBoot3.5.7 + Testcontainers2.x としてしまっても動いたりはするのですが、SpringBootは3.5.8でTestcontainers2.xにせず、Testcontainers2.xにしたのはSpringBoot4から。 ということで SpringBoot3.5.7 + Testcontainers2.x とするのはあまり筋が良くなさそうです。 ちゃんとしないとTestcontainersが1系と2系が混在することになっちゃいますし、この組み合わせはSpringBootDependenciesで検証されているものではないため、「SpringBootを使用する際はSpringBootDependenciesのバージョンに乗っかる」(私的)ベストプラクティスに逆行することになります。

とにかく更新すれば動くのは動かしてみたらわかりますが、自分の使っている道具がどのようになっているかを理解して対応を考えることも大事です。 全ての道具の低レベルなところまで理解しろというのは不可能に近い昨今ですが、こういう時に一段階だけでも深堀りしておくなどして少しずつ守備範囲を広げるのがいいんじゃないかなって。

ということで調べ方ですが、たとえばSpringBoot側の対応を見ると docker-java.properties というものでAPIバージョンを指定することで対応としていることがわかります。(SpringBootのコミットとかを辿ってみてください。)

動作している対処方法から、それがどのように作用しているかを見て把握するというアプローチ。 常にできるものでもありませんが、答えがわかっているところから辿るのは繋がることが保証されているのでやりやすいです。 (答えに辿り着くかどうか不明なものを試行錯誤するのは苦痛に感じることもあるわけで。) 不具合でも「直し方はわかっているけどなぜそれで直るのかはわからない」と言うのは稀によくある話。 とにかく直すのは大事ですが、直したとに「なぜそれで直るのか」を調べて裏をとっていくのもある種のスキルかと思います。

docker-java.properties は名前が示す通りTestcontainersではなくdocker-javaの設定です。 今回はファイル名がそのままなのでわかりやすかったですが、たとえば hoge.properties のような名前だったら「このプロパティは誰が読み取ってどう使っているんだ?」と探っていくことになります。 いつかは到達するのでしょうが、これも面倒臭い。わかりやすいファイル名で作ってくれていることに感謝です。

以上から「docker-javaの使用するAPIバージョンをテスト時に指定すればOK」ということになります。 ここまでわかったので、docker-javaの説明を見に行きましょう。

docker-java/docs/getting_started.md at main · docker-java/docker-java · GitHub

色々な指定方法があることがわかります。 その中で自分の状況にあった指定方法を選ぶことになります。

  • システムプロパティ
    • 実行時に都度指定するならこれが良さそう。単発実行ならこれかな。
  • 環境変数
    • システムプロパティは届かない時もあるからできるなら環境変数の方が良いかもだけど、今回は . を含むから使えないかな。
  • クラスパスの docker-java.properties
  • HOMEの .docker-java.properties
    • 個人の環境のDockerのバージョンに依存する話と捉えればこれかな。アップデートされても普通に動いてるうちは削除するの忘れたりしそうだなぁ。

みたいな。

万能な解があることってあんまないので、使える選択肢と、その選択肢はどういう状況の時に使うかと、今の自分(たち)の状況を見て選択していくのは重要な訓練かなと思います。 できれば言語化もしておくといい。私もうまくできているわけではないけど、うまくなるためにはやるしかないかなって。

きっとAIに書かせたら選択肢や条件もそれっぽいことを書いてはくれるんだろうけど、その内容を評価して選択するためには書く練習もいると思うんだよね……少々自分に老害感も感じつつ。

おまけ: SpringBootの自動更新について

SpringBoot4.0.0 がリリースされていますが、まだ3.5系を使用し続けているところも多いかと思います。

dependabotなど自動で最新化するツールを導入している場合であっても、SpringBoot4への更新を見送っていることがSpringBoot3.5.8への更新を覆い隠す状態になっていることで、やるべきアップデートを受け取れなくなるなどもあります。 「常に最新」という方針でないなら、バージョンを指定して調整する方法も道具箱に入れておきましょう。

たとえばdependabotなら「(当面は)4系はignoreにしておく」のような設定をしておく感じです。

Dependabot options reference - GitHub Docs

うまくいかないふりかえりとふりかえりの成果

ふりかえりについて思うところを書きます。

ここで言う「ふりかえり」は、それなりに短い期間で繰り返し行われるチームの活動です。 四半期とかそれ以上の期間を置いて行われるセレモニーのことではありません。

ふりかえりをうまくやりたい

ふりかえりカタログ などがあるように、ふりかえりににはたくさんの手法があります。

たくさんの手法があるということは、うまくいくやり方が定まっていないということだと思います。 知られている手法は「どこかでうまくいったかもしれないやり方」です。車輪の再発明するくらいなら車輪を借りるところから始めるのは便利ですが、「うまくいくやり方」として模倣するのはたいがいうまくいきません。

ふりかえりをうまくやりたいと言う話はよく聞きますし、私もうまくやりたいなぁとはたびたび思います。 思うんだけど、その話を迂闊にやると結構なコンテキストが乗っちゃうんだ。その一部を書いてみます。

なぜ自分たちのふりかえりはうまくいっていないのか?

よそでうまくいっているふりかえり手法をそのまま導入してもうまくいきません。

どの本で読んだかは忘れましたが「某有名企業でうまくいった方法をそのまま導入してもうまくいくわけはない。あなたの会社はその会社と同じ国で同じ規模の同じサービスを開発しているんですか?」みたいなことが書かれていました。その書籍ではふりかえり手法ではなく組織体制の話ではありましたが、構図は同じだと思っています。

組織に関しても「組織パターン」や「Fearless Change」などでもたくさんの手法が紹介されています。たくさんの手法があるということは、うまくいくやり方が定まっていないということだと思います。

ところで「なぜうまくいっていないのか」と見出しをつけたこのセクションですが、こういう表現には注意が必要です。 詐欺師の話術みたいなものにあったと記憶しているのですが、「なぜXXXなのか?」はXXXであることを強引に前提としてしまうテクニックの一つです。

と言うと、「うまくいっていない」が急にきな臭く見えますよね。 ……と言って注目させるのもテクニックだったりするのですが、その意図はないです。素直に捉えてください。こう言うことばっかり言ってると何もかも疑心暗鬼に捉えられるのではないかって疑心暗鬼に(無限ループ)

置いといて「うまくいっていない」に焦点をあててみます。

ふりかえりが「うまくいかない」とは?

定義が曖昧だと「うまくいっているか」が評価不能です。 不思議なことに、評価不能なものを人間は「うまくいっていない」と評価しがちです。

何をもってふりかえりの良し悪しを判断しますか?何かしらの定量指標がありますか?ある場合もあるでしょうが、明確な定量指標を置いてふりかえりをしているところは少ないんじゃないかなと思います。

なお「定量指標があるか?」を問うと「定量指標を作らなければならない!」と考えがちなのも人間の仕方ないところかと思います。 念の為表明しておきますと、私は「定量指標を置いてみてもいいけれど、ない方が好ましい」くらいのスタンスです。状況次第、要はバランスだね。

これで終わるとなんでこのエントリを書いているのか自分でも謎になるので仮説を書きます。一言で言うと 期待値が高すぎる です。 期待すべきでないことを暗黙に期待しているから、うまくいっていないと感じるのです。

ふりかえりはチームが直面している問題を解決する場ではありません。わかっている問題があるなら解決のための個別のアプローチをとりましょう。

ふりかえりはメンバーのスキルを向上させる場ではありません。必要なスキルがあるならばそれを修得するための学習だの訓練だののアプローチをとりましょう。必要なスキルがわからない?そんなものをふりかえりに期待してどうするの。

ふりかえりはXXXの場ではありません。「XXX」は任意の文言です。これが言語化できるのであれば、それに特化したアプローチはおそらく存在します。XXXの成果を主として期待するのであれば、ダイレクトにXXXに向かいましょう。

ふりかえりは短期的な成果を期待するものではありません。これは異論あるかもしれませんが、私は短期的な成果が主目的ではないと思っています。副次的に得ることは否定しませんが、そこに目を向けすぎると歪になると思っています。

短期的な成果を期待するふりかえり手法にKPTがあります。Tは次のふりかえりで評価されるため、Tの成果を期待しているように見えます。これはこれで大事なのですが、KPTの持つフォースとして「短期的に取り組める活動ばかりフォーカスされる」はよく知られている落とし穴でしょう。

私はKPTを採用する狙いは「小さい改善を積み重ねる経験値を積むこと」だと思っています。自分のやっていることを自分で改善すると言うスキルを持っている人は存外少なくて、学校教育などで「言われたことを言われた通りにやること」の訓練は長年やっているため非常に練度が高いです。慣れている道具と慣れていない道具であれば慣れている道具でものごとをこなしたいと思うのは自然なのですが、それ一辺倒だと不確実性の高い環境では厳しいものがあります。 そうしたスキルを成功体験も失敗体験も積みながら身につけられるのがKPTなどで、ふりかえりカタログでの「アクションを決める」とマークされているものだと思っています。

と言うことで、ふりかえりに対する期待値が高いと「うまくいっていない」と感じることになります。 高いというか、期待すべきでないものまで期待していると言う感じ。 期待とのギャップがあると「うまくいっていない」と感じるのは仕方がないでしょう。

ふりかえりの期待値が高くなる構図

そもそも構造としてふりかえりは期待値が高くなるようになっています。 わかりやすい成果を置きづらい一方で、さまざまな成果があがりがちです。 雑な期待は「悪いところを直して良いところを伸ばす」なので、あらゆることが成果として出てきうるものになっています。 期待するなと言うのも難しい。

ここで重要な考え方が ふりかえりは自分たちのもの です。 外部から期待をかけられても無視してよいです。自分が外部なら期待を抱くのは仕方ないですが、それを要求してはいけません。

自分が当事者なら精一杯期待しましょう。と言うか改善できると未来の自分たちに期待をかけてこそなところがあります。 「どうせ何も変わらないし」と自分たちが思ってふりかえりをする状況だと何も期待できません。 (この場合も往々にして当人たちのせいではなく、その状況にした環境の影響だったりするのですが、それは別の話。考え方は 表出した事象を叩き潰してはいけない の通りです。)

外部の期待がチームにかかるのは当然です。受け入れましょう。しかしながら外部の期待がふりかえりにかかるのはガン無視すべきです。

自分たちの期待がふりかえりにかかっている場合は少し難しいです。 個人の暗黙の期待であれば共有はしておきましょう。チームで共有された期待であれば、全力で取り組みましょう。 ただ前段で書いた通り、それをふりかえりにかける?特化した別のアプローチではない?はたまに考えてみてもいいかもね、とは思います。

体重計と体重のたとえ

体重に悩んだことのない方にはピンと来ない話かもしれませんが、体重計と体重でふりかえりをたとえてみようと思います。 コロナ禍以降の外出機会の激減やその他もろもろの影響で、結構体重が増えていました。 その過程で、「ああ、これふりかえりだな」と思ったのがこのエントリのきっかけです。 体重に関しては体質などセンシティブな話題でもありますが、私が自分の体質を前提に思ったことを記したもので、それ以上の意図はないことをご了承ください。

ふりかえりとは体重計に乗ることと似ています。体重計にのっても体重は変わりません。ここまではいいでしょう。

ここで問題になるのが「体重を測るだけで痩せる人がいる」です。 この手の人は体重を測り続けるだけで体重が減ります。 まぁ一昔前の私なんですけど。

で2年前はそんなだったんですが、3ヶ月前に久々に体重測ったらまた増えてて「やばくね?」となりまして。 体重計に乗るようにしたんですが、1ヶ月間はぜんぜん減りませんでした。

増えはしなかったのでその効果はあったのかもしれないですが、この時の私の感覚は「おかしいなー、体重測ってるのに体重減らないぞー?」です。 「うまくいくと言われているふりかえりの方法でふりかえりしているのに改善されない」と同じ構図に思います。

で、7月の後半から8月の前半にかけては「え、体重計乗ってるのに体重増えてる?なんでだ??」です。 字面だけ見るとなかなかインパクトある。 仕事でこう言うこと言われると困るよね。

ここで「摂取カロリーの記録」を始めました。 食事制限とか運動とかじゃなく、観測指標を増やしただけ。 そしたら減り始めました。

いわゆる観測者効果なんですが、適切な観測指標を持つだけで行動が変わって結果に繋がるのであれば、行動を直接変えるような手法をとる必要はないと言う例だと捉えています。 たとえば「毎日n分運動する」などの目標をたてて取り組むのは有効なのかもしれませんが、私にはおそらく合っていません。

実際のところ運動したらそれだけ「運動したなー」とか言って間食するのが私です。 去年平日に時間がとりやすかった時期があって数ヶ月プールに通ってたんですが、その期間一切体重減りませんでした。 家とプールの間にコンビニがあるのが悪い

あといろんなことをやろうとすると「なんで体重のためにこんなことせにゃならんねん」みたいに面倒になってやめるのも私。

……「良いたとえ話を思いついた」と思って書いてみたんだけど、十数年前の自分には全然伝わらないんだろうなと確信できるツイートも見つけてしまった。

10年も経てばなんもしなかったら増えるよ!>過去の自分

10年後の自分がこれをどう捉えるかは少し楽しみである。

……全体みたらこのセクションは蛇足に見えてきたけど、この話がなかったらこのエントリを書く理由が私にないので仕方ない。

ふりかえりをうまくやるには?

ふりかえりをうまくやるには?を考えるならば。 ふりかえりのふりかえりなんじゃないかなぁとは思います。

うまくできている点を見つける。うまくできなかった点を見つける。 なにはともあれふりかえりは名前の通り「ふりかえって見ること」です。王様は観測。 アクションを含むふりかえりもありますが、すべてのふりかえりにアクションがあるわけではありません。 すべてのふりかえりに観測はあります。

体重計に乗るだけでいいタイプであれば、観測だけで良いです。むしろそれ以外の余計なことはしない方が良いです。「ふりかえりで決まったことをやる、きまらなかったことはやらない」のようなしがらみは機動的な改善活動を阻害します。 いくつかの「うまくできている」チームの話を聞いてみると、単にやったことを共有するだけだったりします。特別なフレームワークなどはなく「前回のふりかえりからなにあった?」と言う雑談を少しする程度。誰でも真似できるにも関わらず成果は真似はできない、極致の一つでしょう。(その共有すら余計なこととできるものもあるかもしれませんが、人類のチームでは難しいんじゃないかなって思ったり。)

体重計に乗るだけだと不足するタイプなら、色々とやってみるのが良いです。 今の自分たちにあったやり方を見つけ、調整し続けられていれば「うまくできている」と言って良いと思います。 調整の幅はそれぞれでしょうし、頻繁に変わるのはそれはそれで異常事態(観測がやりやすいのは定点観測です)なので変えるのが良いこととは定義できませんが、数十回やって変わっていないのであれば、うまくいっていないことを疑っても良いかと思います。

私的にはふりかえりでのアクションは挙げるとしても、あまり具体的にはしたくないと思っています。 第一に、実行時点での自由度が欲しいです。不確実性の高い取り組みには状況に応じた判断が有効だと思っているから。その方が効果が出るかは不明ですが、もともと不明なもの。アクション単体ではなくその取り組みの結果から得られるフィードバックは多くなります。 第二に、具体的なアクションはそのまま形式化された「やることリスト」のようなものになりがちだからです。継続的にやるとそれがどんどん積み重なっていって、長大なチェックリストのように役に立たないものになることが目に見えているからです。

話を戻して。ふりかえりをふりかえることで、そのふりかえり手法が自分たちに合っているかを観測しましょう。

「ふりかえりをふりかえることでふりかえりを改善する」が回せれば「うまくいっていない」はたいした問題でなくなります。 そのうちうまくいきます。 あと、もしいま「うまくできている」であっても、何かの拍子で「うまくいっていない」に変わるものです。よほど完成されたチームでない限りは変わると思います。変わらないなら鈍感さを疑うかもしれない。 本当にうまくできていないかは先に挙げた通り期待値のズレがそう思わせているだけなのかもしれませんが、何かが改善されたり状況が変わったりしたシグナルの可能性も高いので、感覚は大事にするのがいいんじゃないかなぁと。

まとめ的な

最初の方にふりかえりの評価の話をしましたが、私はふりかえりの成果を「自分たちで改善したプロセス」と置いています。(よりメタ的に「自分たちでプロセスを改善できるチーム」と言うこともあります。) 自分たちのプロセスのハンドルを自分たちで握るのが、不確実性の高いプロジェクトには有効です。

プロセスの改善を自分たちでできているのであれば、ふりかえりはうまくいっています。 そうでなければ、ふりかえりはうまくいっていません。 実にわかりやすい。

わかりやすくはあるのですが、長期的に見る必要があります。 うまくいっているかどうかの短期的な評価には使用できないのが悩ましいところです。 短期的にプロセスがコロコロ変わるのは 改善ではなく迷子 です。

ふりかえり手法は色々ありますが、必ずうまくいくやり方があるわけではありません。 体重計に乗るだけで体質が改善する人もいますが、そうでない人もいます。 人や状況にあったやり方を模索せざるをえない、模索することこそが活動のコアなんじゃないかなーと。

GoogleSlidesで出力したPDFがプレビューでうまく表示できない

たとえば「左端がページの端にくっついた、水平グラデーションで塗りつぶした図形」

こういうの

GoogleSlidesのスクショ

これをPDFダウンロードしてMacのプレビューで開くと、こんなふうに水平グラデーション(下)だけ色だけ落ちる。上の円形グラデーションは問題ない。

PDFをプレビューで開いたのスクショ

謎。

なおPDFをChromeやEdgeで開くと期待通り塗りつぶされる。Safariはプレビューと同じで塗りつぶされない。

PDFをChromeで開いたスクショ

なのでPDFファイルに情報は入っているんだろう。 SpeakerDeckにアップロードしても見えたし。

ダメなパターンを見つけよう

と思ってGoogleSlidesで作ったの

でPDFを出してプレビューで開く。

結果

サイズとかの問題ではなく、X=0の時が条件ぽい。これやるまで「横幅がページと同じやつ?」と思ってた。

見ての通り、背景色も同様に表示されない。X=0扱いなのかな。

まとめ

deckを使ってみようと思ってGoogleSlidesをつかった時に踏んだから、GoogleSlidesの問題かと思ったけど、どうも濡れ衣のよう。

雑に調べたらプレビューとかのQuartz PDFKit?の既知の不具合っぽい?

よくわからんし水平グラデーションやめとくか・・・