Kengo's blog

Technical articles about original projects, JVM, Static Analysis and TypeScript.

ビジネスとは問題解決のフラクタル構造でしょ的な割り切りの話

「戦略の要諦」を読みました。この本が語っている「戦略」は戦略の一部であり狭義の存在なので、あまり「戦略」という言葉を使ってほしくなかったなぁというのが第一印象でした。戦略論の世界的権威に何言ってるんだとは自分でも思いますが。。。

広義の戦略について理解していると、狭義の戦略を理解する助けになる

もう少し掘り下げて説明すると、自分の中では「戦略とは現状を理想に近づけるための実現可能なアプローチのこと」だという理解ができていて、実際に著者が言っている戦略はその「広義の戦略」のサブセットとして説明できると感じました。著者は組織的課題を克服するための戦略について話していて、その過程で出てくる「良い戦略」「良い目標」そして「戦略ファウンドリー」はすべて他の戦略でも適用できます。

graph TD
  理想的状態 
  眼前の現状
  組織の理想
  組織の現状

  眼前の現状 --->|広義の戦略| 理想的状態
  理想的状態 <-.->|問題(理想と現実の差分)| 眼前の現状

  組織の現状 --->|本書の戦略| 組織の理想
  組織の理想 <-.->|問題(理想と現実の差分)| 組織の現状

中でも「戦略ファウンドリー」は、アジャイルで頻出の概念やスクラムマスターの心得を別の角度から言い換えたものが多く含まれています:

  • 判断の先送り→アイスボックス
  • タイムトラベラーになってみる→プレモーテム
  • 組織の問題に目を向ける、なぜ困難なのかを考える、反省的思考を行う→レトロスペクティブ
  • 現実的に取り組み可能な戦略課題を見つける、近い目標に集中する、期間を設定する、即席戦略を考える→スコープの管理
  • 宣誓式、課題から始める→プランニング

のでこの本は組織的課題克服の実践を学ぶうえでは良書だと思いますし、自分も多くを学びましたが、問題解決というフレームワークの運用に自信があるならばそこまで収穫はないかもしれないと感じました。ただ改めて問題解決フレームワークの重要性に気づけたため、ここを掘り下げて考えてみたいと思います。

ビジネスにおいて問題とは同じ構造が入れ子になっているもの

「戦略の要諦」が組織課題の解決に問題解決フレームワークを適用したように、事業課題や製品課題、顧客課題の解決にも問題解決フレームワークが適用できます。組織や個人、製品といった異なる主体が抱える課題にも適用できます。

さらにちょっとデカめの問題解決をすると、問題解決のための戦略がさらに問題を内包していることに気づくと思います。複数の問題が循環参照を持っていることも少なくありません。だから因果関係をツリー状に整理して、真の問題・ボトルネックを特定するフレームワークである現状問題構造ツリー(CRT、ザ・ゴール2に掲載)*1などによって問題の間に横たわる関係性を描いて、真に解くべき問題を洗い出して優先度をつけることになります。

ここから学ぶべきことは、自分が直面している問題の外側にも問題があるということです。自分が認知していないだけで「外側」に問題があると意識するだけで、相談するべき人や想定すべき影響、自分が意識できてない視点などを見つける手がかりになります。

Findyさんのとこid:Soudai さんが使っていらっしゃるこの図がわかりやすいので引用すると、問題の外側(図で言う視野外の事実)があることに自覚的になると、視座を上げるための行動を取りやすいということですね。

図1 問題解決が入れ子になっていると意識すると視座を上げて新たな視点を得る助けになる

ビジネスにおいて問題は複数の関心に投影される

問題解決は外と内という視座の違いで入れ子構造を作るだけでなく、同じ視座でも異なる視点に投影できるという特徴もあります。たとえば「納期が守れない」という問題を解決する戦略を営業と製造の観点から作成すると、全く異なる戦略が出てくるでしょう。

図2 投影という概念の例示(TensorFlowのロゴ)

ここで重要なのは、営業と製造の双方の戦略をよしなにマージしないと真の問題解決にはならないということです。実際は営業と製造だけではなく、経理や調達をはじめとした多角的な視点からの検討が必要でしょう。もちろん自分にとってControllableな範囲でぱぱっと解決を作ることも重要なんですが、広範な視点を統合すること、すなわち関係者のモチベーションを高めて巻き込んではじめて「チームで問題解決ができる」ので。わざわざ法人というチームを作って問題解決にあたるビジネスにおいては必須だと言って良いでしょう。

