日本のソフトウェアエンジニアの求人を見ると、いまだにEC、広告、SaaS事業が中心な求人が多い
もちろんこれらも重要な分野だけど、安定していて伸びしろが読みやすい領域ばかりに人材と資金が集まっている印象が強い
一方で、アメリカの求人を見ていると、
AI/GPU、仮想通貨、自動運転、バイオテック、eVTOL、ドローンなど、次の10年をつくるような領域に挑戦できるポジションが本当に多くて羨ましいよね
単なる給与水準の差ではなく、どんな未来を作るかという選択肢の広さにギャップを感じる
SCSKは業務用大型コンピューターで用いるプログラミング言語「COBOL(コボル)」利用企業の支援事業を本格的に始めたと発表した。金融機関システムなどで取り入れられてきたものの、利用が縮小傾向にあるコボルを使ったシステム刷新や開発、運用を後押ししていく。
「COBOL PARK(コボルパーク、東京・江東)」を6月に設立した。SCSKが株式の66.7%を保有し、残りをベトナムIT大手FPTの日本法人、FPTジャパンホールディングス(HD、東京・港)が出資する。
コボルは業務用大型コンピューター「メインフレーム」で動作するソフトウエアの開発に使われてきた。ただクラウド化が進む中で、メインフレーム市場が縮小。コボルを扱える技術者が減少し、システムの刷新が難しくなっている。
■ 1. スタートアップの失敗率と主要因
- スタートアップの失敗率は推定で10社中9社
- 大半のスタートアップは巨大な競合による「他殺」ではなく内部問題による「自殺」で終わる
- YC創設者Paul Grahamは「スタートアップは他殺よりも自殺で死ぬ可能性が高い」と指摘
- 最大の脅威は通常会社の外部ではなく内部から来る
■ 2. 自殺vs他殺の概念
- Silicon Valleyの格言「スタートアップは死なず自殺する」
- 起業家Justin Kanは多くの若い企業が選択肢を使い果たすずっと前に崩壊することを観察
- スタートアップはまだ十分に存続可能な状態で自らを諦める
- 創業者が燃え尽きるか心が折れチームが終了を宣言
- 創業者はスタートアップが困難で大規模な疲弊を引き起こすことに気づき別の仕事に就くか学校に戻るか単に離れていく
- Y CombinatorのHarj Taggarは多くの企業が単に創業者が努力を止めるために失敗することに気づいた
- 成功するスタートアップは継続し続けるもの
- 勝つ方法は死なないこと
- 早すぎる諦めがしばしば真の殺し屋
- 内部問題の蓄積(明確な牽引力なし・絶え間ない障害・チームの意見の相違・ストレス)が絶望につながる
- YCの段階では企業は諦めるか創業者が仲良くできないために失敗する
- もう一つの大きな理由は企業が人々が本当に望むものを作っていないこと
- プロダクトマーケットフィットに到達していないか共同創業者と毎週戦っている場合創業者が継続する意志を失う理由は明白
- 外部競争だけが直接スタートアップを殺すことは稀
- 優れた製品と堅実なチームがあれば競合は簡単に破壊できない
- はるかに頻繁にスタートアップは不作為・対立・焦点の喪失によって自らを打ち負かし競争は単に見ているだけ
■ 3. 資金不足という最終症状
- 資金不足はスタートアップが死ぬ最も目に見える方法の一つ
- 100以上のスタートアップの事後分析で資金不足は失敗の第2位の理由
- しばしばスタートアップは次の資金調達ラウンドを間に合わせられないか初期資金が枯渇する前に収益が実現しない
- 資金不足は通常症状であり根本原因ではない
- より深い問題はなぜスタートアップが最初に資金不足になったのか
- 多くの場合プロダクトマーケットフィットを達成できなかったため
- 真に望む人がほとんどいないものを作っていたため収益と投資家の関心が低いまま
- ベンチャーキャピタリストMarc Andreessenは「第1の企業殺しは市場の欠如」と述べる
- 誰も必要としない製品を構築すればシード資金がいくらあっても最終的に現金は何も示さずに燃え尽き資金調達は不可能
- スタートアップはプロダクトマーケットフィットに決して到達しないときに失敗する
- プロダクトマーケットフィット以外に財務管理の誤りが終焉を加速させる可能性
- 一部のチームはビジネスを検証する前にあまりにも積極的に支出(多くの人を雇用・豪華なマーケティング)しキャッシュクランチを引き起こす
- 他のチームはマネタイズや資金調達が遅すぎ単に時間切れ
- 資金不足になった多くの創業者は実際には成功の瀬戸際にいたが早すぎる諦め
- Justin Kanは指標が急上昇しているときに創業チームが諦めるのを見ることは稀だと指摘
- 大半は成長が横ばいで資金が少ないときに諦める
- それはまさに忍耐と反復が必要な瞬間
- 一夜にして成功は実際には一夜にして起こらない
- 忍耐し滑走路を延ばす方法を見つける人(燃焼を削減・ピボット・ブリッジラウンドの確保)は事態を好転させる機会を得る
■ 4. 創業者の対立とチームの崩壊
- 資金不足が棺桶の最後の釘ならば共同創業者の対立はしばしば最初に棺桶を構築したもの
- Harvard研究者Noam Wassermanの統計では高い潜在性を持つスタートアップの65%が共同創業者間の対立により失敗
- 初期段階では創業チームが会社そのもの
- チームが崩壊すれば会社も一緒に崩壊することが多い
- 共同創業者の内輪もめは投資家を遠ざけ意思決定の麻痺を引き起こし社内から企業文化を毒する
- 間違った共同創業者を選ぶことは間違ったアイデアを選ぶことと同じくらい致命的
- スタートアップの伝承は共同創業者を結婚したカップルに頻繁に例える
- 関係が悪化すれば面倒な離婚が製品が有望であってもスタートアップを殺す可能性
- 大きな質問での不一致(急速に拡大すべきかペースを調整すべきか・会社を売却すべきかIPOを目指すべきか・成功をどう定義するか)は最終的に和解できない相違につながる
- 一人の創業者が10億ドルのユニコーンを構築することを想像し別の創業者が小規模で安定したビジネスで満足なら戦略と目標で衝突
- 明白な対立を超えて重要な創業者や初期チームメンバーが去るシナリオもある
- 共同創業者が辞めると若いスタートアップの士気と運営に信じられないほど厳しい
- 残りのチームは「単一創業者」問題を抱える
- すべての負担が一人の肩にかかる
- Paul Grahamは最初から単一創業者を持つことについて実際に警告
- 複数の創業者を持つスタートアップには優位性がある
- スタートアップを始めるのは一人には難しすぎる
- ブレインストーミングをする同僚が必要でありうまくいかないときに元気づけてくれる人が必要
- その仲間意識を失うとスタートアップの低い時期が耐えられなくなる可能性
- 創業チームメンバーが去った後すぐに会社が崩壊するのを見てきた
- 失われたスキルのためだけでなく感情的な接着剤がなくなったため
- 場合によっては残りの創業者が自信と勢いを失いゆっくりと消えていく
- 創業者間またはチーム間の不適合は良いアイデアでさえ沈める可能性
- 創業チームが整合し一緒にうまく機能することを確実にすることはスタートアップの生存に絶対的に重要
■ 5. 焦点の喪失と創業者の燃え尽き
- もう一つの一般的な自傷行為は創業者が焦点や動機を失うとき
- スタートアップは一途な献身を要求する
- リーダーが気を取られ始めると悪い兆候
- CB Insightsの分析では焦点を失うことはスタートアップが失敗する上位20の理由の第11位
- 時には創業者が新しいサイドプロジェクトを追い始める(別のスタートアップアイデアをいじる・コンサルティングギグを引き受ける・新しい趣味に手を出す)
- 他の時にはより微妙でチームが一つの戦略にコミットせずに新しい方向にピボットし続けるか一度にあまりにも多くの機能を追求して自分自身を薄く広げる
- いずれにせよスタートアップはリーダーが一つの明確なビジョンに全力投球していないため勢いを失う
- 焦点の喪失はしばしば情熱の喪失と結びついている
- 初期の頃には避けられない課題を乗り越えるために膨大な量の熱意が必要
- 創業者の心がもうそこにないなら進歩は停止する
- 成長が停滞したときに創業者が精神的にチェックアウトするのを見てきた
- 倍増する代わりに他の機会について空想を始める
- Justin Kanは辞めたい誘惑がJustin.tv中に何度も彼を襲ったと説明
- 物事が暗く見えたときに諦めて先に進む寸前に来る
- 苦痛な労苦から逃れたいと思うのは人間の本性でありスタートアップを運営することは確かに労苦になる可能性
- 創業者は極度のストレスと燃え尽きにも直面しモチベーションを奪う可能性
- 長時間・生き残るためのプレッシャー・感情的なジェットコースターが疲弊につながる可能性
- 創業者が燃え尽きると先延ばしを始めたり厳しい問題を避けたり重要な決定を委任したりする可能性
- これらはすべて腹の中の火が消えかけているサイン
- 最終的に情熱が再燃しなければスタートアップは放置からゆっくりと枯れる
- スタートアップは通常餓死しない・すべての機会と気晴らしに溺れる
- ミッションに焦点を合わせ続けることは聞こえるよりも難しいが自己誘発的な死を避けるために絶対に必要
■ 6. スタートアップの自殺を避ける方法
- 共同創業者を賢く選びビジョンで整合する:
- 共同創業者を選ぶことはアイデアを選ぶことと同じくらい重要
- 価値観と長期目標を共有することを確認
- 不一致の願望(一人の創業者は迅速な売却を望み別の創業者は永遠に構築したい)は対立につながる
- スタートアップの65%が共同創業者の対立により失敗することを覚えておく
- 共同創業者関係を注意深く扱いオープンにコミュニケーション
- 期待(株式分割・役割・出口戦略)を後で戦うよりも早期に整理する方が良い
- 人々が望むものを作る(プロダクトマーケットフィットを達成する):
- これはYCからの黄金律でユーザーが望むものを作らないことが究極の殺し屋
- ターゲットユーザーと絶え間なく話し実際の問題を解決していることを検証し神経に触れるまで反復する意志を持つ
- 顧客が本当に製品を愛しているなら死ぬ可能性ははるかに低い
- 牽引力は多くの問題を解決する・投資家を引き付けチームの士気を高め滑走路を延長する収益を提供
- Harj Taggarが言ったように多くのスタートアップは企業が人々が本当に望むものを作っていないために失敗
- 技術自体に恋をしない・人々にとって本当に重要な痛点を解決
- 滑走路と財務を慎重に管理する:
- 資金不足は多くの場合予防可能な失敗
- 常に滑走路(残りの現金の月数)を知り空になるずっと前に資金調達または収益マイルストーンを計画
- コストを管理下に保つ・ゆっくり雇用し針を動かすものに支出し虚栄心には支出しない
- 多くのスタートアップはあると良いものに資金を燃やし後で後悔
- 経験則として次の主要なマイルストーン(製品の立ち上げ・ユーザーターゲット・収益目標)に到達するのに十分なお金にバッファを加えて調達するよう試みる
- 物事が長くかかる場合は費用を削減するか延長ラウンドを調達する準備をする
- 魅力的ではないが生存はしばしば慎重な現金管理に帰着
- 投資家は「時間内に調達できない場合何をしますか」と尋ねる・答えを持つ(燃焼を減らす・戦略的パートナーを見つけるなど)ので危機に陥らない
- 本質的に機能するものを見つけるための時間を買う
- 焦点を保ち完全にコミットする:
- 一度に2つの会社を運営しようとしないしスタートアップをサイドハッスルのように扱わない
- 繁栄するスタートアップは通常創業者が両足で飛び込むもの
- 輝く新しいアイデアは常に誘惑する・すべてのウサギを追いかけることに抵抗
- Paul Grahamの「13文でのスタートアップ」のアドバイスは単に焦点
- チームは四半期ごとの最優先事項を知り気晴らしにノーと言う
- これは厳しい時期を耐え抜くことも意味
- 小さな勝利であっても進歩を続けていれば諦める多くの人々を生き延びる
- 格言にあるように失敗を保証する唯一の方法は試みるのをやめること
- ほぼすべての成功したスタートアップは物事が厳しく見えた段階を経たが創業者は継続した
- 決意と回復力をコアチームの価値観として育成
- 健全な共同創業者関係とチーム文化を育成する:
- 内部不和がスタートアップの殺し屋であるためチームを整合させ続けることに投資
- 共同創業者と絶えずコミュニケーション・パフォーマンス・株式・方向性についての厳しい会話を後ではなく早く行う
- 役割や報酬を調整する必要がある場合は対処
- 意見の相違を解決するメカニズムを設定(信頼できるメンターまたは仲介できる取締役会メンバー)
- 多くの対立は明確なコミュニケーションと共感によって和らげることができる・スタートアップを勝たせようとしている同じ側にいることを覚えておく
- また全員が懸念を声に出せ燃え尽きが認識される文化を構築
- 完全な疲弊を避けるために必要なときに休憩を取るよう人々(創業者自身を含む)に奨励
- 支援的でミッション駆動型の文化は欲求不満と不一致を防ぐのに役立ちしばしばスタートアップの自殺につながる
- 成功(と失敗)を一緒に計画する:
- 悲観的に聞こえるかもしれないが物事が南に行く場合に何が起こるかを事前に議論
- 一人の創業者が出たい場合はどのように処理するか
- 買収オファーが来た場合は両方とも売却にオープンか
- これらのシナリオで整合することは後で多くの心痛を節約できる
- 反対側で成功のための共有計画を作成・すべてがうまくいけば私たちのビジョンは何か
- 共通のビジョンを持つことは暗い日々の間皆のモチベーションを維持
- 共同創業者が同じ最終ゲームとなぜそれが戦う価値があるかを見るときにコミットし続けることが容易
■ 7. 結論
- ほとんどのスタートアップは市場の捕食者のために終わりを迎えない
- 内部の失策・壊れた関係・意志の喪失のために終わりを迎える
- 経験豊富な創業者からの事後分析とエッセイはすべてこの真実を反映・スタートアップの運命は主に自分の手の中
- 反対側は力を与える・古典的な落とし穴を避けチームの世話をすれば生存の確率を大幅に高める
- 人々が望むものを構築しチームを団結させ賢く支出し決して早すぎる諦めはしない
- そうすれば自分のスタートアップが単に自殺を避けるだけでなく実際に繁栄しビジョンが生き返るのを見る機会を劇的に高める
- Paul Grahamが有名に暗示したように勝つ方法は死なないこと
- 生き続ければ最終的に成功する機会を自分に与える
■ 1. 技術概要
- SPhotonixが5Dメモリクリスタルの商用化に向けて450万ドルの資金調達を完了
- 2025年12月に英国とスイスに拠点を置くディープテック・スタートアップが発表
- 溶融シリカガラスを用いた事実上の恒久保存を実現するデータストレージ技術
- 宇宙の年齢に匹敵する138億年の耐久性を誇る
- 既存ストレージ(HDD・SSD・磁気テープ)は数十年から100年程度で限界を迎えるのに対し圧倒的な優位性を持つ
■ 2. 5次元記録のメカニズム
- フェムト秒レーザーによるナノ構造化技術:
- サウサンプトン大学Peter Kazansky教授が20年以上研究
- 1000兆分の1秒という極めて短いパルス幅を持つレーザーを使用
- 5つのパラメータでデータをエンコード:
- X座標(空間的位置)
- Y座標(空間的位置)
- Z座標(空間深さ)
- 配向(ナノ構造の向き)
- 強度(光の遅相軸の強さ)
- 溶融シリカガラス内部に微細なボクセル(3次元ピクセル)を刻み込む
- ボクセルは複屈折特性を持ち入射する光の偏光や方向によって異なる屈折特性を示す
- 偏光させた光を照射しその変化を光学的に検出することでデータを復元
- 5インチのガラスディスク1枚に最大360TBのデータを格納可能
- 一般的な大容量HDD(30TB級)の10倍以上の密度を実現
■ 3. 耐久性と安全性
- 190℃の高温環境下で138億年のデータ保持が可能
- 耐熱性・耐環境性:
- 石英ガラスは化学的に極めて安定
- 磁気の影響を受けない
- 放射線・水・湿度による劣化がほぼ皆無
- データ保持に電力を一切必要としないエアギャップなメディア
- ランサムウェア攻撃に対する究極の防御策として機能
■ 4. 市場背景とエネルギー問題
- コールドデータの定義と分類:
- 世界中に保存されているデータの60〜80%がコールドデータ
- ホットデータは5ミリ秒未満でのアクセスが必要(SSDの領域)
- ウォーム/クールデータは数秒以内のアクセスで十分
- コールドデータはアーカイブ・法的記録・科学データなどアクセス頻度は低いが長期保存が義務付けられ取り出しに10秒以上かかっても問題ない
- 現状の問題点:
- 慣性により人々はコールドデータ保存にも寿命が短くエネルギーを大量に消費するHDDやSSDを使い続けている
- AIの台頭によりデータ生成量は指数関数的に増加
- IDC予測によれば2028年までに年間生成データ量は天文学的な数値に達する
- 持続可能性の観点:
- 全データを回転するHDDや通電が必要なSSDで保存し続けることは電力消費と廃棄物の観点から持続不可能
- HDDは数年ごとのリプレイスが必要でそのたびに莫大なコストと廃棄物が発生
- SPhotonixのガラスメディアは一度書き込めばリフレッシュや空調による厳密な温度管理なしに永久にデータを保持可能
- データセンターのTCO(総所有コスト)とカーボンフットプリントを劇的に削減する可能性
■ 5. ビジネス戦略
- 資金調達:
- 2025年11月25日にCreator FundとXTX Venturesが主導するプレシードラウンドで450万ドルを調達
- 技術成熟度レベルをTRL5(技術検証段階)からTRL6(プロトタイプ実証段階)へ引き上げるために投資
- Arm/NVIDIAモデルの採用:
- 製造会社になるつもりはないとIlya Kazansky CEOが明言
- 自社で大規模なガラスディスク量産工場を建設せず核心となるイネーブリング・テクノロジーを開発しライセンス供与するモデル
- ハイパースケーラーやストレージベンダーとコンソーシアムを組みデータセンターにプロトタイプを展開する計画
- コストとパフォーマンス:
- 書き込み装置は約30,000ドル(約450万円)
- 読み取り装置は約6,000ドル(約90万円)
- 現在の転送速度は書き込み4MB/s・読み取り30MB/s
- 3〜4年以内に読み書き共に500MB/sまで引き上げる計画
- 実現すれば現在のアーカイブ用磁気テープシステム(LTOなど)と競合可能な水準
■ 6. 競合分析
- Microsoft Project Silica:
- 同様にフェムト秒レーザーと石英ガラスを用いたストレージを開発
- Azureクラウド向けのアーカイブソリューションとして実証実験を進行中
- 自社のAzureインフラへの垂直統合を主眼に置く
- Cerabyte:
- セラミック素材を用いたストレージを開発するスタートアップ
- SPhotonixの優位性:
- オープンなエコシステム志向
- ライセンスモデルを通じて多様なデータセンター事業者やハードウェアメーカーが技術を利用できるプラットフォームを提供
- 元Project Silicaの研究者を採用する計画を明かし技術的な知見の集約を図る
■ 7. 文化的意義と実績
- 技術の象徴的なデモンストレーション:
- 全ヒトゲノムデータを結晶に保存
- Eon Ark Time Capsuleとして2024年〜2025年の会話記録をアーカイブ
- 名作ゲーム『Heroes of Might & Magic 3』を保存
- 映画『ミッション:インポッシブル/ファイナル・レコニング』において技術がフィーチャー
- 人類の知識と文化を文明の存亡を超えて保存する究極のバックアップとしての役割
■ 8. 技術的意義と展望
- 磁気や電荷という不安定な現象への依存から脱却し結晶構造という物理的な恒久性を手に入れる転換点
- ハイパースケーラー各社が直面するエネルギー問題とデータ爆発の圧力が今後数年で技術の実用化を強力に後押し
- 読み書き速度の向上とコストダウンという課題は残存
- TRL6への移行とライセンスモデルの採用により技術が実験室を出てデジタル社会の基盤となる日が近い
- 数千年後の未来において現代の文明を伝えるのはSPhotonixのクリスタルに刻まれた光の記憶である可能性
■ 1. 背景と課題
- DBコストが毎月徐々に上昇する問題に直面
- 予約管理システムで薬剤師が最新の予約情報をリアルタイムで確認できることが重要な要件
- フロントエンドから30秒間隔でAPIをポーリングする実装を採用
- システムの成長とともに問題が顕在化
- ポーリング間隔は30秒で1回あたりのAPIコール数は9回
- 予約検索APIの秒間リクエスト数は約2,000リクエスト/秒
- 予約一覧・予約詳細・ステータス情報など画面表示に必要な情報を複数のエンドポイントから取得していたため1回のポーリングで9回のAPIを呼び出し
- 多数の薬局クライアントが同時にポーリングを実行するためリクエスト数が膨大化
- 予約データは日々構造が複雑になりデータベースのテーブルにインデックスを張っても大きな負荷がかかる状況
- ポーリング方式の根本的な問題はデータに変更があってもなくても定期的にリクエストが発生する点
- 予約データに変更が発生する頻度はポーリング頻度と比較してかなり低い
- 大半のリクエストは「変更なし」という結果を返すだけで実質的な価値を生み出していない
- 無駄なリクエストが継続的にデータベースへ負荷をかけインフラコストを押し上げる要因
- プロジェクトで導入店舗数が倍増し月次のインフラコストレビューでDBコストの上昇トレンドが明確化したことが転機
■ 2. 解決策の設計思想
- 変更があったときだけ通知を受け取る方式への転換を決断
- 従来のプル型(ポーリング)からプッシュ型(イベント駆動)への転換により不要なリクエストを根本的に排除することを目指す
- 処理フロー:
- 予約データに変更が発生(イベント発火)
- イベント伝播用マイクロサービスがサブスクライブ
- マイクロサービスがFirestoreの薬局別ドキュメントを更新
- フロントエンドがFirestoreの変更を検知
- 必要な予約データをAPIから取得
■ 3. アーキテクチャコンポーネント
- 予約サービス(イベント発行元):
- 予約の作成・更新・キャンセルなどの変更を検知しイベントを発行
- 既存の予約システムに最小限の変更を加える形で実装
- Cloud Pub/Sub:
- Google Cloudが提供するフルマネージドなメッセージングサービス
- イベントの非同期配信を担いシステム間の疎結合を実現
- イベント伝播サービス:
- GKE上で稼働する軽量なマイクロサービス
- Pub/Subからイベントを購読しFirestoreの更新を行う
- 独立させることで関心の分離と保守性の向上を図る
- Firestore:
- 薬局ごとのイベント状態を管理するリアルタイムデータベース
- 各薬局に対応するドキュメントを用意しイベント発生時にタイムスタンプを更新
- フロントエンドクライアント:
- Firestoreのリアルタイムリスナー機能を使用して自身に関係するドキュメントの変更を監視
- 変更を検知したら必要なデータをAPIから取得
■ 4. 技術選定の根拠
- Firestoreを選んだ理由:
- リアルタイム同期機能が標準装備でSDKを使うだけで面倒な接続管理なしにリアルタイム同期が実現可能
- Google Cloudのマネージドサービスとして自動的にスケールしクライアント数の増加に対してインフラ側での対応が不要
- 薬局ごとのドキュメント分離により各薬局が自身に関係するドキュメントのみを購読するため不要なデータを受信しない
- 既にGKEやPub/Subを使用していたため同じエコシステム内で完結できる
- Pub/Subを介在させる理由:
- システム間の疎結合化により予約システムはFirestoreの存在を知る必要がなく「イベントを発行する」という責務のみを持つ
- 信頼性の向上でPub/Subはメッセージの永続化と再送機能を持つため一時的な障害が発生してもイベントが失われない
- Pub/Subのメトリクス(未処理メッセージ数・処理時間など)を監視することでシステムの健全性を把握しやすい
- 将来的には分析基盤への連携・通知サービスへの連携などイベントの配信先を追加する可能性があり拡張が容易
- Cloud Tasksを選んだ理由:
- 動的なタスクスケジュールに最適でフルマネージド
- 指定した時刻に1回だけHTTPリクエストを送信するというシンプルな機能を提供
- キューの管理やスケーリングを意識する必要がない
■ 5. スロットリング機構の実装
- 課題:
- 予約の登録や更新・キャンセルなどが短時間の間に行われた場合に多数のイベントが発生
- 同じ薬局に対して数秒間で何十回もFirestoreが更新される
- フロントエンドが変更を検知するたびにAPIを呼び出し結局大量のリクエストが発生
- スパイク時の負荷が改善されない
- 解決策:
- Cloud Tasksを使ったスロットリング機構を導入
- 一定時間内に発生した複数のイベントを1回の通知にまとめる
- Cloud Tasksで遅延実行を行い指定時刻にHTTPリクエストを送信
- スロットリング間隔の調整:
- 10秒という値を採用
- 通常の予約操作ではユーザーが10秒以内に複数回更新することは稀
- 複数イベント発生時のイベント集約効果が十分に得られる
- ユーザーが体感する遅延として許容範囲内
- モニタリングの結果を見ながら調整を継続
■ 6. テスト戦略
- イベント発生ケースの網羅:
- イベントが正しく発火されることがシステム全体の動作に直結
- イベントの発火漏れがあればフロントエンドに変更が伝わらずユーザーは古い情報を見続ける
- イベントが発生するすべてのケースを洗い出し網羅的にテストを実施
- ケースの洗い出し:
- 予約作成(処方箋事前送信予約・オンライン服薬指導予約・店頭受付)
- 予約更新(日時変更・ステータス変更・患者情報変更・メモ追記)
- 予約キャンセル(ユーザー操作・自動キャンセル・管理者操作)
- 動作確認の観点:
- イベントが正しく発火されるか(Pub/Subにメッセージがパブリッシュされることを確認)
- イベント内容が正しいか(薬局ID・予約ID・イベントタイプが正確に設定されていることを確認)
- Firestoreが更新されるか(該当薬局のドキュメントが更新されることを確認)
- フロントエンドが検知するか(画面上で変更が反映されることを確認)
- リグレッションテストとの擦り合わせ:
- 既存のリグレッションテストで今回洗い出したイベント発生ケースがカバーされているか確認
- カバーされていないケースがあれば新たにテストケースを追加
- イベント発火の確認をリグレッションテストの検証項目に追加
- 本番リリース後のイベント発火漏れはゼロを達成
■ 7. 導入結果
- 定量的効果:
- 予約検索APIの秒間リクエスト数は約2,000/秒から約1,000/秒へ50%削減
- DBコストは30%削減
- ネットワークトラフィックは大幅削減
- 定性的効果:
- リアルタイム性の向上で従来は最大30秒の遅延があったが予約の変更がほぼリアルタイムで画面に反映
- システム安定性の向上でポーリングによる定期的な負荷スパイクがなくなりデータベースへの負荷が平準化
- 開発者体験の改善で各コンポーネントの責務が明確でデバッグや機能追加がしやすくなった
■ 8. 運用上の考慮事項
- 成功要因:
- 段階的なリリースでまずは一部の薬局から段階的に展開し想定外の問題があった場合の影響範囲を限定
- 監視体制の整備でPub/Subの未処理メッセージ数・Cloud Tasksの実行遅延・Firestoreの読み取り/書き込み数・フロントエンドからのAPI呼び出し数を監視
- チーム内での知識共有で新しいアーキテクチャについて設計の意図や運用方法をドキュメント化し属人化を回避
- 留意すべき事項:
- イベント欠損への対策としてPub/Subの再送機能を活用(デッドレターキューの設定)
- 順序保証の考慮で分散システムにおいてはイベントの到着順序が発生順序と一致するとは限らない
- Firestoreコストの試算で導入前に試算を行いトータルでコストメリットがあることを確認
■ 9. 今後の展望
- スロットリング間隔の動的調整で時間帯やイベント発生頻度に応じて動的に調整することでさらなる最適化が可能
- 他システムへの水平展開で今回得られた知見を他のポーリング処理を行っているシステムにも展開予定
■ 1. 記事の背景と概要
- 履歴というデータを取り扱うことのために考えていること・戦い方について整理した内容である
- 履歴のデータはとても重要になる場合があり履歴管理や監査証跡・時点復元・法令対応などで「過去の状態を正確に残したい」という要件が発生することがある
- この記事の概要:
- 「状態」の保存は一見シンプルだが履歴要件が入ると破綻しやすい
- Bi-temporalは強力な設計手法だがクエリ・運用の複雑さが課題になりやすい
- Event Sourcingは「変化」を中心に据えることで履歴が自然に残すことができる
- ただしRead ModelやVersioningなど別の複雑さとのトレードオフがある
■ 2. 一般的なRDB設計の問題点
- ほとんどのRDBで管理されているデータは「現在の状態」だけを保存するように設計されている
- このテーブルで「注文をキャンセルした」という履歴を残そうとすると以下の方法が考えられる:
- 方式A:変更前スナップショット方式
- 方式B:ステータス更新+別途「変更履歴テーブル」にINSERT
- 方式C:有効期間を持たせるテンポラルテーブル方式
■ 3. 方式A:変更前スナップショット方式の問題点
- 変更前の状態だけを履歴テーブルに保存する方式である
- 悩みポイント:
- 「何に変わったか」が分からない:変更前の状態しか保存していないため履歴テーブルだけを見ても「何に変わったのか」が分からない
- 時点復元が困難:valid_toがないのでどの履歴レコードがいつまで有効だったか分からない
- 変更理由・操作内容が残らない:なぜ変更したのかどんな業務操作だったのかこれらのコンテキストが失われるため監査証跡としては不十分になる
- 連続した変更の追跡が複雑:A→B→Cと3回変更された場合履歴から「2025-01-02時点の状態」を導くには推論する必要がある
■ 4. 方式B:ステータス更新+変更履歴テーブルの問題点
- ステータス更新と同時に変更履歴テーブルにINSERTする方式である
- 悩みポイント:
- ステータス以外の属性変更が追跡できない:この方式はstatusの変更だけを追跡しておりtotal_amountが変更された場合その履歴は残らない
- 元テーブルと履歴テーブルの整合性が保証されない:2つのテーブルを別々に更新するためアプリケーションコードで「必ず両方更新する」ルールを徹底する必要がある
- 履歴の正しさを検証できない:元テーブルの現在のstatusと履歴テーブルの最新to_statusが一致している保証もなく履歴の連続性も保証されない
- 「作成」と「削除」の表現が曖昧:注文が最初に作成されたときのfrom_statusや注文が削除されたときのto_statusをどうするかが曖昧になる
- 時点復元は改善されるが完全ではない:status以外の属性の時点復元はできない
■ 5. 方式C:テンポラルテーブル方式の問題点
- 有効期間を持たせるテンポラルテーブル方式である
- 悩みポイント:
- 「現在の状態」を取得するクエリが複雑になる:シンプルだったSELECTが毎回時間条件付きになる
- 関連テーブルもテンポラルにすると「ある時点での注文とその明細」を取得するクエリがより複雑になる
- 更新では「終了+INSERT」の2ステップが必要:必ずトランザクションで実行しないと不整合が起きてしまいアプリケーションコードも煩雑になる
- 誤入力の訂正で監査証跡が失われる:過去の行を直接UPDATEすることになり「元々何が記録されていたか」が消えてしまう
- Valid Timeだけでは「いつシステムがその情報を認識していたか」が分からない:これを解決するにはSystem Timeも必要になりBi-temporalへの対応が求められる
- 「同時点で複数有効」を防ぐ制約が難しい:標準的なUNIQUE制約では表現できない
■ 6. Bi-temporalの構造と利点
- Bi-temporalテーブルの各行は通常4つのタイムスタンプを持つ:
- Valid From/To:現実世界でその事実が有効な期間
- System From/To:データベースがその事実を知っていた期間
- この構造により「現在の知識に基づくと先月の価格は10000円であるしかし先週時点の知識では先月の価格は9800円であると認識していた」という複雑な問いに答えることができる
■ 7. Bi-temporalの複雑さと問題点
- 誤入力訂正が入ると「過去のSystem Timeを書き換える」必要がある
- 1つの訂正で複数行の更新・追加が必要になる:「金額10000円→9800円」という1つの訂正で既存の2行を終了し新しく2行をINSERTし合計4行の操作が必要になる
- 「何が訂正されたか」の追跡が困難:system_toで終了した行と新しくINSERTした行の関連付けは暗黙的であり訂正理由も記録されない
- クエリもさらに複雑になる:「2025-01-03時点で業務上もシステム上も有効だった注文一覧」を取得するだけで複雑なクエリになる
- Bi-temporalにテーブルを紐づけるとさらに複雑になる:紐づく先のテーブルもBi-temporalにしないと整合性が取れなくなる
■ 8. 状態中心の設計が難しくしている理由
- ここまで見てきた方式やBi-temporalなどすべてに共通するのは「状態」を保存しようとしていることである
- 状態とは「ある時点での結果」である
- 状態を保存するということは結果だけを切り取って保存することになる
- そのため以下の情報が失われる:
- なぜその状態になったのか
- どうやってその状態になったのか
- 誰がその変化を引き起こしたのか
- 履歴を残そうとすると失われた情報を補うために追加のカラムやテーブルが必要になり結果として設計が複雑化していく
■ 9. 変化を中心に考えるイベント中心の発想
- 「状態中心」の発想を変える:
- イベント中心の発想では「何が起きたか?」を記録する
- 状態を知りたい場合はイベントを順番に適用して現在の状態を導出する
- イベントは「起きた事実」そのものである
- 状態とイベントの比較:
- 状態は結果でありイベントは原因である
- 状態は変わりうるがイベントは変わらない
- 状態は「今どうなっているか」でありイベントは「何が起きたか」である
- 状態はスナップショットでありイベントは事実の記録である
■ 10. 状態中心とイベント中心の具体的比較
- 状態中心の場合:
- 「各時点での状態のスナップショット」を保存する
- どの行がどう関連しているか何が起きたのかこのデータだけでは分かりにくい
- イベント中心の場合:
- 「何が起きたか」をそのまま保存する
- 何が起きたかなぜ起きたか誰が起こしたかすべて明示的に残すことができる
- occurred_atは業務上発生した時刻でsystem_fromはシステムが記録した時刻である
■ 11. 現在有効なデータの取得方法
- 状態中心の場合はWHERE句で時間条件を指定するクエリを実行する
- イベント中心の場合は2つの方法がある:
- 方法1:イベントをリプレイして導出する:イベントが少なければ十分だがイベントが膨大になるとリプレイのコストが高くなる
- 方法2:Read Modelを使う:現在の状態を別テーブルに保持しておきイベント発生時に更新する
- Read Modelはイベントから導出された状態のキャッシュでありいつでもイベントから再構築できるため要件に応じて自由に設計できるのが特徴である
■ 12. Event Sourcingの課題1:最新状態の取得
- イベントをリプレイして状態を導出する方式はイベント数が少なければ問題ないが数万〜数十万件になると現実的ではなくなる
- 解決策としてSnapshotとRead Modelを導入することが考えられる:
- Snapshot:定期的に「ある時点での状態」を保存しておきそこからリプレイを開始する
- Read Model:現在の状態を別テーブルに保持しイベント発生時に更新する
- ただしSnapshotやRead Modelを導入するとシステムの複雑性は増していく
■ 13. Event Sourcingの課題2:有効期間の表現
- Event Sourcingは「何が起きたか」を記録するが「いつからいつまで有効だったか」という期間情報は直接表現しない
- 単純に「最新の状態」を持つRead Modelだけでは不十分で期間情報を持った別のRead Modelが必要になる
- Bi-temporalが必要だった理由は「訂正時に過去の認識を残すため」だったがEvent Sourcingではイベントは不変で追記のみであり訂正もイベントとして記録される
- つまりイベントストアがシステム時間の役割を担っているのでRead Modelは業務上の有効期間だけを持てば十分である
■ 14. Event Sourcingの課題3:イベントスキーマのVersioning
- イベントは不変なので一度保存したイベントのスキーマを変更することはできない
- しかしビジネス要件はフェーズが進むにつれて変化していく
- 過去のイベントを読み込むとき新しいコードで正しく処理するにはv1からv3に変換するロジックであるUpcasterパターンを用意する必要がある
- Upcasterパターンとは主にEvent Sourcingで使われる設計パターンで過去に保存された古い形式のイベントを現在の最新のイベント形式に変換するための仕組みである
- 上記以外に「過去のイベントを物理的に新しいスキーマに書き換える」アプローチもあるがEvent Sourcingの原則を破ることになり監査証跡としての価値が下がる可能性がある
■ 15. Event Sourcingの課題4:取り消しと訂正
- イベントは不変だが「このイベントは間違いだった」というケースは現実に発生する
- この問題に対応するためにCompensating Event補償イベントというものを導入する必要がある
- 「取り消し」や「訂正」も新しいイベントとして記録する
- ただし「どこまで遡って訂正するか」「関連するイベントへの影響をどう扱うか」は慎重に設計しないと破綻してしまう
■ 16. Event Sourcingの課題5:結果整合性とその他
- イベント発行からRead Modelの更新は同期的に行われるわけではないためタイムラグがある
- そのためユーザーが「保存したのに反映されていない」と感じるStale Read問題が発生する
- UI側で楽観的更新を行ったり同期的な読み取りが必要なケースではイベントストアから直接リプレイすることで対応する
- 他にも「イベント設計」「Read Modelの設計と更新ロジック」「Snapshot戦略」「エラーハンドリング」など考えないといけないことはたくさんある
■ 17. Event Sourcingを採用すべきかの判断
- Event Sourcingは「履歴」という要件にはとても強力だがトレードオフは必ず発生する
- メリット:
- 完全な履歴が自動的に残る
- 任意の時点の状態を復元できる
- 「何が起きたか」が明示的
- 監査証跡として価値がある
- デメリット:
- 最新状態の取得に工夫が必要
- Read Modelの設計は難しい
- イベントスキーマのVersioningへの対応が必要
- 結果整合性への対応が必要
- Bi-temporalのようなテンポラルデータモデルで運用し続けるのも難しい
- 少なくとも「履歴」という要件が厳しいときにはEvent Sourcingを1つの選択肢として検討してみると良いかもしれない
- Event Sourcingを導入するときに一番大切なのは「やり切ると決めたら最後までやり切る」という気持ちである
■ 1. 楽観的同時実行制御の普及と盲信への警鐘
- ADO.NETを使うと楽観的同時実行制御を容易に実装できる
- 超有名な「楽観的ロックでいいじゃん!」のお陰で楽観的同時実行制御は特にWebアプリケーション開発では広く使われている
- 大概のアプリケーションでは楽観的同時実行制御で十分なのかもしれない
- しかし「楽観的同時実行制御こそが正義だ」と盲信されかねない空気に警鐘を鳴らす必要がある
■ 2. 悲観的ロックと楽観的ロックの定義
- 大西彰さんの記事「楽観的ロックでいいじゃん!」による定義:
- 悲観的ロック:ステートフルなロックで更新したい対象のリソースを照会して取得した直後から更新が終わるまでロックを維持することでロック時間は長時間でロックは独占的
- 楽観的ロック:ほぼステートレスなロックで更新したい対象のリソースを照会してもロックはかけず本当に更新が必要になった段階でその対象リソースをロックすることでロック時間は短時間でロックは非独占的
■ 3. 同時実行制御の概念による整理
- 悲観的同時実行制御:
- 衝突が頻繁に発生する事が前提の同時実行制御
- 楽観的同時実行制御:
- 衝突が殆ど起こらない事が前提の同時実行制御
- 楽観的同時実行制御は「競合・衝突が全くあるいは殆ど起こらないために衝突に関しては楽観的に考えてよい」ものである
- 悲観的同時実行制御は「競合・衝突が殆どにおいて発生しトランザクション量も多いため衝突に関しては悲観的に考えなければならない」ものである
■ 4. よくある勘違いとその弊害
- 肝要でありよく勘違いされるのが「DBMSのロックメカニズムを使うことが悲観的同時実行制御である」という事である
- そのせいか長時間ロックを回避する為にWebアプリケーション開発では楽観的同時実行制御を大前提に設計をしてしまう事が多々ある
- しかしトランザクション量が多く競合・衝突が頻発するにも関わらず楽観的同時実行制御を行ってしまうと極端に使い勝手の悪いアプリケーションになってしまう
- 予約システムのように仮予約されたチケットがいざ購入の段になって「他の人に獲られました」ではクレームの嵐である
- 仮予約チケットは他の人が見れないようにロックする必要がある
- かといって長時間トランザクションにDBMSのロックメカニズムを使う訳にはいかない
■ 5. 業務排他制御という解決策
- 独力で同時実行制御を作り込む事が考えられる
- 「.NETエンタープライズWebアプリケーション開発技術大全Vol.5トランザクション設計編」では「業務排他制御」と表現されている
- 「悲観的ロックを使わないで悲観的同時実行制御を行う」とでも表現できる
- テーブルに排他制御専用の列を2つ3つ追加し編集ステータスや編集開始日時などをチェックすれば良いだけで実装自体は比較的容易である
- ただし実装は容易でも業務フローの難易度は高くなる
■ 6. Webアプリケーションと楽観的同時実行制御の適性
- クライアントユーザー数が多いであろうWebアプリケーションの方が楽観的同時実行制御には向いていないとさえ言える
- ただしユーザー数が多くても大半のユーザーが参照アクションしか行わないのであればその限りではない
- 楽観的同時実行制御が向いているのはマスタデータメンテナンス等を行うクライアントユーザー数の限られたWindowsアプリケーション等ではないか
- もちろんWebアプリケーションでもあり得る
- 「Webアプリケーションでは悲観ロックはあり得ない楽観同時実行制御こそが正」と決めつける前によくよく仕様を揉んでみるべきである
- その要件は楽観的に考えられるかを検討する必要がある
■ 1. 排他制御の2つの方法と歴史的背景
- データベースのトランザクション処理を実行する場合対象となる行の排他制御が必要である
- 排他制御は同時実行処理において必要不可欠だが使い方を誤ると簡単なはずの処理が難しくなる可能性がある
- リソースをロックする方法は2種類ある:
- 悲観的ロック
- 楽観的ロック
- スタンドアロンでプログラムが動いていた時代は1ユーザ・1プログラム・1データのみが存在するため排他制御を考えなくてもアプリケーションの開発は行えた
- コンピュータがネットワークでつながるようになってデータが複数のユーザからアクセスされるようになると排他制御を無視してプログラムを書くことはできなくなった
- DBMSが利用できるようになってファイルレベルでの同時実行制御からデータベースレベル・テーブルレベル・ページレベル・行レベルといったロックのメカニズムが提供された
- 現在はHTTPという不安定なプロトコルの上でのトランザクションが求められている
■ 2. 悲観的ロックと楽観的ロックの定義
- 悲観的ロック:
- ステートフルなロック
- 更新したい対象のリソースを照会して取得した直後から更新が終わるまでロックを維持する
- ロック時間は長時間でロックは独占的
- 楽観的ロック:
- ほぼステートレスなロック
- 更新したい対象のリソースを照会してもロックはかけず本当に更新が必要になった段階でその対象リソースをロックする
- ロック時間は短時間でロックは非独占的
■ 3. 悲観的ロックのメリットとデメリット
- 悲観的ロックは「俺様が更新するリソースは全部俺様のものだ他人にはアクセスさせないぞ」というものである
- DBMS上でロックを実行したユーザアカウントのコンテキストでロックが解放されるまで排他制御が実行され続ける
- メリット:
- ロックを取得したユーザが見ているリソースが他者から変更されないことを保障する
- デメリット:
- ロックが維持されている間他のユーザはそのリソースにアクセスできない
- ロックを維持することによりデッドロックを引き起こしやすくなる可能性が高い
- この記事で提示したいのは「そのロック本当に悲観的じゃなきゃいけないの?」という疑問である
■ 4. 楽観的ロックで十分な理由1:認証と認可
- ユーザの認証と認可をきちんと処理していれば更新の競合はほとんどありえない
- データベースを設計する際に考えなければならないのは「ユーザの認証」と「ユーザの権限」である
- 悪い例は何でもできる特権を持ったユーザアカウントですべてのデータベースオブジェクトを作りアプリケーションからのアクセスもそのアカウントで実行してしまうこと
- 権限レベルの段階:
- Level0:アクセス許可なし
- Level1:読み取り専用
- Level2:読み取り・書き込み可能
- Level3:特定データベースの変更・構成可能
- Level4:全権限の所有
- 理想的にはデータベース設計者がデータベースを完成させたら権限をDBAに委譲してデータベース設計者からすべての権限を奪うのが望ましい
- Level0からLevel2までの範囲で権限を設定していれば無駄なトランザクションの発生を抑えられる
■ 5. 楽観的ロックで十分な理由2:業務プロセスとワークフロー
- 業務上同一行を複数人で同時に更新するプロセスはほとんど考えられない
- 業務システムにおいて情報が更新されるためには何らかのビジネスプロセスと対応している必要がある
- 例えば人事情報の変更を考えた場合人事部に変更届を提出するのが普通である
- 何らかの届けが提出されそれが認知されて処理されるにあたっては「審査」というワークフローを通る必要がある
- 審査が通るまではトランザクション処理は実行されることがない
- このような「変更」-「審査」といった業務フローの場合同じ行が複数の人から同時に更新されることは起こりえない
- 業務における「変更」には必ず権限を持つ人の「承認・審査」が伴うはずである
- この制約がある限り「変更」は即座には実行されず「変更要求」-「承認・審査」-「変更実行あるいは変更の却下」の流れになる
■ 6. 楽観的ロックで十分な理由3:対照表による履歴管理
- 動的に変化するデータを対照表の形で作成してしまえば追加のみなのでロックは必要ない
- 例えば小売店における商品の売価を考える
- 商品というエンティティに売価を入力して更新するやり方は後に営業分析する際に売価の動きを追跡することが難しくなる
- 売価を対照表で管理すると商品ID・店舗ID・発生日時・イベント・売価などで管理できる
- このモデルに従うと商品の売価においては変更が生じてもデータベース側では「行の追加」しか発生しない
- 変更イベントが発生しても商品の売価という対照表の行を更新するということは起こりえない
- したがって楽観的ロックすら必要がない
■ 7. 楽観的ロックで十分な理由4:データの所有権管理
- データの所有権を管理すれば更新の競合はほとんどありえない
- アプリケーションによって行に所有権を設定し所有権のある行だけを処理の対象とすることを考える
- 所有者IDをUPDATEステートメントのWHERE句に含めることで他の所有者の行を更新することがなくなる
- 行の所有者を明確にしているので悲観的ロックにすることなく楽観的ロックで十分になる
- しかし所有者の変更を追跡しようとすると多対多のモデルになるので結局は対照表の構造に帰着する
- したがって理由3の繰り返しになり行を更新するという話がなくなる
■ 8. アーキテクチャの変遷とトランザクション軽量化の重要性
- 時代はメインフレームによる集中処理からクライアントサーバの分散型・Webシステムにおける集中処理型・スマートクライアントによる分散型と集中・分散を繰り返している
- どのようなアーキテクチャが採用されるにせよコンピュータのメモリは有限でありデータをどこかの2次記憶装置に永続化する必要がある
- 工夫次第でトランザクションを軽量なものにすることができる
- 最終的に一番負荷がかかるのはデータベースが稼動しているサーバである
- スケーラビリティやパフォーマンスを求めるのであればいかにサーバリソースを消費しないで同時実行性を高めるかということにつきる
■ 9. 実体験に基づく楽観的ロックの優位性
- 12-13年前にCA-ClipperというXbaseのシステムで悲観的ロックモデルによりアプリケーションを作成した際にこのロックモデルの欠点がよくわかった
- ネットワークのトラフィックの増大・アプリケーションパフォーマンスの低下を招くことが低性能のPCで証明された
- 結局楽観的ロックに切り替えられるようクライアントでトランザクション用のキューを作りサーバ側にバッチアップデート要求を出すような作りにした
- MS-DOSのファイルシステムレベルでの排他制御も経験したがロック時間が長くなればパフォーマンスが低下することがわかった
- ロック時間は短いほうがいい
- SQLを利用するDBMSにおいても結局理屈は変わらない
- ユーザのロールモデル・業務上のワークフロー・データベースの設計方法を工夫するだけでも「悲観的ロック」から逃れることができる
- SOAのアプローチになってサービスとの疎結合が求められると「楽観的ロック」中心のアプローチでないとサービスの開発ができない
- 永続化処理を軽量にすることが今後も求められる
■ 1. 背景と用語定義
- 一休.comの宿泊予約のシステムで予約部分のリニューアルを進めている
- リニューアルの中で取り組んだ予約処理の結果整合を実現するための実装について説明する
- 用語の定義:
- トランザクション:予約処理全体を指す
- ローカルトランザクション:カード決済や在庫引当と言った個々の処理を指す
- ロールバック:DBトランザクションのロールバックに限らずローカルトランザクションを補償トランザクションにより論理的にロールバックすることも指す
- 補償トランザクション:ロールバックを実現するための手段として利用する
■ 2. 要件
- 宿泊予約トランザクションの中で発行される主なローカルトランザクション:
- 在庫引当
- カード決済
- 一休ポイント登録
- サイトコントローラーへの通知
- ユーザーへのメール通知
- これに加えて予約データの永続化がある
- 少なくともこのようなローカルトランザクションを予約全体として結果整合させる必要がある
■ 3. Sagaパターンの概要
- 複数のローカルトランザクションを結果整合させるためのパターンとして有名なものにSagaパターンがある
- Sagaパターンは補償トランザクションを利用してローカルトランザクションをロールバックすることそしてそのローカルトランザクションの実行やロールバックを全体で結果整合させるための設計パターンである
- Sagaパターンにはいくつか種類がある:
- コレオグラフィパターン:ローカルトランザクション同士が相互に協調しあって全体をコントロールする
- オーケストレーションパターン:中央集権的なオーケストレータが全体のローカルトランザクションの実行やロールバックをコントロールする
- 更に詳しく各ローカルトランザクションの通信の同期や非同期整合性が結果整合かアトミックかを加えた分類もある
- 一方でその具体的な実装に踏み込んだ説明は多くない
- この記事では具体的なパターンを網羅的に説明したりパターンの中で何に該当するのかと言った体系的な説明というよりは実際自分たちがどのような実装をしているのかというところを説明する
■ 4. リニューアルの実際
- 予約リニューアルに伴いドメインモデルを捉えなおし合わせて技術的な詳細についても見直せる部分は見直してきた
- 今回紹介する実装パターンについても既存のシステムで大きな問題なくここまで運用されてきたものであるため抜本的に設計しなおしたというものではない
- 既存のシステムをあらためて解釈し整理できる部分は整理していき改善できる部分は改善したところこのような形に落ち着いたというのが実際のところである
■ 5. ピボットトランザクションの決定とローカルトランザクションの分類
- トランザクションの成否を決定するローカルトランザクションのことをピボットトランザクションと呼ぶ
- ピボットトランザクションが失敗した場合そのトランザクション全体も失敗として扱われる
- その場合ピボットトランザクション以前に実行したローカルトランザクションも失敗として扱う必要がある
- これを決定し各ローカルトランザクションはピボットトランザクションよりも前に実行されるのか後に実行されるのかを明確にすることで全体の設計が見通しやすくなる
- ピボットトランザクションは予約データの永続化と捉えた
- ローカルトランザクションの性格:
- カード決済や在庫引当はそれが失敗したら予約も失敗として欲しい
- ユーザーへの予約通知メール送信やサイトコントローラーへの予約通知についてはそもそも予約が失敗していたら実行して欲しくない
- ピボットトランザクションよりも前に実行するローカルトランザクションは予約の成否に応じて補償トランザクションでロールバックする
- ピボットトランザクションよりも後に実行するローカルトランザクションはピボットトランザクションが成功している以上は最終的に成功として扱いたいものになる
- 後者の最終的に成功として扱いたいを実現するパターンとしてはTransactional Outboxパターンなどがある
- このoutboxはいわゆるメールの送信トレイを意味していて送信時にはoutboxのみを作っておいてoutboxをもとにしてリトライするなどで最終的に送信されることを目指すというものである
- サイトコントローラーへの送信などはこのTransactional Outboxパターンを利用している
- 具体的にはピボットトランザクションとなる予約データの永続化のトランザクションの中でサイトコントローラー用のoutboxのデータを作成している
- どうしようもないものは人手での運用にまわしているものもある
■ 6. 補償トランザクションの実装パターンと補償ログの導入
- トランザクションが失敗として定義された場合実行されたローカルトランザクションに対し補償トランザクションを実行していくことになる
- この際ローカルトランザクションが実行済みであるということを把握する必要が出てくる
- そのために実際のローカルトランザクションを実行する前に補償ログというデータを登録する
- 補償ログというのは一般用語ではなく造語である
- 概念としてはデータベースのUNDOログに近い
- ローカルトランザクションが成功した後にピボットトランザクションが失敗したケースを考える
- この場合補償ログがあればそれに対応する補償トランザクションを実行するということになる
- 補償ログ・補償トランザクションを実装する際に重要なポイント:
- ポイント1:補償ログはローカルトランザクションの実行前に登録する:
- 補償ログはローカルトランザクションの実行前に登録する必要がある
- 仮にローカルトランザクションの実行の後に補償ログを登録するという実装にしていた場合ローカルトランザクションの実行には成功したが補償ログの登録には失敗したというシチュエーションを考える必要が出てきてしまう
- これは基本的にローカルトランザクションのロールバックが不可能になってしまう
- したがってローカルトランザクションの実行前である必要がある
- UNDOログを例に出したが実行前に登録する必要があるというのもデータベースのWrite-Ahead Loggingに似た考え方である
- 補償ログの登録に失敗した場合そのローカルトランザクションは実行せず失敗として扱う必要がある
- ポイント2:ローカルトランザクション実行前に補償トランザクション実行に必要な情報がそろっている必要がある:
- 補償ログには補償トランザクション実行に必要なIDなどの情報を登録しておく
- したがってローカルトランザクション実行前に補償ログを登録するということはローカルトランザクション実行前に補償トランザクション実行に必要な情報がそろっている必要があるということになる
- 例えばローカルトランザクションの実行結果としてあるリソースのIDが手に入りそのIDが補償トランザクションのリクエストパラメータとして要求されるようなAPIではこの要件を満たすことが出来ない
- 補償ログには補償トランザクション実行に必要十分なIDなどの保存にとどめ逆に個人情報等は保存しないようにする
- ポイント3:補償ログはピボットトランザクションの成功後に削除する:
- 補償トランザクションを実行する場合補償ログは補償トランザクションの実行後に削除する必要がある
- 補償ログの登録の話と同じく仮に補償ログを削除してから補償トランザクションを実行するようにした場合補償トランザクション実行に失敗した場合に補償トランザクションを再度実行できなくなってしまう
- さらに補償ログの削除はピボットトランザクションの成功後に削除する必要がある
- ピボットトランザクションがトランザクション全体の成否を決定するためピボットトランザクションが成功するまではローカルトランザクションをロールバックする必要がある可能性があるため
- したがってピボットトランザクションが成功するまでは補償ログを削除することは出来ない
- ポイント4:補償トランザクションは冪等にする:
- 補償トランザクションは冪等である必要がある
- これは補償トランザクション実行に失敗した場合や補償トランザクションに成功した後補償ログの削除に失敗した場合などで再度補償トランザクションが実行されうる状態になるためである
■ 7. ピボットトランザクションとピボットマーカーの導入
- ローカルトランザクションの補償ログとそれを利用した補償トランザクションの実行のための実装パターンを説明した
- ピボットトランザクションとローカルトランザクションを関係づけることでトランザクション全体の結果整合性を実現することが出来るようになる
- ピボットトランザクションに対してもローカルトランザクションと同様それが進行中であることを示す必要がある
- ピボットトランザクションに対する補償トランザクションは存在しないため補償ログではなくピボットマーカーと呼ぶことにする
- このピボットマーカーも一般用語ではなく今回導入した造語である
- このピボットマーカーをローカルトランザクションの開始前にまず作成しそしてピボットトランザクションとアトミックに削除することで全体としての結果整合性が実現できることになる
- 重要な点:
- ポイント1:ピボットマーカーはピボットトランザクションとアトミックに削除する:
- トランザクション全体で結果整合性を担保する上でこれが最も重要である
- ピボットマーカーはピボットトランザクションとアトミックに削除する必要がある
- これによりピボットマーカーが存在している=ピボットトランザクションが完了していないピボットマーカーが存在しない=ピボットトランザクションが成功したと解釈出来るようになる
- ピボットマーカーを予約データ永続化先と同じDBに保存し予約データ永続化と同じDBトランザクションでピボットマーカーを削除することでこの要件を満たしている
- ポイント2:補償ログとピボットマーカーに親子関係を設ける:
- 補償ログとピボットマーカーに親子関係を設けることでローカルトランザクションの補償トランザクションの実行要否とピボットトランザクション成否を結びつけることが出来る
- これによりトランザクション全体の結果整合性を担保することが出来る
- ピボットマーカーが存在していれば実行済みのローカルトランザクションが存在する可能性がありロールバックする場合はローカルトランザクションに対して補償トランザクションを実行する必要がある
- ピボットマーカーが存在しなければトランザクション全体を成功とみなすためローカルトランザクションに対して補償トランザクションを実行する必要はないと解釈することが出来る
- ポイント3:補償トランザクションを実行する際は常にピボットマーカーを起点に実行する:
- 常にピボットマーカーから補償ログを辿って補償トランザクションを実行するようにする
- こうすることでピボットマーカーが存在している場合にのみ補償トランザクションが実行されるようになる
- つまりピボットトランザクションが成功した場合は絶対に補償トランザクションが実行されることはないとすることが出来る
■ 8. トランザクション全体のロールバックの例
- ここまでの実装でトランザクション全体としてロールバックを冪等に実行することが出来るようになる
- ローカルトランザクションの一部が失敗した場合を考える
- ロールバックの流れ:
- ピボットマーカーが作成され
- その後のローカルトランザクション1と2と3と実行されるがローカルトランザクション3が失敗し
- ローカルトランザクション1と2に対して補償トランザクションを実行してロールバック
- 補償ログ削除
- 最後にピボットマーカーを削除
- このようにしてトランザクション全体をロールバックすることが出来た
- このプロセスは冪等に実行することが可能である
- ロールバック処理では複数ある補償トランザクションのうちのひとつの実行に失敗したりすることがあり得る
- そのほかサーバーのプロセスごと落ちたなどでロールバック全体が完了しなかった場合にも実行する必要のある補償トランザクションを確実に実行する必要がある
- そのため一連のロールバック処理を予約の失敗時にサーバーから同期的に実行することに加えて定期的に残っているピボットマーカーを見てサーバーから実行したものと同じロールバック処理を再実行するジョブをCloud Run Jobsで用意している
- ロールバック処理を冪等に実行出来るようにすることでこのように確実にロールバックが完了するように実装することが出来る
■ 9. 制約
- ここまで説明してきた実装パターンが適用出来る前提:
- ローカルトランザクションが同期的に実行できること:
- ここでいう同期的とはローカルトランザクションの成否がピボットトランザクション実行までに確定していることを指す
- ローカルトランザクション同士が強く結合していないこと:
- 順序制約はあってもよいが補償トランザクションに必要な情報が前段の実行結果に依存しないこと
- 実行前に補償ログへ必要情報を確定できること
- トランザクション全体としての一貫性は結果整合で良いこと:
- 予約失敗の場合には一時的にでも在庫が引当されてはいけないと言った制約がある場合はこの実装パターンには向かない
- これよりも厳しい要件が必要な場合この実装パターンそのままは適用できない
■ 10. この実装パターンの特徴と利点
- 紹介した実装パターンの特徴や利点:
- Sagaパターンなどを意識せずドメインロジックの実装が可能:
- アプリケーションロジックを実装する際はこのようなことを気にせずに進められるならそれに越したことはない
- ここまで説明してきた実装パターンは主にI/Oを実行するレイヤでのみ気にすれば良いものになっている
- したがってドメインロジックとI/Oを適切に分離できていればここまでの補償トランザクション周りの実装についてもドメインロジックを実装する際に意識する必要はなくなる
- ローカルトランザクションの追加が容易:
- ローカルトランザクション毎に補償ログ・補償トランザクションの実装を用意すればローカルトランザクションを追加することは比較的容易である
- 実際に予約リニューアルプロジェクトを進める中で段階的にローカルトランザクションを大きな労力なく追加していくことが出来た
- ローカルトランザクションの変更が容易:
- ローカルトランザクションそれぞれの独立性が高いためローカルトランザクションの実行タイミングや順序などが変更しやすくなる
- 例えば在庫引当はもっと早いタイミングに実行してしまいたいと言った変更である
■ 1. SQLiteの再評価とDB Proでの活用
- DB ProではSQLiteを愛用している
- SQLiteには制限があるが弱点ではなく適切にデプロイされ慎重にチューニングされればプロダクションで使用できる
- SQLiteは過去数年で復活を遂げている
- libSQLやTursoへのフォークやPocketBaseのような人気バックエンドフレームワークでの採用などが見られる
- DB Pro自体のローカルデータベースもSQLiteで動作している
- DB Proのユースケースにはこれ以上の代替手段は存在しない
- 過去3ヶ月間SQLiteを本格的に使用してきた結果多くのことを学んだ
- SQLiteのより興味深い機能とニュアンスを扱う短いブログ投稿シリーズを計画している
■ 2. SQLiteのJSON機能の発見
- SQLiteにはJSON関数と演算子があることを最近まで知らなかった
- Hacker Newsのコメントでbambaxという人物がSQLiteのJSON演算子について述べた内容を発見した
- bambaxのコメントの要点:
- 各JSONドキュメントをそのまま1つのカラムに保存する
- json_extractの組み合わせを使用してクエリしたい特定の情報を保存する仮想カラムを作成する
- これらのカラムにインデックスを作成する
- これにより超高速検索が可能になる
- 挿入時にインデックス対象を選択する必要がなく必要なときにいつでも仮想カラムを追加できる
- インデックスされていない生のJSONも検索できるが大規模コレクションでは時間がかかる可能性がある
■ 3. bambaxの提案する4つのステップ
- bambaxの提案を実際に試してみることにした
- DB Proのブログには埋め込みSQLite-in-the-browserコンポーネントがあるため動作例を作成した
- bambaxが述べている内容の分解:
- JSONドキュメントを生のまま保存する
- json_extractを使用して仮想生成カラムを作成する
- これらの生成カラムにインデックスを追加する
- 完全なB-treeインデックス速度でJSONをクエリする
- これによりインデックス戦略を事前に選択する必要がなくなる
- 後で新しいJSONフィールドでクエリする必要があることに気づいた場合は生成カラムを追加してインデックスを追加するだけで完了する
- データ移行もスキーマの書き換えもETLも不要で純粋な柔軟性が得られる
■ 4. 実装手順1:生JSONの保存
- まずJSONカラムを持つシンプルなテーブルを作成する
- JSONドキュメントは到着したそのままに自然に保存される
- スキーマの複雑な操作も不要である
■ 5. 実装手順2:仮想生成カラムの追加
- bambaxが魔法が起こると言っている箇所である
- 仮想生成カラムを追加する
- 生成カラムはオンデマンドで値を計算する
- これらは実際にはデータを保存しない
- 書き込みは発生しないと考えられる
- バックフィルも不要で即座に実行される
- 仮想カラムはクエリするたびにJSONデータからオンザフライで計算される
■ 6. 実装手順3:パフォーマンスのためのインデックス追加
- これがケーキのアイシングである
- インデックスを追加してこれらの仮想カラムを超高速にする
- 突然JSONが完全なインデックスサポートを持つ通常のリレーショナルカラムのように動作する
■ 7. 実装手順4:フルスピードでのクエリ
- クエリが非常に高速になる
- いくつかの例でそれを試すことができる
■ 8. 後からの新しいクエリパターンへの対応
- このパターンの最も強力な点の1つであると考えられる
- 後日JSONの形状が変わった場合でも別のカラムを追加して別のインデックスを作成するだけでよい
- 例えばuser_idでクエリする必要があることに気づいた場合:
- ALTER TABLEで新しい仮想カラムを追加する
- CREATE INDEXでインデックスを作成する
- 既存の行に触れることなく最適化される
■ 9. このパターンが強力な理由
- このパターンはSQLiteでJSONを扱う方法についての考え方を完全に変えた
- スキーマレスデータの柔軟性とリレーショナルデータベースのパフォーマンスとエルゴノミクスを組み合わせることができる
- 早期にコミットしすぎたり自分自身を追い込んだりすることなくこれを実現できる
- これらの小さなSQLiteスーパーパワーは他にもたくさん隠れている
- これは共有したい最初のものにすぎない
Architecture Decision Records(ADRs)は、アーキテクチャ上の意思決定をドキュメントとして残す方法の1つです。Release It!の著者であるMichael Nygardのブログによって広まり、ThoughtWorks社の[Technology Rader https://www.thoughtworks.com/radar/techniques/lightweight-architecture-decision-records]でも「adopt」になっています。
■ 1. クラフトの定義と発生原因
- クラフトの起源:
- 技術的負債という言葉はしばしば手抜きなコードや読みにくいコードを指して使われる
- 本来の意味とは違うという指摘がよく入る
- ウォード・カニンガムの定義:
- 最初にリリースするコードは負債を抱えるようなもので少しの負債は開発を加速させるが迅速にリファクタリングで返済される必要がある
- 開発速度と将来のリファクタリングを引き換えにする行為を負債を負うことに例えた
- マーティン・ファウラーの定義:
- 負債を負う選択をした結果予測が外れると理想とは異なるコードができてしまいその後のメンテナンスに悪影響を及ぼす
- 内部品質の問題をクラフトと呼んだ
- クラフトの発生要因:
- 技術的負債以外のさまざまな要因でも発生する
- 明確な設計やコーディングルールが定まっていない状態で作られた不統一なコード
- コーディング規約やアーキテクチャの方針が曖昧なまま進められたプロジェクトでは各開発者の経験や好みで異なるアプローチが採用され全体の一貫性が失われがち
- 設計に問題があると認識していても解決方法が分からなかったり時間的制約から動作するから良いと判断して後回しにしたまま本番環境にデプロイされたコード
- ビジネス要件の急激な変化や予期せぬスケジュール短縮で十分な設計検討ができなかった場合
- クラフトの影響:
- 技術的負債に起因するかどうかに関係なく一度クラフトが生まれると解消されない限りメンテナンスコストを増加させ続ける
- コードの理解や修正にかかる時間の増加
- バグの発生率の上昇
- 新機能追加の難易度上昇
- この負のスパイラルは時間とともに加速し最終的にはシステム全体の健全性を脅かす
■ 2. クラフトの解消方法
- リファクタリングの必要性:
- ウォード・カニンガムもマーティン・ファウラーもクラフトを解消する最も有効な手段はリファクタリングであると指摘している
- クラフトは放置していても自然に消えることはない
- コードベースにおける変更コストの非線形的増大を通じて時間とともにシステム全体の開発速度を低下させる
- ファウラーが述べるように設計上の腐敗として現れ修正コストが逓増する前に手を打たなければ後のリファクタリングは指数的に困難になる
- XPの原則:
- リファクタリングは変更のための投資活動とみなされ機能開発と同列のタスクとしてスプリント内に組み込むことが推奨されている
- 重要なのはクラフトが顕在化した箇所を単に修正するのではなく体系的にリファクタリングを進めること
- クラフト解消のコスト:
- クラフトの解消には必ずコストがかかる
- 全てのクラフトを悪と捉えて躍起になって修正する必要はない
- リファクタリングに要する時間やテストの再実行やレビューといった工数は短期的には機能開発の速度を低下させる
- クラフトを残したままメンテナンスを続けると変更コストが継続的に増大し最終的には累積コストが解消コストを上回る
- この二つのコストを比較し解消の優先順位と実施タイミングを定めることが合理的なクラフト管理の出発点となる
■ 3. クラフトが溜まる理由
- スピード重視の問題:
- アジャイル開発やリーン開発では速く出すことが重視される
- 意思決定のサイクルを短くし顧客からのフィードバックを迅速に得ることで学習速度を高めるのが目的
- この学習速度と実装速度は混同されがち
- コードを速く書くことは学習を早めるための手段でありゴールではないはず
- 仮説としての実装:
- スピードを優先するチームは意思決定を仮説として捉えることがある
- 完全な理解を待たずに仮説として設計や実装を進める
- これは合理的な選択だがその仮説が外れたまま長期間放置されるとコードベースに局所的な歪みすなわちクラフトが生じてしまう
- 問題の本質はスピードそのものではなく仮説を検証した後に修正する時間を確保しないことにある
- 整えるフェーズの欠如:
- 多くのチームでは技術的負債を記録せず修正の優先順位を明示的に管理しないためクラフトが静かに堆積していく
- コードの整合性を取り戻す機会はスプリント外に追いやられ結果として速く出すことが修正できない構造を作り出す
- これが短期のスピードが長期の速度を奪う典型的なパターン
- クラフトが溜まるのは速度の問題ではなくサイクルの非対称性すなわち作るフェーズはあるが整えるフェーズが欠けていることによって生じる
- 負債返済計画の必要性:
- ウォード・カニンガムが述べたように負債は返済を前提とする限り健全なもの
- 問題は返済計画のない負債を繰り返し発生させることでありそれがクラフトの主要な供給源となる
- スピード重視の開発を持続可能にするにはどの負債をいつ返すかを明文化しリファクタリングを開発プロセスの一部としてスプリントに組み込む必要がある
- スピードと品質は対立しない
- 両者の調和は仮説としての実装と検証としてのリファクタリングを一つの循環とみなせるかどうかにかかっている
- 真にアジャイルなチームとは速く作るだけでなく速く修正できる構造を維持し続けるチーム
■ 4. 意思決定の記録の重要性
- ADRの必要性:
- 戻せる構造を制度的に支えるのが意思決定の記録
- どのような仮説のもとにどんな妥協を選択したのかどのリスクを受け入れどの技術的負債を意図的に残したのかを明文化しておく必要がある
- この記録がないまま時間が経過するとコード上の痕跡から意図を再構成することは困難になる
- 結果として後任の開発者はなぜそうなっているのかを理解できず同じ問題を再発させる
- クラフトの多くはこのように技術的選択の文脈が失われた状態から生じる
- クラフトの抑制にはリファクタリングだけでなく意思決定の透明性を保つ仕組みが不可欠
- ADRの構成要素:
- ADRは単なるドキュメントではなく現時点での最良の仮説を記録するメタ構造
- 決定の背景
- 選ばなかった代替案
- 想定している寿命
- 検証すべき条件
- これにより将来の開発者はこの判断はどのような前提でなされたかやどの時点で再評価すべきかを再現的に理解できる
- ADRの役割:
- ADRとは技術的負債を再構築可能な形で管理する装置
- 負債そのものを悪とみなすのではなくいつやどのように返済するかをチームが合意できるようにするための会計帳簿のようなもの
- これが存在すれば速く作ることは短絡的なスピードではなく可逆的な実験としてのスピードに変わる
- コードだけでなく意思決定の履歴までもがリファクタリング可能な構造になる
- クラフトを溜めないために必要なのはスピードを抑えることではなくむしろ速く動きながらも意思決定の痕跡を残す習慣を持つこと
- ADRはそのための最小限の形式であり継続的リファクタリングと並んで技術的負債を健全な仮説として管理するための基盤
■ 5. 技術的負債に伴うクラフトの4分類
- 分類の概要:
- 設計時点の予測と後になって判明した事実との乖離
- これこそが技術的負債に伴って発生しやすい問題だが大きく4つに分類できる
- 4つの分類:
- 混在: 異なる概念が同じ場所に置かれる
- 分散: 同じ概念が分割されて別々の場所に置かれる
- 冗長: 同じ概念が重複してあちらこちらに置かれる
- 欠落: 必要なのに実装されていない
■ 6. 混在の問題と対処法
- 混在の発生:
- 設計時には業務理解が足りず本来分離すべき概念を同じものとして扱ってしまうことがある
- ECサイトの有料会員プランの例:
- 会員プランには3つがありそれぞれ利用可能な機能が異なる
- フリープランは基本的な購入機能のみ
- スタンダードプランは送料無料と5%割引
- プレミアムプランは送料無料と10%割引と優先配送と限定セール参加
- 契約プランによって機能の利用可否を判定するとプランやその特典は会員獲得やリテンション向上を目的として頻繁に追加や変更される
- 問題点:
- プラン判定ロジックがControllerに直接書かれている場合プランが追加されたりプランで使える特典が変わったりするとこれがクラフトになる
- 判定のif文をあちこち修正しなければならない
- 契約プランで判定しているため契約なしで有料機能が使えるキャンペーンを実施する際もこのif文の修正が大変になってしまう
- 対処法:
- 契約プランと使える特典の制御を一体化して考えてしまっていることが原因
- 契約プランと適用される特典を切り離すことでプランを追加したり内容を変更したときの影響範囲を小さくできる
- 業務理解が浅い段階ではこうした判断は難くとりあえずリリースしてから考えようと技術的負債を選択しがち
- セールス都合での仕様変更は他の機能に比べて頻繁に発生する
- 変動性の異なるものは初めから切り離しておくことでクラフトを最小限に抑えられる
■ 7. 分散の問題と対処法
- 分散の発生:
- 分散のクラフトは技術的負債を選択しなくても発生する可能性がある
- 過剰なレイヤー定義などによって責務の不明確な処理が作られることがあるから
- よくあるケース:
- Web層とService層を分けているものの各レイヤーで扱うデータが変わらないまたは同じような型に詰め替えているだけというケース
- これでは再利用性はなく結局Web層とService層のコンポーネントは密結合してしまう
- ホテル予約の例:
- リクエストをもとに予約サービスを呼び出す
- 予約サービスはService層のコンポーネントなのでReservationRequestはそのまま使わず似たような構造のReservationDtoに詰め替える
- この2つの型はほぼ同じ構造を持っているがバリデーションアノテーションの有無だけが異なる
- Web層のReservationRequestにはバリデーションアノテーションがあるがService層のReservationDtoには存在しない
- 問題点:
- Web層でバリデーションを行っているため一見問題ないように思えるが予約サービスを他のエンドポイントや別のシステムから再利用する際に問題が発生する
- ReservationDtoが満たすべき条件が分からないから
- Web層とService層でレイヤーを分けるならServiceの呼び出し条件をReservationDtoの不変条件として表現しなければならない
- そうしなければServiceは特定のエンドポイント専用になってしまう
- 対処法:
- 予約に関するデータの処理の分散を避けるためには業務としてValidであることを保証する型を作るのが有効
- Reservationクラスはコンストラクタで全ての不変条件をチェックしインスタンスが生成された時点で業務として妥当な状態であることを保証する
- Web層ではReservationRequestからReservationを生成しService層ではReservationを受け取る
- コードに重複はあるがそれぞれが異なる関心事を表現している
- Web層のバリデーションはユーザー体験のためドメイン層の不変条件はビジネスルールの保護のため
- 実装の工夫によりコードの重複も避けることも可能
■ 8. 冗長の問題と対処法
- 冗長の性質:
- 冗長はDRY原則に違反するものであり技術的負債とは無関係にクラフトとして現れることがある
- ドメインへの理解が浅い段階でDRY原則にこだわり過ぎると誤った抽象化をしてしまう危険がある
- DRY原則の本質はコードの重複を避けよではなく知識の重複を避けよ
- 十分な知識がなければこの判断はできない
- Rule of Three:
- DRY原則を適用する前にはRule of Threeを意識する
- Three strikes and you refactorすなわち3回出るまで抽象化しない
- ホットスポットの存在:
- 初めから考えておいた方が良いものもある
- 多くのシステムには他の機能に比べて明らかに追加や変更が頻繁に発生するホットスポットが存在する
- モバイルオーダーのキャンペーン例:
- 初回注文20%OFFやオフピーク100円引きやアプリ決済5%OFFなどのキャンペーンを実施したい要求がある
- 今後どういうキャンペーンがあるかも分からないのでキャンペーンごとにバラバラに実装することは技術的負債を選択する観点からも理にかなっている
- 問題点:
- キャンペーンが増えるにつれて同じような割引計算ロジックがあちこちに散らばり保守性が低下していく
- 各割引は独立しているわけではなく適用順序や併用条件が存在するためキャンペーン間の関係性も管理しなければならない
- このような場合は早い段階でキャンペーンを抽象化する仕組みと割引の適用ルールを一元管理する設計を導入しておかないと後からの追加は難しくなってしまう
- 対処法:
- これは混在で述べたセールスの都合と通じるものがある
- キャンペーン機能は頻繁な変更が予想される領域であり早期に抽象概念を作っておく価値が高いホットスポット
- こういったホットスポットは同種のOSSプロダクトやSaaSプロダクトの設計を知っておくと勘所がつかめるようになる
- 今回のディスカウントの仕組みならShopifyのDiscount APIのような柔軟な割引設定が参考になる
- Shopifyでは割引の種類や適用条件や併用ルールなどを統一的なインターフェースで管理できる
- こうした既存の成功事例から学ぶことで将来クラフトになりそうな領域を見極め適切な抽象化のタイミングを判断できるようになる
■ 9. 欠落の問題と対処法
- 欠落の発生:
- 技術的負債を選択する際今は必要ないので作らないと判断するのは実は非常に難しい
- ファイルアップロード機能の例:
- Excelファイルをアップロードし内容をパースしてデータベース登録する
- 元のファイルも残しておきダウンロードできるようにする
- どこまで作り込む必要があるか
- 実装判断の例:
- 同期的にアップロードするか非同期にするか
- アップロード中のユーザーへの進捗表示をするか
- エラーレコードをユーザーにどう知らせるか
- ファイルサイズの上限をチェックするか
- アップロードファイルを一時ファイルに書き出す設計にするか
- アンチウイルスのチェックをするか
- これらのうち現時点でおそらく不要と判断して実装を省略したものが後になって実は必要だったと判明するケースが欠落に該当する
- 技術的負債として今は作らないと決めたつもりでも実際には作るべきだった機能が抜け落ちている
- 対処法:
- 非機能要求が明確に定義されていないと欠落として現れやすくなる
- 性能要件やセキュリティ要件や可用性要件などが曖昧なまま開発を進めると後になってこの規模のデータ量では処理が遅過ぎるやこのレベルのセキュリティ対策が必要だったといった問題が発覚する
- これはシステム運用継続のノックアウトファクターにもなりえる
- 開発するシステムのミッションクリティカル性にもよるが非機能要求に関わる実装は決して後回しにして良いものではない
- 非機能要求に関わる問題は後から対応しようとするとシステムアーキテクチャの根本的な見直しが必要になるケースが多いから
- 具体例:
- 同期処理で作られたファイルアップロード機能を後から非同期化しようとするとUI層からデータベース層まで広範囲な変更が必要になる
- セキュリティ対策が不十分なまま本番稼働してしまうと個人情報漏洩などの重大なインシデントにつながるリスクがある
- 技術的負債として後で対応するという選択は機能要求に対しては有効
- しかし非機能要求に対しては往々にして取り返しのつかない設計上の欠陥を生み出してしまう
■ 10. まとめ
- クラフトをゼロにすることの不可能性:
- 技術的負債に伴うクラフトの分類とその抑止可能性について見てきた
- 当然ながらクラフトをゼロにすることはできない
- 未来予測の活用:
- 技術的負債を選択する際の意思決定において未来予測を完全に捨てる必要はない
- むしろ過去の経験や類似システムの知見やチームの技術的強みやドメインの特性を考慮に入れることでより賢明な判断ができるはず
- キャンペーン機能のように頻繁な変更が予想される領域では早期の抽象化を一方で一時的な機能では最小限の実装を選択するといったメリハリのある意思決定が可能になる
- 持続可能なアプローチ:
- 完璧なコードベースを目指すのではなく技術的負債とクラフトの性質を理解し継続的な改善を通じてビジネス価値を提供し続けながらシステムの品質を維持していく
- それが現実的で持続可能なアプローチ
■ 1. マネジメントスキルの学びにくさ
- 多くの専門職ではロールモデル・スキルアップのロードマップ・キャリアが会社の仕組みとして整えられ社内の話題にもよく登る
- マネジメントを主たる業務にしている人にとってこの土台は薄く感じる
- 技術的な専門職の仕事は客観的な良し悪しで判断される
- 質の良い仕事とまずい仕事は自分も周囲も同じように認識できる
- 技術的な仕事は結果からの明確なフィードバックを得られやすい
- プログラミングなら間違っていればエラーが返ってくることによって間違いがはっきりする
- 人によって意見が分かれる高度な技術テーマであってもこれは人によって認識が異なるテーマであることは同意されやすい
- マネジメントは良し悪しで判断しにくい理由:
- マネージャー同士が働く機会が限られている
- マネージャーは少数者
- 未経験者からの評価という非対称性
- 好き嫌いや人間関係の相性
- マネジメントとリーダーシップの混同
- 多くの専門職は同じ専門職と働く機会があるがマネージャーはマネージャーと一緒に働く機会は多くない
- 同じ職能から学びにくいという働き方の性質がある
- 職能組織はあっても職位組織はなかなかない
- マネジメントそのものが理解される機会が限られマネジメントとして素晴らしい仕事/悪い仕事は何かという判断の質は育ちにくい
- マネージャーは組織構造上少数者で少数者というだけでも悩みは深くなる
- 現場のメンバーから評価される際はマネジメント未経験者から評価されるという非対称性がある
- 好き嫌いや人間関係の相性もマネジメントへの理解を難しくする
- 本来異なるスキルであるマネジメントとリーダーシップがマネージャーという一つの役職にまとめられていることもよくある
- ある人にとっては良いマネージャーと評価されても別の人にとっては悪いマネージャーと評価される
- マネージャー本人にとってもどのようにすればよりよいマネージャーになれるのか分からなくなる
■ 2. 1950年代の職場環境
- 戦後復興のさなか中学校や高校卒業したばかりの若い人達は金の卵と呼ばれ企業はこぞって採用
- 人口動態において若者が多く若手が果敢にチャレンジする機会があった
- がんばれば昇格できる時代
■ 3. 1980年代の状況
- 戦後復興を乗り越えて高度成長期の栄華を極めた1980年代では1950年代の人材がベテランとなり企業組織の中核を担う
- 企業の成熟と共に組織の人数に対してキャリアアップの受け入れ先となる課長や部長といった職位が足りなくなる
- ポスト詰まりが常態化
- 組織階層を増やしてもポストが足りなくなり当時の若い人達にとってキャリアを積み上げる難易度が高くなる
■ 4. 1990年代の変化
- 企業規模の拡大の停滞が始まりポスト詰まりは更に悪化
- 第二次ベビーブーム世代が就職するタイミングでバブル崩壊が重なる
- 就職を希望する若い人が多いにもかかわらず企業は人を受け入れることができない状況
- 多くの若い人が正規雇用に付くことが難しくなる
- 正規雇用を得たとしてもライバルが多く昇進を手にする人は一握り
- 企業間競争よりも組織内の出世競争が激しくなる
- 人事施策は育成から選抜へと変化:
- わざわざ育成するコストを掛けるのではなく過酷な状況でも勝手に自分で育つ人を引き上げる
- リーダー・マネージャーは損をするなのにやりきる責任感のある人を登用
- 台風でも出社するような人が忠誠心として認められ評価される
- 生存者バイアスが人事育成の方針になる
- 企業にとって労力のかかるキャリアの用意や育成を当事者に押しつけることによって低コストで実施
- 成果主義を導入した大企業の中には自分の評価を上げるために部下の育成よりもプレーヤーに徹したマネージャーも増加
- 若手の育成は自分のライバルを増やすことにもなりかねない
- 停滞は数年で終わること無く長く続くことによって人材育成の組織的な機構が空洞化
- 人材育成を負担に感じていた中堅企業や新興IT企業では顕著
- 当時20代で今の40〜50代にマネジメント育成を会社からしてもらった経験を聞けばその手薄さに驚く
■ 5. 2000年代のフラット化の悪影響
- バブル崩壊の影響は少なくなるが就職氷河期は続く
- 職位のヒエラルキーへの嫌悪が強くなり組織ヒエラルキーのフラット化が進む
- フラット化によって段階的な中間管理職(係長/課長代理/課長/部長代理/部長)やそこでの段階的な経験機会が失われる
- 戦略レベルの意志決定者と現場リーダーの二極化が進む
- 職位が減るものの評価グレードは残り続ける
- 組織はフラットだが昇格ポストはさらに狭くなり若者から見たポスト詰まりは悪化
- フラット化は多くの場合でポジティブのように語られる
- 新人にとって職位の3つ4つ先が突然社長という構造の有効性への疑問
- 風通しが良いと形容されるが本当に風通し良く話せているのか
- 職位の境界を担う中間職位に負担が押し込められているケースが多々ある
- 1980年代後半からマネジメントの経験機会の細さが長く続く
- 会社組織としてのマネジメント層育成の動機の欠如と現場にとってのマネジメントへの関心の薄さが常態化
■ 6. 2010年代後半から2020年代の転換
- 2010年代に入り若い人の就職状況において数十年ぶりに安定した売り手市場になる
- 働き方改革によって無理な働き方をさせることはしてはならないこととなる
- 高い職位からの厳しさや率直さの指摘はひとまとめに加害と被害の関係として解釈されやすくなる
- 部下への干渉はリスクと見なされるようになる
- 職場の人間関係の距離が遠くなるかと思えば分業化した個人主義的な働き方からチームとして頻度の高いコミュニケーションを通して仕事をするように変化
- プロダクト開発でも人材においても新しい働き方に合わせたマネジメントへの関心が高くなる
■ 7. 現在のマネージャーをとりまく混乱
- 2025年において依然として40-50代のマネジメントの知識・経験にはバラツキが大きい
- 多くの40-50代にとって自分のロールモデルはいないし教育投資も限られている
- 現在の40-50代のマネジメント層にとって自分のキャリアをふりかえるとまるでサバイバル
- それを若手に繰り返させることは許されない
- 20-30代の次世代のマネージャーにはマネジメントのあり方を示さなければならない
- 解消しなければならない状況:
- 技術と比べて標準的な学習の機会が乏しい
- 教育を受けたこともないのに教育を提供しなければならない
- 人格の評価と専門職としての評価が混同される
- 職能経験の非対称性から専門スキルとして評価されることが難しい
- なのにふるまいとして見本を見せなければならない
- 職能表に基づいてマネジメントスキルを伸ばそうと思っても実際には人格者としてのふるまいを期待されることが多い
- 高い言語化能力や情緒的な求心力まで求められている
- プレイングマネージャーはよくないことだと合意はありつつも実態としては包括的なリーダーシップが求められている
- 職能表に書かれるマネジメントばかりしていてはマネージャーとして失格と見なされる
- マネージャーなのに実態はリーダーと混ざっていたり様々な期待が足かかっている状況
- 自己犠牲は避ける時代になったはずなのに依然としてリーダー・マネージャーは損をする状況が続いているケースを多く見る
■ 8. マネジメントスキルの明確化と学習環境の整備
- ここ数年で状況は変わりつつある
- 学習可能な一般技術としてのマネジメントの萌芽は始まっている
- 環境整備の兆候:
- 現場経験の状況に寄り添ったマネジメントに関する書籍が増加
- 戦略的意志決定者と現場リーダーの間を埋める職位の定義や任命も進行
- 会社を超えて交流できるようなイベントも増加(Regional Scrum Gathering Tokyo・emconf・pmconf)
- マネージャーの横の繋がりというテーマで豊富に語られる活動が増加
- よりマネージャーという職能を学びやすく評価されやすくなる
- 一度プロダクトマネージャーになってから現場の職能に戻る人やエンジニアリングマネージャーを経験した後にエンジニアに戻る人もぽつぽつ増加
- メンバーからマネージャーへは一方通行なキャリアでは無く自分の仕事の幅を広げる通過点として双方向に開いているケースが増加
- 有識者の間で整理が進みつつある具体テーマ:
- マネジメントスキルの明確化(リーダーシップや人格との区別)
- 対象の明確化(プロダクトのためのマネジメント・メンバーのためのマネジメント・プロセスのためのマネジメント)
- 負荷とスキルの平準化(マネージャーとマネジメントの区別・マネージャーだからこそのマネジメント・メンバーも習得する共通スキルとしてのマネジメント)
- 習得方法(産業や業界として知見共有・組織における一般的な教育投資・職位同士のピアコーチングや相互メンタリング)
- 2026年はマネジメントにとってもマネージャーにとっても働きやすくなる年になる
■ 1. 問題の背景
- アプリケーション開発においてだいたい同じだが一部が異なるデータを管理する必要がある場合がある
- 具体例:
- サイト全体の設定を元にプロジェクトごとに一部だけ変更した設定ファイル
- 共通の契約書テンプレートデータを元に顧客ごとに特約を書き加えた契約書
- これらは元となるテンプレートデータとそれを活用しつつ改変されたインスタンスデータの関係にある
■ 2. 分析の2つの軸
- 連動性:
- テンプレートデータの変更をインスタンスデータにどこまで自動で追従させるかという軸
- 3つの段階がある:
- テンプレートの変更がすべてのインスタンスに即座に反映される場合
- まったく反映されない場合
- 一部だけ反映される場合
- データ効率:
- テンプレートと同じ内容のデータの重複をどれだけ避けているかという軸
- 効率が高い設計では同じデータを複数箇所に保存せず参照によって共有
- 効率が低い設計ではデータを複製するため重複が多くなる
■ 3. パターン1:マスター型
- 概要:
- インスタンスデータはマスターデータを直接参照して活用
- インスタンス側での改変は許容しない
- 変更はすべてマスターデータの修正や追加で実現
- 事例:
- 料金管理における標準料金プランマスタと地域別料金プランマスタ
- 地域別プランは基本的に標準プランを参照して使用
- 地域固有のプランが必要な場合は子マスタに新規追加
- 標準プランの価格改定などはすべての地域プランに自動反映
- 特徴:
- 連動性:マスターを更新すれば即座にすべてのインスタンスに反映される
- インスタンス側で変更したい場合もマスターデータに変更を加える必要がある
- データ効率:高い
- データは一箇所に集約され重複がない
- 使いどころ:
- インスタンスのデータがマスターデータと連動して変更されてよい場合
- インスタンスでの変更が少ない場合
- 不適切な場合:
- 計画と実行のようにインスタンスのデータを保存する必要がある場合
- インスタンス側でマスターデータと異なるデータを多数作る場合
■ 4. パターン2:テンプレート型
- 概要:
- インスタンスデータは明示的に管理されたテンプレートデータを完全に複製して作成
- 作成後はテンプレートデータとの関連性は一切なくなる
- 完全に独立したデータとして管理と改変が行われる
- 事例:
- 顧客ごとの契約書
- 共通の契約書テンプレートデータをコピーし顧客ごとに個別の契約書で契約を結ぶ
- テンプレートを変えても過去や現在結んだ契約に影響がない
- 顧客ごとに契約内容を調整しても問題ない
- 特徴:
- 連動性:コピー後はテンプレートデータとインスタンス側のデータの間に関係はない
- テンプレートデータが更新されても既存のインスタンスには一切影響しない
- インスタンス側はテンプレートの変更を気にせず自由に改変できる
- データ効率:低い
- コピーが増えるほど同じ内容のデータが重複する
- 使いどころ:
- テンプレートデータとインスタンスのデータが連動してはならない場合
- 計画と実行という構造で実行時の履歴としてその時のテンプレートデータを保持する必要がある場合
■ 5. パターン3:テンプレートなし型
- 概要:
- 明示的に管理されたテンプレートデータが存在しないパターン
- 2つの種類がある:
- 過去に作成した実例をコピーしてベースに新しいデータを作成するパターン
- 単純にテンプレートを管理していないパターン
- 事例1:過去の実例を引用して再利用するケース
- 業務報告における週報作成
- 毎週フォーマットや構成がほぼ同じ週報において最新の週報をコピー
- 日付や内容の一部だけを修正して今週分を作成
- 事例2:単純にテンプレートを管理していないケース
- 顧客管理における顧客データの新規作成
- 各顧客が独自の会社名や住所や担当者や取引条件を持ち共通部分がほとんどない
- テンプレートを作ってもほぼすべてのフィールドが個別に入力されるためテンプレート管理のコストに見合わない
- 特徴:
- 連動性:明示的に管理されたテンプレートデータが存在しないためテンプレートとの連動という概念自体がない
- データ効率:低い
- データをコピーして作成するため同じ内容のデータが重複する
- 使いどころ:
- テンプレートデータの管理をしたくない場合
- 過去の実例を引用して再利用するケース
- 運用をシンプルにしたい場合
- テンプレートデータを管理する必要性がない場合
■ 6. パターン4:差分管理型
- 概要:
- 未改変の部分はテンプレートデータを参照し連動性を保つ
- インスタンスに改変があった場合は改変された箇所だけをテンプレートからの差分データとして格納
- 事例:
- UI設定におけるユーザー別のダッシュボード設定
- システムデフォルトのダッシュボードレイアウトテンプレートを持つ
- ユーザーが一部のウィジェットのみ表示/非表示を変更する場合はその差分のみを保持
- 未変更のウィジェットはテンプレートの更新(新機能追加など)に追従
- 特徴:
- 連動性:未改変部分のみがテンプレートの更新に追従
- 未改変の部分はテンプレートの更新を自動で反映しつつ改変した部分は独立して管理できる
- 柔軟性と連動性を両立できる
- データ効率:高い
- 差分データのみを格納するため重複が少ない
- 使いどころ:
- テンプレートデータとインスタンス側のデータの差分が何かを正確に管理したい場合
- データ効率を重視するとき
- 注意点:
- システムの仕組みは煩雑なのでその実装難易度を許容する必要がある
■ 7. 4パターンのまとめ
- マスター型:
- 連動性:テンプレートの変更がすべてのインスタンスに即座に反映
- データ効率:高い
- 最適な選択基準:一貫性最優先で個別改変が基本的に不要な場合
- テンプレート型:
- 連動性:コピー後はテンプレートと無関係
- データ効率:低い
- 最適な選択基準:完全に独立した成果物が欲しい場合
- テンプレートなし型:
- 連動性:テンプレートが存在しないため無関係
- データ効率:低い
- 最適な選択基準:テンプレート管理の必要がなく実例コピーや独立したデータで十分な場合
- 差分管理型:
- 連動性:未改変部分のみテンプレートの更新に追従
- データ効率:高い
- 最適な選択基準:柔軟性とデータ効率の両立が必要な場合
■ 8. 考察
- OOPの継承と合成の関係に似ている点が興味深い
- テンプレートなし型の過去の実例を引用して再利用するケースに実務で出会ったことが記事執筆の経緯
- テンプレートデータ管理自体が本当に必要なデータではないという事実がある
- あくまで雛形が欲しいだけでありそのための管理にどこまで工数を投入するかは議論の余地がある
MoZuku は、MeCab・CaboCha を活用した日本語文章の解析・校正を行う LSP サーバーです。
特徴
- 形態素解析: MeCab による高精度な日本語トークン化
- 文法チェック: 二重助詞、助詞連続、動詞-助詞不整合の検出
- セマンティックハイライト: 品詞ごとの色分け表示
- コメント内解析: C/C++/Python/JavaScript/TypeScript/Rust のコメント内日本語を解析
- HTML/LaTeX サポート: ドキュメント本文も解析
- ホバー情報: 単語の原形、読み、品詞情報、Wikipedia のサマリーを表示
■ 1. CSV処理における課題
- 業務アプリケーション開発においてCSVインポート機能は避けて通れない
- 仕様が複雑になるにつれて以下の課題に直面する:
- バリデーションとパース処理が混在しエラーの発生箇所が追いづらい
- Shift_JISなど多様なエンコーディングへの対応でビジネスロジックが複雑になる
- パースやバリデーションエラーを即座にリターンするとユーザーは「モグラ叩き」のような修正サイクルを繰り返すことになる
- データが正しい状態か保証されないまま後続の処理に渡されてしまう
■ 2. Parse don't validateの考え方
- 「Parse don't validate」という考え方を参考にCSV処理のライブラリを実装した
- これは入力を単に検証して終わるのではなく型のあるデータ構造に変換することでその後の安全性を型システムで保証するという考え方である
- 処理を以下の3つのフェーズに分割した:
- Reader:エンコーディングの詳細を隠蔽
- Parser:CSV行→構造体への変換
- Validator:中間型→検証済みの型への昇格
■ 3. Reader層の実装
- 日本の業務システムではExcelから出力したCSVが頻繁に使われShift_JISやBOM付きの場合がある
- ビジネスロジックの段階ではエンコーディングの違いを意識せずに済むようにしたい
- 読み込み時にエンコーディングを自動判定・変換し常にUTF-8のReaderを返すように実装した
- エンコーディング処理の順序:
- BOM付きUTF-8のCSVファイルをサポート
- BOMなしUTF-8をサポート
- Shift_JISをUTF-8へ変換してサポート
- この層が腐敗防止層として機能することで後続の処理はファイルがどのような形式で保存されていたかを知る必要がなくなる
■ 4. Parser層の実装と中間型の定義
- 読み込んだ行をGoの構造体にマッピングする
- ここでは型変換とマッピングのみを行いビジネス的なバリデーションは行わない
- 中間型Parsed[T]の定義:
- ColumnCountStatus:カラム数の過不足状態を表す
- ParsedRecord[T]:1行ごとのパース結果
- Parsed[T]:パース処理全体の結果
- カラム数が合わないといった構造的な問題も即座にエラーにするのではなくステータスとして記録する
- これはエラーの集約を実現するためである
- パース段階で見つかった不備で即座にエラーを返すとユーザーは修正とアップロードを何度も繰り返すことになる
- Parserは起きたことの記録に徹し後続のValidatorで他の入力ミスと合わせてファイル内の全エラーをまとめて報告できるようにしてユーザー体験を損なわない設計としている
■ 5. Validator層の設計思想
- ライブラリには汎用的な検証フローだけを持たせ具体的なビジネスルールは外部から注入する形をとった
- 型定義:
- Valid[T]:バリデーション後の安全なデータ
- ValidateRecordFunc[T]:外部から注入するバリデーション関数の型定義
- Validate関数の処理フロー:
- ヘッダー構造の検証
- レコードごとの検証で注入された関数を実行
- エラーがなければ有効なレコードとしてリストに追加
- エラーがあればValid[T]は返さない
- 全て合格して初めてValid[T]を返す
- Parsed[T]からValid[T]への変換が成功すればデータは整合性が取れていることが保証される
■ 6. 利用例の実装
- このライブラリを使う側のコードは非常に宣言的になる
- 利用手順:
- 取り込みたいCSVの構造を定義する
- パースを実行して読み込みと構造化を行う
- バリデーションルールの定義でドメイン固有のロジックを記述する
- バリデーション実行でルールの注入を行う
- エラーがあれば何行目の何がおかしいかをまとめて返却できる
- 後続処理に来る時点でvalidDataは*Valid[UserCSV]型でありすべてデータがルールに適合していることが保証されている
■ 7. 設計のメリット
- CSV処理は外部からの入力を扱うため複雑になりがちだが責務を分けることでメンテナビリティを向上させることができた
- Reader層の利点:
- エンコーディングの詳細を隠蔽し腐敗防止層として機能
- Parser層の利点:
- CSV行を中間型へ変換しエラーは即時リターンせず状態として記録してUX向上に貢献
- Validator層の利点:
- 中間型を検証済みの型へ昇格し汎用的な検証フローを提供して具体的なルールは外部から注入する
- バリデーションロジックを関数として注入する設計にしたことでライブラリ自体を変更することなく様々なCSVに柔軟に対応できる構成となった
■ 1. 航空宇宙ソフトウェアの歴史的背景
- 1996年6月4日、Ariane 5ロケットが打ち上げ36秒後に爆発した。原因は64ビット浮動小数点数を16ビット整数に変換する際の未処理例外であり、5億ドルが一瞬で失われた。
- F-35の設計者はこの教訓から、JSF C++標準のAVルール208で「例外を使用してはならない」と規定した。
- 1970年代初期、F-4 Phantomには実質的にソフトウェアが存在せず、爆撃コンピュータは歯車とカムの箱であった。
- F-14 Tomcatプロジェクトで、Garrett AI Researchが世界初のマイクロプロセッサを開発した。これはIntel 4004より数年早く、かつ高速であったが、1998年まで機密扱いであった。
- F-14の可変翼設計には手動操縦では対応できず、約2500行のマイクロコードで多項式方程式を処理した。これが航空機における最初の本格的なソフトウェアとなった。
■ 2. 軍用ソフトウェアの言語戦争
- 初期のソフトウェア時代、米陸軍、空軍、海軍はそれぞれ異なるコーディング標準を持っていた。
- 空軍はJovial(Jules's Own Version of the International Algorithmic Language)を使用していた。
- 海軍はF-18でCMS2という独自言語を採用し、互換性は皆無であった。
- 機上ソフトウェアの量は指数関数的に増加した:
- F-16Aで12万5000行
- B-1で100万行
- F-35で900万行
- 当時450以上の異なるプログラミング言語が使用されており、適切な標準が存在しなかった。
- 国防総省は全ての言語を置き換える高級言語としてAdaを開発した。
- Adaの使用は約15年間義務付けられ、使用しない場合は不可能であることを証明する必要があった。
■ 3. C++への移行とJSF標準の誕生
- 1990年代、航空宇宙分野ではAdaが主流であったが、同時期にインターネット、Windows 95が登場し、多くのゲームがC++で動作していた。
- 当時、コンパイラは有料で数千ドルもしたが、C++とGCCは無料であり、学生はC++を学習した。
- Lockheed MartinはF-35プロジェクトでAdaの代わりにC++の使用を国防総省に提案した。
- 提案者は「法律を破ることを承認してください」という内容を提示したことになる。
- Lockheed Martinは純粋なC++ではなく、言語を制限する計画を用意していた。
- C++の作成者Bjarne Stroustrup自身がJSF規則の策定に関与したことを認めている。
- JSF標準は特定の機能を外科的に除去することで、強力な言語を認証可能なコードに変換する。
- JSF標準は完全に公開されており、オンラインで閲覧可能である。
- Joint Strike Fighterという名称は、Lockheed Martinだけでなく、多数の防衛企業、政府、複数の国が協力して開発したことを示している。
■ 4. JSF C++標準の主要な制約事項
- 例外処理の禁止(AVルール208):
- 例外は予測不可能な制御フローを生成する
- Ariane 5の事故は値のオーバーフローではなく、未処理例外が問題であった
- Bjarne Stroustrup自身は現代のC++例外処理を支持しているが、当時のツールの成熟度では応答時間を保証できなかった
- JSF標準では例外の代わりにリターンコードを使用する
- リターンコードは呼び出し元関数に処理を委ねる
- 再帰の禁止(AVルール119):
- 関数は直接的または間接的に自身を呼び出してはならない
- 再帰はスタックオーバーフローの可能性を生む
- 各再帰呼び出しは新しいスタックフレームを作成する
- 再帰の最大深度が不明な場合、メモリ使用量の上限を知ることができない
- 反復的アプローチで置き換える必要がある
- メモリ割り当ての制限(AVルール206):
- 初期化後のメモリ割り当てと解放を禁止する
- 動的メモリ割り当てはコードに予測不可能性をもたらす
- メモリマネージャーが利用可能なメモリを見つけるのにかかる時間が不明である
- 十分なメモリが利用可能かどうかも不明である
- ヒープ上の割り当てはフラグメンテーションを引き起こす
- 解決策として最大データサイズをハードコードし、事前割り当てを行う
- 循環的複雑度の制限(AVルール3):
- 関数の循環的複雑度は20を超えてはならない
- 循環的複雑度は関数内の決定パスの数を示す
- if文、whileループ、forループ、論理演算子(andやor)、switch文などがカウントされる
■ 5. 実装例とシミュレーション
- XPlane 12フライトシミュレータとF-35Bを使用したデモンストレーションが実施された。
- マルチファンクションディスプレイ(MFD)がF-16スタイルで構築され、リアルタイムの飛行データに接続された。
- XPlaneのWeb APIを通じてライブ飛行データが配信される。
- フロントエンドはPython、バックエンドはC++で実装された。
- JSF標準に準拠したC++コードで密度高度計算、飛行データ、旋回計算、V-NAVデータ、風計算などが実行される。
- 非準拠コードでは未処理例外が発生し、プログラムがクラッシュするシナリオが示された。
- 準拠コードではリターンコードを使用し、呼び出し元関数がエラーを適切に処理する。
- 初期のF-35はMotorola G4 Power PCプロセッサベースのミッションコンピュータを使用していた。これは2003年のAviation Todayの記事で公開された情報である。
■ 6. JSF標準の影響と現代への継承
- F-35 C++標準の原則は他の分野や標準にも広がった。
- NASAのF-Prime標準は2017年に公開され、メモリ割り当て禁止、例外処理禁止、再帰禁止という同様の制約を持つ。
- 自動車業界にもコーディング標準が存在する:
- MISRAとAutoSAR(Automotive Open System Architecture)
- AutoSARはC++14標準の影響の一つとしてJSFを名指しで参照している
- AutoSARではスマートポインタが許可されるなど、より現代的なC++の機能が利用可能である
- 自動車は車輪付きコンピュータと言える存在になっている。
- BMW、Ford、Toyotaなど主要な自動車メーカー全てがAutoSARに依存している。
- これらの言語安全性は数十年前に国防総省が下した決定に基づいている。
■ 7. 結論と提言
- Bjarne Stroustrup自身、JSF標準の策定委員会の一員であったが、現在はC++ Core Guidelinesの使用を推奨している。
- 現代のC++は過去20年間で進化し続けており、JSF標準は当時の素晴らしいエンジニアリング成果であったが、より新しく安全な現代的C++を使用すべきである。
- JSF標準は歴史的に重要かつ興味深い部分であり、一見の価値がある。
- JSF標準はC++のような複雑な言語を、重要なインフラストラクチャに安全な予測可能なものに変換することに成功した。
- 最も賢いプログラマーであることが重要なのではなく、どの要素を「飛行前に取り除く」かを知る規律を持つことが重要である。
アメリカ空軍や航空自衛隊が運用する戦闘機「F-35」はC++でコーディングされたソフトウェアを搭載しています。このC++コードは「Joint Strike Fighter Air Vehicle C++ Coding Standards(JSF AV C++)」と呼ばれるコーディング規則に沿って記されているとのことで、Googleの研究者で航空機関連プログラミングにも詳しいLaurieWired(Laurie Kirk)氏がJSF AV C++の特長を解説しています。
F-35よりも前に開発された戦闘機にはアメリカ国務省が開発を主導した「Ada」というプログラミング言語が採用されていました。しかし、F-35の開発当時はすでにAdaが陳腐化しており、代わりにC++を採用することとなりました。C++を採用しつつアリアン5型ロケットのような失敗を防ぐために策定されたコーディング規格がJSF AV C++というわけです。
Dewyは各ホストに常駐し、CIによって作られたアプリケーションやデータ、コンテナを、ホスト上のプロセスとして常に最新となるようにします。いわゆる継続的なデプロイメントを可能にします。継続的なデプロイメントは、Kubernetesを使っているとエコシステムであるArgo CDのようなGitOps ソフトウェアによって、当然のこととして実現できますが、Kubernetesが使えない環境だと既存のデプロイツールで頑張るしかありません。ひょっとすると、SSHで手動デプロイだったり、SCPやSFTPを使った趣のあるshellの実行になるかもしれません。あまり考えたくないですね…
■ 1. はじめに
- 最近「仕事に適した道具」を使うのではなく仕事にある道具を使っていることに気づいた
- そのことが自分が知っているプログラミング言語をほぼ決定していた
- 過去数ヶ月間仕事で使わない言語を実験することに多くの時間を費やした
- 目標は習熟度ではなく各言語が何に適しているかについて意見を形成することに興味がある
- プログラミング言語は非常に多くの軸に沿って異なるため比較するのが難しい
- トレードオフがあるという明らかに真実だが完全に退屈で役に立たない結論にデフォルトでたどり着いてしまう
- もちろんトレードオフはある
- 重要な問いはなぜこの言語はこの特定のトレードオフのセットにコミットしたのかである
■ 2. 言語選択の視点
- この問いは興味深い
- 加湿器を買うかのように機能のリストに基づいて言語を選びたくない
- ソフトウェアを構築することと自分のツールを気にかけている
- 言語はトレードオフを行う際に一連の価値観を表現する
- どの価値観が自分に共鳴するかを見つけたい
- この問いは結局のところ機能セットが大幅に重複する言語間の違いを明確にするのにも役立つ
- 「Go vs. Rust」や「Rust vs. Zig」についてのオンライン質問の数が信頼できる指標であれば人々は混乱している
- 言語Xは機能a、b、cを持っているのでWebサービスを書くのに優れているが言語Yは機能aとbしか持っていないということを覚えるのは難しい
- 言語Xは言語Yがインターネットを嫌いインターネット全体のプラグを抜くべきだと信じている人によって設計されたためWebサービスを書くのに優れていると覚える方が簡単だと思う
■ 3. 本文の目的
- 最近実験した3つの言語についての印象を収集した
- Go、Rust、Zigである
- 各言語での経験をその言語が何を重視しそれらの価値をどれだけうまく実行するかについての包括的な評決に統合しようと試みた
- これは還元的かもしれないが還元的な偏見のセットを結晶化することがここでやろうとしていることである
■ 4. Goの特徴
- Goはミニマリズムによって特徴づけられる
- 「現代のC」と表現されている
- GoはCのようではないがガベージコレクションされ実際のランタイムを持っている
- 言語全体を頭の中に収めることができるという点でCに似ている
- 言語全体を頭の中に収めることができるのはGoが非常に少ない機能しか持っていないからである
- 長い間Goはジェネリクスを持っていないことで悪名高かった
- これは最終的にGo 1.18で変更されたがそれは12年間人々がジェネリクスを言語に追加するよう懇願した後のことであった
- タグ付きユニオンやエラー処理の糖衣構文など現代の言語で一般的な他の機能はGoに追加されていない
- Go開発チームは言語に機能を追加するためのハードルが高いようである
- 最終結果は別の言語でより簡潔に表現できるロジックを実装するために多くのボイラープレートコードを書くことを強いられる言語である
- しかし結果は時間の経過とともに安定しており読みやすい言語でもある
■ 5. Goのスライス型の例
- Goのミニマリズムの別の例としてGoのスライス型を考える
- RustとZigの両方にスライス型があるがこれらはファットポインタでありファットポインタのみである
- Goではスライスはメモリ内の連続したシーケンスへのファットポインタであるがスライスは成長することもできる
- つまりRustのVec
型とZigのArrayListの機能を包含している - またGoはメモリを管理してくれるためGoはスライスのバッキングメモリがスタックとヒープのどちらに存在するかを決定する
- RustやZigではメモリがどこに存在するかについてはるかに真剣に考える必要がある
■ 6. Goの起源と目的
- Goの起源神話は基本的に次のようなものである
- Rob PikeはC++プロジェクトのコンパイルを待つことにうんざりしていた
- GoogleのC++プロジェクトで他のプログラマーがミスを犯すことにもうんざりしていた
- したがってGoはC++がバロック的であるところでシンプルである
- それはプログラミングの一般階級のための言語である
- 90%のユースケースに十分であると同時に理解しやすいように設計されている
- 特に並行コードを書く際にそうである
- 仕事でGoを使っていないが使うべきだと思う
- Goは企業のコラボレーションに奉仕するためにミニマルである
- これを軽蔑として意味しているわけではない
- 企業環境でソフトウェアを構築することには独自の課題がありGoはそれを解決する
■ 7. Rustの特徴
- Goがミニマリストであるのに対しRustはマキシマリストである
- Rustに関連付けられることが多いタグラインは「ゼロコスト抽象化」である
- これを「ゼロコスト抽象化、そしてたくさんの抽象化!」と修正したい
- Rustは学習が難しいという評判がある
- Rustを難しくしているのはライフタイムではなく言語に詰め込まれた概念の数であるというJamie Brandonの意見に同意する
- 特定のGithubコメントを取り上げるのは最初の人ではないがそれはRustの概念密度を完璧に示している
- もちろんRustはGoがミニマリストであろうとするのと同じ方法でマキシマリストであろうとしているわけではない
- Rustが複雑な言語であるのはそれが達成しようとしていることが安全性とパフォーマンスという幾分緊張関係にある2つの目標を実現することだからである
■ 8. Rustの安全性とパフォーマンス
- パフォーマンス目標は自明である
- 「安全性」が何を意味するかはそれほど明確ではない
- 少なくとも自分にとってはそうだったがおそらく長い間Pythonに慣れすぎていたのかもしれない
- 「安全性」は「メモリ安全性」を意味する
- 無効なポインタを逆参照したりダブルフリーを行ったりできないようにするという考えである
- しかしそれはそれ以上のことを意味する
- 「安全な」プログラムはすべての未定義動作(UBと呼ばれることもある)を回避する
- 恐ろしいUBとは何か
- それを理解する最良の方法は実行中のプログラムには死よりも悪い運命があることを覚えておくことだと思う
- プログラムで何か問題が発生した場合即座の終了は実際には素晴らしい
- なぜならエラーがキャッチされない場合の代替案はプログラムが予測不可能性の薄明の領域に入り込むことだからである
- そこでは次のデータ競合に勝つスレッドや特定のメモリアドレスにたまたまあるガベージによって動作が決定されるかもしれない
- 今やハイゼンバグとセキュリティ脆弱性がある
- 非常に悪い
■ 9. Rustのコンパイル時チェック
- Rustはコンパイル時にチェックすることによって実行時のパフォーマンスペナルティを支払うことなくUBを防ごうとする
- Rustコンパイラは賢いが全知ではない
- コンパイラがコードをチェックできるようにするにはコードが実行時に何をするかを理解する必要がある
- したがってRustには表現力豊かな型システムと特性のメナジェリーがあり別の言語では単に明白な実行時の動作であるものをコンパイラに表現できる
- これによりRustは難しくなる
- なぜならただ物事を行うことができないからである
- Rustがその物事に対して持っている名前を見つけ出す必要がある
- 必要な特性などを見つけてRustが期待するように実装する必要がある
- しかしこれを行えばRustは他の言語ができないコードの動作について保証を行うことができる
- これはアプリケーションによっては重要かもしれない
- また他の人のコードについても保証を行うことができるためRustではライブラリを消費することが簡単になる
- これがRustプロジェクトがJavaScriptエコシステムのプロジェクトとほぼ同じくらい多くの依存関係を持つ理由を説明している
■ 10. Zigの特徴
- 3つの言語のうちZigは最も新しく最も成熟していない
- この執筆時点でZigはバージョン0.14にすぎない
- その標準ライブラリにはほとんどドキュメントがない
- それを使用する方法を学ぶ最良の方法はソースコードを直接参照することである
- これが真実かどうかはわからないがZigをGoとRustの両方への反応として考えたい
- Goはコンピュータが実際にどのように機能するかについての詳細を曖昧にするためシンプルである
- Rustはその多くのフープをくぐらせることを強制するため安全である
- Zigはあなたを自由にする
- Zigではあなたが宇宙を制御し誰もあなたに何をすべきか言うことはできない
■ 11. Zigのメモリ管理
- GoとRustの両方でヒープ上にオブジェクトを割り当てることは関数から構造体へのポインタを返すのと同じくらい簡単である
- 割り当ては暗黙的である
- Zigでは自分で明示的にすべてのバイトを割り当てる
- Zigは手動メモリ管理を持つ
- Cよりもさらに多くの制御がある
- バイトを割り当てるには特定の種類のアロケータでalloc()を呼び出す必要がある
- つまりユースケースに最適なアロケータ実装を決定する必要がある
- Rustでは可変グローバル変数を作成することが非常に難しくそれを行う方法についての長いフォーラムディスカッションがある
- Zigでは問題なく作成できる
■ 12. Zigの不正動作の扱い
- 未定義動作はZigでも依然として重要である
- Zigはそれを「不正動作」と呼ぶ
- 実行時にそれを検出し発生時にプログラムをクラッシュさせようとする
- これらのチェックのパフォーマンスコストを心配する人のためにZigはプログラムをビルドする際に選択できる4つの異なる「リリースモード」を提供する
- これらのいくつかではチェックが無効になっている
- アイデアはチェックされたリリースモードでプログラムを十分な回数実行してチェックされていないビルドで不正動作がないことについて合理的な確信を持つことができるようにすることのようである
- これは非常に実用的な設計のように思える
■ 13. Zigとオブジェクト指向プログラミング
- ZigとGoとRustの別の違いはZigのオブジェクト指向プログラミングとの関係である
- OOPはしばらくの間不人気でありGoとRustの両方がクラス継承を避けている
- しかしGoとRustは他のオブジェクト指向プログラミングイディオムに対して十分なサポートを持っているため望むならプログラムを相互作用するオブジェクトのグラフとして構築することができる
- Zigにはメソッドがあるがプライベート構造体フィールドや実行時ポリモーフィズム(動的ディスパッチとも呼ばれる)を実装する言語機能はない
- std.mem.Allocatorはインターフェースになりたがっているにもかかわらずである
- 私が知る限りこれらの除外は意図的である
- Zigはデータ指向設計のための言語である
■ 14. Zigの手動メモリ管理の意義
- 2025年に手動メモリ管理を使用してプログラミング言語を構築することは狂気に思えるかもしれない
- 特にRustがガベージコレクションさえ必要とせずコンパイラにそれを行わせることができることを示した時には
- しかしこれはOOP機能を除外する選択と非常に関連した設計選択である
- GoやRustやその他の多くの言語ではオブジェクトグラフ内の各オブジェクトに対して一度に少しずつメモリを割り当てる傾向がある
- プログラムには何千もの小さな隠されたmalloc()とfree()がありしたがって何千もの異なるライフタイムがある
- これがRAIIである
- Zigでは手動メモリ管理が多くの面倒でエラーが発生しやすい簿記を必要とするように思えるかもしれないがそれはすべての小さなオブジェクトにメモリ割り当てを結びつけることにこだわる場合のみである
- 代わりにプログラム内の特定の賢明なポイント(イベントループの各反復の開始時など)で大きなメモリのチャンクを割り当てて解放し操作する必要があるデータを保持するためにそのメモリを使用することもできる
- Zigが奨励しているのはこのアプローチである
■ 15. ZigとRustの違い
- 多くの人々がRustが既に存在するのになぜZigが存在すべきなのかについて混乱しているようである
- Zigがよりシンプルであろうとしているだけではない
- この違いがより重要なものだと思う
- Zigはコードからさらにオブジェクト指向的な思考を切除することを望んでいる
- Zigには楽しく破壊的な雰囲気がある
- それは(オブジェクトの)企業のクラス階層を打ち砕くための言語である
- それは誇大妄想狂とアナーキストのための言語である
- 好きである
- すぐに安定版リリースに到達することを望むがZigチームの現在の優先事項はすべての依存関係を書き直すことのようである
- Zig 1.0を見る前にLinuxカーネルを書き直そうとすることは不可能ではない
■ 1. NotebookLMの進化と便利さ
- NotebookLMが驚くほど進化した
- 雑に書いたメモを投げるだけで驚くほど綺麗なスライドが返ってくる
- デザインも構成も洗練されていて「これでいいじゃん」と思わせる仕上がりになる
- その便利さの裏側で大事なことを見落としつつある
- 文章を書くこと、文章を読むことの本来の難しさを見落としている
■ 2. 文章の本質
- 文章は単語・文・構造のレイヤーが連動しながら書き手の思考と意図を運ぶ媒体である
- 文章は単なる情報の入れ物ではなく思考そのものの外在化である
- 読み手はその外に出された思考を自分の中で正確に再構築することではじめて理解に到達する
- 読むことも書くことも思っている以上に高度な営みである
- 文章は書き手の頭の中にある思考モデルを言葉という形式に変換し、それを読み手が再構築することで意味が成立する
- このプロセスは一方向の伝達ではなくある種の共同作業に近い
- 書き手は自分の思考を「構造→文→単語」という順で形にする
- 読み手はその逆方向から「単語→文→構造」へと読み解きながら思考を復元していく
- この同期作業がうまくいったとき文章ははじめて役割を果たす
■ 3. 読むという行為の複雑さ
- 読む行為は思っているよりはるかに複雑である
- 脳はまず単語を処理し、次に文法構造を組み立て、最後に文章全体の構造を理解する
- これはボトムアップの処理である
- 読み慣れている人ほど文章の冒頭から「これはこういう話なのではないか」と構造を仮置きする
- その予測に照らして文や単語を読み直すトップダウンの処理も同時に走っている
- この二つが往復することで読み手は意味を確定させていく
■ 4. 読むことの各レベル
- 単語レベル:
- 読むとは書き手の単語選択の意図を拾いにいくことである
- そこに書かれている単語がなぜその単語なのかを探る
- 似た単語ではなくちょうどその一語が選ばれている理由を探りにいく意識を持つことが求められる
- 語の温度差やニュアンスの微妙な違いを拾おうとしない読みは意図の半分を取りこぼす
- 単語を捉えることはその細部に踏み込む行為である
- 文レベル:
- 読むとは文の骨格を正しく組み立てることでもある
- 主語はどれか、述語は何にかかっているか、修飾語はどの範囲を指しているのかを問いかける
- こうした構文的な問いかけを怠ったまま読み進めても文章は理解できない
- 構文を読み解くことは読解の必須プロセスである
- 構造レベル:
- 読むとは段落や見出しがつくる全体の構造を把握することである
- どの話題が主軸でどこが補助なのかを理解する
- 論点はどう展開され何に向かって進んでいるのかを把握する
- 文章は構造がわかってはじめて意味が正しく伝わる
- 構造を読まずに文だけ追っていても部分の寄せ集めにしかならない
- 読むとは書き手の思考の構造を読み手側で再構成することである
■ 5. 書くことの難しさ
- 書くとは読み手が上記のプロセスを誤らずにたどれるよう言葉の配置や情報の順序を設計することである
- 単語レベル:
- 語彙の選択は思考の解像度をそのまま反映する
- 同じように見える二つの語でも距離感やニュアンスがまったく違う
- 書ける人はここにかなりの意識を払っている
- 文レベル:
- 文の流れをどうつくるかが重要である
- 主語と述語の関係、文同士の接続、文長とリズムを考慮する
- 箇条書きは便利だが断片の羅列になった瞬間、文章ではなくその場にいた人だけがわかるメモになってしまう
■ 6. 箇条書きの問題点
- 問題1:分類の軸が途中で変わっている
- 会社という軸で並んでいるのに途中から突然今後(時系列)に切り替わっている
- 軸が変わると読み手は何を基準に並んでいるのかを見失う
- これに気づかないまま箇条書きを続けると読み手の頭の中では構造が崩れ始める
- 問題2:同じ階層に抽象度の違う情報が混じっている
- タスク、状態、イベントという種類の違う情報が同じレベルで並んでいる
- 読み手の脳は同じ階層=同じ種類のものが並んでいると期待して処理する
- タスク・状態・イベントが混ざると構造が曖昧になり意味のまとまりが生まれない
- 問題3:ネスト(階層)が深くなるほど文脈の種類が混ざる
- 意思決定項目とサブタスクが同じ階層に混在する
- 階層を深くすればするほど文脈の種類を統一しないと読み手の負荷は急増する
- 問題4:因果も優先順序も見えない
- なぜ見積を再提示するのか、稟議待ちとどうつながるのか、ミーティングは何を決める場なのかといった意味の関係が抜け落ちている
- 読み手は断片から因果関係を補完しなければいけない
- これは文章ではなくその場にいた人だけが理解できるログになっている
- 書き手が省略した思考コストを読み手が肩代わりしているだけである
- 人に正しく伝えるためにはログを文章に変える必要がある
■ 7. 構造レベルの書き方
- 構造とは読み手にどの順番で理解してもらうかを設計する仕事である
- 結論、背景、根拠をどう配置するのかを考える
- どこで区切りどこで流れを転換させるのかを決める
- 構造は読み手の認知負荷を左右する
- 書ける人ほどここが驚くほど丁寧である
■ 8. AI時代の危険性
- NotebookLMのようなツールは多少雑なメモを渡してもそれなりに整ったスライドや要約に仕上げてくれる
- 構成もデザインも綺麗で読めばなんとなく理解した気になってしまう
- その便利さには一つ厄介な側面がある
- 中身がとんちんかんでもAIが構造的に美しい形に整えてしまうという点である
- 人間は外形が整っているものに対して「これは正しいのだろう」と無意識に信頼を寄せる
- 思考が雑であってもそれっぽく再構成されると破綻に気づきにくくなる
- AIの構造化が良すぎるせいで人間の側の思考の粗さが見えなくなる
- さらに厄介なのはAIが整えたアウトプットを見て「そうそう、これが自分が言いたかったことだ」と感じてしまう現象である
- よく考えてみると自分の中にそんな整理された思考はもともと存在していなかったりする
- 綺麗な構造のほうに自分の思考を後付けで寄せてしまう
- この錯覚が積み重なると本来必要だったはずの深く考えるプロセスが徐々に失われる
- AIは文章を整えてくれるが思考そのものの破綻には気づかないし直してもくれない
- 整っているように見えるという理由だけでその破綻を見逃してしまう
- AI時代の危険とは文章が壊れていくことではなく思考が壊れていくことに気づけなくなることである
■ 9. 書ける人がAI時代に強くなる理由
- 書ける人はそもそも自分の思考を構造として組み立てられる
- その構造がしっかりしていればAIに投げたときに要点がズレることはない
- むしろAIはその構造をそのまま増幅しより見やすくより伝わりやすい形に整えてくれる
- 逆に思考の構造が曖昧なまま書いた文章をAIに渡しても出てくるアウトプットは曖昧なままである
- これはAIの性能の問題ではなく入力となる思考の精度の問題である
- AIは製造機ではなくて増幅器である
- 粗い入力は粗いまま、精密な入力はより精密なかたちで返ってくる
■ 10. 形式変換の容易さ
- 書ける人は文章を書いた後にこれをどんな形で伝えるのが一番いいかを自然に考える
- 文章で伝えるべきか、図解にすべきか、スライドが合うのかを考える
- 今まではその形式変換にそれなりの時間がかかっていた
- AIがここを代わりに担ってくれる
- 文章さえしっかり書いておけば読み手の特性に合わせた形をほぼゼロコストで作れるようになる
- 書ける人は書いた瞬間にあらゆる読み手へ同時に届けられる人になる
- 形式変換という作業はAIに任せられるようになった
- 今の時代に問われるのは何をどう構造化して書いたかという根本の部分である
- 書ける人はAIと組んだ瞬間に生産性も影響力も跳ね上がる
- 書けない人はAIに任せてもズレ続ける
- この差はこれからどんどん広がっていく
■ 11. 読む・書く・考えるの三位一体
- リクルートワークス研究所が出しているWorks誌のNo.163ではこれら三つの行為は分離できないと指摘している
- 読むには書き手の意図を推測し自分の中で意味づける思考が必要になる
- 書くとはその思考を構造化して外に出すことである
- 一度外に出した文章を読み直すことでまた考えが深まり書き直したくなる
- 読む→考える→書く→読むという循環を回すことでしか思考は洗練されていかない
- 読む力が弱ければ書けないし書けなければ考えが浅くなる
- 考えが浅いままでは他人の文章も深く読めない
- 三つが相互に支え合っているからこそ切り離せない
■ 12. AI時代における能力の差
- AIは文章を整えてくれるが思考そのものを鍛えてはくれない
- AIを使いこなすには読む・書く・考えるという循環が前提になる
- 読む力は理解の質を決め、書く力は思考の質を決め、そして両方を支えるのが考える力である
- AIが文章をきれいに整えてしまう時代だからこそ人間は文章を創る能力で差がつく
- 書ける人はAIと組んだ瞬間に影響力が跳ね上がる
- 書けない人はAIに任せてもズレ続ける
- 他人の文章をAIで要約・スライド化していても仕事は進捗するが自分の能力は伸びない
- 読む・書く・考えるという三位一体の言語能力を備えていることがAI時代にこそより強く求められる
■ 1. 前置きと問題意識
- 著者の会社はFindy Team+ Award 2024, 2025を2年連続で受賞した高い開発生産性を持つ
- 技術的な側面として「DRYとの向き合い方(境界設計)」が開発生産性に強く作用していた
- 早期のプロダクト開発では「まずはスピードを最優先」という判断がしばしば下される
- 短期効率だけを信じて場当たり的な共通化、とりわけ「誤ったDRY」を積み重ねると、ほんの1ヶ月後にはその短期効率こそが最大の足かせになって返ってくる
- 初速を上げたつもりが境界が溶けたコードベースのメンテに追われ、「本当にやりたい開発」に時間を使えなくなっていく
- 開発効率は時間とともに自然減衰するものだが、誤った共通化はその減衰曲線を自ら急角度に傾ける
- Google社も2024年に「Don't DRY your code prematurely」という記事を公開し話題を呼んだ
- アーキテクチャカンファレンス2025でも「変更容易性(Modifiability)」こそが持続可能な開発の最重要資産であると多くの登壇者が語った
- AI時代だからこそ「Adaptable AI(AIの変化に適応し続ける設計)」が必要である
■ 2. DRYとOAOOの違い
- OAOO原則(Once and Only Once):
- 同じロジックやデータ操作をプログラム中で2回以上定義しないことを目指す考え方
- 主に「コードの重複」を対象とする
- DRY原則(Don't Repeat Yourself):
- 「同じ知識・ビジネスルールが複数箇所にバラバラに埋め込まれている状態」を避け、単一の表現に集約する考え方
- 主に「知識の重複」を対象とする
- DRYは単なる「コピペ排除」ではない:
- 同じコードでも、背負っている「意味」や「前提」が違うなら、必ずしもDRYの対象とは言えない
- 逆に、コードとしては違っていても、同じビジネスルールを複数箇所に書いているならDRY違反になり得る
- 本記事で扱う問題は、本来は異なる意味を持つ操作やユースケースを「同じ知識」と見なしてしまい、1つの関数に押し込めてしまった結果の失敗である
■ 3. DRYの誤用が発生する場面
- 粒度の大きい一連の手続き(ワークフロー)に対して行われる
- 「同じ処理がありそうだから」という理由だけで共通化する
- 背景にあるユースケースの違いを無視する
- 無理に共通化の抽象を導入する
- 本質的には異なるユースケース・異なる概念を「見た目のコードが似ている」というだけで一つにlumping(ひとまとめ)してしまう問題が起きている
- これはDRYの本来の目的である「知識を一意に保つ」こととは異なる
■ 4. 具体例:ユーザ作成ユースケースの悪い共通化の段階的悪化
- ステップ1:素朴な手続き:
- 「ユーザを1人作成する」というユースケースがフラットに記述されている
- この時点では問題は少ない
- ステップ2:別ユースケースでの「ほぼ同じ処理」の登場:
- 部署の初期構築の一環としてユーザを1人作成するユースケースが追加される
- 見た目上は重複があるが、この段階ではまだ「ユースケースが2つあるだけ」である
- ステップ3:「重複しているから」という理由だけの共通化:
service_add_userという共通関数にロジックをまとめる- まだこの時点では致命的な問題は顕在化していないが、「ユースケースごとにフラットに書かれていたもの」を「大ぶりな共通関数に吸い寄せ始めている」状態である
- ステップ4:再利用志向がN+1を生む:
- 「複数ユーザを一括作成する」要件が加わる
- 既存の
service_add_userを再利用すると、「1人用の処理を、バルク処理でもそのまま流用する」という安易な再利用によってN+1的な非効率I/Oを潜在させてしまう- 元々
service_add_userは「1人のユーザを作る」ための手続きとして書かれたものであり、「多数ユーザを一括作成する」というユースケースを考慮して設計された抽象ではない- ステップ5:オプショナルパラメータ地獄と責務の膨張:
- 「メールアドレスだけで仮登録できる」ユースケースが追加される
service_add_userを拡張して対応すると、name/ageがオプショナルになり、実際の振る舞いは「パラメータの組み合わせ×条件分岐×デフォルト値」に依存し、関数内部に隠蔽される- 「通常登録」と「仮登録」という別ユースケースが、どちらも同じ入力型に押し込められる
- 型定義からは必須なのか任意なのか読み取れない
■ 5. 問題の本質
service_add_userは守るべきルールを表す抽象にはなっていない- 代わりに複数のユースケースをまとめた「なんでも入り処理関数」になっている
- DRYの名のもとにやっているのは:
- ビジネスルールの重複をなくすことではない
- ユースケースの違いを無視して1箇所に押し込めること(lumping)である
- 本来DRYを適用すべきなのは守るべきルール(不変条件)そのものであって、手続き・段取り(オーケストレーション)に対してではない
■ 6. 正しい設計:ルールと手順の分離
- ルールを集約したUserクラスの導入:
- ユーザに関する「守るべきルール(不変条件)」を集約した構造体
- このインスタンスが存在する限り、データは常に正しい状態であることを保証する
- コンストラクタで不正な状態を防ぐ
- 「通常登録」「仮登録」の違いを生成メソッドで明示する(
create_regular,create_reserved)- ユースケースは「手順の管理」に徹する:
- 共通関数を作ろうと頑張るのではなく、ユースケースごとの手順を素直にフラットに書くことに徹する
- ルールのチェック・状態の正当性はUserクラスに集中する
- ユースケース層では「どのルートで、何人分、どのような粒度でI/Oするか」を素直に書く
- 一括作成ユースケースでは必要に応じて
bulk_saveなどの最適化を行える- 結果として:
- DRYの対象は「ユーザの整合性ルール」
- 共通化しない(あえてボイラープレートを許容する)のは「ユースケースごとの手順」
■ 7. 抽象化を導入してよいかを判断するチェックリスト
- その共通化は「知識」を一意にするか:
- 単にコードが似ているだけでなく、ドメインルールや整合性チェックを一箇所に集約しているか
- その関数の責務はユースケースに引きずられていないか:
- 明らかにユースケースが違うものを同じ関数に押し込んでいないか
- 新しいユースケースを追加したときにその関数が壊れそうにならないか
- 「データの整合性を守る構造体」として切り出せるか:
- その共通処理はデータの正しさを保証するためのものか
- もしそうなら手続きの一部として書くのではなく、ルールを持った構造体として独立させられないか
- 共通化によってパフォーマンス制約を固定化していないか:
- 「1件処理する関数」を共通化した結果、バルク処理の最適化余地を消していないか
- 変更頻度が高い部分を無理に一箇所に寄せていないか:
- ビジネスルールとして安定していそうな部分だけを共通化できているか
- 仕様が変わりやすいユースケース単位の手順は、しばらくは重複を許容したほうが楽ではないか
■ 8. AI支援開発における境界設計の重要性
- AIのコード生成は「型と境界」を手がかりとして推論する:
- 関数やメソッドの引数の型、データ構造の形状、インターフェースの粒度、責務の境界などを手がかりにする
- オプショナルだらけの入力データ定義、ユースケースを無理やりまとめた巨大な関数、前提が暗黙化した共通化はAIが推論するための手掛かりを失わせる
- 結果としてLLMが誤った前提でコードを生成したり、リファクタリング提案の品質が著しく落ちる
- これは設計の品質がAI推論可能性に直結していることを示している
- AIは「明確なルール」を理解しやすい:
- ルールとデータをひとまとまりの構造体として閉じ込めた設計はAIと非常に相性が良い
- 構造として明示されているとAIは非常に正確に推論を行える
- オプション引数の組み合わせ次第で挙動が変わる関数はAIにとって「解釈不能な塊」となる
- AI支援型リファクタリングは「型の境界」単位で作用する:
- 型、メソッドの定義、レイヤー境界、依存の方向性が明瞭であるほどAIのリファクタリング精度は劇的に上がる
- 境界が曖昧だとAIは誤った提案をする
- 設計の曖昧さはそのまま「AIが壊すリスク」になる
- 境界が明確だとAIとの協調作業が「加速」する:
- 既存構造に沿った拡張提案が極めて正確
- 新ユースケースを自動生成しやすい
- I/O最適化の提案がしやすい
- 変更の影響箇所を極めて正確に推論する
- AIの性能が最大化される
■ 9. AI時代の「速さ」の本質
- ソースコードを書くコストは劇的に下がった
- AIを使えば構造の崩れたコードも誤った共通化もこれまでとは比較にならない速度で量産できてしまう
- これは技術的負債をマッハで積み上げられる時代の到来とも言える
- 真に競争力を持つのは「最初にコードを書き殴ったチーム」ではない
- 市場のフィードバックを受け、仕様変更に耐え、システムを破壊することなく安全に進化させ続けられる(Modifiabilityを持つ)チームである
- 「ルールを守る構造体」や「責務の分離」といった設計はドメイン駆動設計(DDD)における戦術的設計の一部である
- これらはAIによる爆発的なコード増殖のなかで「変更容易性」という最大の資産を死守するための極めて実利的な防衛手段である
- ビジネスのコアをコードに反映させ、変更に強い構造を作る「戦略」を持つことがAIという強力な増幅器を積んだ開発者が壁に激突せずにトップスピードで走り続けるための唯一の条件である
- 1. 大文字小文字の区別(#14750)
- 2. omitempty の定義変更(#11939, #22480)
- 3. string オプションの適用範囲(#34268)
- 4. nil スライス、マップの出力(#27589, #37711)
- 5. 固定長配列の長さチェック
- 6. バイト配列([N]byte)のエンコード
- 7. ポインタレシーバのメソッド呼び出し(#27722, #33993)
- 8. マップの出力順序(#27179)
- 9. HTML エスケープ
- 10. 無効な UTF-8 の扱い
- 11. 重複キーの扱い(#48298)
- 12. null のマージ動作(#22177, #33835)
- 13. 複合型のマージ動作(#21092)
- 14. time.Duration の表現(#10275)
- 15. 空の構造体
- まとめ
- おわりに
■ 1. イベント概要と背景
- 2025年11月14-15日に福岡工業大学でYAPC::Fukuoka 2025が開催された。
- 田中翼(yoku)さんが「今、MySQLのバックアップを作り直すとしたら何がどう良いのかを考える旅」というトークを実施した。
- yokuさんは日本MySQLユーザ会副代表で、2025年5月にさくらインターネットに入社したデータベース専門エンジニアである。
- さくらインターネットはガバメントクラウドの正式認定を受けるため、さくらのクラウドに機能追加を進めている。
■ 2. ガバメントクラウドのデータベースバックアップ要件
- ガバメントクラウドの調達仕様書には約300項目の技術要件が記載されている。
- データベースバックアップに関する要件は以下の4点である:
- DBのバックアップを差分で取得でき、取得したバックアップはいつでもDBの復元に使用できること。復元時は別のサイズを選択できること。
- DBのバックアップは一定期間(例:5分)以前のどの時点にでも戻せる形(Point In Time Restore: PITR)で取得できること。
- DBのバックアップは予め設定したタイミング、周期、世代で自動的に定期実行できること。
- DBのバックアップイメージはCSPの中であれば別のシステム、別のネットワーク、別の環境からも利用できること。
- 特に「DBのバックアップを差分で取得できること」と「どの時点にでも戻せる形(PITR)で取得できること」の2点が重要な検討事項となった。
■ 3. データベースバックアップ手法の分類
- フルバックアップ:
- データベース全体のバックアップを取得する手法である。
- 差分バックアップ:
- 前回のフルバックアップと現在のデータベースの差分を取得する手法である。
- 増分バックアップ:
- 前回のバックアップと現在のデータベースの差分を取得する手法である。
- 前回のバックアップがフルバックアップとは限らない点が差分バックアップと異なる。
- 1月1日から1月8日にかけて3種類のバックアップを混在して実施する例が図で示された。
■ 4. PITR機能の実装方法
- PITR機能は3種類のバックアップ手法を組み合わせて要件を満たすバックアップを取得する。
- MySQLにおけるPITRはバイナリログを使用して実現される:
- バイナリログはデータベースの変更操作を記録したものである。
- フルバックアップを取った時点のバイナリログ情報を記録し、それ以降のバイナリログを継続的にコピーし続けることで実現できる。
- バイナリログは増分バックアップに相当する。
- ガバメントクラウドの要件「バックアップを差分で取得」とは厳密には異なるが、PITRを実現するにはフルバックアップとバイナリログだけで実装する方がシンプルである。
- 要件「一定時間(例:5分)以前のどの時点にも戻せる形で取得できること」は「少なくとも5分に1回バイナリログをバックアップすればよい」と解釈できる。
- mysqlbinlogコマンドでバイナリログをストリーミング出力させ、バイナリログが出力され次第すぐにバックアップとして保管される仕組みを実装した。
- バックアップコマンド例:
- target_binlogを特定し、mysqlbinlogコマンドで継続的に出力する。
- リストアコマンド例:
- xtrabackup_binlog_infoからtarget_binlogを取得し、該当するバイナリログファイルを順次取得してmysqlbinlogコマンドで適用する。
- リストアの流れ:
- 戻したい時刻を指定する。
- それよりも一番近いフルバックアップを入手する。
- フルバックアップよりも後、かつ戻したい時刻よりも前で最新の差分バックアップを入手し適用する。
- 戻したい時刻と差分バックアップの間のバイナリログを入手し適用する。
■ 5. MySQLのフルバックアップツール
- MySQLのフルバックアップを取得するツールは以下の通りである:
- コールドバックアップ
- MySQL Enterprise Backup
- Percona XtraBackup
- CLONE INSTANCE
- mysqldump
- MySQL Shell Dump/Load Utility
- MyDumper
- mysqldumpは有名だが遅いため推奨されない。
- 差分が取れるフルバックアップツールはMySQL Enterprise Backup(MEB)とPercona XtraBackup(xb)の2つである。
- これらのツールの動作原理:
- ibdファイル(InnoDBのデータファイル)をコピーしている間、継続的にInnoDBログをコピーし続けることでバックアップを取得する。
- リストアはバックアップ時にコピーしたibdファイルとInnoDBログを使用して実行する。
■ 6. バックアップとリストアの実装例
- xtrabackupを使用したフルバックアップと差分バックアップの実行例:
- フルバックアップ: xtrabackupコマンドで--backupオプションと--target-dirオプションを指定する。
- 差分バックアップ: 最新のフルバックアップを特定し、--incremental-basedirオプションで指定する。
- 増分バックアップは常に取り続ける(リストア時に必要となるため)。
- xtrabackupを使用したリストアの実行例:
- フルバックアップからのリストア: 指定時刻より前の最新のフルバックアップを特定し、xtrabackup --prepareコマンドで--apply-log-onlyオプションを指定して実行する。差分バックアップがない場合は--apply-log-onlyをつけてはいけない。
- 差分のリストア: 指定時刻より前の最新の差分バックアップを特定し、xtrabackup --prepareコマンドで--incremental-dirオプションを指定して実行する。
- mysqlshを使用したバックアップとリストアの実行例:
- フルバックアップ: mysqlshコマンドでutil dumpInstanceを実行する。
- リストア対象の識別: 指定時刻より前の最新のフルバックアップを@.jsonファイルから特定する。
- @.jsonファイルからバイナリログの情報(binlogFile、binlogPosition、gtidExecuted)も取り出せる。
■ 7. まとめと成果
- MySQLのバックアップはxtrabackupとバイナリログを使用することで実現できる。
- mysqlshを使用する方法もあり、フルバックアップも増分バックアップもmysqlshコマンドで取得可能である。
- 今回の成果はさくらのクラウドのデータベースアプライアンスにおけるPITR機能としてリリースされた。
- PITR機能が使用できるのはMariaDBのみである。
- MariaDBはMySQLから派生したソフトウェアだが、現在は互換性がなくなっているため、検討した内容がそのまま実装されているわけではない。
- 検討した成果によってガバメントクラウドの要件をいくつかクリアできた。
- さくらのクラウドはガバメントクラウドの正式認定を目指して前進を続けている。
- ユーザーと同じ環境でものを見る
- デザインツールと実装環境の違い
- コードで管理する最大の価値
- 型の力で強制できる
- 無理やり実装を防ぐ仕組み
- コードだからこそ実現できる強制力
- 最初から徹底できる
- 後付けでは浸透しない
- AI時代の開発スピードに対応する
- デザインをコード管理することは必要不可欠
- Figma Schemaが示す方向性
■ 1. 早すぎる目的・KPI設定の問題点
- 会議やSlackのやりとりで「目的とKPIは?」という問いかけが出ると、すぐにアクションに移すべきだった内容が停滞する
- 目的とKPIが決まるまで実行できなくなり、「なぜやるのか、どう計測するのか」を決めるための会話に時間が取られる
- 目的の話がまとまると「別の方法が良いのではないか」という議論になり、1、2ヶ月が経過する
- 最終的には「検討します」のまま塩漬けになり、その施策の話がされなくなる
■ 2. KPI・目的設定自体の意義
- KPIや目的を決めること自体は良いことである
- 数字や言語化された目的があれば、目的に向かってブレずに動きやすい
- やるべきことにリソースを集中させることができる
- 大きな目的やKPIが早すぎる段階で語られることで、理解を深めることや観察のためのアクションが阻害される
- 結果的に単に動きが悪くなってしまう場合がある
■ 3. 過剰管理の発生メカニズム
- 未知や不確実性への恐れが過剰管理を生んでいる
- 「施策ごとにKPIとか目的が設定されるべき」という言葉は一見正しいように見える
- 「まず触れてみて、感触を掴む」という目的で十分なときには過剰管理となる
- 未知や不確実性への恐れが「ちゃんとした目的やKPIがあるべき」という過剰管理を生んでいる
- 「触ってみる・やってみる」によって学んだり観察したりする探索的アクションすら禁止される状況が生じる
■ 4. AI開発ツール導入の具体例
- AIを活用した開発をしていない開発チームがCursorやClaude Codeをエンジニアに使ってもらおうとする場合を例示している
- 「目的はなんですか?ツールを使うことは目的ではないですよね。開発生産性を上げることですよね。開発生産性はどのように計測して、ROIは……」という問いかけが出る
- このような早すぎる目的・KPI設定の要求は、試行錯誤を阻害する
- AIを使った開発でどういうことが起きて何がこれまでと違うのかを知らない人が「どのくらい効率良く開発できるようになるのか出せないなら、AIを使うべきではない」と言い出すと終わる
■ 5. 状態目標と経験の価値
- やってみて経験する・理解を深めるということが事業的に意味のある状況ならば、それは十分に「状態目標」として機能する
- 経験すること自体が事業成長という目的に向かっている行為として機能する
- 目標達成したかどうかが感覚的にしかわからないことがダメな理由はない
- 事業的に意味のあるアクションが「厳密に測定可能ではない」というだけで阻害される方が損失である
■ 6. コンテンツマーケティングの具体例
- 自社の情報を発信するときに「まずは書いてみて、どのくらい大変か」や「自分たちは、どんな品質の記事が書けるか」を体験してみる必要がある
- 試行錯誤した経験もないまま「毎月のPVはどのくらいを目指していますか」と聞かれると試行錯誤が阻害される
- 試行錯誤した経験がないため誤ったKPIを設定してしまう
- 探索的に動くだけでも良いのにKPIや大きな目的に縛られて「うまくいかないので止めます」を繰り返す状況が発生する
■ 7. 勝ち方を知らない段階での問題
- 勝ち方(うまくいく方法)もわかっていない段階から「勝ちに行く手」を決めようとしてもダメである
- 勝ち筋かどうかを測定しようとしてもダメである
- 手触り感がないことにKPIを決めるのはアホである
■ 8. 逆の極端な状況への警告
- 観察と理解が十分な段階に進んでいるのにいつまでも「とりあえず色々やってみましょう」を続けるのはアホの極みである
- 目的を目指すためのKPIを決めてリソースをつぎ込めば良いのにいつまでも「色々試してます」で留まってしまうのは良くない
- もう仮説を立てられるのにいつまでもなんとなくやってみるのもアホの極みである
■ 9. 適切な対応方法の提案
- 「これをする目的とKPIは?」と言われたときに、まだ試行錯誤や探索的アクションが必要であれば適切な説明をすべきである
- 「まずは、短期間だけでも経験して学習するための探索的アクションを積ませてください。定量目標がなくても、アクションに対して学んだことを振り返りする方が、良かったかどうかや今後どうすべきかがハッキリします」と伝えることが有効である
- どうしても必要であれば仮当てのKPIくらいはあっても良い
- 定量目標や本質的な目標の前に肌感を掴むというのは感覚的な話になるため怖がる人がいるのは理解できる
- 勇気をもって感覚を掴む方がうまくいく状況もある
■ 1. はじめに
- 医師を辞めてAI・スタートアップ界隈に来てからもう少しで3年になる
- 自分自身はAI業界に転身したつもりなのでスタートアップ界隈という認識は薄い
- やっていることはザ・スタートアップである
- 医療AIはほとんど開発していない
- ずっと画像生成、音声合成、大規模言語モデルといったエンタメやディープテックに近い領域で戦ってきた
- toBよりもtoC寄りである
■ 2. 医師から虚構の世界へ
- 医師からこの業界に来て最初に食らった洗礼は言葉の重みの違いであった
- 医療の世界では正確性とエビデンスが命である
- 誇張は患者の死に直結する
- スタートアップの世界:
- 実現していないことを高らかに語ることは嘘ではなくビジョンと呼ばれ称賛される
- できないとは言わず(資金があれば)できると言う
- ピッチは飛ばしてなんぼであり夢は大きければ大きい方がいい
- 実際にスタートアップはある閾値を超えると指数関数的に成長していくから多少の誇張は現実になる
- エンジニアの視点から見るとなんとも夢物語で10年後でも無理だろうというものがワンサカ出てくる
- この真逆のルール「虚構を現実に変えていくゲーム」に慣れるまでには少なからず脳の切り替えが必要であった
■ 3. エアフレンド時代の経験
- 医師を辞めて最初に飛び込んだのはエアフレンドというスタートアップであった
- CEOの圧倒的な熱量に惹かれてジョインした
- 来る日も来る日もアプリの仕様や骨格を煮詰めた
- それは自分にとってまさに青春とも呼べる宝物のような日々であった
- AI/Backendエンジニアとして、PMとして、画像生成AIの研究に没頭した
- ひたすら良いものを作ることにコミットしていた
- 致命的な落とし穴:
- 良いものを作れば勝手にユーザーが集まるというエンジニア特有のナイーブな幻想を抱いていた
- ビジネスとしての骨格よりもプロダクトの美しさを優先してしまったのかなと今振り返ると思う
■ 4. Livetoon時代の挑戦
- その後LivetoonでCTO(最高技術責任者)として活動するようになった
- 現在もAIキャラクターや音声合成(TTS/STS)などの領域でプロダクト開発を続けている
- AIプロダクト開発には別の地獄がある
- それは技術の陳腐化速度が異常だということである
- OpenAIやGoogleが発表するモデルやプロダクトによって数カ月かけた作ったものが一夜にして無価値になる
- 音声合成AIを研究・開発している真っ只中に海外から人間と区別のつかないレベルのAPIが公開され全てが過去の遺物になるなんてこともあり得る
- 昨日の必殺技が今日の標準装備(デフォルト)になり明日にはゴミになる
- この徒労感と戦いながらそれでもなお自社プロダクトとしての価値をどこに見出すか
- 今のAIスタートアップにおけるプロダクト開発はまさにこの巨人の足元で踏み潰されないように城を築くようなヒリヒリする戦いの連続である
- 自分が下した決断も少なからずこういった影響を受けている
- LLMの自社開発・提供に待ったをかけたのも日本語TTSという海外の巨人がまだ来ていないジャンルに投資したのもそういった判断によるものである
■ 5. AI受託開発の実態
- プロダクト開発の苦行を横目に今のAIスタートアップの8割くらいが選んでいる道がある
- それはAI受託開発である
- PoC工場の実態:
- やることはシンプルである
- 大企業からの「これってAIでできないの?」という問いに対しChatGPT等のAPIを裏で回して「ほら、AIでこんな未来が作れます!」とパフォームしPoC(概念検証)を回す
- 2024年頃まではAIというジャンルの先進性だけでそれなりにパイを取ることが可能であった
- 2025年後半になって急に雲行きが怪しくなってきた
- 理由は単純に誰でもできるようになったからである
- プロダクト開発能力を持たないため技術的な参入障壁がない
- 先行者利益など存在せずあるのはリソース勝負だけである
■ 6. 学生インターンの人海戦術
- 技術力で差別化できないとなるとAIのAPIを触れそうな学生インターンを大量投下して馬車馬のごとくPoCを高速回転させる必要がある
- うかうかしていると隣のスタートアップがさらに多くのインターンを投入してくる
- しかもAIの進化は目まぐるしく半年前に納品したPoCはあっという間に陳腐化する
- こうなると最終的にはコネクションゲームになる
- 技術ではなく誰が言っているかが重要になる権威性ゲームの始まりである
- そうなると強いのがドメインに入り込んで顔を売っていた人たちか圧倒的なネームバリューを持っている人たちである
- 後者の場合これはもう当たり前に東大勢(東大発ベンチャー)が圧倒的に強くなる
- 東大発というブランドで受託を取りM&Aによるイグジット(人生のアガリ)を目指すことが一つの勝ちパターンとして定着してしまっている
- 東大発スタートアップ界隈には尊敬する友人や共に戦う仲間がたくさんいる
- 彼らが真剣に技術と向き合っているのを知っているからこそ一部のブランドを騙る層が余計に目に付くのかもしれない
■ 7. 魑魅魍魎なエコシステム
- 真面目にやっている人たちが大半であるがこの歪んだ市場構造にはならず者も集まってくる
- 資金調達至上主義:
- スタートアップの戦闘力は何故か調達額で測られがちである
- シリーズどれくらい?からマウント合戦が始まる
- ロジックの美学:
- まずはやってみなはれとは真逆である
- 妄想ワールドの中でロジックの穴を乳繰り合うコンサル上がりの文化である
- ヤバい奴ら:
- 投資資金を私的に利用し夜の街でフラフラしている
- いつの間にか蒸発する声だけデカい人々である
- 制度ハック勢:
- 売上はほとんど無いが補助金で食いつないでいる会社である
- 最近では東大系の一部もこれに目をつけハックしきっている印象すらある
■ 8. デューデリジェンスの違和感
- 投資家(VC)について触れずにはいられない
- お会いしてきたVCの方々は皆さん本当に人格者で親身になって相談に乗ってくれる優しい方ばかりである
- 起業家の夢を応援したいという熱意も本物だと思う
- しかしいちエンジニアの視点から見ると技術の目利き(デューデリジェンス)という点ではどうしても違和感を感じてしまう瞬間がある
- 彼らは自分でAIモデルを作ったりGPUのエラーログと格闘したりするわけではない
- なのでどうしても判断基準がXのトレンドやChatGPTの派手なアップデート情報そしてわかりやすい権威に寄ってしまう傾向がある
- AIスタートアップに投資するといいつつ実態の調査は殆どできず表層の理解にとどまっている
- 東大発、松尾研出身といったブランドへの信頼が厚いのも理解できる
- しかしその結果として中身の技術的な難易度や独自性よりも安直に回収できそうな受託メインの優等生に資金が流れていないか
- 最近話題になったオルツの上場後の動きなどを見ても実態としてのAI産業を育てることよりもバリュエーションを上げて売り抜けるマネーゲームの側面が強くなっているように感じる
- これは私の観測範囲の偏りに過ぎないのかもしれない
- 本当に技術の本質を見抜きリスクを取って基盤産業を育てようとしている凄い投資家は存在するのに単に私のレベルが不足しているためにそういった方々に巡り会えていないだけなのかもしれない
- そうであれば完全に私の力不足であり精進あるのみである
■ 9. 雲の上のマネーゲーム
- 数千万円の調達やGPUコストに頭を抱えているのとは裏腹に桁違いの資金が動いている世界もある
- Third Intelligenceが初のラウンドで80億円、Sakana AIが追加で200億円調達するニュースがある
- 正直ここらへんはもう自分が生きている世界とはレイヤーが違いすぎて分からない世界である
- 彼らが掲げるAGI(汎用人工知能)や壮大なビジョンが具体的にどうなっていくのか分からない
- 分からないことには口を出さない主義なので深いコメントは避ける
- ただあるところにはあるんだなぁと感じる
- 現場で泥臭くコードを書いている身からするとどこか遠い国の神話を見ているような気分になる
■ 10. おわりに
- 医者を辞めこの世界に飛び込んだ
- そこにあったのは煌びやかな未来というよりは虚構と欲望そして地道な技術の積み上げが混在するカオスな世界であった
- 華やかな資金調達ニュースや東大ブランドの受託ビジネスを横目に見つつたぶん自分は現場で手を動かし続けると思う
- バブルが弾け流行りが去ったあとに残るのは結局のところ誰かの役に立つプロダクトを作れるエンジニアや実行者だと信じているからである
■ 1. Linuxへの移行が進んでいる証拠
- 同僚のJack Wallenと筆者は以前からWindowsからLinuxへの乗り換えを提案してきた
- 一部の人々にその声が届いているようである
- Zorin OS 18の事例:
- 公開からわずか1カ月余りで100万件のダウンロードを達成した
- そのうち78%以上がWindowsユーザーによるものである
- 78万人ものWindowsユーザーが3.5GBものLinuxデスクトップディストリビューションをダウンロードするのは単なる気まぐれではない
- Linuxデスクトップの愛好家なら異なるディストリビューションを試すのは趣味の一環だが、Windowsユーザーの場合は本気でLinuxへの移行を検討していると考えるべきである
■ 2. Linuxデスクトップの市場シェアの成長
- StatCounterのデータによれば、2020年にわずか1.5%だったLinuxデスクトップの世界シェアは、2024年には4%を超え、2025年には米国で過去最高の5%超に達した
- StatCounterの最新の米国データ(10月まで)ではLinuxは3.49%と表示されている
- ただし「unknown」が4.21%を占めている
- 推測としてこの「unknown」はLinuxを動かしているのではないか
- 他にFreeBSD、UNIX、OS/2である可能性は低い
- ChromeOSは3.67%とされているがこれは低すぎる印象である
- ChromeOSもLinuxの一種である(KDE PlasmaやCinnamonなどのLinuxデスクトップ環境ではなく、Chromeブラウザーをインターフェースとして使っているだけ)
- これらを全て合算するとLinuxデスクトップの市場シェアは11.37%になる
■ 3. エンドユーザーOS全体におけるLinuxの立場
- PCだけでなくスマートフォンやタブレットを含むエンドユーザーOS全体を見れば、Linuxの立場はさらに強固である
- 米国ではAppleのiPhoneが人気だが、StatCounterの最新データによるとAndroid(これもLinuxディストリビューション)が41.71%のシェアを誇っている
- 世界全体ではAndroidが72.55%という圧倒的なシェアを持っている
- PC、タブレット、スマートフォンを含むエンドユーザー向けOS全体の指標を広げて捉えるならば、Linuxこそがすでに支配的な立場にあると合理的に主張できる
■ 4. Digital Analytics Program(DAP)から見た現状
- StatCounterの数字には問題があるとの指摘がある
- 筆者がOSのシェアを確認する際に好んで使うデータソースは米国連邦政府のDigital Analytics Program(DAP)である
- このサイトは米国政府のウェブサイトへの訪問数とその分析をリアルタイムで提供している
- 過去30日間の平均セッション数は16億件に達し、1日当たり数百万のユーザーが訪問している
- DAPはデータを加工することなく、人々が実際に何を使っているかを詳細に示している
- DAPはGoogle Analyticsのアカウントから生データを取得している
- DAPはデータをウェブ上に表示するコードやデータ収集コードをオープンソース化しており、JSON形式でデータをダウンロードして自分で解析することもできる
- DAPの集計結果:
- Linuxデスクトップのシェアは現在5.8%である
- 筆者が10年前にDAPの数字を見始めた頃、Linuxデスクトップのシェアはわずか0.67%だったことを考えると驚くべき成長である
- Chrome OS(1.7%)とAndroid(15.8%)を加えると、米国政府のウェブサイトにアクセスするユーザーの23.3%がLinuxユーザーということになる
- Linuxカーネルのユーザー向けの存在感は「デスクトップLinux」というラベルが示す以上に大きい
- Windows 10とWindows 11の状況:
- Windows 10はすでに引退期に入っているはずだが、DAPの数字では依然として人気があり16.9%を占めている
- Windows 11は13.5%である
- これに対しStatCounterでは米国においてWindows 11がリードしており、全Windowsユーザーの64.83%を占め、Windows 10は31.92%と大きく後退している
- それでもWindows 10を使い続けてセキュリティリスクを抱えているユーザーがあまりにも多い
- IT資産の検出とインベントリーを行う企業Lansweeperによると、1500万以上の消費者向けデスクトップOSを分析した結果、Linuxデスクトップは現在PC市場シェアの6%強を占めている
■ 5. Linuxが成長している理由(当初挙げた5つの要因)
- 筆者は2025年、WindowsからLinuxへの移行を促す要因として5つを挙げた:
- MicrosoftがWindowsを製品として扱う姿勢からMicrosoft 365やクラウドサービスへ重点を移したこと
- SteamとProtonによるゲームの実用性向上
- 主要ディストリビューションの使いやすさが劇的に改善されたこと
- ハードウェア対応の拡大
- プライバシーやデータ管理への懸念の高まり
■ 6. 追加で浮上した3つの要因
- Windows 11へのアップグレードができないハードウェア制約:
- 多くの企業やユーザーがWindows 11に「アップグレード」できないにもかかわらず、まだ十分に使えるWindows 10マシンを所有している
- ControlUpの調査によると、消費者および企業のWindows 10マシンの約25%はWindows 11に移行できない
- このハードウェア制約はMicrosoftの仕様を満たすためだけに新しいマシンを購入するのではなく、Windows 10のサポート終了後も使い続けようとする大きな理由になっている
- Windows 11への移行を強く望んでいない事実:
- 英国の消費者団体Which?が2025年9月に実施した調査では、回答者の26%がアップデート終了後もWindows 10を使い続ける意向を示した
- 興味深いことに6%はLinuxなどの代替OSへの移行を計画している
- ユーザーがためらう主な理由は3つ:
- Windows 10は「十分に良い」
- Windows 11は意味のある改善と見なされていない
- 強制的なインターフェース変更(中央配置のスタートメニュー、コンテキストメニュー、既定アプリの挙動、Copilotの統合)を好まない
- ゲーマーはWindows 11がゲームを遅くしたり互換性の問題を引き起こしたりするのではないかと懸念している
- 実際、Windows 11の10月のアップデートではNVIDIA搭載の一部ゲーミングPCでパフォーマンスを低下させるバグが発生した
- Windows 11のAIエージェント型OSへの変貌:
- Windows 11がAIエージェント型OSへと変貌していることを全ての人が歓迎しているわけではない
- AIブームにもかかわらず、Microsoftに行動を逐一監視されるようなAIを望まない人もいる
- MicrosoftでWindowsおよびDevices担当プレジデントを務めるPavan Davuluri氏が11月10日に「Windowsはエージェント型OSへ進化し、デバイス、クラウド、AIを接続して、インテリジェントな生産性と安全な作業環境を実現する」とXに投稿した際、ユーザーがこのビジョンを歓迎することを期待していた
- しかし現実は違った
- 最も多くの反応を得たコメントは「それはMacやLinuxへの移行を促す製品に進化している」というものだった
- AIによる監視を受けず、自分のPCで何が起きているかを完全にコントロールできる従来型のデスクトップを求めるなら、今後Linuxがほぼ唯一の選択肢になる
■ 7. デジタル主権の問題
- WindowsからLinuxへの移行を検討する最後の理由は、米国のユーザーにとってはあまり重要ではないが、米国外のユーザーにとっては非常に大きな意味を持つ
- 欧州連合(EU)の政府は米国の政治的圧力の下でMicrosoftがサービスの約束を果たすことを信用していない
- この不信感は「デジタル主権」という取り組みに発展し、EU企業が米国のテック大手よりもはるかに信頼できる存在と見なされるようになった
- その結果、多くのEU加盟国はMicrosoftのプログラムを廃止し、オープンソースソフトウェアへと移行している
- それはデスクトップ分野にも及んでいる
- あるEUグループは「EU OS」を開発した:
- FedoraベースのディストリビューションにKDE Plasmaデスクトップ環境を採用したLinuxデスクトップの概念実証版である
- こうした動きはEUに限らない:
- 英国もまたMicrosoftにデータを委ねることを信用しなくなっている
- 2024年にComputer Weeklyが報じたところによると、Microsoftはスコットランド警察に対しMicrosoft 365やAzureのデータが英国国内にとどまることを保証できないと伝えた
- 当時、英国内閣府の元ICT責任者であるNicky Stewart氏は「Microsoftは『主権クラウド』と称するものを売り込んでいるが、主権とは何を意味するのか。真に主権的なデータであれば、いかなる状況でも海外に送られることはないはずだ」と語った
- Windows 11のデータが米国のデータセンターとの間でやりとりされる可能性がある以上、今後ますます多くの政府がWindowsを信用することに慎重になる
■ 8. 結論
- これら全ての変化を総合するとLinuxはもはや「マニア向けの特別な選択肢」ではなく、Windowsのアップグレード地獄やサブスクリプションモデルから抜け出したい人々にとって現実的な選択肢となりつつある
- デスクトップLinuxは長年の「負け犬」から脱却し、日常的なコンピューティングにおいて小さいながらも意味のある存在へと進化している
- 特に技術に精通したユーザー、米国外の公共機関、そしてより安価で信頼できるデスクトップを求める一般消費者や企業ユーザーの間でその存在感を高めている
まとめ
チーム分割は、チームの仕様検討力を阻害していた。
(STEP1) 役割が固定化されると、理解は属人化する。
(STEP2) チームで語り、合意を育てる文化が自己組織化を支える。
(STEP3) 設計を「書く」から「語る」へ。 プロダクトの成長をチームで考え、実現し続けられる状態を作ることが、 長期的なプロダクト開発にとって大切なことだった。
■ 1. AIと歴史的先例の比較
- AIは様々な歴史的先例(電気、産業革命など)と比較されてきた
- 最も強力な類似性はAIを新しいコンピューティングパラダイムとして捉えることである
- なぜなら両者は根本的にデジタル情報処理の自動化に関するものだからである
■ 2. Software 1.0時代の特徴(1980年代のコンピューティング)
- 1980年代に雇用市場へのコンピューティングの影響を予測する場合、タスク/仕事の最も予測力のある特徴は「指定可能性(specifiability)」であった
- 指定可能性とは、機械的に情報を定型的で簡単に指定できるアルゴリズムに従って変換しているだけかどうかである
- 例:タイピング、簿記、人間計算機など
- 当時、これはその時代のコンピューティング能力が手作業で手動で書くことを可能にしたプログラムのクラスであった
- 筆者はこの手書きプログラムを「Software 1.0」と呼んでいる
■ 3. Software 2.0時代の特徴(AI時代)
- AIによって、これまで手作業では書くことができなかった新しいプログラムを書くことができるようになった
- 方法:
- 目的(例:分類精度、報酬関数)を指定する
- 勾配降下法を介してプログラム空間を探索し、その目的に対してうまく機能するニューラルネットワークを見つける
- これが筆者が以前のブログ投稿で述べた「Software 2.0」である
- この新しいプログラミングパラダイムでは、注目すべき新しい最も予測力のある特徴は「検証可能性(verifiability)」である
■ 4. 検証可能性の定義と条件
- タスク/仕事が検証可能であれば、直接的にまたは強化学習を通じて最適化可能である
- ニューラルネットは極めて優れた動作をするように訓練できる
- これはAIがどの程度何かを「練習」できるかということである
- 環境は以下の条件を満たす必要がある:
- リセット可能(resettable):新しい試行を開始できる
- 効率的(efficient):多くの試行を行うことができる
- 報酬可能(rewardable):行われた特定の試行に報酬を与える自動化されたプロセスが存在する
■ 5. 検証可能性と自動化の関係
- タスク/仕事が検証可能であればあるほど、新しいプログラミングパラダイムにおける自動化に適している
- 検証可能でない場合、以下のいずれかに依存する必要がある:
- ニューラルネットの汎化の魔法から生じることを期待する(指を交差させて祈る)
- 模倣のようなより弱い手段を使う
■ 6. LLMにおける進歩の「ギザギザした」フロンティア
- 検証可能なタスクは急速に進歩する:
- トップエキスパートの能力を超える可能性も含む
- 例:数学、コード、動画視聴に費やされた時間、正解のあるパズルのように見えるもの
- 他の多くのタスクは比較的遅れている:
- 創造的なタスク
- 戦略的なタスク
- 現実世界の知識、状態、コンテキスト、常識を組み合わせるタスク
- これがLLMの進歩における「ギザギザした(jagged)」フロンティアを推進している
■ 7. まとめ
- Software 1.0は指定できるものを簡単に自動化する
- Software 2.0は検証できるものを簡単に自動化する
■ 1. GitHubの考察記事の公開
- GitHubは開発ツールとしてAIが導入されていくことで、プログラミング言語やフレームワークの選択にどのような影響を与えるかを考察したブログ記事を公開した
- 記事タイトルは「TypeScript, Python, and the AI feedback loop changing software development」(TypeScript、Python、そしてAIフィードバックループがソフトウェア開発を変えていく)である
■ 2. AI導入による静的型付け言語の選択傾向
- 静的型付け言語の方がAIがより正確なコード生成を行いやすい傾向にある
- それゆえにAIツールを利用する開発チームでは開発者の好みよりもAIとの相性が良いプログラミング言語が選ばれるようになる
- 多く使われるプログラミング言語はAIによる学習がより強化される
- それによってさらに多くの現場で使われるようになるというフィードバックループを形成していく
- 今年GitHubで最も使われている言語として、昨年まで1位だったPythonを抜いてTypeScriptが1位となった
- その背景にはこうした理由があったとされている
■ 3. AIとの相性が良い言語の特徴
- AIとの相性が良い言語が選ばれやすくなる傾向はTypeScriptに限らない
- Python、Java、Goのようにすでに大量のサンプルコードが世の中に存在し、同時にさまざまな目的に利用できるフレームワークが充実しているプログラミング言語ほど、AIによるコード生成で目的の達成が容易である
- そのためAIによる目的の達成が容易なプログラミング言語ほど、開発言語として選択されやすくなると予測されている
- AI登場以前、プログラミング言語の選択はランタイムとライブラリエコシステム、そして個人の習熟とのトレードオフであった
- しかしAI登場後は新たな制約が表面化する
- それはある言語を選択したときに、それがAIモデルによってどれほどの利点があるか、という点である
■ 4. AIによる適切な言語選択の容易化
- AIの登場は人気のプログラミング言語の人気をさらに増加させる傾向がある一方で、プログラムとプログラムをつなぐ「ダクトテープ」のような役割を担うBashのようなシェルスクリプト言語の利用増加にも貢献した
- それはコーディングの面倒な部分をAIに任せることができるようになったことで、開発者はその言語の好き嫌いよりも適切なツールかどうかを選択基準にしやすくなったためである
- つまりAIは単純にTypeScriptのようなプログラミング言語への人気の集中を招くわけではなく、開発者の好き嫌いや習熟の度合いによって乗り越えられていなかった目的に沿って適切なプログラミング言語を選択することも容易にする
■ 5. 結論
- 開発者はTypeScriptのように特定の言語を学ぶべきというわけではない
- 次の10年で生き残るであろう言語とツールとは、デベロッパーが最も好むものではなく、デベロッパーとマシンの両方が最も利点を共有できるものになるだろう
■ 1. 発表者の背景とテーマ
- 発表者は横山(ハンドルネーム:ゆずたそ)で、風音屋という会社に所属している
- データウェアハウスやデータ分析系の活動を行っている
- 風音屋はデータ分析、データ基盤の構築を支援する会社である
- 昨年「アジャイルデータモデリング」という訳書を出版した
- テーマはExcelデータ分析でディメンショナルモデリングを扱う
- エントリー向けの内容を紹介する
■ 2. データ分析の前提条件
- 構造化データを扱うことを想定している
- 構造化データとは行や列など表形式で表現されるデータのことである
- これは従来のデータベースが前提としている形式で、最も安定してデータを管理利用しやすい
- テーブル(表形式)で管理するデータの関係性を表現したER図がある
- テーブル名と列名があり、Excelで例えるとシート名とその中に並ぶ列のようなイメージである
- 複数のテーブルをIDや識別値で結合していく
- 細かくテーブルを分けていくとデータの更新箇所が最小限で済む
- モデルの書き方として概念モデル、論理モデル、物理モデルといった書き方がある
- 正規化と呼ばれる概念がある:
- データの重複や不整合を防いで効率的に管理するために行う
- いくつか正規化の形があり、その条件を満たすようにテーブルを分解していく
- 第3正規化された状態のことを第3正規形と呼ぶ
■ 3. Excelでのデータ分析における課題
- ビジネスパーソンは以下のような流れでデータ分析を行っている:
- ローデータ(機関システムから出力したものなど)を一旦貼り付ける
- 注文テーブル、商品のシートなどがある
- それらを元にして別のExcelタブで集計を行う
- 最終的に表示したい形式(例:商品カテゴリー別の毎月の注文数)を出す
- この集計データを作ってからグラフに表示する
- 最終的に見たい形は正規化されたものではなく、分析要件に基づいて集計した結果である
- 営業地域別と業種別の切り替えの問題:
- 多くの会社では日々の業務要件に適した形でデータを管理しがちである
- 営業地域ごとに営業署があり、それぞれの中で管理している場合、営業地域別でデータを管理することになる
- 担当エリアがあり、エリアに合わせてフォルダーが分かれている
- 年月ごとにシート分けしている(例:京都の1月、2月、3月)
- この単位で入力するため、入力しやすい形でシステムが作られていく
- モニタリングも基本的には年月と地域の単位で行われる
- 当初は想定していなかった観点(例:業種別)でレポートを作るニーズが発生することがある:
- マーケット環境が変化した時に適用するため
- コロナのような事態が発生した場合、業種別で数字を見る必要が出てくる
- 飲食店などの店頭サービス業での契約が減っている可能性がある
- 逆にこの状態で伸びている業種があるかもしれない
- Excelファイルごとに分かれていると全部のシートを開いて業種の列を抽出していく作業が発生する
- これはあまり現実的ではない
- 当初の要件を満たすテーブルではなく、切り口を柔軟に変更できるテーブルが求められる
■ 4. データ分析における複数データソースの組み合わせの必要性
- データ分析を行う時は複数の元のデータを組み合わせていくことが一般的である
- 例:駅に近い店舗は雨の時だけ注文が上がった/下がったからクーポンを打つ場合:
- 駅がどこにあるのかという情報が必要
- 店舗がどこにあるのかという情報が必要
- 駅に近いかどうかを判定する必要がある
- 天気の情報が必要
- 注文数がどう変わっているかの情報が必要
- これらを組み合わせて使う必要がある
- 駅と店舗は住所が書いてあるが距離を測るには緯度経度が必要になる可能性がある
- 住所と緯度経度を変換するための前処理が必要で、そのための変換データを引っ張ってくる必要がある
- 店舗マスターは社内にある、駅の情報もどこかにある、住所と緯度経度の変換データもどこかにある、天気のデータは気象庁から引っ張ってくるなど、様々なものを集めてきて組み合わせていく
- データは事前に統合されていて一元管理されている方が分析する側からすると嬉しい
- データ基盤という言葉が一部で注目されている
- 複数のユースケースと複数のデータソース(情報源)をリボンのように結びつけていく一連のサービス群がデータ基盤と呼ばれるものである
■ 5. 正規化の問題点
- 正規化すれば解決するのではないかという考え方がある
- シートを細分化して第3正規形などで作る
- 契約の一覧、相談問い合わせ、契約明細、商品一覧、プロモーション一覧、顧客一覧、業種一覧、都道府県一覧、従業員一覧、所属一覧、部門一覧、担当エリア一覧などに細かく分ける
- 顧客の中に業種IDや都道府県IDがあるため、都道府県IDを見ていたところを業種IDを見るようにすれば集計は簡単にできる
- 理屈上は可能である
- ただし使う側(ビジネスユーザー、ITスキルが必ずしも高くないユーザー)からすると使いにくいポイントがある:
- 毎回分析やモニタリングをするたびにER図を読む必要がある
- そもそもER図の読み方を勉強しなければいけない
- 数十枚あるシートを連携していく必要がある
- 毎回その結合時の注意点をチェックしていく必要がある
- キャンペーンの分析をする場合は日付の曜日や祝日を毎回計算する必要がある
- データをどう組み合わせるかを使う時に考える必要がある
- 使う側のリテラシーを求めてしまう
- 分析の時にこれとこれとこれを結合してというのはややこしい
- 結果として使う側がユーザー手元でカスタマイズして結局自分用の使いやすいシートを作ってしまう
- 顧客一覧、業種一覧、都道府県一覧を3つのシートに分けるのではなく、顧客一覧シートの中で列として業種や都道府県の結果も書いてしまう
- これは使われないモデリングである
- 第3正規形が悪いわけでは当然なく、システム作る上で分けていった方がいい場面はもちろんある
- 記入やインサート・アップデートを考えてももちろん正規化の方がやりやすい
- ただし使う側がこうやって使ってしまうことは起きがちである
- 使う側の立場にちょっと寄り添う必要がある
- 最初から使われるこのシートをモデリングする側が提供するのも一つある
■ 6. ディメンショナルモデリングの基本概念
- トランザクションとマスターで分けるとちょうどいい
- ファクト(トランザクションに近いもの、集計対象となる出来事):
- 例:契約シートが1個ある
- これを見ると合計でいくらの契約になったかが分かる
- ディメンション(マスターに近いもの、比較の切り口となる軸):
- 顧客ディメンション:業種別、エリア別の契約金額などの切り口のヒントになる
- 従業員ディメンション:部署別の契約金額や営業成績などに使える
- カレンダーディメンション:今月の契約金額、祝日や曜日によって効果が違うかを見る
- 日付に対して祝日かどうか判定するフラグがあってもいい
- データ分析の場合、日付は結合キーになることがあり得る
- キャンペーンの取り組みと実際に注文があった時を紐付けて、このキャンペーンには効果があったかを判定することがある
- ファクトとディメンションを組み合わせて使えば使うだけで良い
- 契約の件数がどのくらい増えているか減っているかは、顧客のシートと組み合わせて顧客のシートの方で業種や都道府県を切り替えて見ていけばいい
- 使う側の都合だけを言うとこのくらいシンプルだと分かりやすい
- これがディメンショナルモデリングと呼ばれるものである:
- ディメンション(分析の切り口)とファクト(集計対象となる出来事・事実)を提供するテーブル設計手法である
- これらを組み合わせてデータ分析を行う
- 昨年出版した「アジャイルデータモデリング」という本はこれを紹介する本である
■ 7. データ分析の概念的説明
- 緑のキューブがあり、これが売上累計30億円という大きな事実(ファクト、出来事)の塊である
- データを分析する時はスライスしていく:
- いろんな次元にスライスしていく
- この期間での売上という風に切るとそれが2億円まで減る
- さらに製品で切っていくと5000万円まで減る
- さらに店舗という場所で分けていく
- 全体のキューブの中のこの部分まで絞ると800円になる
- これを比較する:
- この製品とこの製品で比べてどうなのか
- 去年と比べて去年調子良かったのか悪かったのか
- コロナの前と後でどのくらい減っているのか
- こうやって分けて比べていくのがディメンション(次元)である
- 多次元で切っていく、分析していくからである
- 実際の例:倉しコム(数年前に上場した新興企業、ECサイトを提供):
- BIツールを使って画面上でディメンションをポチポチと絞り込んでいく
- 直近90日で日時で見たい、モバイルアプリとウェブサイトで分けて見たい、商品のカテゴリーごとに分けたいなどを指定していってボタンを押すと欲しいデータが出てくる
- 使う側は相当楽である
- ファクトとディメンションの組み合わせをポチポチ選んでいけば集計できる状態が使う側だけからすると理想である
■ 8. BEAMフレームワーク
- BEAMとは:
- ビジネスイベントアナリシス&モデリング(Business Event Analysis & Modeling)の略である
- ビジネス上の出来事から要件分析してテーブルを設計していく
- 結果としてスタースキーマ(真ん中にファクトがあって周りにディメンションがある形)を作る
- スタースキーマは星型に見えるのでスターと呼ばれる
- ステイクホルダーと協力しながらブレインストーミングを行ってデータモデリングを進めるアプローチである
- このモデリングは使う人向けのテーブル設計である
- この本ではモデルストーミングと呼んでいる
- BEAMテーブル:
- どんなデータが欲しいのかを具体的に書いていく
- この人がこれをいつここで買ったみたいな情報が欲しいというのをずらっと実際に書いていく
- なるべく具体的に書いていく
- 最大で10年前まで遡りたい、最短で翌日にはデータを使いたい、物販と自社のECと外部ECまで分析したいなどの要件が見えてくる
- 元のデータベースは違う可能性がある(物販の店舗だとPOSレジにデータがある、自社のECと外部ECでデータベースも違う)
- データをどこに保存するかというモデリングをするとこれらはバラバラになるはず
- しかし使う側からするとこれらはまとめて分析したいので同じディメンションに入れる必要がある
- この差が見えてくる
- クリエイト(作成)やアップデート(更新)をするのとは別にリード(読み取り)に特化したモデルがあるだろう
- そのためにはその要件を顕在化するにはどんな風にデータを使いたいんですかというところの分析をする人がどんなデータが来るといいのかという具体例を書いていくことによって隠された要件を暴り出していく
- イベントマトリックス:
- ファクトとディメンションをマトリックスで書いていく
- 縦にディメンション、横にファクトを書いて、その組み合わせをチェックしていく
- これらを使って定期的なミーティングでこれらの中間成果物を更新したりしながら、次はこれを整備していこうかというTODOリストを作ってそれを対応していくサイクルを回していく
- これをアジャイルのプラクティスに沿ってやっていくことによって変化に対応していく
- これがアジャイルデータモデリング(原書タイトル:アジャイルデータウェアハウスデザイン)でアジャイルという言葉を使っている理由である
■ 9. ファクトのモデル化
- 分析対象の構造を確認する:
- ビジネスの構造、業務フロー、業務の流れ、ユーザーの行動などをまず把握していく
- ファクト(集計対象、トランザクションファクト)は以下に分けられる:
- 出来事
- 指標
- 計算方法
- ビジネスイベントの洗い出し:
- モデル化した図からビジネスイベントを洗い出す
- 来店して注文して発送して返品するみたいな流れがある
- 注文と呼ばれるビジネスの中にも指標がある(件数、人数、商品数、金額など)
- さらに計算方法もメリットがあるかもしれない(合計値、1人当たりの注文件数、1商品あたりの注文件数、YoY(去年に比べて今年がどのくらい増えているか)、増加率、増加数など)
- ビジネスイベント:
- ビジネスにおいて発生する出来事である
- この1つ1つのビジネスイベントが繋がってビジネスは実現される
- ビジネスを改善するのはこの1つ1つのビジネスイベントを改善することとニアリーイコールである
- 例:来店を増やす、注文を増やす、発送を早くするなど
- 指標:
- ビジネスイベントを定量的に評価するための指標を定める
- イベントがどうなって欲しいか、どうなると困るかを見ていくと決まるはず
- 件数、人数、商品数、金額、時間、距離など
- 多い少ない、長い短い、重い軽いなどの観点がある
- 計算方法:
- 注文の中にも合計、1人当たり、1品あたりといったものがある
- 場合によってはツールに任せるケースもある
- テーブルとしてモデルに反映するのか、ツールに任せるのかはやり様がある
■ 10. ディメンションのモデル化
- ディメンションは5W1Hで考えると分かりやすい:
- 誰が、何を、いつ、どこで、なぜ、どのように
- ビジネスにおけるデータ分析の場合、分析軸5W1Hで比較することが多いから
- 例:都心の店舗は郊外の店舗よりも客が多い(Where)、今年は去年より注文が増えている(When)、バッグは靴よりも平均単価が高い(What)
- どんな軸で分けて比べるのかを洗い出していく必要がある
- 洗い出しのヒント:
- 業務フローから洗い出すパターン:
- 誰が何に対してどんな作業をいつするのかが見えてくる
- 店頭スタッフという人がいて、各商品の在庫があって、毎日20時お店が閉まった後に棚卸しをするなどが見えてくる
- スタッフ別の切り口で分析をするかもしれない、商品ごとや在庫ごとに分析をするかもしれない、閉店後か閉店前かによって分析の軸が変わってくるなどが見えてくる
- 具体例(レコード)から洗い出すパターン:
- 同じ商品AとBがあった時に両方とも衣類という共通点がある場合、商品カテゴリー「衣類」がある
- サイズで言うと同じ衣類でも夏物と冬物がある場合、販売時期という観点で見ていくとポイントがあるかもしれない
- 一般的に冬物の方が重くて値段が高かったりすることが多い
- 同じレコードの中のレコードの共通点や差異点を言語化していくと、そこがそのまま切り口になっている可能性が高い
- 階層図:
- 同じ商品でもカテゴリーもあればサブカテゴリーもある
- 衣類があれば衣類の中に夏物というカテゴリーがあるかもしれない
- 価格帯も1円単位の価格よりは1万円単位でまとめるとか
- ユーザーや人間も性別と年齢がある
- 性別と年齢は相互に連動しない概念である
- ただし年齢「◯◯歳」と「◯◯代」はここは階層の粒度がより荒いのと細かいのになっている
- 25歳と20代は粒度の関係になっている
- 荒い方から細かい方に直すことはできないが、細かい方から荒い方に丸めることはできる
- 20代から25歳は言えない(26歳かもしれないから)が、25歳は20代であることは言える
- 細かい方で持っておけば荒く出すことはできる
■ 11. ディメンションテーブルの具体的設計
- 商品ディメンションの作り方:
- 使う側が便利なExcelを作ろうとしたらどうなるか
- 正規化しない状態でどうやって作るか
- 価格という1円単位の列があった後に価格帯1万円単位という列も作っておく
- 27円みたいなのが次は「1万円台」という値が入る
- カテゴリーとサブカテゴリーがあるなど
- 横に必要な粒度で集計できるように1番細かい状態を持たせておきながら、必要な粒度があるんだったらそれも集計できるようにしておく
- カレンダーディメンションの考え方(よくある質問):
- 8月1日13時29分11.55秒をディメンションテーブルでどうやって切り出すか
- ディメンションは単に5W1Hで切ったものではなく、あくまで分析軸である点がポイント
- 0.55秒であることを軸にして何かカウントしたいか集計したいか→大抵の場合ノーである
- たまに工場の産機器や自動車の機器が特定の時にだけ変な挙動をする可能性もあるかもしれないが、それは分析定義はアドホックで都度個別的にクエリを書いた方が良く、毎月毎月Excelシートで役員たちがモニタリングをするのとは違う
- これであればテーブルとして用意するのではなく都度仮説があったらデータを直接見る方がいい
- 8月1日であることを軸にしてカウントしたいか→イエスである(ケースバイケースだが、こういったケースが多い)
- 日付からロールアップして、8月は例年売上が高い、この月曜日は、夏は毎年こうだ、この曜日は毎週こうだという特徴があるかもしれない
- 8月1日を軸にしてこういったいろんな属性をつけていくことはあり得る
- カレンダーディメンションを作っておいて日付ごとに1レコードのテーブルを作っておくのは1つのプラクティスとして有効である
- 13時であることを軸にしてカウントしたいか→三角(UELか)くらいである
- 飲食店だったらこの昼の時間帯や13時代の客数を集計したくなる可能性はある
- シフトを決めるのにどのくらい来るのかによってシフトを決める必要があるから
- 大きな経営計画を立てる時にざっくりとした推定を行うにはこういった情報があった方がいいかもしれない
- ただしこれは8月1日とは関係なくはないかもしれないが、ちょっとまた別の文脈である
- やるとしたらカレンダーディメンションとは別に時計ディメンションを作っておいて日付を付与しないで何時何分だけ持たせるのが1個テクニックとしてはある
- 分析の粒度でこれを本当に1時間単位にするか、細かく1分単位にするか、10分単位や30分単位にするかは分析の粒度に合わせて調整していくのが現実的である
- 5W1Hに囚われるというよりは分析軸を意識して設計する
■ 12. アジャイルデータモデリングの必要性①チームの変化
- チームが変わるからデータモデリングを変えていくことが大事である
- 仮想ケースの例:
- 刑人(経営者):データをモニタリングできるようにしたい
- コンサルタント:ERPを整備しよう、収支や在庫などの経営資源を管理するのが重要
- 取締役:リソース調整はできるようになったが、もうちょっとビジネスを成長させるための中身の話をしていきたい
- 事業部長:うちのメインの事業、Web経由の申し込みで結構予算達成が左右される、ここを見た方がいいんじゃないか、事業成長のエンジンをウォッチするのが大事
- マーケティング担当:アクセス解析ツールで見ましょう、どこの工程で止まっているのか、どの経路が活発なのか見よう
- 経路5はすごく調子がいい、経路3は割と早々に工程2で止まってしまう
- 経路3は一旦捨てて経路5に集中しようという会話ができる
- この日人気YouTuberが商品言及してくれた、SNSですごい話題になった
- アクセス解析ツールを見ると指名検索(商品名で検索してきている)であることしか分からないが、YouTuber効果なんじゃないか
- そしたらもうYouTuberとガンガンコラボしたり広告出した方がいいんじゃないか
- SNSの投稿なども含めていろんな関連データを社内外横断して見たい
- それをできれば社員全員がモニタリングしてどんどん仮説を回していきたい
- データエンジニアやソフトエンジニアがそういった基盤を作ってマーケティング担当がこれを見ながら全社員マーケティングやってくぞという動きになってくるかもしれない
- 会社全体で追うべきデータは当初の想定とはだいぶ違ってくる
- チームが何を重視するかは本人たちでも事前には予測できない
- 当然見るべきデータも変わってくる
- 見るべきデータが変わるということは、データをどこに保存するかを一旦置いといて、どうやって見るか、データを分析する時にどういうデータの形式だと使いやすいかという使う側のデータモデルのあり方は少なくとも変わってくるはず
- アジャイルな仮説検証サイクルは大事だが、今どんなデータがあるといいんだっけというのを言語化して、それを実装してデータを整備して分析してまた色々見えてくるので要求が変わってまた反映していくというサイクルを回す
- このデータモデルを継続的に改善するというサイクルを回して要求の変化に対して迅速に対応していく、適用していくのがポイントである
- だからアジャイルデータモデリングである
■ 13. アジャイルデータモデリングの必要性②ビジネスの変化
- ビジネス自体が変わる話をする(仮想ケース、あえて極端な話):
- 自動車メーカーからゲームメーカーに転進することがあるかもしれない
- 乗り物の部品を作っている町工場のメーカーがあった
- 売上は堅調だが物価高等で苦しくなってきた
- 主要販売先や銀行からプレッシャーを受けている
- 反応を拓の位置を下げるために展示会で新素材を体験してもらおう
- デモンストレーションとして体験型の運転シミュレーションゲームをセットで設置した
- ものづくり好きな技術者が最高のクオリティに仕上げてしまった、レベルが高すぎる
- 展示会にゲスト参加した海外の著名人がSNSで言及して世界中で話題になった
- 試しにゲームを販売したら世界中で飛ぶように売れる
- しかも円安でソフト産業は限界利益が少ない、部品に比べて収益率がすごい高い
- 本当に黒字赤字ギリギリみたいな状態だったら部品の利益を超える可能性もある
- 部品メーカーとして20年使えるはずのデータモデルを設計してERPを導入したところが、今ゲームメーカーとしてどんどん伸びている
- どっちかっていうとゲームのプレイヤーの利用状況やSNSで話題になっている箇所、どこがスクリーンショットで取られているのかを分析する方が実は重要になってくる可能性もある
- さらにCG制作会社、芸能プロダクションになってくることもあるかもしれない
- 物の珍しさで最初はゲームが売れたが、徐々に売れなくなってくる
- むしろ他のゲームメーカーからゲーム内の乗り物のCGを作ってくれないかという相談を受ける
- CG制作会社として大活躍、めちゃくちゃ細かいところまで作り込んでいる
- ゲームだけではなくて映像作品、世界中の映像作品でも引っ張りだこになる可能性もある
- 日本のアニメーション映画が全世界でヒットしているというトレンドに乗って、海外のあらゆる映像関係者が注目するような会社になるかもしれない
- CG制作会社としてモニタリングをすることになるかもしれない
- 映画特集のテレビ番組に社員が出演する、社員の対応が結構いい感じで俳優じゃないかということでまた話題になる
- 各局に呼ばれるかもしれない、結果芸能プロダクションとして有名になる可能性も0じゃない
- 芸能プロダクションとしての形態のモデルになってくる
- 実際にビジネスは結構変わっている:
- 旗売機を作っている会社が自動車を作り始める(トヨタ)
- アニメーション映像を作っている会社がテーマパークも作り始める(ディズニー)
- 花札を作っている会社がビデオゲームを作ってストリーミング販売に対応していく(任天堂)
- 広告の雑誌を作っている会社がPOSレジや結婚相談を始める(リクルート、結婚相談はこの間やめることが発表された)
- 専門書の物販を行っている会社がデータセンターを建設する(Amazon)
- 進学塾を提供していた会社がホテルなどの不動産事業に切り替える(四谷と呼ばれる会社)
- フリマアプリを作っている会社が決済アプリを作る(メルカリ)
- メルペイの立ち上げは1年間で決済を立ち上げる、毎週毎週加盟店が増えていく、当然加盟店ごとにスキームや契約のスキームは違うだろうということでめちゃくちゃ大変だった
- 発表者自身がこれを体験したからこそすごく思うことがある
- マーケットやビジネスが変わり続ける
- 10年後、20年後本当に未来を見通せるんだったら皆様今頃億万長者になっているはず
- そうじゃないんだとしたら自分は10年後、20年後読み通せないと思っていた方がいい
- マーケットやビジネスが変わり続けるという中で当然ながら見るべきデータも変わる
- 当然ながらそうするとデータモデルも変わる
- 継続的に要求を見直して設計を見直してモデリングを見直してそれを実装して整備して分析してまたサイクルを回すのが大事である
■ 14. AIエージェントとディメンショナルモデリング
- 生成AIによってデータ分析の自動化がすごい楽になりつつある:
- ジュニアの分析者よりも正確だし、シニアの分析者よりも安いし早い
- クロードデスクトップといったツールでデータを繋いでやっていけばそれっぽいレポートをすぐに作ってくれる
- BIツール上の対話エージェント機能なども提供されている
- 生成AIがデータを正しく使うにはやっぱりデータの整備が必要である:
- 社内の売上テーブルが50個あったらどの売上で分析すればいいか判断できない
- 売上って何なのか(消費税含むのか含まないのか、途中解約ってどうやって計上するのか、年間契約って月で割り算するのか、割引ってどこで引くのか、返金って後で引くのかそれとも遡って引くのか、通販サイトやアプリ決済の場合決済手数料ってどうやって管理するのか)
- 年間契約の場合、ある分析では今年の今月の売上すごい伸びていると報告しても、別の売上別の分析では月割で割り算したら半分になる
- AIが生成した2つのレポートを見比べると今年の今月の売上が10倍近くずれる
- これは話にならない
- ファクトとディメンションのテーブルが用意されているといい:
- ここに売上テーブルがあり、カラムで消費税データを管理すると嬉しい
- ファクトとディメンションのテーブルは用意されている
- この時点でディメンショナルモデルだとAIは理解してくれる
- この形式を見た瞬間に、これはディメンショナルモデリングで作られたテーブルだと気づける
- こういう集計をするにはファクトのこれとディメンションを組み合わせて使えばいいんだろう、集計対象がファクトだろう、切り口がディメンションだろうということに気づける
- このIDの列で結合すればいいんだろうということが判定できる
- 割り算とか消費税抜きとかという列が仮にあると、こういった条件だったらこれを見ればいいんだろうということが見えてくる
- AIが事業年度を多分日本の企業は4月から翌年3月なんじゃないですかって推測するんじゃなくて、事業年度列が既にあったらそれを使えばいい
- 整備されているほどデータ品質が安定する、データの分析の品質が安定する
- そうすると従業員がカジュアルに生成AIに頼れるようになってくる
- 実際の事例:
- MicrosoftのPowerBIというBIツールを使う場合はディメンショナルモデリング(スタースキーマ)を結構前提としている
- コパイロットの機能を使う場合も当然その前提である
- メルカリ社のソラテスという分析のAIエージェントは、ベーシックテーブルと彼らが呼んでいるテーブルに依存して、このテーブルだけは見るようにという整備をしている
- データ活用の課題:
- 活用効果が期待以上となる要因としてデータ品質が日本・アメリカ共に2位として上げられている
- 国内686社の調査でデータ活用の課題として、セキュアな量を備えたデータの取得・整備ができないことが言われている
- オラクルの2020年の調査で、データが細分化されていて使いにくいということを世界のグローバルの670人のテクノロジー部門の上級決定者とCO的な人達のうち73%が答えている
- シングルソースオブトゥルース(信頼できる唯一の情報源):
- ここを見たら一旦ここを見ればいいんじゃない、ここを見たらデータを分析できるんじゃないという信頼できる軸がある���いい
- 全体売上と言ったらこの箱を見る、こういった切り口で見ていくと見れるというのが概念としては必要なはず
- 画面のイメージで言うとポチポチボタン押していくと欲しいデータが取れるになっていると使いやすいはず
- データパイプライン:
- ファクトとディメンションを作るのはいきなりこれで作るんじゃなくて、機関システムなら機関システム、SNSならSNSからのデータ、スクレイピングしたデータなど各データがあるはず
- それをやっぱり一元で前処理をして集計ロジックをかました上でファクトとディメンションを作っていく
- これは使う側(理由側)のモデルとビューに分けるとしたら、こっちがモデルでこっちがビューみたいな感じ
- DDD的に言ったら永続化とプレゼンテーション層と言ってもいい
- 今回はこっち(ファクトとディメンション)の話をする
- これを作るにはこれらのデータを組み合わせて作っていく必要がある
■ 15. 本書で扱わなかった内容
- 今回はエントリーの内容なので取り扱わなかったポイントがいくつかある:
- 実際にファクトとディメンションをどんな風に設計するのか例をいっぱい知りたい
- 今回ファクトが1個あってディメンションが周囲にあるという紹介をしたが、叩いたの関係もあるはず
- マスターの値が変わる場合(ユーザーが静岡から東京に引っ越した場合、そのままマスターを上書きしちゃうと去年の購入が静岡じゃなくて東京に計上されてしまう)どうするのか
- これらの回答は「アジャイルデータモデリング」の本に書いてある
■ 1. 発表者の背景と取り組み
- 発表者はVALUソースという会社を経営している
- 要件定義とシステムの可視化を行っている
- 最近はAIを使った要件定義に注力している
- いかにして要件定義をAIでやらせるかを毎日取り組んでいる
■ 2. AIで要件定義を行う際の前提条件と課題
- 前提条件:
- AIは個別の企業のことを何も知らない
- 3つの課題:
- LLMの出力をいかに理解するか(最も大きな問題である)
- ある程度少量のデータで大量に出てくるため、どうやって理解するかが問題である
- AIに適切なコンテキストをどうやって用意するか
- 中規模から大規模なシステムでは最初の入力だけではどうにもならないため、軌道修正しながら最終的な要件に組み立てていく必要がある
- 軌道修正をどうするかについて一つの形が見えてきている
■ 3. 課題解決のアプローチ
- 初期要望の入力:
- ビジネスの背景や概要などの初期要望を入れてAIに要件定義させる
- 要件のビジュアライズ:
- 文章だけではなかなか理解できないため、様々なものの繋がりをビジュアライズする
- 画面の確認:
- 画面を中心に話をすると要件的にも進みやすい
- LLMが出した出力から各アクター別にどんな画面になるのかをすぐに確認できるようにする
- LLMが出したものがどういうものなのかということを理解するために用意している
- 要件の妥当性検証:
- AIが出してきたものが本当に現場に適用できるのかを検証する
- 環境を入力してそれで妥当性検証を行う
- 論理データモデルの活用:
- 論理データモデルを出して、論理データモデルから要件を突き上げて正しいのか判断する
- 中心となるモデル:
- 要件定義における要件には構造があると定義している
- その定義に従ってAIを作業させる
- モデルの周りにビジュアライズ、画面出力、論理データモデル作成などが付随している
- 最終的にAIが出した要件を確認していく
■ 4. 入力サンプルの内容
- システムの概要を入力する:
- サンプルとして訪問介護のシステムを使用している
- どんな背景なのか、要求、ビジネスポリシーなどを記述する
- ビジネスパラメーター(介護会員のランク、サービススタッフの働き方の種別など)を記述する
- 業務概要を記述する
■ 5. 実装方法の変遷
- 昨年の実装:
- プログラムでAIを使って要件定義させることをトライしていた
- プログラムからAIのAPIを呼んで要件定義させて保存するという流れを何フェーズかに分けて実行していた
- 現在の実装:
- 昨年の暮れからエージェントがすごいことになり出した
- プログラム作成では全然追いつかないと判断した
- 要件を定義することに関しては全てエージェントにやらせることに方針転換した
- 動作環境:
- カーサーを使用している(クロードコードやCLIツールでも可能)
- フェーズが4つあり、フェーズごとに出力される
- 徐々に出力を厚くしていくやり方をしている
- 実際の出力には2〜3分かかる(デモは10倍速)
- 現在の能力:
- モデルがかなり賢くなっているため、ほぼほぼ全てAIで要件定義できるレベルになっている
■ 6. ビジュアライズ機能
- 全体俯瞰:
- AIで出したものをビジュアルに表現している
- 業務とコンテキストが表示される
- コンテキストを選ぶとその中にどんな情報があって、どのケースと繋がっているのかが出てくる
- 情報の表現:
- IDを中心としてある程度具体的なエンティティを出す
- 細かいものは出さず、ビジネスで認識しているIDを情報という形で出している
- この関係付けもAIが行っている
- 様々な視点からの確認:
- 訪問介護スタッフを選ぶと、その訪問介護スタッフを中心にどういう画面を使っていて、その画面はどのケースに繋がっていて、そのユースケースはどの業務でどのアクティビティなのかが全部俯瞰して見える
- 1つのアクターに多数の画面がついている場合、ロールが足りていないことが分かる
- 1つのロールでそんなに多くの画面を扱うことは普通ないため、ロール見直しの必要性が判断できる
- 画面が多すぎる場合、システム化する必要がないのではないかという議論もできる
- 状態遷移の確認:
- 状態遷移があり、この状態遷移に関わるユースケースは何があるのかが見える
- この状態は本当に役に立っているのか、この状態を実現するための情報は何なのかという話もできる
- 活用方法:
- 1回AIでガーっと出すとこのビューを使って様々に分析しながら本当にこの要件でいいのかを考えていく
- AIに引きずられているような感じになるが、AI要件定義そのものはもうAIでできることが分かったため、いかに理解するかが重要になっている
■ 7. 画面イメージの生成
- アクター別の画面を作成する:
- 具体的にその画面でどういうことが行われているのかが分かるように、AIにアクター別の画面を作らせる
- 介護スタッフを選ぶと介護スタッフの使う画面が見える
- イメージではあるが、この介護スタッフはどういう業務でどういうビジネスケースでこの画面を使うのかをイメージしながら要件定義をしていく
- アクターごとに確認しながら使っていく
■ 8. VGモデルによる妥当性検証
- 左側(要件生成):
- フェーズ1234の4つのフェーズでAIが出力したものを作成する
- 右側(妥当性検証):
- 本当にその要件が妥当なのか、このままシステムとして導入して役に立つのかを検証する
- 検証方法:
- 対象システムの拠点やアクターにどういう制約があるのかを入力する
- この制約と組み立てた要件をぶつけて妥当性を検証する
- ある程度その環境を入力することによってAIが生成した要件が妥当なのかどうなのかを判断する
- 検証結果:
- 色々と出てくるが、感覚的には60点ぐらいである
- 重要度や改善提案がやたらに出てくるが本当かなというものもある
- ただし出力された要件を見直すという意味においては、VGモデルの右側からどういう環境にシステムを入れるのかを入力するのは結構有効である
- そもそもこの入力を作るという行為そのものがかなり重要であり、これで現場というものを強く意識できる
■ 9. 論理データモデルとビジネスルールの生成
- ビジネスルールの叩き台:
- 要件として出されたビジネスルールの叩き台を作る(正式なものではない)
- ラドラという手法では条件という名前のものがビジネスルールを表す
- スキルマッチング条件があった場合、それはどのケースから呼ばれていて、その条件はどういうサービス種別やスキルレベルなどのバリエーションに繋がっているかが書かれている
- この条件からビジネスルールを作ってくれとAIに言うと叩き台が出てくる
- 実際の仕様においては、仕様化の時にこの形式で本当にいいのか、もうちょっと違った形でビジネスルールをきちっと書いていく
- 叩き台があるだけでかなり見通しは良くなる
- 論理データモデル:
- 要件から論理データモデルを作ってというとそこそこの論理データモデルが出てくる
- データモデルの得意な人はデータモデルを見るとかなり業務が分かる
- こちら側から今回の要件が妥当なのか、ピントがボケているなどが判断できる
- 論理データモデルが読めない・苦手という方は、エンティティの役割と他のエンティティとの関係からこの論理データモデルのできることや役割を分かりやすく説明してとAIに訊ねると、それなりに説明してくれる
- 分かりにくい場合はさらに質問すれば分かってくる
■ 10. 適切なコンテキストの提供
- 重要性:
- コンテキストとして生成したものを積み上げていくことが大事である
- 4つのフェーズの構成:
- AIが要件をどう組み立てていけばいいのかというナレッジをあらかじめ入れている
- IDEではラドラナレッジというところに各々フォルダーを切ってその中に様々なプロンプトなどが入っている
- 人が行うこと:
- 基本的に人が行うことは初期の要望を書くことである
- それでフェーズごとに実行して出力された内容を見直して、また次のフェーズに行くことを繰り返していって洗練化する
- 軌道修正:
- AIが出した出力を人間が見直して軌道修正する
- 細かく見て直すというのは人間にとってかなり負荷が高いため、明らかに違うということだけ直す
- いらないものを基本削除するという方向で修正していく
- 実際の運用:
- 最初に初期要望を入れて1回動かすと解像度が悪い感じになるため、この初期要望を見直す
- ある程度こんな感じかなと思ったら次からどんどん次に行く
- 当初はフェーズ1見直したらフェーズ2、フェーズ3と思ったが、人間の負荷から言うとフェーズごとに見直すのはかなり耐えられない
- 今は初期要望と最初のフェーズを繰り返したらあとは一気に最後まで行くという感じである
- 一気に最後まで行って要件として組み立てたら、その後でビジュアライズしたもので色々な角度で見直して再度生成し直す
- その方が楽である
- 最終確定:
- AIで出されたものはどこまでも叩き台である
- 最終的にはラドラという手法の形式で出して人間が最終的に要件を確定するというやり方をしている
■ 11. モデルベースのアプローチ
- ラドラという手法の構造:
- 要件には形がある、構造があると規定している
- 4つのレイヤーがあり、各々要素があって、その要素が全部繋がっている
- 右から左に依存するという構造を持っている
- 右の要素は左の要素がホワイトになっている
- 左の要素がこうだから右の要素はこうだという考え方である
- クラス図による表現:
- この構造をクラスで表すことができる
- この構造に従って要件を定義させるので連続的に要件が定義できる
- 段階的なモデル構築:
- 最終形に持っていくために段階的にモデルを組み立てる
- 徐々にオブジェクトを増やして関係付けすることを内部で行っている
- AIで出力されるのは表形式だが、内部ではこれらが全部完全に繋がり合っていてオブジェクト構造として持たれている
- 詳細なレベルから俯瞰したレベルまで見ることができる
- 画面生成の仕組み:
- このオブジェクト構造があるため、定義されたオブジェクト構造から画面用のアクター、画面、項目という構造に変換する
- 当初これをエージェントで変換していたが、こんな決まりきったことをエージェントでやるのはトークンが無駄だと判断した
- エージェントにプログラムを作らせるようにしている
- この構造のものをこっちの構造にしてくれという構造変換のプログラムを作らせる
- プログラム変換させたものをJSONとして出してこのJSONを画面が読んで生成されたものの画面をアクター別に出す
- モデルの言語化:
- クラス図の1個1個のクラスと関係を言葉で定義している
- アクターとはこうだ、業務とはこうだということを書いて言語化している
- これを食わせている
- 実際には表形式で出ているため、表形式はダイアグラムの関係性を表として再現できるようにしている
- この表の構造も全部言語化して、こういう繋がりはこういう表で出力してくれということを全部書くことによって出力される
■ 12. まとめと提供サービス
- IDEの活用:
- IDEの中であらかじめナレッジをモデルベースで入れておく
- 初期の要望をファイルに入れて実行すると要件定義が生成される
- 複雑なタスクへの対応:
- 要件定義みたいな複雑なものはまずフェーズに分ける
- フェーズごとのナレッジを作る
- フェーズごとの成果物のフォルダーを用意する
- 成果物のフォルダーがAIに渡すコンテキスト情報になるため、それを見直すことによって軌道修正してちゃんと辻褄の合った要件定義に持っていく
- 無料相談の提供:
- 要件定義や家の設計など創造的で難しいところをどうやったらAIでやれるのかを悩んでいる方向けに無料相談を提供している
- XのアカウントにてDMで相談を受け付けている
■ 1. ドメインモデルの定義と階層
- ドメインモデルの基本概念:
- 現実世界の複雑さを抽象化して表したものである
- 枝葉となる環境や実装技術に依存した部分を切り落として業務の本質的なコアの部分を抽象化したものである
- ドメインモデルの3つのレベル:
- データベースやデータモデリングに概念モデル、論理モデル、物理モデルというレベルがあるように、ドメインモデルにも概念モデル、仕様モデル、実装モデルというレベルがある
- この区別は2000年頃の論文「Modeling with sense」(マーティン・ファウラーのサイトに掲載)で提唱されている
- 現状の課題:
- 実際にはこの仕様モデルと実装モデルがあまりはっきりした区別をされずに今まで来ている
- ドメインモデルは抽象概念なので仕様レベルでの話が重要である
- しかしオブジェクト指向プログラミングのエッセンスなど実装の都合や技術都合に引きずられてどう実装するかの話で片付けられることが多い
- DDDも実装論ばかりされているように見える
■ 2. 仕様モデルの定義
- 仕様モデルの役割:
- ソフトウェアシステムが何をしなければいけないか、どのような情報を保持しなければならないか、どのような振る舞いを示さなければならないかを定義する
- 端的に言えばデータと振る舞いを定義する
- 仕様ドメインモデルの構成:
- 仕様ドメインモデルは工学的な抽象レベルで記述された業務のデータと振る舞いで構成される
- 主にはデータと振る舞いで構成されるものである
■ 3. オブジェクト指向と関数型のドメインモデリング
- オブジェクト指向のドメインモデリング:
- データと振る舞いの関係性をマッピングしていく
- 行列を並び替えながらうまいことクラスだったっぽいものを見つけてクラスとして整理していく
- クラスターの決め方は自由度が高い
- 人によって設計できる人と設計できない人のばらつきが出る
- 関数型のドメインモデリング:
- 基本的には同じであるがそれぞれの振る舞いができる限り全域性を満たすようにする
- 対象とその全ての入力データに関して定義できない振る舞いは実装しない、別の振る舞いにするかデータ型を分ける
- 例外を発生させないように振る舞いやデータを調整していく
- 全域性を保つことで組み合わせ可能性(コンポーザビリティ)が高まる
- 本質的な違い:
- 仕様ドメインモデルのレベルでは本質的な違いはない
- オブジェクト指向の方が自由度が高い
- 関数型モデリングはさらに全域性を保つなどの制約が加わるためより厳密になる
■ 4. 仕様モデルの記述方法
- 従来ツールの問題:
- 従来のモデリングツールでは仕様のモデルを書いているのか実装のモデルを書いているのかが曖昧である
- モデル駆動開発(MDA)で仕様書いたらそこからコードがジェネレートされるという夢の世界の影響があった
- 実装モデルに近い設計要素が入ってしまっている
- 記述のアプローチ:
- 従来のツールは一旦置いといて純粋にデータと振る舞いだけを書き出すことにフォーカスする
- DSL的に簡単なシンタックスで記述する
- データの定義はデータ型で名前をつけて何から構成されるかを書く(代数データ型と同じ)
- ANDで直積とORで直和を使ってデータと振る舞いを表していく
- データ定義の例:
- データはANDで複数の要素を組み合わせる
- ORで複数の選択肢から1つを選ぶ(例:連絡先はメールアドレスか電話番号か住所)
- 振る舞いは基本的に入力から出力への変換である
- 入力のデータとそれが出力のデータとして何が出てくるのかを定義していく
■ 5. 抽象化の重要性
- 振る舞い抽象:
- 実装の詳細を知らなくてもその振る舞いが提供する機能を利用できることである
- 実装の用語で言えばインターフェースに対して実装していくことと同義である
- データ抽象:
- 対象のデータの詳細を知らなくてもそのデータに対しての振る舞いを実行できることである
- 仕様モデルの要件:
- 仕様モデルはこれらの振る舞い抽象とデータ抽象でなくてはならない
- 振る舞いがない場合は実装の詳細を仕様として書いてしまいがちである
- SI現場で見られる詳細設計書のように実装レベルの処理順を書いてしまうと、中身の実装を全部知らないとロジックを安全に呼び出せなくなる
- プログラム修正においても詳細全部を知らないと何も修正できなくなる
■ 6. 仕様記述の要素
- バーバラ・リスコフの手続き抽象の仕様構成要素:
- 入力と出力(データ抽象が入力と出力になる)
- Requires(事前条件):入力が受け付けられないものがある場合にその条件を書く
- Modifies(変更条件):中で書き換えられる入力があったらそれについても書く
- Effects(効果):入力についての書ききれない振る舞いの詳細を書く
- 良い仕様の3つの条件:
- Restrictiveness:使う側にとって受け入れられない実装が全て排除されていなければならない
- Generality:受け入れられる実装を仕様として排除してはならない(実装の選択肢を勝手に削らない)
- Clarity:仕様の読み手がその意味を十分理解できること
■ 7. 全域性の追求
- 全域性の定義:
- 取りうる入力の全てに対して対応する出力が必ず存在することである
- 全域性の実現方法:
- 振る舞いが受け入れられない入力を仕様として示すのではなく、型として調整する
- 例:割り算で除数が0ではないことをRequiresとして仕様に書くのではなく、NonZeroInteger(0を除いた整数)という型を定義する
- これにより自然言語として書かなければいけない仕様が少なくなっていく
- ステータスの問題:
- ステータスは全域性を損なうサインである
- 注文ステータスがあるということは、そのステータスによって適用できる振る舞いが違うことを意味する
- ステータスではなくデータ抽象で表すことで適用できる振る舞いの条件が明示される
- 仕様レベルではステータスがなくなるようにデータ抽象を作っていくことが重要である
■ 8. 実装の選択肢を残す
- Generalityの実現:
- 良い仕様は実装者が要求を満たす上で最も最適な実装が選べるように最大の選択肢を残してあげなければならない
- SI現場では実装の話まで仕様にたくさん書いてしまいがちである(例:ループ処理、データベースアクセスの方法など)
- これは性能問題に直結する
- データ抽象の適切な設計:
- テーブル駆動で設計するとデータ抽象が適切に設計されないことがある
- 例:受注生産の場合だけサプライヤーIDが入るという仕様で、このフィールドがNULLかどうかで受注生産商品を判定するロジックが各所に埋め込まれる
- これは抽象が漏れ出している(Leaky Abstraction)状態である
- 対策はデータ抽象をちゃんと分けること(通常商品と受注生産商品を別のデータ型にする)
■ 9. Clarityの向上
- スタンプ結合の廃止:
- 入力のデータの全部をその振る舞いで使うわけではないことがよくある
- 大きなデータを渡しがちだがそうするとテストしにくくなる
- 使ってないデータに依存した振る舞いがあるので修正時の影響調査が必要になり修正コストが高くなる
- データ抽象の粒度が大きいと何をやっているかが分からなくなる
- ビジネス不変条件の保証:
- 仕様としてのデータ抽象はビジネス不変条件をちゃんと保証するものでなければならない
- 例:チェックイン日はチェックアウト日よりも前の日付でなければならない
- これを型として明示しておくとより不変条件が明らかになる
- バラバラのフィールドではなく「宿泊」というデータを別に作り、それを「日付の範囲」として定義する
- 単一責務の原則:
- 振る舞い抽象は単一責務でなければならない
- 複数の責務が混ざっている振る舞いは正確に名前に反映させることで発見できる
- 名前に「〜の場合は」「〜をして〜をします」「そして〜をします」(英語だとAND/OR)が入る場合は複数の責務が混ざっている
- 正直正確で完全な名前を一回つけてみて、そこにAND/ORが繋がるようだったらそこで分割する
■ 10. 仕様モデルから実装モデルへ
- 良い仕様モデルの条件:
- スタンプ結合を除去する
- 振る舞いが全域性を持つようにする
- 振る舞いを単一責務にする
- これらは疎結合や高凝集を目指す良い設計と全く同じ話である
- これを仕様レベルでちゃんと保とうということである
- 実装モデルへの変換:
- 良い仕様ドメインモデルが書ければ実装言語に合わせて実装ドメインモデルにエンコーディングすればよい
- データと振る舞いをクラスごとに整理するのがオブジェクト指向言語向けのドメインモデルである
- データを型に、振る舞いを関数にエンコーディングするのが関数型のドメインモデルである
■ 11. 開発アプローチの転換
- アウトサイドイン開発の問題:
- 現状のSI現場で多い開発スタイルはアウトサイドイン開発である
- 業務コアの概念が分からないまま画面設計書を作り、テーブル設計を作り、そこで開発をスタートする
- 外側(実装の詳細)から詰めていって中(業務コア)に向かって開発を進めていく
- 仕様モデルを書く隙間がこのプロセスにはない
- 結果として配線プログラミング(画面項目とデータベースのマッピング線だけ設計する)になる
- システムの理解容易性と変更性が低下しやすい
- インサイドアウト開発への転換:
- 仕様モデルをちゃんと書いて、その仕様モデルに沿ったプレゼンテーションのモデルや永続化のモデルを書いて画面と繋げていく
- インサイドアウトの開発にすべきである
- 仕様モデルがちゃんと書けていればこの外側に向かってコードを書く部分は生成AIがうまいことやってくれる
■ 12. 仕様モデル駆動設計
- 従来の仕様駆動開発(SDD)の問題:
- 仕様として何が必要かという定義がない
- 従来の開発延長線上に仕様駆動開発をやってみようとなるとアウトサイドインになる
- AIが勝手に想像して変なコードを出してしまう
- 仕様モデル駆動設計の提案:
- ちゃんと仕様モデルを先に書いてインサイドアウトで開発すると、当然ながらそのモデルが先に作られている状態である
- AIはそれをちゃんと理解した状態で画面やDBにマッピングしてくれるので割と綺麗に作ってくれる
- これを仕様モデル駆動設計と呼んで広めていく
■ 1. ワークショップ1:モデル駆動設計の実践
- 開催概要:
- 講師は増田氏と佐藤氏である
- 先週月曜日に4時間(13時から17時)で開催された
- 会場はNEC本社を借用した
- ワークショップの内容説明15分、モデリング3時間、増田氏によるレビュー45分で構成された
- 2人から4人のテーブルに分かれてワークを行い、30分に1回程度全体で議論した
- 参加者属性:
- 申し込み者数は26人で当日参加が23人、アンケート回収数が15である
- システムエンジニアとプログラマーの方が多数を占めた
- 現業務現場でのモデリング経験がある方が66.7%で、3人に2人はモデリング経験がある
- UMLの利用経験が3年以上の方が40%、1から3年が26.7%、1年未満が20%で、約80-90%がUML利用経験を持つ
- ワークショップの内容:
- モデル駆動設計とはという導入部を6個のスライドで説明した
- 調整さんのようなものをテーマにルールをコードで記述することを課題とした
- シンプル版として特定の日付に決定するルールをプログラミング言語で表現することから始めた
- 終わった方から段々ルールを複雑にしていくことに取り組んだ
- 参加動機:
- 講演内容に興味があった(モデル駆動設計)
- 講演者に興味があった
- モデリング技術に関する最新情報収集のため
- 会社からの案内、UMTPのメールとホームページ、川島氏のXのポストが情報源となった
- 満足度と使用ツール:
- 非常に満足と満足を合わせて73%の満足度があった
- 使用ツールはJavaが10件、Goが5件、UMLが5件、C#、Python、Ruby、Mermaidも使用された
- プラス評価:
- 最後45分間の増田氏による3人の方の実際のコードレビューが非常に良かった
- グループで30分に1回程度どういう風にやっているかを話した際の意見や解釈、感覚を共有したのは収穫であった
- 調整さんの表から分かる表からモデルコードに落とし込む作業が予想以上に大変だったことを体感できた
- モデルをコードで表現するという観点を強く意識する機会となった
- 4時間集中して取り組む時間になった
- 改善点:
- 増田氏ならどのような実装になるのか見てみたかった(あえて模範回答を用意しない方針だった)
- 増田氏のレビューを受けたかったのでレビュー時間を長くして欲しい(45分でも足りなかった)
- コードによるモデリング方法の具体的な説明がなくモデル駆動設計の解像度が上がらなかった
- モデル=コードという考え方が伝わらなかった
- コードではなくても(図などで)レビューして欲しかった
- チーム分けで得られるものが異なり、テーブル内で同じような接近になってしまった
■ 2. モデル駆動設計の核心概念
- モデル=コードの原則:
- 今回のポイントはコードでモデルを表現することである
- モデル=コードが理解して欲しいポイントである
- ドメイン駆動設計(エヴァンス本)では「モデルと設計の下」において、モデルと設計及びコードを単一の活動として改良し続けることを説明している
- 1つ作ればモデルにもなるし設計にもなるというのがポイントである
- モデルで表現すべきもの:
- 事業、業務、業務ルール(ビジネスルール)をコードで表現してモデルにもなる
- テクニックとしてDDDで語られているエンティティ、値オブジェクト、ユビキタス言語を使った命名などがある
- モデルとコードの乖離:
- 手続き型で処理順に書いていってしまうとモデルとコードが乖離していく
- 実際に多くの参加者のコードでこの乖離状態が見られた
- 実装が進んでレベルの高い方でもこの問題が発生していた
- 具体的な問題点:
- 重要概念がクラスではなくプリミティブ型の変数で表現されていたため、重要概念がモデルとして伝わってこない
- 処理が書いてあってそこにコメントで一生懸命説明しているが、それがコードに現れてきていない
- このような状態ではモデルとコードが乖離している
■ 3. 開催者の所感
- モデリングの習得における課題:
- モデリングを頭で理解するのと体得の間には崖がある
- 実際に参加者がモデリングしているところを見てこれを実感した
- 本を読んで頭で理解したつもりでも実際やってみるとできないというギャップがある
- ワークショップの価値:
- モデリングの体得のきっかけとしてワークショップという場は価値がある
- 頭で理解したつもりだったけども実際やってみるとできないということに気づくきっかけとなる
- 気づいたら自分で色々書いてみたり、実プロジェクトで部分的にやってみたり、師に習う(お互いにレビューし合ったり、習得した人に見てもらう)ことが重要である
- AI時代におけるモデリング体得の必要性:
- 生成AIがモデリングをするにしても人が体得することは必要である
- 生成AIがモデリングして人がそのAIが作ったモデルの良し悪しを判断できないと体得していないので良いか悪いか判断できない
- 判断できないと知らないうちに歪んだ設計がソフトウェアに埋め込まれていく
- AIで動くものは作っていくが知らないうちにソフトウェアの内側から劣化して開発生産性や品質が低下し、リリーススピードが低下して事業に悪影響を長期的には及ぼす
- 生成AIがモデリングしたとしても人がAIが作ったモデルの良し悪しを判断して最終的には受け入れ判断をする必要がある
- そうするとソフトウェアの内側が綺麗に保たれて変更容易性が高まって生産性が上がって事業にどんどんリリースできるので事業に貢献できる
- ドメインのところをソースコードから綺麗に保っていくことでソフトウェアの変更容易性が高まって事業に貢献できることにつながる
■ 4. ワークショップ2:モデルとは何かの本質洞察
- 開催概要:
- 11月19日にリモートで開催された
- 参加者は16名で19人で実施された
- 企画の方、アーキテクトの方、学生、プロダクトデザイナーなど多様なバリエーションの参加者がいた
- 最も多かったのはシステムエンジニアとプログラマーである
- 目的:
- モデルについてみんなで対話を重ねて深く考える時間を持つこと
- いろんな立場の様々な視点の人々との対話からモデルとは何かを探っていく
- 自然言語でモデルとは何かを思考実験して検討していく
- 特定のUMLを使うことは目指していない
- 概念工学に近いことをみんなで体感する
- 本質洞察の実践という形で自分の実感体験と言葉によるある程度明確な記述をいかにすり合わせて近づけていくかを繰り返す
- 共通性を見つけ本質の定義に近づいていく
- いろんなエピソードを少しでも広くカバーできるような概念を見つけ出す
- 実感体感と一般化、抽象化、理想化、形式化の間を行ったり来たりしながらうまい表現記述を見つけ出す
- 参加者属性:
- モデリングの現場での経験がある方が83%である
- UMLの利用経験が3年以上の方が33%、1から3年が10%未満、1年未満が16%で、40%の方は使ったことがない
- 満足度と感想:
- それなりに満足度は高かった
- モデリングの良い経験になった
- グループで異なる方と議論ができた
- モデルに対する理解を深めることができた
- 業務で役立つ知識を得られたような感じはしなかった(目的はそこではなかった)
- モデリングを学んだというよりモデリングについて学んだという感じで実務には役立たなさそうだった
- ワークショップではかなり良い体験ができた
- 新モデリング宣言に関して哲学とソフトウェア工学をどのように結びつけられるかを知ることができた
- モデリングとは何かを再確認し、またモデリングを展望する機会となった
■ 5. ワークショップの流れ
- エピソード収集:
- モデルやモデリングというキーワードを含んだ自分の実体験のエピソードを2つ以上書く(200字以上400字未満程度で2つ分)
- 文章をお互いに見せ合い説明し合いながら自己紹介タイムを実施した
- 体験、実感というものが大事で、これが核になって初めて共同感覚を引き出せる
- 多様なエピソード:
- プラモデルを作るというモデリング経験
- 救援活動の納得感を構成するためのモデリング
- PTA活動の際の組織構成の構造を作る経験
- 日常生活業務やIT開発設計業務など様々な場面でのモデリングの実感を伴ったエピソードが集まった
- 本質洞察の実践:
- 本質洞察とは何かを説明した上でモデルの本質とはどんなところにあるのかを語ったエピソードの中から共通性を抽出する作業を実施した
- カードに書いていく形式で進めた
- 揺さぶりをかける新しい視点:
- 画家が絵を描く際のモデルさんというモデル
- ファッションモデルは一体何のモデルなのかという問いかけ
- 数学の理論に対してその理論を適用した具体例のことをモデルと数学では呼ぶが、その理論とモデルがITやエンジニアリングの分野のモデルの扱いと逆転しているように見えるのはなぜか
- チームごとの整理:
- Aチームはモデルの目的やモデルの特徴をいろんな観点で整理した
- Bチームはソフトウェア開発という分野に絞ってモデルの共通性を導こうと努力した
- Cチームは複雑な内容を短時間で共有するというコミュニケーションに着目してそれを整理しようとした
- 追加された観点:
- 型という観点、お手本という観点、具体例という観点、象徴という観点、抽象化、予測可能性といった観点が追加された
■ 6. モデルの定義試作
- Aチームの定義:
- 共通言語、コミュニケーション、文法がある程度存在する
- 抽象度を変えることができて可視化できる
- 関係性が明確化に明確になっている
- Bチームの定義:
- モデルとは共通認識の形成のために作られ、関心ごとの対象をシンプルかつ他人に共有可能な形式で表現したものである
- さらに洗練してモデルとは現実世界を認識再利用するためにモデルを共有する人や社会が共通に理解できる表現対象である(50文字以内に収まった)
- Cチームの定義:
- 物事の基準で再現可能なものである
- 目的に応じた要素に絞り複数要素とそれらの関係で構成する
■ 7. モデルの語源と二重構造
- モデルの語源:
- ラテン語で測定器具や基準という意味から始まっている
- 伝統的なモデリング:
- 画家の人やファッションモデルのようにある基準がモデルで、それを参照して何か作品を作るモデリングの仕方がまず最初に現れた
- 工学的モデリング:
- 工学の世界では色々な具体事例をうまくコントロール制御してより良い製品、より良い作品をするためにはどんなお手本があったらいいだろうということを考える
- 今度は具体的な作品事例から逆算してモデルというものを作るということが行われるようになってきた
- 二重構造の統合:
- 従来のお手本から作品を作るという次元のモデリングと、具体例を基準となる作品を作る際にお手本にするといいようなエッセンスを人工的な構成物として作り出すという新しい活動が二重に重なっている
- アジャイルなぐるぐるモデリングのように、作品が色々ある中からいい基準を見つけ出してそれをモデルとして抽出し、それに基づいて作品をまた作り、それをまた妥当性を判断し、それをまた抽象化するということがぐるぐる回るようなエンジニアリング的な活動に移ってきた
- UMTP新モデリング宣言との関連:
- このような従来のお手本としてのモデルが工学的な活動の中で三角関係になっていき、ぐるぐる回るモデリングに移行してきた
- これはUMTP新モデリング宣言で呼ばれるところのリベラルアーツとしてのモデリングに通じる
【本書の構成】
◆第1部 導入編
第1章 なぜデータの「意味」が大切なのか?
◆第2部 文法編
第2章 概念データモデルの文法の基礎概念
第3章 KEYとRKEY
第4章 分類構造と分担構造
第5章 関係
第6章 エンティティ類型
第7章 加工データとSPFチャート
◆第3部 手順編
第8章 データモデリングプロジェクトの手順
第9章 データモデリングプロジェクトの成果物
第10章 データモデリングプロジェクトの知識
◆第4部 実践編
第11章 業務システム領域の概念データモデル
第12章 データ活用領域の概念データモデル
実践で学べるドメイン駆動設計!
この本は、TypeScript を使用してドメイン駆動設計(DDD)の原則に基づいた Web API サーバーの構築を学ぶためのガイドです。
この本ではオンライン書店サービスをドメインとして扱い、その中でもカタログ管理に関するサービスを取り上げます。そのドメインを実装するための Web API サーバーの構築を通してドメイン駆動設計の基本的な概念や原則、実践的な実装方法を学びます。ハンズオン形式で進んではいきますが、辞書のように使っていただくことも可能となっています。
著者は、ドメイン駆動設計を利用して TypeScriptでWeb API サーバーの構築を行う際に、十分な情報やガイドを見つけられず、苦労しました。本書を通じて、複雑なビジネス要求を効果的にソフトウェアに反映する手法を探している開発者の方々へ、実践的な知識とノウハウを共有できたら幸いです。
■ 1. AIブームの根本的誤解
- ベンチャー企業Cognitive Resonanceの創業者ベンジャミン・ライリー氏の主張:
- AIブームは言語能力と知能についての根本的な誤解に基づいている
- 大手IT企業幹部の発言:
- Metaのマーク・ザッカーバーグCEOが「超知性の開発は今や目前に迫っています」と発言した
- OpenAIのサム・アルトマンCEOが「従来理解されてきた意味での汎用人工知能(AGI)を構築する方法について、私たちは今や確信を持っています」と主張した
- 大手IT企業の幹部らはAGIの構築に自信を見せている
- ライリー氏の反論:
- 人間の知能に関する科学的見解やこれらの企業が生み出してきたAIシステムを見る限り、とてもこれらの発言を信じることはできない
■ 2. 大規模言語モデルの本質
- 現在のAIの基本構造:
- OpenAIのChatGPT、GoogleのGemini、AnthropicのClaude、MetaのAI製品群のいずれも「大規模言語モデル」である
- これらは基本的に膨大な量の言語データを収集し、単語(トークン)間の相関関係を見つけ、入力されたプロンプトに対してどのような出力が続くのかを予測するものである
- これらの企業が開発するAIはどこまで行っても、本質的には言語モデルである
- 「言語=思考」仮説の問題:
- 仮に「言語=思考」なのであれば、AI開発企業が世界に関する膨大なデータを収集し、それをますます強力なコンピューティングパワーと組み合わせることで統計的相関関係を改善していけば、あっという間にAGIは実現する
- 大きな問題は、現在の神経科学に基づくと、人間の思考は言語とほとんど無関係だという点である
- 言語と思考の関係:
- 確かに人間は言語を用いて推論や抽象化、一般化といった知能の成果を伝達している
- 言語を使って思考することもある
- だからといって「言語=思考」とはならない
- いくら言語モデルを洗練させていったところで、それが人間を超える知能につながるという保証はどこにもない
- ライリー氏の批判:
- この理論には重大な科学的欠陥がある
- 大規模言語モデルは言語のコミュニケーション機能を模倣する単なるツールである
- どれだけ多くのデータセンターを構築したとしても、思考と推論という独立した明確な認知プロセスにはならない
- この違いを理解することが、科学的事実とAIに熱狂するCEOたちの空想的なSFを区別する鍵となる
■ 3. 言語と思考に関する科学的研究
- Nature論文の概要:
- 2024年、マサチューセッツ工科大学やカリフォルニア大学バークレー校などの研究者らが「Language is primarily a tool for communication rather than thought(言語は思考というよりもコミュニケーションのためのツールである)」という論文を学術誌のNatureに発表した
- この論文は言語と思考に関連する数十年にわたる科学的研究をまとめたものである
- AIブームを取り巻く誤解をひもとく上でも役立つ
- 「言語が思考力や推論力を生み出す」という概念の誤り:
- 仮に言語が思考に必要不可欠だとすれば、言語が奪われれば思考能力も奪われるはずである
- 高度な機能的磁気共鳴画像法(fMRI)で脳のどの部位が活性化しているのかを調べると、「数学の問題を解く」「他人の心を推測する」といった思考を行う際には、言語能力とは異なるネットワークが活性化している
- 脳損傷やその他の障害によって言語能力を失った人において、思考能力全般が損なわれるわけではないことは明らかである
- 重度の言語障害を抱えながらも数学の問題を解いたり、非言語的な指示に従ったり、他者の動機を理解したり、論理的推論や因果的推論を行ったりすることは可能である
- 言語能力を獲得する前の赤ちゃんも、日々の暮らしの中でさまざまなことを発見・理解し、世の中について学んでいる
- 科学的にいえば言語は人間の思考能力の一側面に過ぎず、多くの知能は非言語的能力に関わっている
- 言語の本質:
- 言語は人々が互いに考えを共有するためのツール、すなわち効率的なコミュニケーションコードである
- 言語は生成しやすい上に理解・学習が容易である
- 簡潔かつ効率的に使用でき、ノイズに対して堅牢である
- こうした特徴により、人類は言語を用いて知識を共有することが可能となり、世代を超えて並外れた文化を築き上げることができた
- 人間の認知能力が言語によって底上げされるからといって、思考全般が言語によって生み出されたり定義されたりするわけではない
- たとえ話す能力を奪われようと、人間は考え、推論し、信念を作り上げ、恋に落ち、世界中を探索することが可能である
■ 4. 大規模言語モデルの限界
- 言語モデルの構造的制約:
- 人間において「思考=言語」ではない
- 既存のAIの基盤となっている大規模言語モデルから言語を取り除くと、文字通り何も残らない
- AIが人間とはまったく異なるルートで超知能に到達する可能性もゼロではない
- しかしテキストベースの訓練によってAGIに到達できると考える明確な根拠もない
- AI研究コミュニティの認識変化:
- 「大規模言語モデルだけでは人間の知能モデルとしては不十分だ」という認識が高まりつつある
- ヤン・ルカン氏の取り組み:
- AI研究でチューリング賞を受賞したヤン・ルカン氏はMetaを辞任した
- 「物理世界を理解し、持続的な記憶を持ち、推論でき、複雑な行動シーケンスを計画できるシステム」である世界モデル構築のためのAIスタートアップを設立した
- ヨシュア・ベンジオ氏らの定義:
- ルカン氏と共にチューリング賞を受賞したヨシュア・ベンジオ氏らは、AGIの暫定的な定義を「十分な教育を受けた成人の認知的多様性」を持つものと定義した
- 知能は「Knowledge(知識)」「Math(数学)」「Working Memory(ワーキングメモリー)」「Visual(視覚)」「Auditory(聴覚)」など、さまざまな項目から成り立っていると主張している
- ライリー氏の評価:
- 大規模言語モデルにとらわれてきた従来の枠組みを脱するという点では評価できる
- しかしこれらの合計がAGIであると見なすのは難しい
■ 5. 認知的飛躍とAIの限界
- 革新的発見の可能性:
- 仮にベンジオ氏らが主張する知能をすべて達成するAIが登場したとしても、それは革新的な科学的発見につながるようなAIではないだろう
- たとえAIが人間の思考を模倣できたとしても、人間が行うような「認知的飛躍」を達成できる保証はない
- パラダイムシフトの本質:
- 「パラダイム」は人々から熱心に支持されるユニークさを持ち、さまざまな問題を研究グループに提示する業績のことを指す
- 科学の歴史ではたびたびパラダイムが大きく転換するパラダイムシフトが起きている
- これは反復的な実験の結果ではなく、既存の科学的記述に当てはまらない新しい疑問やアイデア、つまり認知的飛躍が起きた時に発生した
- 複数の認知領域にまたがるAIの限界:
- 複数の認知領域にまたがるAIシステムは、確かに与えられた指示に対して、高い知能を持つ人間のように予測・再現することができる
- しかしこれらの予測はいずれも既存のデータを電子的に集約・モデル化することで実行される
- 入力されたデータそのものに不満を抱くことは難しい
- 結果として人間のような認知的飛躍を達成する可能性は低い
- ライリー氏の結論:
- 確かにAIシステムは私たちの知識を興味深い方法でリミックスし、再利用するかもしれない
- しかしAIにできることはそれだけである
- AIは私たちがデータにエンコードし、学習に使用したボキャブラリーの中に永遠に閉じ込められてしまう
- 思考し、推論し、言語を用いて互いの考えを伝え合う存在である実際の人間は、世界に対する理解を変革する最前線にとどまり続ける
「英国の銀行システムには、今も1960~1970年代に書かれたソフトウェアコードが使われている」――経営コンサルタント会社Baringaが英国の銀行員200人を対象に実施した調査では、回答者の16%が1960年代のソフトウェアを、約40%が1970年代に書かれたソフトウェアコードを使用し続けていることが分かった。約50%の回答者は、「退職間近の従業員数人のみが理解しているソフトウェアに依存している」と答えた。
半世紀前のコードが支える現代の銀行システム
調査は、英国の銀行システムがレガシーな技術基盤に依存している実態を浮き彫りにした。同調査によると、38の金融機関がパンチカードなど、物理的なシステム上で動作するように設計されたコードを今も使用していると回答した。15%の回答者は、かつて販売されていた、部屋を占有するサイズのメインフレーム用に書かれたコードを稼働し続けていると答えた。
現場からは切実な声も寄せられた。ある回答者は「銀行のATMネットワークは、パッチを当てた古いWindows NT系のサーバで運用している」と述べる。別の回答者は「主要銀行の基幹システムは1970年代に構築され、今もCOBOLを使い続けている」と明かす。COBOLは、税務当局、銀行、保険会社、住宅ローン会社などが使用する信頼性の高い金融、管理システムの頼りになる技術だった。
ある金融機関の上級IT専門家は、1960~80年代のシステムを数多く扱ってきた経験から次のように語る。「古いシステムが長く使われたのは、シンプルで安定し、大量の単純取引を効率よく処理できたからだ。しかし今やレガシーなシステムの理解者は退職を控え、若手はCOBOLを学びたがらない。結果として、金融機関はこれらのシステムから徐々に離れざるを得ない状況にある」
Baringaのポール・ミハイロビッチ氏(銀行および市場技術部門エキスパート)は「複雑な技術資産の中に古い技術が一部残ってしまうのは避けられない」と指摘する。「金融機関は巨大な組織であり、国全体で数百万の顧客にサービスを提供している。技術革新のたびにインフラを全面的に作り直すことは現実的ではない」 銀行が直面する2つのリスク
ミハイロビッチ氏は、数十年前に書かれたコードを使い続けることで銀行が直面するリスクを2つに整理している。
・重要インフラへの深刻なリスク
特定の用途向けに運用されたシステムで長期間使用され、少数の高齢の専門家によって保守されているコードは、重要なインフラにとって重大なリスクとなる。維持できるのは少数の高齢専門家だけで、トラブルが起きても修復は困難となる恐れがある。
機敏性の欠如とコストの増大
・特定のレガシーシステムを維持するためだけに専門家を抱える状況が続けば、顧客ニーズの変化に素早く対応できない。維持コストも膨大になる。
一言で言うと、これは「ClaudeがToolを呼び出す処理をPythonコードとして生成し、 Anthropicが提供するサンドボックス内で実行する」機能です。
従来のTool Useでは、Toolを1つ呼ぶたびにClaudeが次のアクションを判断し、 その結果をすべてコンテキストウィンドウに追加していました。 10個のToolを連鎖して呼び出すと、10回分の推論と、 10回分の生データがコンテキストを圧迫します。
実際、この問題は Claude for Excel で顕著でした。Anthropic 公式記事でも「数千行以上のスプレッドシートを読むだけで、中間データがコンテキストを圧迫し、推論が破綻する」という課題が挙げられています。
Claude for Excel は PTC を利用し、
- スプレッドシートの巨大データをすべてコード実行側で処理し
- Claude が受け取るのは 最終的な集計・分析結果だけ
という形にすることで、コンテキスト肥大化を根本的に解決しています。
PTCでは、Claudeは「Tool呼び出しを含むPythonコード」を一度だけ生成し、 あとはサンドボックス内でPythonが逐次実行します。 中間結果はサンドボックスのメモリ内に閉じ、 Claudeのコンテキストに戻るのは print() で出力した最終結果だけです。
■ 1. Embulkの「メンテナンス・モード」発表
- 発表の経緯:
- 2025年10月15日、GitHubのembulk organizationに入っていたメンバーにメールを送付
- Embulkというオープンソースプロジェクトの「メンテナンス・モード」への移行を提案
- 背景となった問題意識:
- RubyGems周辺で発生したセキュリティ事件から教訓を得た
- 「複数の利害関係者が交わるオープンソース・プロジェクトでは、問題が起こる前にコミュニティで平和的に民主的に話し合えるうちにプロジェクトのガバナンスを実態に即して整えて形にして明示しておくべき」
- 特にセキュリティが重要な課題となりえて、かつ営利企業や金銭が関わる場合には重要
- Embulkの現状:
- 著者がメンテナーとして非アクティブとなり「アクティブなメンテナーはいない」状態になって既に半年が経過
- 本体に近いところでは著者と佐藤さんのみが見ている状態
- ときどきJDBC関係で@hito4_tさんにお声をかけて見てもらっている
- embulk-output-bigqueryについては独立したメンテナーが何人かいる
■ 2. メンテナンス・モードの具体的内容
- 対応内容:
- GitHub orgのメンバーやCore Teamを「今後もそれなりには関わり続ける気がある人」の最小限に絞る
- 「もう積極的にメンテナンスを続けられる状態ではない」ことを残るメンバー間で合意する
- 管理する対象自体(Zulipチャットなど)を減らす
- Embulkそのものについて引き継ぎたいと手が挙がったときは残るメンバーで検討する
- 以上をもって「メンテナンス・モード」とし外部に見える形で宣言する
- 今後の見通し:
- Embulkがアクティブにメンテナンスされることを期待しないでほしい
- pull requestなどを送っていただいてもレビューもマージもされないかもしれない
- Embulkはもともと無保証のApache License 2.0でライセンスされている
■ 3. organizationに残るメンバー
- 最終結果:
- 18人にメールを送付し、10人から期日内に返信があった
- 最終的に4人のみがGitHubのembulk organizationに残ることになった
- @frsyuki(原作者)、@hito4t、@hiroyuki-sato、@dmikurube(アナウンスの書き手)
■ 4. 更新の見込み
- 今後の更新について:
- 「二度と」更新しないというつもりはない
- 気が向いたときには更新するかもしれないが期待はしないでほしい
- ちょっとした改善や整理は入れるかもしれない
- もっと先のJavaへの追随や非互換ライブラリの更新(Jackson 2から3など)のような大きな更新を入れるのは現実的ではない
- 引き継ぎの可能性:
- 引き継ぎたいという人から手が挙がれば残るメンバーで議論する
- ただし実現しないだろうと個人的には思っている
- 昨年にはアナウンスを出していたが積極的な提案や反応はなかった
- 引き継ぎの難しさ:
- 「引き継いでくれるのなら誰でも、私たちが知らない人でも引き継ぐ」という態度は必ずしもユーザーのためにはならない
- 機密データの転送にもEmbulkを使っている組織がある
- 悪意を持つ誰かにEmbulkを引き渡してしまったら問題が起きる
- 悪意を持った引き継ぎの提案は拒否して単純にプロジェクトを継続しないほうがユーザーにとっても良い選択肢かもしれない
■ 5. ミドルウェアの定義と特性
- ミドルウェアの特徴:
- ミドルウェアを直接「使う」のは人間よりも主に誰か他の人が書いたソフトウェア・プログラム
- 「複数のソフトウェア・プログラムから同時に使われる・依存される」ソフトウェアという整理ができる
- ライブラリとの違い:
- ライブラリなら非互換を少し入れてしまっても「アプリケーション・コードのほうを直してね」で済む
- ミドルウェアではそうはいかない
- 典型的なミドルウェアであるRDBMSがいきなりSQL文法や接続プロトコルを変えてしまったら依存関係を考慮した複雑な対応が必要になる
- ミドルウェアの宿命:
- 依存関係グラフが深く複雑になるほど対応も複雑になる
- GuavaやJacksonのような「いろいろなJavaライブラリやミドルウェアから推移的に依存され互換性問題で悲鳴が上がるようになってしまったライブラリ」はミドルウェア的な宿命を背負わされて「ミドルウェア化」してしまった哀しきライブラリと見ることもできる
- 多様なプラグインから依存され、そのプラグインとEmbulkを組み合わせて使う多様なユーザーがいたEmbulkは正しく「ミドルウェア」だった
■ 6. オープンソースとメンテナンス
- メンテナンスの長期性:
- あるソフトウェアがミドルウェアであることと「長期間メンテナンスされ続けてきた」ことはほぼ不可分
- あるソフトウェアが他のソフトウェアから依存され互換性を気にされることはそのソフトウェアがそれなりに長期間メンテナンスされ信頼されてきた証
- オープンソースの現状:
- 近年では使われるミドルウェアの多くをオープンソースが占めるようになった
- この十年強の間に新しく生まれたミドルウェアは企業のsource-availableソフトウェアを除けば大部分がオープンソース
- 大規模なミドルウェアをメンテナンスする苦悩にはオープンソース・プロジェクト運営の苦悩も同時につきまとうようになった
- Honoの例:
- YAPC::Fukuoka 2025でHonoのYusuke Wadaさんが「OSS開発者の憂鬱」というトークをされた
- 「クリエイターからメンテナーへ」「作っていればよかったのが保守しなくてはいけなくなる」「Noを言うには体力がいる」「政治に巻き込まれる」
■ 7. Linux開発者の見解
- Linus TorvaldsとDirk Hohndel氏の発言:
- 「メンテナーの疲労と、その仕事がいかに消耗させられる、ストレスが強いものか」という問題
- Linuxカーネルのメンテナーはその必要不可欠で大変な仕事に以前よりも強い緊張を感じるようになっている
- 「オープンソースの世界はプログラミングがすべてだと思っている人も多いが、実はコミュニケーションが占める割合も大きい」
- 「メンテナーの仕事は翻訳であり、それは必ずしも言葉を翻訳するということではない。文脈、つまりそのコードであるべき理由を説明するということであり、それは大変な仕事だ」
■ 8. 悪意の存在
- サプライチェーン攻撃の現実:
- オープンソース・プロジェクトがソフトウェア・サプライチェーンの重要な位置を占めるようになった
- 悪意を持つ攻撃者にとってオープンソース・プロジェクトは格好の攻撃対象になっている
- サプライチェーンの根っこのほうを乗っ取れれば攻撃者にとって得るものが大きい
- XZ Utilsの事例:
- XZ Utilsに悪意のあるコードが挿入された問題(CVE-2024-3094)が確認されたのが2024年3月
- これは偶然にも氷山の一角が見つかった幸運な事例
- おそらくいくつかの攻撃は既に成功していて私たちのソフトウェア・サプライチェーンには悪意のあるコードがとっくに入り込んでいると認識しておくべき
- Embulkでの経験:
- 確実な証拠や確信こそ無いものの「これは攻撃だったんだろうな」という事例があった
■ 9. 個人によるメンテナンスの限界
- 現状の問題:
- 多くのオープンソース・ミドルウェアや「ミドルウェア化」したオープンソース・ライブラリが「個人」の手になるメンテナンスに依存
- 多くのメンテナーが「疲弊」している
- この数ヶ月の間だけでもcurlやlibxml2の話題が挙がっている
- エコシステムの持続性への疑問:
- 個人で続けられるか疑問
- 私たちのソフトウェア・エコシステムがいつまで保つか
- 2025年の日本各地で問題のクマ対応とも相似形の問題を感じる
■ 10. Embulkの場合の詳細
- 著者の状況:
- 半年ほど前にTreasure Data(TD)を退職
- Embulkの「アクティブ」なメンテナーから「降りて」いる状態
- この時点でEmbulkには「個人」のメンテナーしか残っていない状態だった
- 新しい職場でEmbulkを使う見込みはなかった
- 以前からの活動:
- 「オープンソースとしてのEmbulkのメンテナーを他にも割り当ててちゃんと引き継げる状態にしませんか」という活動を社内で数年前からしていた
- 社外でもEmbulkを使っていると対外的にも知られた企業さんなどに「一緒にメンテナーやりませんか」と言ってきた
- Core Teamのような形を作って少しずつでも関わってもらおうという取り組みもしていた
■ 11. プロジェクトをたたむ決断
- 決断の背景:
- 引き継ぐ意志を明示的に示す人や組織が現れない限り既定路線だった
- 当時の勤務先から積極的なサポートも見込めなかった
- 自分はオリジナルの作者でもない
- 個人として続けても安定した収入に結びつくわけでもない
- メンテナンスを続けるしんどさだけがそこにある
- 「これは攻撃だったんだろうな」の件も最後の追い打ちになった
- たたみ方の方針:
- 「メンテナンスを静かに止めて言及も止めてアナウンスもせず、いつの間にかフェードアウト」のような態度を取るべきでないと考えた
- 企業などで重要データを運ぶこともあるEmbulkのユースケースを考えれば盛大に事故る前に落ち着いて切り替えができるうちに公式なアナウンスをしておくことがメンテナーの責務
- 悪意を持った人や組織にプロジェクトを引き継いでしまうくらいなら、プロジェクトをちゃんとたたむほうが結果的にユーザーにとっても良い
■ 12. 軟着陸のための方針
- 取り組み内容:
- 「このままだと続かないよ」という広報を陰に陽に続け、引き継ぐという人や組織が現れれば歓迎し、引き継ぐために労力を割く意志も示す
- 引き継ぎやすくするために今のEmbulkの設計について「なぜそうしたのか」を記録したドキュメント(Architectural Decision Record的なもの)をなるべく書き残す
- 「メンテナンス・モード」になっても即座に「使えなく」はならない程度に「塩漬け」の準備をする
- 評価:
- 100%狙いどおりにいったとは言えないが、たたみ方として悪くない着地になった
- Embulkのコア機能やSPI(Service Provider Interface)の設計はよくできている
- もうしばらくはこのままでもいちおうは「使える」
- ただし無保証のオープンソース・ソフトウェアなので保証はない
- 「いちおうは使える」うちに落ち着いて移行や社内forkなどを進めることをおすすめする
■ 13. 引き継ぎの困難さ
- 現在の引き継ぎの可能性:
- いまからでも引き継ぐ道筋はいちおう残している
- ただし当時ほど現実的な選択肢ではもうない
- 困難な理由:
- 「引き継ぎのために著者が割けるのは100%プライベートの時間のみになった」こと
- 「引き継ぎを申し出た人や組織に『悪意がない』ことを確認するのが難しい」こと
- それらを乗り越えてでも引き継ぐ意志のある組織の方がいれば連絡してほしい
■ 14. メンテナーの仕事と責任
- メンテナンスの困難さ:
- オープンソース・プロジェクトを、中でも「ミドルウェア」的な立ち位置になったソフトウェアのメンテナンスを「個人」の手のみによって続けるのは無理
- これは一つのオープンソース・プロジェクトのメンテナーを十年近く続けてみることで得た当事者としての結論
- 開発とメンテナンスの違い:
- 新規のオープンソース・ソフトウェアを開発するとか定期的に「コントリビューションする」とかはけっこう「個人」でできる
- しかし「メンテナー」の役務はこうした「開発」とはまったく異なる
- オープンソース・ミドルウェアのメンテナーが担うのは聞き取り、コミュニケーション、判断、意思決定、その意思決定の末にやってくる結果に責任を負うこと
- 責任の本質:
- オープンソースは「無保証」でありユーザーが損害を被ってもメンテナーはその損害に責任を負うものではない
- しかし「俺は俺が公開したいコードを好きに公開してるだけだし、ユーザーのことなんか知らね」と考える開発者なら最初からオープンソース・ミドルウェアの開発やメンテナンスなんかやっていない
- 「あのときの自分の判断と意思決定の結果、どれだけのユーザー開発者がどのような影響を受けたのか」に向き合い続けるのがオープンソース・ミドルウェアのメンテナー
- Linuxからの教訓:
- メンテナーは異なる意見を持つ開発者間の調停役を務めたりベンダーやユーザーとやり取りをする必要もある
- 「開発者を見つける方はずっと簡単だ。開発者はたくさんいる」
- 「メンテナーになるためには、他人のコードの善し悪しを判断できるだけのセンスを持っていなければならない」
- 「それは通常、単に十分な経験があるかどうかの問題だ」
■ 15. 企業・組織の貢献と責任
- 企業ユーザーの困難:
- 「企業ユーザー」が依存し始めた「ミドルウェア」のメンテナンスを「個人」の手のみによって続けるのは無理
- しかし「企業ユーザー」は無理では困ってしまう
- コントリビューションの誤解:
- 「もっと積極的に『コントリビューション』します」と考えるなら記事を読み返すべき
- 徒に「コントリビューション」(pull requestなど)ばかりを増やすのはむしろメンテナーの負担を増やすだけの結果になるかもしれない
■ 16. オープンソース・プロジェクトの現在地とポリシーを知る
- 把握すべきこと:
- 依存しているそのオープンソース・プロジェクトはどこの誰がどう開発やメンテナンスをしているか把握しているか
- 様々なケース:
- 一個人が趣味で開発・公開しただけのまだ「メンテナンス」という段階ですらないもの
- 開発者自身がオーナーシップを握って互換性など気にせず変えながら外部からのコントリビューションも入れず好きなように開発したいと思っているもの
- 個人や数人レベルで開発しつつそろそろライブラリやミドルウェアとして安定してきていろんな人に使ってもらいたいと思っている段階のもの
- 企業発のオープンソース・プロジェクトだが社内で作ったコンポーネントをせっかくだからと公開しただけで広く使ってもらおうという気は特になく社外の互換性都合など気にするつもりもなく外部からのコントリビューションを受け付ける気もないもの
- 企業からオープンソース・プロジェクトとして公開しているが外部からのコントリビューションを受ける気はなく自社プロダクトを購入してもらうための導線として公開しているだけのもの
- 企業発の門戸を開いたオープンソース・プロジェクトとして主導権は持ちながらエコシステムとともに発展させたいと考えているもの
- 個人や企業から始まったオープンソース・プロジェクトだが大規模化して複数の個人や企業関係者が意思決定に参加するはっきりしたガバナンスを持つプロジェクトになっているもの
- 個人発でも企業発でも今後のメンテナンス継続に限界を感じている状態のもの
- これらのケースの間のグラデーションのどこかに位置するあいまいな状態のもの
- 判断の必要性:
- 一口に「オープンソース・プロジェクト」といってもいろいろ
- 「オープンソース」はただのライセンスでしかない
- あなたの企業はそのオープンソース・プロジェクトに依存しても大丈夫か
■ 17. オープンソース・プロジェクトが求める貢献の形
- pull requestの誤解:
- プロジェクトをGitHubに公開すると問答無用でpull requestを受け入れる状態にさせられてしまう
- 「オープンソース・プロジェクトにはpull requestという名の『コントリビューション』を送るものなんだ」という「誤解」がすっかり広まってしまった
- オープンソースであってもすべてのプロジェクトが外部からのpull requestを実際に受け入れているとは限らないし受け入れていても喜ばれるとは限らない
- 求められる貢献の形:
- ただ応援してほしいだけかもしれない
- スターがつくと嬉しいプロジェクトもあるかもしれない
- いろんな人からのpull requestが嬉しいプロジェクトかもしれない
- バグ報告は欲しいがpull requestは求めていないかもしれない
- スポンサーのほうがpull requestよりも嬉しいかもしれない
- 最終的には自社プロダクトを購入してほしいかもしれない
- メンテナーとして共に持続的に役務を負ってくれる人を求めているかもしれない
■ 18. お金をとおしてメンテナンスに貢献する
- スポンサーの方法:
- GitHub SponsorsやOpen Collectiveをとおしてスポンサーするのが話が早い
- このような形でスポンサーを求めていないプロジェクトにスポンサーするのはややこしいが求めているプロジェクトには遠慮なく支払える
- 企業としての検討:
- 企業としてスポンサー支出に正当性を持たせるのが難しいのはわかる
- すべての依存プロジェクトをスポンサーするのは不可能
- ただし「もしこのプロジェクトのメンテナンスが途絶えたらビジネスの継続にも支障が出る」というオープンソース・プロジェクトはないか
- そういう単一障害点すら特定できていないのであればまずその特定をしたほうがいい
- オープンソース・プロジェクトなんていつ止まってしまうかわからない
- その単一障害点にあるプロジェクトくらいスポンサーを検討してもいいのではないか
- 製品購入:
- そのオープンソース・プロジェクトがあくまで製品への導線で企業ユーザーとしてそのプロジェクトに依存するレベルで使おうとしているならちゃんと製品を購入すべき
■ 19. スポンサーの限界
- スポンサーの現実:
- お金をとおして貢献できるプロジェクトばかりではない
- そのメンテナーが人生をかけて個人でやっているのならスポンサーによってメンテナーの命と生活が助かるかもしれないがそんなプロジェクトはごく少数
- 個人メンテナーにとってスポンサーはお小遣いくらいにはなるかもしれないが安定した収入として生活を支えられるようなものにはそうそうならない
- Embulkの場合:
- 企業発という出自もあってスポンサーを募ったりはしていなかった
- 仮にTreasure Dataとは独立にスポンサーを募って個人としてメンテナーを続けたとしても自分や家族の生活を支えられるとは思えない
- 本質的な問題:
- 多くのオープンソース・プロジェクトにとってスポンサーは継続そのものの助けにはならない
- 多くのオープンソース・プロジェクトには結局本来そもそも持続に必要なだけのメンテナーが「いない」
- 多くのメンテナーが手弁当でメンテナンスを続けている(そして続けられていない)
- Linuxにおいてすらそうである
■ 20. 雇用をとおしてメンテナンスに貢献する
- 課題の本質:
- 私たちの「足元」があとどれだけ保つか
- そこにある課題は「持続とメンテナーの安定」
- 「持続と安定」に対して企業に期待される最もわかりやすい貢献は結局「雇用」
- 現実的な提案:
- ほとんどの企業にとって「オープンソース・ソフトウェアのメンテナーをフルタイムで雇用する」なんていうのは難しい
- しかし強く依存する途絶えては困るオープンソース・ソフトウェアが今後も持続するために雇用コストのごく一部でも正式に割くことはそんなに難しいか
- ほとんどのオープンソース・ソフトウェアはかならずしもフルタイムでメンテナンスに従事するほどのメンテナーを必要としてはいない
- 一方で個人の業務時間外の時間のみで持続できるものでもない
- 具体的な提案:
- 自社が依存するオープンソース・プロジェクトとその現状を把握する
- その維持が苦境にあれば会社としてその「メンテナンス」に貢献する意志を示す
- 従業員がメンテナーとして継続的にそのプロジェクトに関与することを推奨する
- その従業員の勤務時間のn割はメンテナンス活動に使うことを認知する
- それを正式に評価する
- フルタイムではなくこれだけでもメンテナーの状況はかなり改善する
- 危機感:
- 世のbig techな企業はそれとはむしろ逆の方向に舵をきっていそう
- 「たたむ」オープンソース・プロジェクトはこれからおそらく増えていく
- その「足元」であなたの会社のビジネスは継続できそうか
■ 1. Rustに対する著者の立場
- 著者の姿勢:
- かつて自分をRustヘイターと呼んでいた
- しかしそれはStack Overflowの調査で最も愛されている言語としてRustがトップになるようなファンボーイ的傾向を相殺するためだった
- C++を嫌う理由は多くあり、著者もC++を嫌っている
- 多くの人がより良いプログラミング言語を待っていたが、代わりにRustを得た
■ 2. Rustの4つの核心的問題
- コンパイルが遅い:
- 単に遅いのではなく非常に遅い
- C++より遅い
- 年々Rustは数倍速くなったが、客観的には2倍ではなく2桁(100倍)速くなる必要がある
- 複雑である:
- C++と同程度に複雑
- しかしC++にはレガシーがあったがRustにはなかった
- Arc<Mutex<Box<T>>>のジャングルを毎回通り抜けなければならない複雑さが、実装されるロジックの品質に直接影響する
- 木を見て森を見ずの状態になる
- C++も同じ問題を抱えているなら、結局言語を切り替える意味は何なのか
- メモリ安全性はそれほど神聖ではない:
- 実際、多くのアプリケーションではクラッシュするよりも誤動作する方が良い
- 特にRustが存在したがっている組み込みの世界ではそうである
- Rustでは99.999%の信頼性を得ることはできない
- 常にクラッシュする
- 可変共有状態の処理において:
- GUI、データベース、ステートフルサービス、OS/ハードウェアなど多くの可変共有状態を扱う場合
- ネイティブのRustメモリモデルのパフォーマンスは劣る
- 非ネイティブのunsafeを使うとコンパイルが遅く、複雑性が高く、結局メモリ安全性もなくなる
- 重い可変状態の仕事に対してRustは実質的に無意味になる
■ 3. C++の問題点
- 未定義動作の遍在:
- 未定義動作(UB)は言語の基本的な側面
- 単にUBに遭遇するのではなく、言語全体がUBの上に構築されている
- 配列のインデックスアクセスで即座にUBに遭遇する
- 言語が範囲外アクセスをチェックしないため
- 多くのUBはパフォーマンスの理由でさえ正当化されない
- Cから引き継がれC++で増幅された完全にずさんな設計
- C++の具体的な問題:
- 暗黙の型変換、暗黙のコピー、暗黙のコンストラクタ、暗黙のオブジェクトスライシング、ほぼすべてが暗黙的
- 関数オーバーロード(暗黙的)、特にSTLでの遍在性を考慮すると
- 例外を後付けとした非統一なエラーハンドリング
- Cから40年経っても#includeでテキストファイルを取り込んでおり、One Definition Ruleはコンパイラによるチェックがほとんどない
- パラダイムの不健全な組み合わせ(子孫クラスでジェネリック関数をオーバーライドする幸運を祈る)
- ジェネリックプログラミングの中核メカニズムとしてのSFINAEの厄介さ
- T、T&、T*、std::optional、std::unique_ptrで似たようなものを記述するが、それぞれ独自の方法で壊れている。その上にconstを載せる
- 結論:
- C++は複雑で、安全でなく、コンパイラが遅い
- Rustはこれらの問題をどのように修正し(あるいは修正していないか)
■ 4. 遅いコンパイルの詳細
- 設計上の問題:
- 一時的な問題ではなく設計によるもの
- Rust開発チームは毎回コンパイル速度を犠牲にしてきた
- 最適化の努力:
- Rust FAQでは、より良いフロントエンド、MIRなど多くの最適化努力があると説明している
- しかしMIRの取り組みは2015年に開始されたが、依然としてコンパイルを大幅に高速化できていない
- コンパイラチェックは高速化している
- 本質的な問題:
- Rustを高速にコンパイルすることは不可能
- 問題はHaskellのような類似のジェネリクス多用言語に固有のもの
- Rustは議論の余地があるがC++よりもHaskellに近い
- テンプレートを多用するC++コードと同じ遅いコンパイルの問題を示す
- 具体例:
for i in 0..limit {}を実行すると、単に反復するのではなく、範囲を作成し、イテレータを作成し、それを反復する- すべてが具体的な型に単相化され、個別に最適化される必要がある
- 最適化されていないRustコードは非常に遅く、デバッグにさえほとんど使用できない
- ボローチェッカーの影響:
- その上に非オプションのボローチェッカーを載せると、非常に遅いコンパイラになる
- ボローチェッカーは容赦ないので、何度も再コンパイルすることになる
■ 5. 複雑さの詳細
- 回避不可能:
- 「コールドパスの高レベルコードを書いているのでパフォーマンスは必要ない、ライフタイム処理の深みに入る必要はない、単に高レベルのロジックを書きたい」という姿勢は取れない
- Rustの1行を書くたびに低レベルの細かい点に強制的に押し込まれる
- ガベージコレクタの不在:
- RustにはGCがなく、今後もない
- すべてのデータを所有権のツリーに半手動でパックする必要がある
- 数行のコードを書くだけでも所有権、借用、トレイトに精通している必要がある
- 高レベルロジックの困難:
- Rustで高レベルのロジックを書くのは非常に困難
- 多くの初期Rust採用者が実際にはパフォーマンスにそれほど敏感でないサービスにはNode.jsやGoに戻っている
- 高い複雑さと遅いコンパイルの組み合わせにより、純粋なRustで複雑なものを書くことが非現実的になる
■ 6. メモリ安全性の詳細
- Rustの妥協しない2つのもの:
- パフォーマンスとメモリ安全性
- Rust設計者はメモリ安全性に関して行き過ぎた
- コンテナの実装:
- コンテナは実際にはunsafe関数で実装されている
- チューリングマシンモデルでは完璧な正しさは不可能
- 慎重に配置されたunsafeなビルディングブロックから安全なプログラムを構築する必要がある
- 他言語との比較:
- Node.jsとGoは実用的に安全な言語と見なされている
- Rustは正気さと実用性をメモリ安全性のために犠牲にした
- そして結局どれも得られず、依然として100%メモリ安全ではない
- 実用性について:
- 多くのユースケースは完璧なメモリ安全性を必要としない
- リモートコードを実行したり秘密を漏らしたりしない安全でないプログラムを実装する方法がある
- ユーザーデータを破損させ散発的に動作するだけ
- ペースメーカーが停止した場合、被害者に「クラッシュ時にメモリは破損していなかった」と伝えても慰めにならない
- Cloudflareの障害事例:
- unwrap()関数でのクラッシュによって引き起こされた最近のCloudflareの障害があった
- 著者の最も強い主張:
- Rustはメモリ安全で信頼性がない
- メモリ安全性の代価は開発者の正気さに加えて信頼性だった
- 言語設計者は行き過ぎた
- メモリ安全性という抽象的な原則のために中核的な実用的品質を犠牲にした
- Haskellの設計者が純粋性のために実用性を犠牲にしたのと同様
- RustとHaskellの類似性を繰り返し指摘する理由
■ 7. 可変共有状態の詳細
- Rustでの可変共有状態:
- 可能だが、Rustで可変共有状態を使用することは意味がない
- ほとんどの利点を失い、Rustのすべての欠点だけが残る
- 成功したRustプロジェクト:
- ほぼすべてが共有の読み取り専用状態、一方向データフロー、非循環データ構造を採用している
- rustcコンパイラ、mdbookとpulldown-cmarkのMarkdownツール、ステートレスハンドラ用のActixとAxum、追記専用ブロックチェーン、シングルスレッドWASM
- モデルはHaskellに非常に似ている
- Haskellもパーサー、ステートレスハンドラ、ほぼ非インタラクティブなCLIツールで優れており、ブロックチェーンで使用されてきた
- Software Transactional Memory:
- Rustの初期プロトタイプには安全な並行性のオプションとしてSTMがあった
- しかしSTMにはパフォーマンスペナルティがあり、単純だが重要なランタイムサポートが必要
- 共有可変状態に踏み込むと:
- メモリ破損は例外ではなくルールになる
- 破損を処理する必要があり、単にクラッシュすることはできない
- ボローチェッカー、所有権は役に立たない
- GCのようなアルゴリズムなしで循環グラフの所有権を分析することはできない
- Sync/Send、Mutex、Arc:
- ロックするか、CPUキャッシュをひどく乱すので、マルチスレッド通信には非効率
- 少なくとも集中的なものには
- 安全だが非効率
- Rustの最初の妥協しないもの(パフォーマンス)を破壊する
- 結論:
- 共有可変状態に踏み込んだ瞬間にRustのすべての利点を失う
- Rustの主要なコンセプトが共有可変状態を決して使用しないことだったことを考えると合理的
■ 8. GUIとRustの問題
- GUIは可変共有状態:
- そのためRustで大きなGUIプロジェクトは見られない
- Zed IDEの例:
- 何年も経ってもまだベータ版
- 開発者がボローチェッカーのジャングルを突破してロジックがバグだらけであることに気づき、まだ何十もの他の機能を実装する必要がある苦痛がほとんど感じられる
- まだ見られないもの:
- 大規模データベース
- スケーラブルなステートフルサービス
- オペレーティングシステム
- 少なくとも重要なLinuxモジュール
■ 9. 結論:Rustの評価
- Rustは良いのか悪いのか:
- どちらでもない
- 開発に何千人月も費やされた平凡なプログラミング言語
- この事実だけでRustは実用的なツールになる
- 棚から取り出してそのまま使用できるため
- 具体例:
- このブログはRustで書かれたZolaで生成された
- 使用するためにRustのコードを1行も書く必要がなかった
- Zolaは不変データの一方向フローを持つ非インタラクティブな性質のためRustに適している
- 著者の願い:
- 「Rustは最高のプログラミング言語だから、みんな開発をRustに切り替えるべきだ」と叫び回らないでほしい
■ 1. フルスタックエンジニアを目指すべき理由
- ひろゆき氏が目指すなら「全部やる」エンジニアである
- フロントエンジニアの限界:
- フロントしかできない場合、バックエンドがよくわからないため誰かに頼まなければならない
- その誰かのコストが高かったり優秀でなかったりしても対抗できなくなる
- 全部できることの利点:
- 自分1人で全部できるようにしたほうがよい
- バックエンドをやっている人を選ぶ時に話が通じる
- 優秀な人を見抜くにはその業界の知識が必要である
- サーバーを立てたことがない人に優秀なサーバーエンジニアを選ばせても、どういう基準で話をしたらいいかわからない
- ひと通り理解することを早めにやっておいたほうが人生で得することが多い
■ 2. コミュニケーション能力の必要性
- エンジニアにコミュニケーション能力は必須ではない:
- ひろゆき氏は月に3、4,000万人が使う「4chan」を運営している
- エンジニアとのやり取りは基本的に全部メールかネットワーク経由である
- 直接会ったことがある人は1人もいない
- 電話で話したことがある人は何人かいる程度である
- テキストベースのやり取りの利点:
- 実際のやり取りはテキストベースである
- その人が本当に英語を理解しているかどうかもわからない
- 翻訳ツールを使っているかもしれないが、「これやって」と言ったらやってくれるので困ったことがない
- タイムゾーンの問題もあるため顔を合わせてやる必要がない
- テキストで「これやっておいて」と言ったほうが口頭で説明するよりも情報が伝播しやすい
- コミュニケーションが苦手な方が有利:
- ある国の山奥に住んでいるエンジニアは「都会は人が多くてゴミゴミしていて、自然が美しくないから嫌だ」という理由で移住した
- たぶん彼はコミュニケーションが苦手だが、何の問題もなく暮らしている
- コミュニケーションが苦手な方のほうがエンジニアはやりやすい
■ 3. エンジニア像の多様化
- リア充エンジニアとギーク文化:
- 最近のIT界隈ではリア充っぽいエンジニアが増えているという指摘がある
- オタク的なギーク文化が失われつつあることへの寂しさを感じる声がある
- 実態は両方が増加:
- オシャレ系エンジニアもコミュニケーションが苦手エンジニアも増えている
- エンジニアの枠自体がどんどん増えている
- エンジニアという職業の人が増えているため、ギーク的でニッチなことが好きなオタクと言われるような人数もめちゃくちゃ増えている
- 多様性のメリット:
- 「同じ考え方のエンジニアだけ集めたいです」というのはやりやすくなっている
- 幅広くなってよかったという話である
- 女性エンジニアもそんなに珍しくないため、「女性同士でエンジニアの話したいです」という人でもちゃんとコミュニティが作れる時代になっている
- いい時代になっている
■ 4. SIerの未来予測
- 大規模SIerの衰退予測:
- これからはプロジェクトに必要なエンジニアが減る
- 外注しなくても自社でエンジニアを迎えるようになる
- SIerが衰退している
- AIによる構造変化:
- 「大規模なSIerにお願いして20人チームを派遣してもらって作る」よりも「めちゃくちゃ優秀なエンジニア1人がAIを使い倒して、20人分のコードを書かせる」ほうがよい状況になる
- 本来ならSIerに頼んで「20人月です」という案件でも、フリーランスのすごい人が「じゃあこれ4ヶ月で俺1人でやりますよ」と言えるようになる
- 発注側もその1人と話すだけで済み、20人月で契約するより安く話が早い
- SIerの今後:
- 大規模SIerはけっこう仕事が取りづらくなる
- 1人でフリーランスをやっててAIを使って「コードはバンバン書けます」という人はかなりいい金額を取れるようになる
- SIer的な仕事自体は残る
- 「20人派遣します」みたいな大人数前提のやり方は銀行業界など特殊なセキュリティ要件があるところを除けばわりと衰退していく
■ 5. 発言スタイルと切り抜かれやすさ
- 意図的な発言スタイル:
- ひろゆき氏はわざと切り抜かれやすいような言い方をしている
- 尖った発言のほうが切り抜かれやすい
- 端的に説明したほうが理解されやすい
- 長文が読まれない時代:
- 長い文章を読めない人が日本で増えている
- もともとそんなに読解力が高くない人たちもインターネットを使うようになってきている
- 結論先行型の話法:
- 結論を最初に「はい」「いいえ」「ノーコメント」みたいに言って、そのあとに理由を説明するほうが伝わりやすい
- それをやると最初に「あなたの意見には乗りません」というのがハッキリしてしまう
- 「理由はこれです」と続けるため、人と仲良くしながらフワッと否定するような日本語っぽい言い方がしづらくなる
- だから引っかかりやすい
- 海外生活の影響:
- 岸谷蘭丸氏も同じしゃべり方をしている
- 海外で、しかも学生として生活していた人はこうなる
- 英語圏で生活すると、最初にYes/Noを言ってから理由を言うというのが身についてしまう
- だから日本語で話すときもその感じが出てしまう
■ 6. 就職先選択の基準
- 最も重要な基準:
- 会社に入るときに一番大事なのは「相談できる相手がいるかどうか」である
- 自分がわからないことや「これどうやるのが正解なんだろう?」と聞いたときに、ちゃんと丁寧に教えてくれる人がいる会社は所属する価値がある
- それがないんだったら「自分ひとりでやってるのと一緒じゃん」という話である
- 業種よりも社風:
- 業種がどうこうというより「同僚が、聞いたらちゃんと答えてくれる空気の会社かどうか」のほうが大事である
- 面接での見極め方:
- エンジニアの面接では一次は人事だけだが、二次以降でエンジニアの人が出てくることがある
- そのときにこちらが何か質問したら、どれくらい丁寧に答えてくれるかを見るとよい
- 「あ、この人はちゃんと答えようとするタイプだな」とわかれば、その会社にはそういうエンジニアがいるということである
- 逆に「え、それも知らないんですか?」みたいな反応をしてくる会社だと「あ、ここは自分が入っても質問しにくいな」となる
- エンジニアにとって質問しやすいかどうかやオープンな社風があるかどうかのほうが大事である
- 業種による違い:
- 業種がSESだったとしても、めちゃくちゃ親身になって教えてくれるスタッフが多い会社もある
- 「みんなでちょっとずつスキル上げていこうぜ!」というタイプのところもある
- 一方で、同じSESでも実態はほぼ個人事業主の集まりみたいになっていて「それ自分で調べて」「お前の仕事手伝っても俺の給料増えないし」みたいな人が多い会社もある
- 社風は面接や実際に話してみないとわからない
■ 7. 企業の自社エンジニア枠の増加予測
- 自社エンジニア枠は増加する:
- AIでエンジニアがうんぬんという話があるが、SES自体が減っていって「これは他社に任せるより自社でやったほうがいいよね」となる
- けっこう増えると考えられる
- オウンドメディアの増加:
- 最近「Nintendo Direct」みたいなオウンドメディアを持つ会社も増えている
- 自社でいろいろやろうとすると結局ぜんぶインターネット経由になる
- 物を売るのも知ってもらうのもインターネットになる
- だったらその部分は他社に丸投げするより自社で持ってたほうがいいという話になる
- コスト構造の変化:
- 今までは自社で抱えるとエンジニアコストが高かった
- わりと優秀な人を1人置いておいて、あとはAIにやらせるようなやり方でもそこそこ回るようになってきた
- 中堅企業でも「自社エンジニア枠」をちょこちょこ入れていく流れになる
- フリーランス活用の増加:
- フリーランスと契約して「うちの会社のこと頼んでいる人なんですよ。フリーランスですけどね」みたいな関わり方をするパターンもある
- そういうタイプの業務はこれから増えていく
■ 1. GrapheneOSの概要
- 特徴:
- オープンソースで開発されているセキュリティとプライバシー保護に特化したAndroid系OS
- Google Pixelなどを安全に使うために利用されている
- 問題点:
- セキュリティの高さから麻薬密売人などに使用されることがある
- プライバシーを保護する機能が強力ということは悪事を働いても露見しにくいということにもなる
■ 2. フランス政府との対立経緯
- フランス政府の姿勢:
- 以前から「GrapheneOSは犯罪者向けのもの」と表現するなど敵対視していた
- フランスの治安当局が「隠れて生きる意思を裏付けるもの」として使用することが罪であるかのような調査報告を出したことがある
- GrapheneOSの反論:
- フランス当局の姿勢に反発
- 「ヨーロッパの独裁政権や政権を支持するメディアで、GrapheneOSやPixelを犯罪者向け製品であるかのような誤った表現が使われている」と非難
- 「GrapheneOSはこれらの勢力が全員に強要しようとしている大規模監視警察国家に反対している」と表明
■ 3. Le Parisienの報道(2025年11月19日)
- 報道の内容:
- フランスのメディア・Le Parisienで「Google PixelとGrapheneOS:麻薬密売人が警察からデータを守るための秘密兵器」というニュースが報道された
- GrapheneOSの反応:
- メディアおよびジャーナリストに対し「GrapheneOSについて根拠のない、そして明らかに虚偽の主張をするためのプラットフォームを提供しながら、それらの主張を確認し反論する機会をまったく提供していない」と憤りを示した
- 検察当局者の発言:
- 「GrapheneOSは犯罪組織とのつながりがあり、捜査に協力しないのであれば法的措置に出る」とコメントが掲載された
- GrapheneOSはこれを「事実無根であり、国家による法的脅迫だ」と問題視
■ 4. 機能に関する誤解
- フランス当局の主張:
- GrapheneOSがアクセス時にデータを消去する機能や偽アプリを含む犯罪者向けのOSと主張
- GrapheneOSの反論:
- それらの機能は公式版には存在しない
- オープンソースとして公開しているGrapheneOSの悪質なクローンや非公式版と混同されている
■ 5. フランスからの撤退発表
- 撤退の理由:
- フランスはオープンソースのプライバシープロジェクトにとってもはや安全ではない国であると判断
- プロジェクトとユーザーを守るため今後はフランスへの進出を完全に避ける方針
- フランスの政府機関と法執行機関の行動と発言が極めて懸念すべき点
- GrapheneOSについて極めて不正確で中傷的な主張をしながら明らかに措置を正当化しようとしている
- 「彼らは手の内を見せたので、何か悪いことが起こる前にフランスから撤退する」と表明
■ 6. インフラ移行計画
- 従来のインフラ:
- 公式サイトやソーシャルメディアなどの主要インフラをフランスに本社を置くヨーロッパ最大のクラウドコンピューティングサービスであるOVHに依存していた
- 移行先:
- MastodonやオンラインコミュニティプラットフォームのDiscourseなどをカナダのローカルサーバーと共有サーバーの組み合わせに移行
- 重要なウェブサイトインフラはドイツに拠点を置くウェブホスティングサービスのNetcupに移行
- OVHから脱却する
- 開発者の制限:
- 安全上の懸念からGrapheneOSの開発者たちはフランス国内での作業を禁止している
■ 7. 今後の方針
- AOSPへの貢献:
- 法執行機関やフォレンジック企業が捜査においてAndroid端末を突破するために使用している脆弱性をGrapheneOSで修正することを目指す
- AOSP(Android Open Source Project)に貢献していくと表明
- Googleへの呼びかけ:
- 「Googleからのご連絡をお待ちしております」と述べている
■ 1. 2ちゃんねる創設の経緯
- 立ち上げの動機:
- 暇だったことが第一の理由
- アメリカで大学生をしていた当時、「あめぞう掲示板」を使用していた
- 「自分で作れるのか」と試したら作れてしまった
- 高いモチベーションがあったわけではなく、できてしまったから惰性で続けた
- 学んだこと:
- プログラムを作る力とサービスとして運営していく力は全く別物
- 動くものができても運用しやすいようにコードを修正する必要がある
- トラブル防止のためのサーバー準備も必要
- 世界中の無料サーバーを契約して回り、「ここが落ちたら次はここ」というルートを事前に用意する運用ノウハウを蓄積
■ 2. 技術選定とシステム設計の考え方
- 使用言語:
- 当時からPerlで書いており、現在も同様
- データベースを使わない理由:
- データベースはたまにデータが壊れる
- 約10年前に某企業のOracleデータベースのデータが全消失した事例がある
- データベースを使うとメモリやCPUのオーバーヘッドが大きくなりサーバーコストが高くなる
- テキストファイル保存の採用:
- テキストファイルに書き出せば壊れにくくできる
- お金がない中での工夫
- 「どうやったら安く、壊れにくく動かせるか」という発想
- このノウハウはその後のIT系会社経営でも活用
■ 3. 潰れない会社の経営哲学
- 基本原則:
- 会社が潰れるのはお金がなくなった時
- お金がなくならなければ会社は生き残れる
- 毎月のランニングコストをいかに安くするかが重要
- よくある失敗パターン:
- 売上を上げていく過程でコストも上がる
- 売上が下がった時に赤字になり大慌てになる
- 一度上がったコストを下げるのは非常に困難
- その結果として倒産するケースが多い
- 実績:
- 1999年に大学生の時に作った合資会社は現在も存続
- 2001年頃に作った株式会社も現在も存続
- 自分の会社を潰したことはない
■ 4. サービスを当てるための考え方
- 仮説の作り方:
- 他にないことで「自分がそれを知りたい・やりたい・おもしろいと思うか」が基準
- 自分自身がおもしろくないと思うと飽きて続かなくなる
- 「別に自分が作らなくてもいい」「既にある」と思うと飽きてしまう
- 自分の欲望に沿うタイプ
- 他のアプローチとの違い:
- 「世間で流行っているから作る」というソシャゲー系の作り方はできない
- 好き嫌いに関係なく儲かるものを作る人もいるが、自分はそれができない
- 人の性格による違い
■ 5. 2ちゃんねる立ち上げ期の戦略
- 当時のインターネット環境:
- 企業がサイトを作って運営することは少なかった
- ネット決済やクレジットカード入力はほぼ存在しなかった
- 個人がブログを書いてサイトを作るのが普通だった
- 情報を出す人が少なかった
- 「日本語で書かれているページはだいたい全部見た」という人がいた時代
- 昔のファミコンで「発売されたソフトはほぼ全部触っている」という人がいたのと同様
- 「全部わかる時代」だった
- 新しいサイトができたら情報を共有するリンク集が流行していた
- 掲示板を選んだ理由:
- 情報が集まる場所として掲示板はずっと残ると考えた
- 誰でも書けるため情報が出回りやすい
- 人が多ければ多いほど情報が増える
- 競合に勝つための設計:
- たくさん人が来ても耐えられる仕組みにする
- 書かれたデータが消えずに残り続けるようにする
- 利便性を上げることで他のサービスより優位に立つ
- コスト構造の優位性:
- 他のサービス運営者は自腹で回していたため、自分の給料以上の規模にできなかった
- 世界中の無料サーバーをひたすら契約し続けた
- 自分の人件費を除けばコスト構造がほぼゼロ
- 無料で規模だけ大きくしていった結果、日本で一番大きい掲示板になった
- 掲示板とSNSの関係:
- 掲示板はSNSの前の姿といえる
- 昔は掲示板で情報収集・情報共有をしていた
- 今はSNSがその役割を担っている
■ 6. 自宅サーバー学習の価値
- 自宅サーバーの意義:
- 2ちゃんねるも自宅サーバーで運営していた時代がある
- 自宅サーバーでしか学べないことがある
- 具体的なメリット:
- 「GPUをぶん回す」ような処理は自宅で回したほうが安いケースがある
- 「オンプレで自前で持つべきか」「クラウドでやるべきか」という比較ができるようになる
- オンプレという選択肢を持っていないと「AWSとGCPどっちが安いか」という比較だけになる
- 「この部分はオンプレにする」「重要なデータだから社内に置く」といった判断ができる
- 結論:
- 自前サーバーの経験はサービスの管理者になるなら持っておいたほうがよい
■ 7. AI競争の価格面の帰着
- 大企業の動向:
- OpenAIや大きな会社がひたすら投資しているものは残り続ける
- 各社が「超優秀なAIを作る競争」をしている
- 一般ユーザーの実態:
- 一般の人たちは「そこまで必要ない」という時代になりつつある
- ChatGPT3と4の違い、4と5の違いを体感で理解しているユーザーは7〜8割もいない
- 今後の予測:
- Metaの「パソコン1台で動く」「スマホの中で動く」モデルがある
- 中国製の「GPUなくても動く」モデルも存在
- スマホやノートPCの中に入って「これで充分」という時代になる
- 巨大なデータセンターや電力の話が問題にならなくなる
- 「能力が高くなくてもこれで足りる」ものが小さく自分のスマホの中で動く時代になる
■ 8. データベースより軽い設計発想
- データベースの課題:
- データベース連携は便利なミドルウェアも多く、いろんな人が触れるようになる
- しかし当時はサーバーのリソースが少なすぎた
- アクセスが増えるとCPUが詰まる
- データベースは同時書き込みでデータが壊れるため「ロックして1人ずつ書く」動きをする
- アクセスが多すぎるとロックがかかったままになりデータの出し入れができなくなる
- 結果としてサービスが止まる
- 分散処理の問題:
- 「同じサーバーを100台並べて分散すれば処理が100倍になる」というやり方はコストがかかる
- 採用した解決策:
- 「多少順番がズレてもいいからロックしないで書く」
- 「多少の誤差は許容する」という方針
- ロックせずにどんどん追記していく
- 「書き込んだ順番が前後することがあってもしょうがない」という誤差を認める
- この方法でコストは大幅に下がる
- テキストファイルでの運用はこの考え方に基づく
- JSONでのAPI操作:
- 「データベースでガチガチにやるのではなくJSONでやる」というのは同様の考え方
■ 1. ひろゆき氏の現在の開発活動
- 使用言語・ツール:
- Google Apps Scriptを使用
- YouTubeのコメントを収集するアプリを開発
- 出力先をGoogleスプレッドシートにすることで無料でデータ保存が可能
- 現状の課題:
- データ量増加に伴い動作が遅くなる問題が発生
- 有料ストレージの契約を検討したが、費用負担を避けて開発が停滞中
■ 2. AIを活用した開発スタイル
- 今回の開発目的:
- AIがどの程度のレベルでコードを出力できるかを検証する実験
- Geminiに仕様を投げ、やりとりしながら仕様書をブラッシュアップ
- AIが出力したコードの精度を確認し、必要に応じて手動で修正
- 開発における役割分担:
- スクラッチ(初期コード作成)は全てAIに任せる
- デバッグや細かい修正は自分で行う
- 「ここだけ変えて」と指示しても別の箇所まで書き換えてしまう問題が発生
- 手戻りを防ぐための指示方法やAIの反応パターンを観察中
■ 3. 開発ツールの選定方針
- 使用ツール:
- Gemini
- ChatGPT(無料範囲)
- GitHub Copilot(無料範囲)
- 無料ツールを選ぶ理由:
- 有料ツールはいずれ廃れる傾向がある
- 企業が有料で作ったツールも、後から無料のオープンソースベースのものに置き換わる
- PhotoshopやIllustratorに対するGIMPの存在が例
- VS Codeはマイクロソフト製だが無料で使える
- オープンソースは無料で広まり、多くの人に修正されて品質が向上する歴史がある
■ 4. 技育祭と若手エンジニア育成について
- 技育祭の意義:
- 手作り感を出し続けることで参加しやすさを維持
- 「とりあえず参加してみる」までのハードルを下げることが重要
- エンジニアの適性:
- 向き不向きはやってみないとわからない
- 優秀なエンジニアには面倒くさがりが多い
- 「手を動かすのが面倒だから自動化しよう」と考えられる人が強い
- やる気なさそうに見えるタイプが実はエンジニアとして優秀なケースがある
- プログラミング未経験で「必要だからやるか」と始めた人が非常に優秀になるパターンも存在
■ 5. サーバーエンジニアの将来性
- AIの限界:
- サーバー契約の最適解や安いサーバーの提案は可能
- 実際にトラブルが発生した際の修正はAIにはできないことがある
- ネット上にない情報やレアなバグへの対応は苦手
- AIはネット上の情報を統計的に処理して最適解を出す仕組みのため、未知の問題には対応困難
- 人間の強み:
- サーバーの仕組みを理解していれば、別サーバーを立てて冗長構成を保ったまま切り替えるなどの対応が可能
- インフラの前提を理解していない人がAIだけで大規模サービスを構築するのは現状困難
- 自分自身の知識と知能で解決しなければならない問題に対しては人間が必要
■ 6. AI時代におけるエンジニアの知識と経験
- 40〜50代エンジニアの活躍:
- AIがコードを書けるようになり、若手に細かい実装を振る必要がなくなった
- 40〜50代は自分でサーバーを立ててOSを入れてアプリを書くという一連の流れを全て手作業で経験した世代
- 仕組みを丸ごと理解しているため、仕様から削る判断や全体設計の見直しが可能
- 部分最適ではなく全体を見たものづくりができる
- 20〜30代エンジニアの課題:
- イチから物を作る経験が不足しているケースが多い
- CPUだけ速くしてもメモリが詰まる、ストレージが遅いとボトルネックになるといった段階的な切り分けの感覚が身についていないことがある
- DBのテーブル設計変更によるI/O削減やサーバーの疎結合化といったノウハウが不足
- AIに丸投げするとお金で解決する設計になりがち
- 「同じサーバーを10台並べてホットスタンバイにする」といった非効率な提案になる傾向
- 推奨される学習方法:
- お金があまりない環境で自分でゼロから立ち上げる経験を積むべき
■ 7. コンピューターサイエンスの知識の必要範囲
- 不要な知識:
- CPUの内部構造
- アセンブラレベルの理解
- サーバーを自分の手でイチから組む能力
- 必要な知識:
- リモート先のサーバーでCPUがどう動いているか
- メモリがどう使われているか
- コンピューターの基本的な仕組み
- プログラミング言語の習得:
- 1つの言語をしっかり身につければ十分
- 1つマスターすると別の言語を見た時に「言い回しが違うだけ」「こういう仕様なのね」と読み替えられる
- 学び直しのハードルが一気に下がる
- 基礎の重要性:
- メモリの概念がわからない人にポインタを教えるのは困難
- メモリの概念を理解している人には「メモリのラベルを使うためにポインタがある」と説明すれば理解が早い
- 抽象概念よりも基礎のハードウェアを学んだほうが理解しやすい
■ 8. AI時代におけるエンジニアの価値
- エンジニアの強み:
- 仕様を設計できる能力
- 「この予算ならここは削ったほうが回る」というコストとのバランスを見る力
- クライアントへの提案力(「ここを外せば納期が短くなる」「ここを簡略化すればコストが下がる」など)
- お金と時間の感覚に基づいた提案
- AIの弱点:
- コスト感は会社ごと・案件ごとに異なる
- その場でさじ加減できる判断は人間のほうが強い
■ 9. 新卒カードの活用と大企業への就職
- 大企業を選ぶべき理由:
- 「AIを使いこなせなそうな大企業」という決めつけは成長を阻害する
- 大企業にいても自分でAIを調べて詳しくなる人はいる
- 中小企業でも趣味で調べて詳しくなる人はいる
- 「企業が何を与えてくれるか」という基準で選ぶのは好ましくない
- 大企業でしか得られない経験:
- 大企業でしか触れられないノウハウ
- 意思決定の流れ
- 「この規模だとこうやって予算が下りる」という構造の理解
- 「このタイプの案件はこの人が決裁権を持っている」といった内部の仕組み
- エンジニアリングの特殊性:
- 大工は20代で家を一軒任されることはないが、エンジニアは20代でもアプリやサイトを1人で作れる
- 「中小に行けば何でもやらされるから経験になる」と言われるが、そのレベルの経験は個人開発でも可能
- 大企業SIerの課題:
- セキュリティの観点でコーディングにAIを使用禁止のところがある
- AIを使わずに手癖が付くメリットはある
- 「ここはもうAIで書く」という領域が増えているため、人力でコーダーを何年もやった経験が役に立たないケースもある
- 「コードを書くのにAIは一切使うな」というスタンスは現代にそぐわない
■ 10. ITベンチャー企業と若手の働き方
- 20代にしかできない経験:
- 馬車馬のように残業時間を気にせず働くのは20代の時しかできない
- 若いうちに振り切って働いた経験があるかないかで、大人になってからの見え方が変わる
- 自分の最大値や限界を感覚で把握できるようになる
- 「最悪ここまでは踏み込める」という判断ができるようになる
- ベンチャー企業の魅力:
- 大企業では労基の観点から限界まで働く経験がしにくい
- ベンチャーで文化祭のように集中して働く楽しさは若いうちに味わっておく価値がある
- ひろゆき氏自身の20代:
- 自分のサービスが好きで1日十数時間自分の作ったサイトを見ていた
- 夜中にサーバーが落ちたら対応、旅行中でも対応という24時間即応態勢
- バグがあったら直るまでずっと起きて対応
- 苦痛ではなくサービスを維持すること自体が楽しかった
- 「全体的には楽しい」の中につらいところもあるという感覚
- 睡眠時間は事故がなければ限界まで寝るタイプで、トラブルが重なった時だけ徹夜
■ 1. 『コンサルタントの秘密』の概要
- ジェラルド・M・ワインバーグによる主著である
- コンサルタント向けの専門書ではなく、相談されたときの思考法をまとめた普遍的な内容である
- 肩書きではなく「どのように人と関わるか」を扱った一冊である
- プログラムやシステムの話はエピソードとして登場するが本質ではない
- 様々なトラブル事例から「コンサルタントの法則」を紹介している
- トム・デマルコの書籍の源泉となった組織論や発想が含まれている
■ 2. オレンジジューステスト
- 設問内容:
- 朝5時から1,000人分の搾りたてオレンジジュースを提供する
- 缶入りジュースや事前準備は禁止である
- 直前に絞ったジュースを全員に行き渡らせる必要がある
- 合格の回答:
- 「できる。これだけのコストがかかる」と答えることである
- 「無茶だ」「現実的でない」と勝手に判断することは失格である
- コンサルタントの役割:
- 可能な選択肢を示すことである
- それにかかるコストを示すことである
- 選択は依頼主が行うものであり、選ばない選択も含まれる
- 原則:
- 相手の要望を勝手に最適化することは相手の判断を奪う行為である
- 相談される側は判断材料を提供する役割に徹するべきである
- 良し悪しまで口出しすることはお節介である
■ 3. 「そこに無いもの」を見る方法
- 課題の特性:
- 見えないものを見つけることは困難である
- 悩みごとの原因は見えていない場合が多い
- 紹介されている技法:
- ピンの技法は、リストアップ手段が無い対象こそ取り組むべきとする
- 3の法則は、計画を台無しにする原因が3つ考えられないなら思考方法に問題があるとする
- 説明の顔をしたアリバイは、ルールから言い訳を探す行為を指摘する
- 「他人という異文化を利用する」事例:
- ワインバーグはプログラマの生産性向上を依頼された
- 職場では要望があればすぐに購入・作成する方針だった
- プログラマへのインタビューでは「足りないもの」が見つからなかった
- 掃除のおじさんに「黒板を拭いてくれと頼まれたことはない」と言われた
- 黒板は「消すな」という警告付きの個人メモで埋め尽くされていた
- 本来の共有ツールが機能せず、購入したソフトやガジェットも共有されていなかった
- 他者の視点により見えない問題を発見できた
■ 4. AIを活用した「足りないもの」の発見
- 「洗濯物リスト」の作成方法:
- 機能設計時にスライド一枚に要件と実現方法を箱で並べる
- 「この一枚が全体像だが、足りないものは何か」と周囲に問う
- 機能不足だけでなく要件の制限や前提の追加が判明する
- ネットワーク設計や非機能要件周りで発見が多い
- AIの活用方法:
- 要件と機能の不足を尋ねる
- タスクの網羅性とコスト見積もりを確認する
- 図が成立する前提で欠けているものを探す
- 計画を台無しにする原因を3つ以上考えさせる
- AIの特性:
- 網羅性の確保に適している
- 「10個考えて」という無茶な要求にも対応する
- 人間が妥当性を最終判断する必要がある
- 1990年の出版時には存在しなかったAIという異文化を現在は活用できる
- コンサルタント業務の多くをAIに任せられるようになった
- 最終判断は人間が行う必要がある
■ 5. AI時代におけるコンサルタントの本質
- コンサルタントの核心的業務:
- どのような問いを投げるかを決定することである
- どこまで自分で判断するかを見極めることである
- 現代における重要性:
- 正解がない時代では答えよりも良い問いが重視される
- 問いへ向き合う考え方が必要である
- 『コンサルタントの秘密』はAI時代だからこそ読み直す価値がある
特にエンジニア採用では「モダンな技術や最新の開発手法が取り入れられておりあの会社は優秀なエンジニアが数多く集まっている。自分もあの中に入ると何か少しエンジニアとして優越感が出そう」という空気感大事なんですよね。金払いがちょっと良いくらいではこの優越感が得られない。
■ 1. もう限界、Linuxへ - 2025年のPC界隈の変化
- 2025年のPC界隈で静かに広がっている合言葉:「もういい、Linuxを入れる」
- 長年Windowsでゲームをしてきた熟練ユーザーやテック記者までがハイエンドのゲーミングデスクトップを丸ごとLinux(特にCachyOSのようなゲーム特化ディストリビューション)へ移行し始めている
- あるベテラン記者はRyzen 7 9800X3DとGeForce RTX 4070 Tiという典型的なハイエンド構成のWindows 11マシンをあえてLinuxに変えると宣言
- 理由:Windowsはどんどん扱いづらくなっているのにLinuxでのゲーム環境は明らかに良くなっているという感覚
■ 2. Reddit での賛同
- 海外掲示板Redditのテクノロジー版では同じ言葉をタイトルにした投稿が立ち、数千件規模の賛同票が集まった
- コメント欄には「もうWindowsの挙動に疲れた」「AIと広告が増えてOSとしての基本が良くならない」といった声が並ぶ
- 長年Windowsを使ってきたユーザーほど不満を募らせている構図が見える
■ 3. Windows 11のエージェントOS化
- 背景にはMicrosoftの路線変更がある
- Windows 11は「エージェントOS」を掲げ、Copilotと呼ばれる生成AIアシスタントをタスクバーやファイルエクスプローラー、設定画面などシステムの至るところに深く組み込もうとしている
- 最新ビルドではファイルエクスプローラーから直接ドキュメント要約やメール下書き生成を呼び出す機能まで用意
- OSそのものが常時AIと会話することを前提に設計されつつある
- 一方でユーザー体験は必ずしも便利になったという実感と結びついていない
■ 4. Copilotを巡る問題
- Copilotを巡る議論では常に画面の隅にいるだけでなく、AIが基本的な操作に失敗した公式広告動画が批判を浴び、Microsoft自身がその広告を削除する事態になった
- AI連携を強めることでブランドを近未来的に見せようとする動きと、「まずファイルエクスプローラーのフリーズやスタートメニューの不具合を直して欲しい」という利用者側の素朴な要求との乖離がユーザーの苛立ちを増幅させている
■ 5. Recall機能の問題
- 象徴的なのがRecallと呼ばれる機能
- Recallは画面の内容を一定間隔で自動撮影し検索可能な「パソコンの記憶」として保存する仕組み
- Microsoftは暗号化やWindows Helloによる保護を強調するが、実際にはデータベースが平文のSQLite形式で保存されていた時期があり、専門家から「悪意あるソフトや物理的なアクセスに極めて弱い」と警告されている
- プレビュー段階での強烈な反発を受けて一度は提供を見直したものの、その後もInsider向けに再投入するなど方向性自体は変えていない
■ 6. 広告的なUIの問題
- ユーザーの視界を埋める広告的なUIもMicrosoftへの不信感を積み上げてきた
- Windows 11のスタートメニューには「おすすめ」と称するエリアがあり、そこにアプリやサービスのプロモーションが表示される仕様が導入されている
- 設定である程度は無効化できるものの、規定では有効な上、更新の度に挙動が変わることも多い
- 最近ではPCのバックアップを推奨する警告風メッセージとしてOneDriveのクラウドバックアップを促す表示がスタートメニューに出るケースが報じられた
- 黄色い感嘆符で「アクションを推奨」という文言でユーザーの不安を煽りつつ、実態はMicrosoft 365やクラウドサービスの利用を後押しする導線になっている
■ 7. Windows 10サポート終了の影響
- 決定的だったのがWindows 10サポート終了のタイミング
- Microsoftは2025年10月14日を持ってWindows 10の通常サポートを終了し、以後は月例のセキュリティ更新や新機能提供を行わないと公式に発表
- Windows 10は依然として世界のWindowsユーザーの4割前後を占めていたとされ、数億台規模のPCが一斉に期限切れの状態になった
- Microsoftは Windows 11へ移行できないユーザー向けにESU(Extended Security Updates:延長セキュリティ更新プログラム)を用意
- 個人向けでは1台あたり年間30ドル相当の料金、あるいはMicrosoftアカウントとの紐付けやポイント交換による無償枠といった複雑な条件が提示されている
- ローカルアカウントだけで使い続けたいユーザーがESUを利用するには結局Microsoftアカウントへの移行を迫られる形
■ 8. Windows 11のハードウェア要件
- Windows 11側にはTPM 2.0やSecure Bootといったハードウェア要件が課されており、古いPCほどアップグレードが困難になる
- サポート終了に伴う解説記事の多くは「Windows 11要件を満たさないPCではLinuxディストリビューションやChrome OS Flexへの移行も選択肢になる」と明記
- つまりMicrosoft自身のライフサイクル戦略が結果的に「今のWindowsを捨てて別のOSへ飛び移ること」を現実的な選択肢としてユーザーに意識させてしまった
■ 9. LinuxとSteam Deckの台頭
- このタイミングで存在感を増したのがLinuxとSteam Deckを中心とするオープンなゲームエコシステム
- Valveが毎月公表しているSteamハードウェア&ソフトウェア調査の2025年10月版では、Linux利用者の割合が初めて3%を超え3.05%に達した
- 1年前の約2%からわずか1年で5割増の水準
- 依然として94%以上を握るWindowsと比べれば小さな数字だが、傾向としては明確な伸びを示している
■ 10. Protonの役割
- Linux側の下地を作った最大の要因がValveが開発したProtonという互換レイヤー
- ProtonはWineと呼ばれる互換技術をベースにしたソフトウェア群で、Windows向けのゲームをLinux上で動かすための翻訳役を担う
- Steamクライアントに統合され、ユーザーはゲームごとに有効化するだけでDirectX APIの呼び出しがVulkanなどのグラフィックスAPIに変換される仕組み
- 2025年秋時点の調査ではProtonDBの統計に基づき、Windowsゲームの約9割がLinuxでプレイ可能という水準に達したことが報告されている
■ 11. Steam OSとSteam Deck
- 物理ハードウェアとしてはSteam OSとSteam Deckの存在が象徴的
- LinuxベースのSteam OSを搭載したSteam Deckは携帯ゲーム機の形をしたPCとして世界的なヒットを記録
- そのOS構成やドライバー最適化がそのままLinuxゲーム環境の標準的な参照例になった
- Valve自身のハードウェアだけでなく、ROG AllyのようなWindows搭載ハンドヘルドがBazziteというFedoraベースのディストリビューションに入れ替えることでフレームレートやバッテリー効率を改善できる事例も報告されている
■ 12. ハードウェアメーカーの対応
- Linux側のゲーム人口がSteam全体の約3%という水準に達した今、ハードウェアメーカーも無視できなくなっている
- Steam Deck向け最適化を意識してAMDがオープンソースGPUドライバーの開発を強化
- 2025年にはWindows向けでメンテナンスモードに移行した旧世代GPUでもLinux側ではコミュニティ主導のRADVドライバーにより引き続き最適化が続くという構図が生まれた
- Windowsでドライバーサポートが先細りになる一方、Linuxでは過去世代GPUが長く活用される可能性が高く、古いゲーミングPCを延命させたいユーザーにとっては魅力的な要素になりつつある
■ 13. CachyOSの特徴
- CachyOSはArch Linuxをベースに「高速、安定性、ゲーミング最適化」を全面に押し出したディストリビューション
- 公式サイトでは「Blazingly Fast」を謳い、x86-64-v3やx86-64-v4といった新しめのCPU命令セットに最適化されたパッケージを提供することで、同じハードウェアでも標準的なバイナリより高いパフォーマンスを目指している
- 心臓部にあるのがCachyOS Kernelと呼ばれる独自ビルドのLinuxカーネル群
- BORE(Burst-Oriented Response Enhancer)やEEVDFといったCPUスケジューラ、LTO(Link-Time Optimization)、CPUアーキテクチャ別のコンパイルオプションなどを組み合わせ、入力遅延の低減とスループット向上を狙っている
■ 14. Linuxの課題
- もちろんLinuxに移れば全てが解決するわけではない
- 最大の難所として挙げられるのがカーネルレベルで動作するアンチチートとの相性問題
- Battlefield 2042やCall of Duty: Black Ops 6のような大型タイトルではSecure BootとTPM 2.0を有効にした上でRiot VanguardやEasy Anti-Cheatといったカーネル常駐アンチチートを要求するケースが増えている
- こうした仕組みはWindowsカーネルを前提として設計されており、Protonが再現するユーザーランドだけでは対応しきれない
- 技術的なハードルも残る:一部のハードウェアではLinux向けドライバーが未整備だったり、ベンダー純正の設定ツールが提供されていなかったりするため、「買ってきてさせばすぐ使える」というWindows的な感覚は通用しない場面がある
■ 15. 現実的な移行ガイド
- それでもWindowsからLinuxへの移行ガイドは年々現実的なトーンになってきた
- かつてはデュアルブートや仮想マシンで遊び半分に触ってみる程度の提案が多かったが、今では「Steamライブラリーの大半はLinuxで問題なく動く、どうしても必要なタイトルだけWindowsに残し、日常のゲーム環境はLinuxへ移す」という構成を推奨する記事も増えている
- ProtonDBで事前に互換性を確認し、必要に応じてローリングリリースのディストロをデュアルブートで入れるといった具体的な移行シナリオが提示されるようになった
■ 16. OSとしての哲学的考察(「沈黙する回路」)
- OSは単なるソフトウェアではない:朝起きて最初に触れる窓であり、1日の思考を流し込む媒体であり、記憶が堆積していく基盤でもある
- そこに絶え間なく広告や提案が降り注ぐと、心のどこかで自分の時間が少しずつ切り売りされている感覚が芽生える
- 便利さと引き換えに集中の静けさが薄く削られていく
- だからこそ何も語らないOSへの憧れが生まれる:起動しても何もおすすめしてこない環境、こちらから呼ばない限り口を開かないAI、更新の度に性格を変えないデスクトップ
- CachyOSのようなディストリビューションはその憧れを実態に変えるためにカーネルの速度やパッケージの構成といった目に見えにくい部分を丁寧に磨き続ける
- そこでは沈黙そのものが1つの設計思想になる
■ 17. 価値観の問題
- OS選択を単なる好みや慣れの問題として片付けるのは簡単
- しかしWindows 10のサポート終了やAIと広告を全面に押し出すWindows 11の路線、ハードウェア要件とアンチチートの強化によって、Microsoftの設計思想そのものがユーザー側の価値観と衝突し始めている
- 自分のPCを自分が主役の道具として保ちたいのか、クラウドサービスとAIのためのプラットフォームとして受け入れるのか
- その分岐点に立たされたユーザーが「もういい、Linuxを入れる」とつぶやきながらCachyOSのインストーラーを起動する姿は単なるOS乗り換え以上の意味を持ち始めている
■ 1. はじめに:複雑性が問題を生む理由
- ソフトウェア開発には「複雑性が問題を生む」という常識がある
- 問い:
- なぜ複雑になると破綻するのか
- どこから複雑と呼べるのか
- どの瞬間に人の理解が追いつかなくなるのか
- 技術負債はなぜ突然「手がつけられない」段階まで膨張するのか
- ソフトウェアの複雑性を計算量、認知負荷、チーム特性という3つのレンズで読み解く
- ポイントは「複雑なコード」ではなく「複雑さ自体の本質」を扱うこと
■ 2. 複雑性とは計算量の爆発を人間が受け止められなくなる現象
- ソフトウェアの複雑性はしばしば計算量の爆発として語られる:
- O(N) → まだ追える
- O(N²) → 何が起きているか曖昧になる
- O(2^N) → もはや理解不能
- しかしこれは人間の脳にもまったく同じことが起きる
- 人間の作業記憶は7±2個しか保持できない(心理学の古典的研究)
- これはエンジニアにとっては「認知の計算量制限」を意味する
- その後の研究では実効容量は4±1個程度という見解も有力(Cowan 2001など)
- つまりコード設計がO(理解)を超えた瞬間、人は壊れる
- 人間の作業記憶は5〜9チャンク程度しか同時に扱えないとされており、複雑な設計はすぐにこの上限にぶつかる
■ 3. 設計の計算量はコード行数ではなく関係性の数で決まる
- 複雑性はコード量では決まらない
- 関係性(依存・制約・フロー)の数で決まる
- 例:
- AがBを知っていて
- BがCを参照していて
- Cが非同期にAを更新する
- これを理解するには人間はA-B-C-Aの閉路を追跡しなければならない
- これは脳にとってDFS(深さ優先探索)のような負荷
- 関係性が増えるほど理解の計算量は指数的に増える
- コードは線形に増えるが理解コストは指数関数的に増える
- だから設計は突然破綻する
- 崩壊は徐々には進まない
- ある閾値を超えた瞬間いきなり崩れる
- まるで「臨界点」を超えた化学反応のよう
- 依存関係の数が増えると開発スピードより先に「依存の管理コスト」が爆発していく
■ 4. 認知負荷は見えない技術負債である
- 複雑性が破綻するのは技術の問題ではなく人間が処理できる情報量の限界を超えるため
- 認知負荷が高い設計には次の兆候がある:
- 一度読んでも理解できない
- 仕様とコードの対応が不明
- 「ここを変えるとどこに影響する?」が見えない
- レビューが摩耗する
- バグが「点」ではなく「面」で発生する
- これらはすべて「計算量過多」「キャパシティ超過」の症状
- 技術負債とは「認知負荷が金利として積もっていく現象」と捉えるべき
- 技術負債は単なる「後回しの修正」ではなく開発者の頭の中に積み上がる認知負荷そのもの
■ 5. アーキテクチャの本質は計算量の制御
- 設計とは格好いい図を描くことではない
- 本質はただ一つ:「理解に必要な計算量をO(1)に近づけること」
- そのためにアーキテクチャが存在する:
- 層で区切る → 認知対象を一定に保つ
- 責務を限定する → 計算経路を短くする
- 境界を作る → 関係性を切断する
- APIを設計する → 認知を抽象化する
- きれいな設計にも理由がある
- それは美しいからではなく脳への負荷を最小化するため
■ 6. 複雑性の破綻ラインは個人ではなくチームに依存する
- 認知負荷は人によって異なる:
- 初心者はすぐO(爆発)
- ベテランはO(ある程度耐える)
- 設計者はO(ノイズを抽象化できる)
- つまり複雑性の破綻ラインはチーム固有のものであり汎用的な「正しさ」では語れない
- 技術は移植できても認知限界は移植できない
- あるプロジェクトでうまくいった設計が別のチームでは壊滅する理由はここにある
■ 7. 実務で複雑性の爆発を防ぐ方法
- (1) 関係性を減らす(依存を切る):
- イベント駆動で発散した依存を整理する
- 双方向参照を禁止する
- 「AはBを知らない世界」を設計する
- 短い例:UI→UseCase→Repositoryだけにし、UIがRepositoryを直接呼ばないようにする
- (2) 読み方をO(1)に近づける:
- コードが「初見で」理解できる必要がある
- 初回で理解できない設計は複雑すぎる
- 短い例:「この関数は何をするか?」が1画面以内で完結するようにする
- (3) ドキュメントではなく構造で説明する:
- ドキュメントで補強が必要な設計はすでにO(1)ではない
- 短い例:「ここは○○層です」と説明不要なようにフォルダと責務を一致させる
- (4) レビューで認知負荷を観測する:
- レビューの摩耗は構造の疲労
- 短い例:PRに「ここ分かりづらい」コメントが連発したら設計の構造疲労を疑う
- (5) チームの認知限界を把握する:
- ベテランの限界ではなくチームの最低ラインで設計すべき
- 短い例:「新人でも追える構造」を基準にしベテラン依存の暗黙知を排除する
■ 8. おわりに
- 複雑性の問題は理論では説明できるが実務ではほとんど語られない
- しかしソフトウェアが破綻するのはいつだって「人間が理解できなくなったとき」
- ソフトウェアの限界は計算資源ではなく人間の認知資源で決まる
- この視点が定着すると設計やレビューやアーキテクチャの見え方が変わる
- 複雑性を避けるのではなく複雑性と「共存できる形」を探すことが大切
■ 1. libxml2のセキュリティポリシー変更
- libxml2のリポジトリに新しいテキストが追加された
- 内容:
- 趣味人たちによって開発され、たった一人のボランティアによってメンテされているオープンソースソフトウェアである
- テストは適当で、メモリ安全ではなく、セキュリティバグも満載である
- 信頼できないデータに対してこのソフトウェアを使用するのは愚かな行為である
- セキュリティバグは他のバグと同様に扱われる
- 受け取ったセキュリティバグ報告は全てただちに公開され、優先的に修正されることもない
■ 2. libxml2の概要
- XMLを処理するライブラリである
- 多くのLinuxディストリビューションやプログラミング言語に導入されている
- ChromeやSafariといったWebブラウザでも使われている
- 事実上業界標準と言える
- PHPにもあり、DOMやSimpleXMLなどがlibxml2に依存している
- 2000年ごろにDaniel Veillardによって作成された
- 2013年ごろからNick Wellnhoferが貢献を始めた
- 現在はNick Wellnhoferがほぼ一人で保守を行っている
■ 3. 協調的脆弱性開示プロセスの背景
- セキュリティバグは基本的に通常のバグ報告と異なる扱いがなされる
- いきなりGitHubやその他メディアなどでセキュリティバグが公開されると、修正が間に合わないうちに攻撃者に利用されてしまうためである
- セキュリティバグについては各企業のバグバウンティプログラムやHackerOne、IPAなどの機関に報告し、修正されるまで待ってから公開する手順が確立された
- 報告を受けた側も修正版がリリースされるまではセキュリティバグについては黙っておくのが通例である
- これは協調的脆弱性開示プロセスと呼ばれ、現在では多くの開発者やアプリケーションがこのプロセスに従っている
- libxml2はこの業界標準を無視し、セキュリティバグも一律全て公開する、攻撃者に利用されても知ったことではない、という斬新なセキュリティ対策に方針を切った
- 対応されてなかろうが90日で開示というポリシーを強行して大批判を食らったGoogle Project Zeroのはるかに上を行く対応である
■ 4. メンテナーの経緯:Stepping down(2021年7月22日)
- 特に頼んだわけでもないが、いつのまにかlibxml2とlibxsltの事実上のメンテナーになっていた
- 幸いなことにChrome VRPバグバウンティとOSS-Fuzz Integration rewardsによって報酬を得ることができていた
- Googleのこれらの優れたプログラムに感謝する
- 残念ながらセキュリティからの収益が急減しており、最低限の資金を確保するめども立たなくなった
- そのためコントリビュータ・メンテナを退任することにした
■ 5. メンテナンスの再開(2022年1月10日)
- Googleからの寄付のおかげで2022年はlibxml2とlibxsltのメンテナンスを継続できるようになった
■ 6. セキュリティ問題への対応(2025年5月8日)
- 毎週何時間も第三者から報告されるセキュリティ問題への対応に追われている
- これらの問題のほとんどは致命的ではないが、それでも大きな作業である
- 無給のボランティアにとってこれは持続不可能である
- libxml2の開発を継続できるようにいくつかの変更を考えている
- 基本的な考え方はセキュリティバグを他のバグと同じように扱うということである
- セキュリティバグはただちに公開され、他のバグと同じ優先度で扱われる
- この方針は一部のダウンストリームを不安に陥れるかもしれないが、もしかしたら貢献意欲を高めるきっかけになるかもしれない
■ 7. OpenSSFとセキュリティ業界への批判
- 長年この仕事をしてきたので、セキュリティ問題に関わる秘密主義のほとんどはただの茶番にすぎないものであるとわかっている
- OpenSSFのような「ベストプラクティス」は、大手テクノロジー企業がOSSメンテナーに罪悪感を抱かせ、無償で働かせようという圧力に過ぎない
- 最近個人経営している会社をOpenSSFのメンバーにしようとした
- そのためにはまずLinux Foundationのメンバーになる必要があり、これは最低でも年間1万ドルかかる
- これらは非常に排他的な組織であり、なにひとつオープンではない
- いまこそ彼らとその支援者を非難すべき時である
- 長期的にはOSSメンテナーに報酬も払わずにこのような要求を課すことは有害である
- 最近libxsltのメンテナーを辞任したが、このライブラリがふたたびメンテナンスされる可能性はほとんどない
- Google Project Zeroという金で買える最高のセキュリティ研究者がボランティアの首根っこをひっつかんでいる現状では、その可能性はさらに低い
■ 8. 企業の責任への批判(2025年5月10日)
- 肝心な点はそもそもlibxml2はブラウザやOSクラスが使用できるレベルの品質を備えていなかったということである
- Appleがlibxml2をOSのコアコンポーネントに導入したことが始まりだった
- その後Googleも追随し、今ではMicrosoftでさえlibxml2を使用している
- このようなことは決してあってはならないことだった
- 元々は成長のハックのようなものだったが、いまでは彼らは数十億ドルの利益を上げている
- しかしより優れたソリューションへの切り替えや自主開発、libxml2の改善といったフィードバックはない
- これらの企業の態度は無責任である
- 彼らはユーザのセキュリティやプライバシーなど気にもかけておらず、対症療法を行っているにすぎない
- もうこのゲームには参加しない
- 彼らがlibxml2の使用をやめれば、このプロジェクトの健全性は向上する
■ 9. メンテナー退任(2025年8月15日)
- libxml2のメンテナーを退任することにした
- つまりこのプロジェクトは現在ほぼメンテナンスされていないということである
- ここ最近libxml2を触っているのはNick Wellnhoferほぼ一人であり、彼が辞めるということはすなわちプロジェクトの放棄と同義である
- libxsltについては最近Iván Chaveroが後任に名乗りを上げたが、contributionもまだまだといったところである
- libxml2については今後どうなるか未知数である
■ 10. OpenSSFの実態
- OpenSSFはオープンソースソフトウェアの開発・保守を持続的に行うことを推進する組織である
- 有名どころとしては協調的脆弱性開示プロセスの策定・推進などがある
- 協調的なビジョンを達成するためには最低でも年間1万ドルの課金を要求する
- 実際のOSS開発者に貢献が還元されることは特にない
■ 11. Google Project Zeroへの批判
- 協調的脆弱性開示プロセスはOSSメンテナーにタダ働きを行わせるための脅迫でしかないという主張である
- 実際問題としてGoogle Project Zeroはオープンソースが相手でも脆弱性の指摘しか行わず、脆弱性を修正したりパッチを作成したりすることはない
- 高い給料もらってるんだからパッチも書けよといった批判も多々上がる
- 批判の声:
- 「Googleが真剣にハッカー対策をしたいのであればパッチを送ったり資金援助したりするでしょう。彼らは単にCVEバッジを集めたいだけです」
■ 12. 現状と今後の展望
- 実は「放棄された」は言い過ぎで、現在は「メンテナがいない」状態であり、誰かが後任に立候補すれば開発は継続される
- しかしメンテナになったところで報酬も利益もなく、負わされるのは時間と責任だけという損しかない立場である
- そのような立場に好き好んで入り込むのはよほど風変わりな人しかいない
- libxml2はあらゆるOSやブラウザや言語にまで入り込んでいる重大なライブラリである
- そんな根幹の部分がこんなことになっている現状、今後のOSSはどこに向かっていくのか不透明である
package main
import (
"encoding/json"
"fmt"
jmespath "github.com/jmespath/go-jmespath"
)
func main() {
// 1. JSONデータを Goの interface{} に変換する
jsonData := []byte(`
{
"users": [
{"name": "Alice", "age": 30, "city": "Tokyo"},
{"name": "Bob", "age": 25, "city": "Osaka"}
],
"status": "ok"
}
`)
var data interface{}
if err := json.Unmarshal(jsonData, &data); err != nil {
panic(err)
}
// 2. JMESPathクエリを実行する
// クエリ: "users"配列から、各要素の "name" の値だけを抽出して配列にする
query := "users[*].name"
result, err := jmespath.Search(query, data)
if err != nil {
fmt.Println("Error:", err)
return
}
// 3. 結果を表示する
// resultは interface{} 型で返される
fmt.Printf("Query: %s\n", query)
fmt.Printf("Result Type: %T\n", result)
fmt.Printf("Result Value: %v\n", result)
// Output: Result Value: [Alice Bob]
}
■ 1. プロジェクトの文脈把握
- 着手前にプロジェクトの背景と意味を短時間で整理する
- 文脈の要素:
- クライアントが達成したいこと
- 読者や顧客の置かれた状況
- 関係者が大切にしたい価値
- タスクが全体で持つ役割
- 依頼内容が曖昧な場合でも「この案件は最終的に何をよしとするか」だけ先に確認する
- 文脈が整っているため判断にずれが生じない
■ 2. 完璧主義を避けた動的な進行
- 全てが揃わないと動けないタイプではない
- 動くことで目的の精度を上げていく手法を採用する
- 具体的な進め方:
- 最小限だけ整えてまず動く
- 仮の流れをつくって全体像を見る
- 動かす中で深掘りが必要な箇所を判断する
- 依頼者には要点だけ短く確認する
- 止めるのではなく進めながら整えるため、プロジェクトが滞らない
■ 3. 工程の事前設計
- 目の前のタスクだけでなく、その後に起きることを早い段階で組み立てる
- 設計される要素:
- 議事録の粒度や優先順位
- 記事や資料構成の作り方
- 誰の判断がどこで必要か
- 編集から校正、公開までの流れ
- 工程が設計されているため、その場の判断がほぼゼロになる
- 任せていても進行が乱れない理由はここにある
■ 4. 予定の先置きによるペース管理
- 期日を受け身で待つのではなく、自分から先に予定を決めて共有する
- 具体的な先置きの例:
- 「〇日午前にドラフト送りますね」
- 「午後に方向性だけ合わせましょう」
- 「その後は〇日までに進めます」
- 先置きによって関係者の動き方が決まり、全体のテンポが整う
- 気分や混雑に左右されないリズムが生まれる
■ 5. 初動の早さと周囲への配慮
- 外向的でも積極アピール型でもないが、仕事が前に進む
- 初動の早さが理由である
- 具体的な行動:
- 不明点は早めに依頼者へ確認する
- 途中段階をすぐ共有する
- 次の人が作業しやすい形で渡す
- クライアントが判断しやすい状態を整える
- 初動が早いと相手の返答も早くなり、全体が前へ転がりやすくなる
■ 6. 原因帰属ではなく打ち手志向
- プロジェクトが進まない理由を外部に置く言葉を使わない
- 使わない言葉:
- 「返事が遅いから進まない」
- 「条件が揃わないから無理」
- 「指示が曖昧だから止まってしまう」
- 使う言葉:
- 「ここだけ確認できれば進めます」
- 「一旦この形で前に出しておきますね」
- 「先に必要な材料を揃えておきます」
- 原因ではなく打ち手を見る姿勢が自然体の強さにつながっている
■ 7. 推進力の本質
- 推進力は説明の上手さや強い主張から生まれるものではない
- 推進力を構成する要素:
- 文脈をつかむ
- 動きながら目的を整える
- 工程を先に設計する
- 予定でリズムをつくる
- 初動を早くする
- 外に原因を置かない
- この積み重ねがプロジェクトを止めない土台になる
- 自然体、素直、誠実という姿勢が信頼を生み、進め方が推進力を裏打ちする
- 推進力は勢いではなく「整える力」の総量で決まる
第7版の「原則」と第6版の「プロセス」が合体した
第6版「5つのプロセス群」が「フォーカスエリア」として復活し、「40のプロセス」として帰ってきた。が内容は7版ベース
各プロセスのInput/Output,ツール,技法(=ITTOs)など実務的な「統合版」になった
既存の書籍の改訂を除けば、おそらく本書が、私がRDBやSQLについて書く最後の本になると思います(そのあたりの事情については次回エントリで触れます)。
■ 1. CSRF攻撃の成立条件
- CSRF(Cross-Site Request Forgery)は古くから知られる攻撃手法である
- 攻撃者が用意したサイトに仕込まれたフォームから、ユーザがログイン中のサービスに対してリクエストを送信する攻撃である
- ログイン済みのCookieが付与されたリクエストがサービスの投稿APIに準拠していれば、そのユーザのアカウントで不正な投稿が受理される
- 攻撃の手軽さと影響の大きさによって、XSSやSQLインジェクションと並ぶ有名な攻撃手法として認知された
- 従来の対策としては、One Time Token(CSRFトークン)をフォームに仕込み、トークンの一致によって投稿を受理する方法が一般的だった
■ 2. CSRF成立の本質的問題点
- CSRF攻撃が成立する根本原因は「攻撃者のフォームからのリクエストにもサービスのCookieが付与される」点である
- しかし、CSRFトークンが機能していた事実は「このリクエストはどこから来たものなのか」が分かれば対策できる証拠である
- 本来注目すべき欠落は「リクエストの出自がわからない」という点である
- SameSite Cookieの導入によって別のサイトからのリクエストにCookieが付与されないようにすることは対策として成立するが、本質的な問題はリクエストの出自が不明であることである
■ 3. Originヘッダの付与
- プラットフォームの回答は「リクエストにOriginヘッダを付与する」というものである
- 現在のブラウザでフォームをsubmitすると、送られるリクエストにOriginヘッダが付与される
- Originヘッダの値を確認すれば、リクエストが正規のサイトからではないことを容易に判別できる
- Cookieの有無に関わらず、サービスは「意図しないOriginからのリクエスト」を弾くことができる
- このヘッダの必要性は少なくとも16年前から議論されており、7年前にFirefoxが実装することで全てのブラウザがフォームのsubmitにOriginヘッダを付与するようになった
- SameSite Cookieが導入されるずっと以前から「リクエストの出自を知る」ことは可能であり、それを用いて攻撃リクエストを弾くことができた
- fetch()を用いた実装でOriginを確認しながら適切なAccess-Control-Allow-Originを返していれば、「どこから来たかわからないリクエスト」を弾くことはずっと可能であった
■ 4. SameSite Cookieの副次的効果
- SameSite Cookieの登場により、積極的な対策をしてこなかったサービスも受動的な変更によって保護される結果になった
- しかしこれはかなり副次的な効果である
- SameSite Cookieの本来の目的は3rd Party Cookieをマークすることであり、3rd Party Cookie Deprecateの終着点はSameSite=None Cookieが送られないようにすることである
- CSRFは3rd Party Cookieよりも遥かに古くから問題だったが、「サイトを跨いだCookieが送られること」よりも「リクエストの出自がわからないこと」の方がプラットフォームが対策すべき問題とされていた
- SameSite Laxがデフォルトになったことを理由に「Originのチェック」を怠った実装は、本質的な対策を怠った片手落ちの実装である
■ 5. CSRFトークンの必要性の再検討
- OWASPのCSRF Cheat Sheetでは今でもトークンベースの対策が推奨されている
- トークンベースの対策を推奨する理由として以下が挙げられる:
- XSSがあった場合の対策
- ヘッダを改変している可能性
- GETでAPIがあると成立する攻撃
- サブドメインが乗っ取られる攻撃
- XSS問題の反論:
- XSS自体を対策すべきであり、XSSによってDOMに展開されたCSRFトークンを盗めない道理はない
- ヘッダ改変問題の反論:
- ブラウザや拡張に脆弱性があれば、サービス側の対策はバイパスできるため、サービス提供者が想定すべき対策として視点がずれている
- ユーザ設定やProxyが意図的にOriginヘッダを改変する環境は、ルールを守っていないためサービス側が許容する必要はない
- GET API問題の反論:
- 様々な条件でSameSiteやOriginが機能しないリクエストを生成できるという指摘は、「APIがGETだった場合に攻撃が成立する」という条件に収束する
- 副作用のあるAPIをGETで提供している実装は前提として間違っている
- サブドメイン攻撃の反論:
- SameSite Cookieだけに依存した対策は問題があるため、一次防御は「リクエストのOriginのチェック」である必要がある
- CSRFトークンの利点:
- 実装がこなれており堅牢である
- フレームワークがデフォルトで提供することが多く、導入コストが低い
- 現状入っているなら積極的に外す理由はない
- 防御の認識の変更:
- CSRFトークンは一層目の防御ではなく、多層防御の二層目であると認識すべきである
- トークンを使用していても「リクエストの出自を確認する」実装は一層目にあるべきである
- 全ての場所でOriginを確認するのがプラクティスである
■ 6. Fetch Metadataの導入
- 本来は全てのリクエストにOriginをつけるべきだが、「OriginヘッダのあるリクエストはXHRからのもの」という前提の実装が蔓延していたため、ドラスティックな変更ができなかった
- Originヘッダとは別にFetch Metadataが定義された
- 現在のブラウザでは以下のヘッダが付与される:
- Sec-Fetch-Dest
- Sec-Fetch-Mode
- Sec-Fetch-Site
- Sec-Fetch-User
- リクエストの出自を確認する手法は整備されており、これらを無視することはプラットフォームが差し伸べている手を振り払うことと同じである
■ 7. 令和時代の実装プラクティス
- 副作用があるエンドポイントの実装における優先順位:
- POSTにする(副作用のあるAPIをGETにしない)
- Originを確認する
- SameSite Lax/Strictを明示する
- Fetch Metadataも確認する
- Fetch Metadataのサポートに不安がある場合は「存在したら値をチェックする」実装でも良い
- Sec-プレフィックスはJavaScriptから操作できないヘッダであるため、値がある場合だけのチェックでも意味がある
- 実装の特徴:
- 追加のストレージコストが不要である
- コードだけで実装できるためレイテンシーが最小である
- フレームワークのレールの基盤として存在することが望ましい
- この実装から逸脱するコードが必要になった場合、プラットフォームが推奨するレールから外れていることを認識した上で、CORSなどの適切な対策をしながら拡張すべきである
- このベースを伴わずにトークンを載せても片手落ちである
- この実装をベースにしてもトークンがないと防げないCSRFが可能であれば、それはプラットフォームにおけるバグの可能性が高く、W3CのWebAppSecなどで議論すべき題材である