これは視座を上げても通用します。たとえば最近地方独立行政法人 岡山県精神科医療センターのランサムウェア事案調査報告書を読んだのですが、多くの人がこれを読んでまず出てくる感想は「医療情報システムと医療機器のベンダーがクソだな」じゃないかと思います。実際私もそうですが、では今ある医療情報システムと医療機器のベンダーを全部潰したらこの事例は良くなるのか?業界の問題は解決するのか?と考えるとそれは違うとも思います*2。徳島・大阪・岡山と大きな事例が続いていることを考えても、病院という仕組み、ひいては医療業界全体になにか問題があると考えるべきでしょう。

わかりやすい悪に飛びつかず中長期的な視点をもとに息の長い社会課題解決ビジネスを行うためにも、問題解決が入れ子構造であることや複数の視点に投影できることに意識的になっておきたいと思いました。

まとめ

理想と現実のギャップに向き合い解決するという問題解決フレームワークを紹介しました。また問題解決は同じような構造が視座や視点を変えても繰り返し現れるフラクタル構造であるとも述べました。これを意識することで異なる視座や視点への想像力が生まれ、より広範な専門家の協力を得て問題解決に臨めるようになるため、息の長い社会課題解決ビジネスを行ううえで重要な発想であると考えました。

*1:問題がMECEに分解できるならロジックツリーだけど、漏れなくはともかくダブりなく分解することはあんま現実的じゃないと思っている

*2:注意点として、筆者は破壊的イノベーションを行う医療情報システムのベンダーに勤めています

うまく失敗するには準備が必要

成功には失敗がつきものだが、無駄な失敗はしたくない

失敗と成功の関係は、この図が一番わかりやすいと思うんです。

絶対成功するやり方知ってる?成功するまでやり続ければ良いんだよ!ってやつですね。成功と失敗の関係はコインの裏表やサイコロの目とは異なります。うまく行けば成功するのではなく、失敗を積み重ねたその先に成功が来るのです。

失敗したことがないってプロジェクトや人間がいたら、その人は単に挑戦したことないんだよって指摘もたまにありますね。ちょっと言葉は強いですが、成功には失敗がつきものだということを端的に表すという点では良いかもしれません。

でもこの理屈はしょせん理屈でしかないですよね。人間の体力や気力というものを度外視しています。実際はずっと失敗していたら病むか金欠か飽きるかして挑戦を止めざるを得なくなるはずです。これが錬金術のような長い目で見るものなら「私が死んでも第2第3の錬金術師が現れて真実を明らかにするだろう…グフッ」とかやっててもいいんでしょうけど、我々がやっているのは日進月歩の事業なので無駄な失敗をする余裕はありません。

ですから「成功したいなら失敗は避けられないが、できるだけ少ない失敗から効率的に成功をつかみ取りたい!」という考え方が出てきます。このブログではそのために必要な2つの要素について説明します。

うまく失敗するための2つの要素

プレモーテム:タイムマシンで過去の自分を助けに行く

イメージしてください。今は2025年12月末日、あなたは重い足取りで忘年会と称した飲み会へ向かっています。心なしか暗い同僚の顔。普段よりもやけに高いマネージャの声。わいわいと楽しい現実逃避を続けていたあなたですが、ぽろっとあなたの口から想いがこぼれ出ます。

ああ、あのプロジェクトはもっとここをちゃんとやっておきたかった。

そうしたらプロジェクトは成功して、お客様もきっと喜んでくれたのにーー

頬を伝ってこぼれる涙。共感からチームへと拡がる後悔と懺悔の輪。今日の酒は妙にしょっぱい、店員を呼んでグラスを変えてもらうか。店員さーん。店員、あれ、あおだぬき……?

のび太くんえらい!それこそが成長というものだよ!ようしちょっと手助けしてあげる!ピコピコーン!タイムマシン〜〜〜〜!ほらこれで1月に戻ってやりなおしてきな。みんなによろしくね!

……はい、おかえりなさいませ。あなたは今、12ヶ月先の未来から帰ってきました。はじめての時空の旅はいかがでしたか?なに?猫型ロボットはガストのやつのほうがかわいい?あんまりそれ本人の前で言わないほうが良いですよ。

それで、12ヶ月先のあなたからは今のプロジェクトについてどんな伝言を受け取ってきましたか?ええ、あなたが取り組んでいるプロジェクトです。採用かもしれないし、導入かもしれないし、営業かもしれないし、情報発信かもしれないし、予実管理かもしれないし、顧客支援かもしれないですが、あなたはいま大小いくつかのプロジェクトに取り組んでいますよね。それについて、何を聞いてきましたか?どうやって失敗したとか、どこで顧客の信頼を失ってしまったとか、どこで泥沼になって引き返せなくなってしまったとか、そういう情報です。そして次があればどう改善したいか、も。

これがプレモーテムです。検死のことをポストモーテムと言いますが、死ぬ前に検死を行うことをプレモーテムというのですね。幸いまだあなたのプロジェクトは失敗していません。いや、始まってすらないかもしれませんね。この段階から失敗を想定することで、どこが外せないイベントであり誰がキーマンなのか、どうしたら最大の不幸を回避できるのかなどを想定して役立てることができるのです。

ただ現実にはドラえもんはいないので、想像力や想定力で補う必要があります。ベストなやり方は人によると思いますが、例えば以下のような問いかけを自分にしてみてはいかがでしょうか:

  • 定性的な目標を達成できない理由や経緯にはどのようなものが考えられるのか
  • 定量的な目標を達成できない兆候はどのようにして事前に発見できるのか
  • いつも怒らないあの人が怒るのは、どういう失敗をしたときか
  • 私が憧れるあの人ならば、いまなにをするだろうか
  • そもそもこのプロジェクトが立ち上がった経緯と、そのときに立てた仮説はなんだったのか
  • その仮説が間違っていた場合、どんな事象としてプロジェクトやお客様に跳ね返ってくるのか

仕事で向き合うターゲットは定量的なようで定性的なものが多く、失敗かどうかを判断すること自体が難しいこともあります。そうであっても楽天的に準備して否定的に進む(なんとかなるさと深く考えずに進んでから、きっとやっても無駄だったと失敗をドブに捨てる)姿勢ではなく、批判的に準備して楽観的に進む(仮説を検証し失敗の可能性を潰したうえで、臨機応変に周りを巻き込んでポジティブに働く)姿勢を取り続けましょう。そのために、失敗したらどうしよう、から考えることが大切ということです。

ダメージコントロール:受け身と命綱

失敗したときは必ず自分にダメージが返ってきます。それは無駄にした時間かもしれませんし、かけてしまった金額かもしれませんし、怪我や信用かもしれません。こうしたダメージについて予め備えておき総ダメージをコントロール可能なレベルまで減らすことをダメージコントロールと言います。

皆さんは体育の授業で柔道をやりましたか?柔道の授業はまずうまい転び方、すなわち受け身の取り方から始まります。相手に投げられたときに受け身を取ることで、身体へのダメージを減らして怪我を減らすことができます。これもダメージコントロールです。

あるいはビルの外面清掃をはじめとした高所作業をイメージしてもいいでしょう。こうした作業では、必ず命綱をつけています。つけなくても落ちないかもしれませんが、万が一落ちてしまったときに文字通り命を守ってくれる装備です。

これらはあらかじめ発生するダメージについて考えておき、回避すべきダメージに対してどう対応するべきかを考えて用意した装備です。我々のプロジェクトでもこうした装備があると安心して失敗しにいけますね。ですからプレモーテムを開催してダメージを洗い出し、それをどう回避するか・最適化するかなどを考えて備えましょう。

業務に具体的にどう活かすか

業務によります!が、それだと答えにならないので、みなさんのヒントになることを期待して自分がやっていることをいくつか書いてみます:

  • 「決定事項に対してなにをやった、やったらどうなった」という話ばかりしていると感じたら、批判的思考(クリティカル・シンキング)を取り入れて「理想に照らすと現状の何が問題でどうしたら解決できると考えたのでこれをします」という仮説ベースで話すようにする。
    • 仮説ができたら検証可能になり、検証可能になればリスク分析をしたうえでの挑戦ができます。建設的な批判はけっこう難度が高いので、何度もやって場数を踏む必要があります。不安なら信頼できる人に伴走してもらいましょう。
    • このあたりは 情熱稟議入門 にも通じるところがあります。何をするかではなく、なぜそうしたいかを伝えましょう。
  • イベント企画時にはまずアンケートや反省会から用意します。
    • すなわち「開催後にどのようなフィードバックを参加者から得たら目的の達成を検証できるか」「次回開催時はどのような情報があると嬉しいのか」を意識的に考えるきっかけを先んじて作っておくということです。
  • 勝利条件を定めましょう。
    • XXをやる・〇〇を終わらせるではなく、XXを解決する・〇〇の業務をなくすといった具体的なアウトカムを書くことで成否を判断しやすく、問題を見つけやすいプロジェクトになります。
  • 撤退条件を定めましょう。
    • これはどこまでダメージを受けて良いかを考えること、すなわち失敗の奨励とダメージの想定に繋がります。どちらもマネジメントの大切な仕事です。

まとめ

ビジネス的に言うならば仮説思考とリスク・マネジメントの話なんですが、「上手く失敗する」の実践イメージを持つためにプレモーテムとダメージコントロールをしよう、という伝え方にしてみました。

挑戦がビジネスに必要なことはもはや疑いないものの、必ずついてくる失敗とどう向き合うかは常に悩ましいものです。運動前の準備体操のように、失敗からの学びを最大化するための準備をしてから、挑戦していくクセや文化を作っていきましょう。そうすれば限られたリソースの中でも、より小さな失敗のうちに多くを学び、価値ある成功へとつなげることができるはずです。

情熱稟議入門

tl;dr

  • 稟議書は「回覧板」である
    多様な読み手に向けて書くことを意識しよう
  • 読み手が稟議書を読むとき、あなた(起案者)は現場にいない
    意思決定に必要な情報は全て書いておく
  • 「買う理由」ではなく「実現したい未来」を明記する

稟議書とは回覧板なのだ

回覧板とは、町内会などでお知らせを“バケツリレー”式に共有する仕組みです。
例えば、お祭りの日程や町内会費の徴収、ご高齢の方へのお祝いの予定などをA4用紙にまとめて回覧します。内容によっては「読みました」の欄にサインをすることもあります。

なぜこんな手間をかけるのかというと、町内会にはいろんな人がいるからです。夜勤がある人もいれば、そもそも町内会活動に時間を割けない人もいる。そうなると、全員が同期的に集まって話をするのは難しいですよね。

そこで回覧板を使えば、会議や電話と比べて時間はかかるものの、非同期的にほぼ確実に情報を届けられるわけです。

稟議書もこれと同じです。会社の重大な意思決定にあたって、多角的な検討をしたい。でも営業は外回りで忙しいし、エンジニアはそもそもデジタルの向こう側にいて捕まりづらい……。そんなときに稟議書を回覧することで、非同期的に意見や知見を集約し、組織として意思決定できるのです。これこそが稟議書の存在意義と言えます。

議事録の読み手は様々な背景と動機を抱えている

さて、稟議書を読むのは誰でしょう?
社長? 財務? それとも上司?

まず社長と財務では稟議書を読むときの“動機”が違います。

  • 社長:事業を前進させる新しいアイデアを探しているかもしれない
  • 財務:企業の財布を守りたい。要不要を見極めたり、投資の優先順位を付けたい

財務向けの情報ばかり書いても社長には刺さらないでしょうし、その逆も同じだというのはイメージいただけるでしょうか。

あるいは社長と上司という組み合わせでも、背景が異なります。

  • 上司:あなたと同じ業務範囲を把握している(ツーカーで通じることもある)
  • 社長:現場レベルの詳細や解像度を共有していない場合が多い

社長が稟議書を読むタイミングで、起案者であるあなたはそこにいません。
チャットなどで質問が飛んでくればラッキーですが、もし憶測や推測で意思決定がなされると、本来得られたはずの機会を失ったり、予想以上のダメージを被ったりするリスクもあります。

読み手ごとの疑問に先回りして回答する

情報が足りず誤読される隙を無くすために、どんな稟議書を書くべきか。
キーワードは「業務想定」です。読み手は何を知りたがり、どんな基準で判断するのか? あなたが本当に伝えたいポイントは何か?これらを押さえるために、「この稟議書を読んで、あの人はどんな質問をするだろう?」と想像して、あらかじめ回答を用意しておきましょう。

例えば、こんな疑問が想定されます。

  • 「前に実行したあの施策とはどう違うのか?」
  • 「この投資はいつ、どのような形で回収できるのか?」
  • 「他に検討されている施策との差別化点は何か?」
  • 「顧客にどのような変化をもたらすのか?」
  • 「不調に終わったときの代替策(コンティンジェンシープラン)は?」

社長・財務・上司といった立場ごとの着眼点も整理しておくと、さらに書きやすいです。

稟議とは未来を生み出す起爆剤

とはいえ、全ての疑問を網羅的に書くと時間も紙幅もかかります。
そのため、せめて「この施策が提案された背景」と「この施策によって実現したい未来」だけは確実に書いておきましょう。

これらの情報は、あなたのアイデアと意欲に共感してもらい、仲間として一緒に動いてもらうために必要最低限の要素だからです。

稟議書は単なる「お金の使用許可申請書」ではなく、回覧板でしたよね。
回覧板で町内会を巻き込み、行動してもらうための仕組みと同じように、稟議書は社長も財務も上司も営業もエンジニアも、みんなを仲間として巻き込むための起爆剤になり得ます。

だからこそ、あなたが熱意を注いで生み出したアイデアを、そのままの勢いで書式に落とし込みましょう。数字を使ったり、成功時のイメージを具体的に描いたりすると、より強く心に訴えかけられます。

まとめ

  • 稟議書は回覧板のように非同期コミュニケーションを可能にするツール
  • 読み手の背景や判断基準を先読みし、必要な情報をしっかりと書き込む
  • 「買う理由」ではなく、「この施策で実現したい未来」を具体的に示す

稟議書は、単に「承認をもらうための形式的な書類」ではありません。
あなたの「熱意」や「未来を創りたい」という想い、情熱を伝えるためのメディアでもあるのです。
ぜひ、そのモチベーションを惜しみなく注ぎ込んで、読み手を動かす稟議書を作成してみてください。

2024年の振り返りと2025年の抱負

2024年終わりました。仕事の面では医療系スタートアップに転職してから3年目に突入、より混沌としてきています。子供も心身ともに大きくなってきていて、自らの加齢を感じることも増えてきました。人生ですね。

さて今年のトピックはだいたいこんなところ↓だと思うので、掘り下げていきます。

  1. 情報処理安全確保支援士試験に合格した
  2. 勤め先でDevelocityを導入した
  3. 技術書典に合同誌を出した
  4. OSS活動を休止した

情報処理安全確保支援士試験に合格した

こちらは独立した記事を書いたのでそちらを参照ください。昨年の医療情報技師に続けての資格取得でしたが、転職前は資格試験から距離をとっていたこともあり、とても新鮮な体験でした。

来年は新たな受験ではなく、資格を仕事に活かす方向でのキャッチアップと発信を心がけていきたいと考えています。

勤め先でDevelocityを導入した

私の勤め先である株式会社ヘンリーはサーバサイドKotlinを推しており、もちろんサービスの開発でも活用しています。この夏に私もモノレポ化について発信していました。

Kotlinプロジェクトのモノレポ化には大きな恩恵がある一方で、増えるコードやテストケースのコンパイルならびにテスト実行をどう高パフォーマンスに行うかという壁があります。この解決にはGitHub Actions workflowの最適化も有効ですが、勤め先ではそれにあわせてGradle社が展開するオンプレサービスであるDevelocityの導入と運用を手がけました。実際有効なので、今後もサーバサイドKotlinを盛り上げる一環に情報を発信していきます。

技術書典で合同誌を出した

前述のDevelocityをはじめとした各種工夫を盛り込んだ本を勤め先の有志で作成し、技術書典に出しました。Re:VIEWでの執筆は初体験でしたが、なかなか好評だったようで良かったです。

GitbookやSphinx、zennなどとはまた違った書き味で面白く、また書いてみたいと思っています。

OSS活動を休止した

ちょこちょこGradleプラグインや自作RDBMSを書き溜めたり、仕事で使っているツールの不具合修正のためのPRを送ったりはしているのですが、実質的にOSS活動は止まってました。

狙ってそうしたというよりは、他にやりたいことがあるので結果的にそうなったという感じで、まぁそういうこともあるのかなという所です。来年もおそらくこの状況が続くと思われます。

2025年の抱負

まだ決めきれてないですが、来年はこんな感じにしようと思っています:

  1. 技術書典に個人で出展する
  2. マネジメントスキルの棚卸し

技術書典の出典には、既刊のMaven本にあわせてGradle本を書き下ろしたいと考えています。Gradleの本って、商業でも同人でもほぼないんですよね。Gradle 9対応で出せれば唯一無二の日本語本ということになりそうです。ただ1人で書ける量には限度があるため、全ての概念を1から教える初心者本ではなく触ったことのある人がステップアップするための本に特化するつもりです。

 

マネジメントについては今年もProduct Managementの真似事はやっていたものの、意図的に距離をとっていました。ICとしての勘や実績、自信が欲しかったのもありますが、何よりもPeople Managementで燃え尽きてしまったのでやりたくなかったんですよね。

People Managementは正直今でもやりたくないですが、充分に休息は取れたのでそろそろ今できることの再確認と古びたスキルの手入れをする時期かなと思っています。Project ManagementやProduct Managementを中心に据えつつ、必要なことをやっていきます。

来年もよろしくお願いいたします

今年は14記事と、昨年の20記事よりは少なくなりました。年間を通じて時間を作ることが難しく、なかなかタフな1年でした。来年もこのへんはあまり変わらない気はしますが、ちょいちょい書いていければと思います。引き続きよろしくお願いいたします。

Testcontainersで単体テスト実行時に必要なデータベースを自動的に用意する

この記事は Kotlin Advent Calendar 2024 10日目の記事です。前回はtsukakeiさんのExposedでStatementInterceptorを使ってSQL文実行前後に処理を差し挟むでした。

先日出した合同誌でも触れましたが、Testcontainersを使うと単体テスト実行時に必要なデータベースを自動的に用意することができます。TestcontainersといえばSelenide (Selenium)でもお世話になりましたが、ブラウザだけではなくデータベースも対応しているんですね。

合同誌掲載ケースではDevelocityのTest Distributionで遠隔テストを実行するのに利用しましたが、手元やGitHub Actionsなどでテストをするにも便利なので紹介します。なお掲載コードはKoinとKotest、Postgresを前提としています。

Testcontainersがなぜ便利なのか

Testcontainersはテストに利用するための外部プロセスをお手軽に利用するためのライブラリです。たとえば従来だとPostgresに依存したテストを実行するには実行環境にPostgresをインストールすること(GitHub Actionsなら services を使ってPostgresを起動する、など)が必要でしたが、ポート番号を環境変数で受け渡すとか、データベース側がちゃんと起動したか確認するとかの手間があり不便です。Testcontainersを使うことでプログラムからデータベースを起動できるので諸々をテストコードとして管理できるようになり、メンテナンス可能性が上がります。

TestcontainersをKotestで使う

公式のQuickStartにはKotestに特化したものがないので説明します。前提としてデータベースに接続するための接続プールをKoinで初期化しているものとします:

// src/main/kotlin/com/example/DatabaseModule.kt
@Module
@ComponentScan
class DatabaseModule {
  @Single
  fun createDatasource(): HikariDataSource { ... }
}

テスト実行時はこれを上書きして利用することにします。java-test-fixtures プラグインを使えばテストコードではないけどテストから利用するコードをテストコードから分離して管理できますので、これを利用すると良いでしょう。

// build.gradle.kts
plugins {
  `java-test-fixtures`
  ...
}

dependencies {
  testFixturesImplementation("org.testcontainers:postgresql:1.20.4")
  ...
}

TestFixtureとテストコードは次のようになります:

// src/testFixtures/kotlin/com/example/DatabaseModuleForTest.kt
fun createTestcontainerModule() = module {
  single<HikariDataSource> {
    // TODO: ここにTestcontainers利用コードを書く
  }
}
// src/test/kotlin/com/example/MyTest.kt
class MyTest : DescribeSpec({
  beforeSpec {
    startKoin {
      modules(DatabaseModule.module + createTestcontainerModule())
    }
  }
  afterSpec {
    stopKoin()
  }
  // TODO: ここにデータベースに依存したテストを書く
})

Postgres公式イメージを使う

Testcontainersの使い方のひとつとして、Postgres公式イメージを使ってデータベースを起動できます。スキーマがなにもない状態で起動しますから、ExposedのSchemaUtilsあたりで初期化する必要はあります。

fun createTestcontainerModule() = module {
  single<HikariDataSource> {
    val container = PostgreSQLContainer("postgres:17-alpine").apply {
      withLogConsumer(Slf4jLogConsumer(logger))
      start()
    }
    val config = HikariConfig().apply {
      jdbcUrl = container.jdbcUrl
      username = container.username
      password = container.password
      driverClassName = container.driverClassName

      // TODO: 他の設定をする

      validate()
    }

    return HikariDataSource(config)
  }
}

なお Slf4jLogConsumer はTestcontainersのログをSLF4Jのロガーに渡すための設定です。SLF4Jを利用していない場合は他の LogConsumer を使うことになるでしょう。

独自のコンテナを使う

すでにコンテナレジストリにある独自のコンテナを使うこともできます。Postgres互換のイメージであることを明示するために asCompatibleSubstituteFor("postgres") の実行が必要です。

fun createTestcontainerModule() = module {
  single<HikariDataSource> {
    val imageName = DockerImageName.parse(IMAGE_NAME).asCompatibleSubstituteFor("postgres")
    val container = PostgreSQLContainer(imageName).apply {
      ...
      start()
    }
    ...
  }
}

コンテナのライフサイクルを考える

PostgreSQLContainerAutoCloseable インタフェースを実装しています。つまりコンテナのライフサイクルをプログラムから管理する必要があります。KotestはJUnit5の基盤で動いているので、Testcontainers組み込みのJUnit4対応は期待できません。オフィシャルサイトを参考に、自分で管理を考える必要があります。

ところでテストコードで Koin を使う場合、すでに KoinApplication のライフサイクルを管理しているはずです。Specごとに KoinApplication を作るとか、テストケースごとに KoinApplication を作るとかの方法がありますが、コンテナのライフサイクルもこれと同じにできるなら、Koin moduleが閉じられたタイミングでコンテナを止めるようにするのがシンプルでしょう。

fun createTestcontainerModule() = module {
  single<PostgreSQLContainer> {
    ...
  } onClose {
    it.close()
  }
  ...
}

またKoinApplication とコンテナのライフサイクルをあわせてしまうとテストの実行パフォーマンスに影響がある場合は、コンテナをSingletonとして扱うことになります。この場合はコンテナの停止はTestcontainersに任せられるので、明示的に close() を呼ぶ必要はありません。

まとめ

Testcontainersを使うとデータベースに依存したテストケースをより簡単に実行できます。ちょっと前だとH2 Databaseなどのオンメモリデータベースを使っていましたが、Testcontainersだと本番環境と同じRDBMSを使えるのでより安心ですね。Postgresに依存するコードをテストする際にお試しください!

2024年に読んでよかった本

医療関係

「看護覚え書」ナイチンゲールが書いた本ということで、初心を理解するのに良いかなと思って購入しました。超人ナイチンゲール (シリーズ ケアをひらく)と合わせて、現代看護の成り立ちみたいなものに触れる良い機会になりました。システム実装やドメイン理解の役に立ったかというとNOですが、看護と聞いて自分が連想するものがとても狭いのだということはよく理解できました。

エンジニアリング

「情報セキュリティの敗北史」セキュリティがとても人間のウェットな部分をクローズアップするテーマなんだということを再認識した本です。マイクロソフト社のかつての過ちとか、様々な立場の人間が利益を最大化するために行動した結果として脆弱性が”活用”されているとか、ぱっと見たときに良さそうな選択肢(例えばバグバウンティ)が一歩引いてみるとそうでもないとか。

自分は性善説や理想論で動きがちな人間なので、改めて情報セキュリティめんどくせぇ奥が深いなぁと思いました。今後もちょくちょく振り返って手に取る本になりそうです。

「本質から考え行動する科学技術者倫理」 この春に放送大学の講義を受講しまして、残念ながら単位取得までは行かなかったんですが、この科学技術者倫理について学ぶ良い機会となりました。倫理というと高校の授業でやるやつですが、自分の高校の教師は歳を食ってある程度フラットに物事が見られるようになった今の自分から見ても疑いなくひどかったので、倫理についてはエッセンスも何もキャッチアップできていなかったんですよね。

失敗学の繋がりで回転ドアの話とかチャレンジャー号事件の話とかは知っていたのですが、AI技術の進展を踏まえた議論などは初めて見たので、きちんと学び直したいなと思い放送大学の講義資料とは別にこの教科書を購入しました。スタートアップで社会課題の解決にもがいていると前人未踏の問題領域に踏み込むことは多く、多かれ少なかれ倫理的判断が求められるシーンはきっとあると思うので、情報システムで社会に切り込むスタートアップに在籍しているタイミングでこの本に出会えて良かったと思います。

「一級建築士矩子と考える危ないデザイン」は単行本を購読しているマンガ「一級建築士矩子の設計思考」のスピンオフ?と言いますか、マンガのキャラクタを拝借して危ないデザインを紹介するというものです。元のマンガを購読していなくても楽しめますし、建築関係なくユーザインタフェースの設計・開発をするITエンジニアには広くおすすめです。

個人的には自分の母校のデザインがかなり危なかったのだなぁということに気づき、ちょっと怖くなりました。1階の庇に柵がついてないのに2階から乗ることができたんですよね。当時はそういうものだろうと思っていましたが、改めて考えると悪いデザインだったと思います。日頃の周囲を見る目が変わる1冊でした。

その他

建築好きなのでちょくちょく間取りや設計、建築についての本や雑誌を買っているのですが、今年は商店建築に加えてこちらの「お宿図鑑」を買いました。スケッチがとても美しく細かくて、自分が現地に赴いても発見できないだろうなと確信できる内容盛りだくさんでした。

掲載されているお宿はおおむね子連れで行ける宿というか、いずれ親と行きたい宿という風情ですね。この本を読んで、家族でゆっくりとした時間を楽しめる未来がより楽しみになりました。

Kotlinからお手製Javaライブラリを呼んでる人のためのJSpecify入門

これはKotlin Advent Calendar 20242日目の記事です。前日は id:take7010 さんの「KotlinとOpenAI APIで領収書の情報を抽出する」でした。

先日Kotlin愛好会オンラインでJSpecify入門について話しました。JSpecifyについては3年前のJJUG CCCでも話しましたが、この夏にv1.0.0が出たので改めて知っていただければと思っています。

speakerdeck.com

JSpecifyの何が嬉しいか

Kotlinの世界に閉じた実装を行っていると、JSpecifyのアノテーションを使う機会はほぼないはずです。JSpecifyが嬉しいのはKotlinからJavaを呼ぶ場合です。 Javaライブラリ側の引数や戻り値をJSpecifyアノテーションで修飾しておくと、null-safetyなKotlinの引数や戻り値と同じように扱えます。 今まではKotlinコンパイラが警告を吐くだけでしたが、Kotlin 2.1.0からエラーとして扱われるようになりました。

どこから始めればいいか

nullableな戻り値を @Nullable で修飾するところから始めましょう。ランタイムの NullPointerException を防ぐために最も重要なアノテーションだと思います。

次点が List<T> のようなGenericsだと思いますが、このへんはけっこう複雑なのでドキュメントに目を通しておきましょう。

なおすべてのnullableな型を修飾したと言えるようになったら、パッケージを @NullMarked で修飾しておけば「 @Nullable が無いところは全てnot-null」だということをコンパイラに伝えられます。 nullableな値を持ち回らないようなコードを書いている場合は便利かもしれません。

Java と Kotlin を安全に橋渡ししよう

Kotlinの強みのひとつとして「Javaの資産を活用できる」のが挙げられますが、そのためにはJavaになくてKotlinにある機能をどう扱うかを検討しなければなりません。 null安全はそのうちのひとつですが、JSpecifyのv1.0.0リリースによってある程度標準的な解決策が用意されたと言ってよいでしょう。 KotlinをJavaで書かれたライブラリやフレームワークと組み合わせて使っている方は、ぜひ試してみてください。

Kotlin Advent Calendar 2024の明日の記事は、 id:tsukakei1012 さんの「Exposedについて①」の予定です。