Slide 1

Slide 1 text

技術的負債を 正しく理解し、正しく付き合う Mar. 23 2025 PHPerKaigi 2025 Shogo Kawase / @shogogg

Slide 2

Slide 2 text

河瀨 翔吾 / Shogo Kawase 株式会社 PR TIMES ソフトウェアエンジニア シン・アジャイルコミュニティ 運営メンバー I LOVE... 型安全 / アジャイル / F1 / ももいろクローバーZ shogogg shogogg 自己紹介

Slide 3

Slide 3 text

We are Hiring!!

Slide 4

Slide 4 text

● 技術的負債という言葉の解像度を上げ、エンジニア同士 だけでなく、非エンジニアとも語れる ようになる ● 技術的負債との付き合い方のヒント を持って帰ってもらう Today’s Goal

Slide 5

Slide 5 text

1. 技術的負債とは 2. 技術的負債はなぜ生まれるのか 3. 技術的負債とどう付き合っていくべきか 4. 技術的負債を最小限に抑える取り組み・テクニック 5. まとめ おしながき

Slide 6

Slide 6 text

技術的負債とは

Slide 7

Slide 7 text

Photo: Carrigg Photography, CC BY-SA 3.0, via Wikimedia Commons ● WikiWikiWeb の開発者 ● アジャイルソフトウェア開発宣言 に署名した17人の1人 ● 技術的負債という概念の生みの親 ※諸説あり Ward Cunningham

Slide 8

Slide 8 text

“負債のメタファー を発明したの は、当時の自社プロダクト WyCash で進めているリファクタリングにつ いて上司に説明するためでした。 〜中略〜 上司に説明するとき、それが金融系 ソフトウェアだったので金融の例え 話を使い、それを「負債のメタ ファー」と名付けました。” Photo: Carrigg Photography, CC BY-SA 3.0, via Wikimedia Commons

Slide 9

Slide 9 text

“もしも自分たちが書いているプロ グラムを、金融の世界に関する正し い捉え方だと自分たちが理解した姿 と一致させることができなくなれば 自分たちは絶えずその不一致につま ずき続けることになり、開発スピー ドは遅くなっていくでしょう。それ はまるで借金の利子を払い続ける かのようです。” Photo: Carrigg Photography, CC BY-SA 3.0, via Wikimedia Commons Ward Explains Debt Metaphor より

Slide 10

Slide 10 text

● Ward Cunningham の語る「負債のメタファー 」は、今日我々が イメージする「技術的負債 」よりも限定的な概念である。 ● その後、このメタファーがあちこちで引用されていった結果、 「技術的負債 」という言葉が定着し、解釈も拡大していった。 ● そのため一般的な原理・原則等と異なり、学術的かつ統一された 定義というものは実は存在しない 。 技術的負債とは

Slide 11

Slide 11 text

「正しい」とは?

Slide 12

Slide 12 text

󰢙

Slide 13

Slide 13 text

なのでここからは すべて個人の意見です 😋

Slide 14

Slide 14 text

Q. 技術的負債 とは?

Slide 15

Slide 15 text

A. ソフトウェアの 変更容易性 を下げる ありとあらゆる要素

Slide 16

Slide 16 text

● コードが十分に整理されていない・ドキュメントが未整備 ➡ 何が書いてあるのか読み取るのが困難 ➡ どこに何があるのか・どれが何なのかわからない ● ライブラリやランタイムのバージョンが古いまま放置されている ➡ 便利な新機能などが導入できない ➡ 脆弱性などが発覚してもすぐに対応できない ● テストが自動化されていない ➡ 変更の度に手動で大量のリグレッションテスト ➡ テスト漏れが生じるリスク 変更容易性が低い状態の例

Slide 17

Slide 17 text

● 改修するための作業量が読めず、やるにしても時間が掛かる 開発速度⬇⬇・開発コスト ⬆⬆ ● 改修によって生じる影響の度合いや範囲が読めない プロダクト品質 ⬇⬇・障害リスク ⬆⬆ ● 変更の手間やストレスが大きく、開発者に負担が掛かる 開発者のモチベーション ⬇⬇・離職率⬆⬆ 変更容易性が低いと……

Slide 18

Slide 18 text

技術的負債=ビジネス的には リスク

Slide 19

Slide 19 text

● ビジネスにおいてリスクは必ずしも避けるべきものではなく、 適切に管理 すべきもの。 ● 負債=借金もその内のひとつ 。もちろん借金には様々なリスクが 伴うが、それによって大きな成長に繋げることもできる。 ● 技術的負債 も同様で、過度に回避しようとするあまり、機動性や スピードを犠牲にしすぎると、逆にそれがネックとなる。 負債のリスクを把握し、適切にコントロールすることが重要 。 ● 技術的負債 はビジネス的なリスクである。つまり開発者だけの問 題ではなく、組織全体で理解し、立ち向かう必要がある 。 技術的負債=リスク=悪?

Slide 20

Slide 20 text

技術的負債はなぜ生まれるのか

Slide 21

Slide 21 text

● スキルの不足や事業ドメインの理解不足 ● 技術の進歩・環境の変化 ● フレームワーク・ライブラリの導入 ● スケジュールの優先と人の性 ● プロトタイプの本番運用 技術的負債はなぜ生まれるのか ※あくまで例であり、他にも色んな理由があります。

Slide 22

Slide 22 text

スキルの不足や事業ドメインの理解不足

Slide 23

Slide 23 text

誰だよ、こんなひどいコード を書いたヤツは…… プログラマーの日常

Slide 24

Slide 24 text

俺じゃん プログラマーの日常

Slide 25

Slide 25 text

スキルの不足や事業ドメインの理解不足 ● スキルの向上 やドメインの理解度向上 によって、数ヶ月前のコー ドを見るとその酷さにめまいがする経験、ありますよね? ● 実装当時はベスト だと思った設計や選択が、後から見直してみると 理想から剥離していることは少なくない。 ● そういった古いコードを放置 していると、それが参考にされたり、 コピーされることで増殖していく 。

Slide 26

Slide 26 text

技術の進歩・環境の変化

Slide 27

Slide 27 text

class User { var $_name; function __construct($name) { $this->_name = $name; } function getName() { return $this->_name; } } PHP 4 時代のクラス プロパティに可視性がなく ”_” で始まる名前は内部用、という慣習 もちろん Property Promotion なんてない 引数も戻り値も型は指定できない

Slide 28

Slide 28 text

class User { function __construct( public readonly string $name ) { } } PHP 8 時代のクラス

Slide 29

Slide 29 text

この10年での PHP の進化(抜粋) ● NULL 合体演算子(PHP 7.0) ● スカラー型宣言(PHP 7.0) ● 戻り値の型宣言(PHP 7.0) ● 型付きプロパティ(PHP 7.4) ● アロー関数式(PHP 7.4) ● 配列スプレッド演算子(PHP 7.4) ● 名前付き引数(PHP 8.0) ● アトリビュート(PHP 8.0) ● match 式(PHP 8.0) ● nullsafe 演算子(PHP 8.0) ● Property Promotion(PHP 8.0) ● enum 型(PHP 8.1) ● never 型(PHP 8.1) ● スプレッド演算子の連想配列対応(PHP 8.1) ● Readonly Propperty(PHP 8.1) ● Readonly Class(PHP 8.2) ● プロパティフック(PHP 8.4) ● 非対称可視性(PHP 8.4)

Slide 30

Slide 30 text

消えていった(消えそうな)機能の例 ● ereg 関数(PHP 5.3 で非推奨、PHP 7.0 で削除) ● mysql_* 関数(PHP 5.5 で非推奨、PHP 7.0 で削除) ● mcrypt 拡張(PHP 7.1 で非推奨、PHP 7.2 で削除) ● 動的プロパティ(PHP 8.2 で非推奨) ● 暗黙的な nullable パラメータ(PHP 8.4 で非推奨)

Slide 31

Slide 31 text

技術の進歩・環境の変化 ● コードは腐る :実装当時は問題なかったコードであっても、時代の 流れと共に陳腐化したり、動かなくなることも。 ● 規模の変化 :ユーザー数やアクセスの増加に伴って、データベース 設計やパフォーマンス面での問題などが顕在化。 ● 運用環境の変化 :クラウド移行やコンテナ化、冗長構成化などに よって、問題なく動いていたコードが使えなくなる。

Slide 32

Slide 32 text

フレームワーク・ライブラリの導入

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Laravel 4.2 ➡ 5.0 で起きたこと ● ディレクトリ構成の大幅な変更 ● Contracts(インターフェース)の導入 ● フィルターの廃止・ミドルウェアの導入 ● FormRequest の導入 ● Form/HTML ヘルパーの廃止 ● (ここに書き切れないその他たくさんの変更)

Slide 35

Slide 35 text

Laravel 4.2 ➡ 5.0 で起きたこと ● ディレクトリ構成の大幅な変更 ● Contracts(インターフェース)の導入 ● フィルターの廃止・ミドルウェアの導入 ● FormRequest の導入 ● Form/HTML ヘルパーの廃止 ● (ここに書き切れないその他たくさんの変更)

Slide 36

Slide 36 text

他にも…… ● Codeception + Specify(5.0 以降は使用不能に) ● Symfony 2.0 ● Angular 2.0 ● Vue 3.0 ● React + Recoil

Slide 37

Slide 37 text

● フレームワークやライブラリを導入することで、短期的には開発速度の 向上が望める。 ● 人気のフレームワークなら人材の確保 でも有利。 ● ただし、どんなフレームワーク・ライブラリにも破壊的変更 や開発終了 のリスクがあるし、人気がいつまで続くかもわからない。 ● 一度導入すれば継続的なバージョンアップ作業 にも工数が掛かる。 (放置すると脆弱性が見つかった時にすぐに対応できない場合も……) ● それらの技術を得意とするメンバーの離職 などによってメンテナンス不 能に陥り、一気に負債化するケースも。 フレームワーク・ライブラリの導入

Slide 38

Slide 38 text

スケジュールの優先と人の性

Slide 39

Slide 39 text

ヤバイ、納期が近い……! コードの整理は後日にしよう。 レビューお願いします、っと……。 よくある話①

Slide 40

Slide 40 text

ちょっと気になる点は残ってるけど、 やり取り多くなるとしんどいし、時間も あまり残ってないし……まぁいっか。 Approve ポチッとな。 よくある話②

Slide 41

Slide 41 text

なんだこれ? よくわからないコードだな……。 手を入れるの怖いし、指示された最低限 の部分だけ変更してコミットしよう。 よくある話③

Slide 42

Slide 42 text

今回のプロジェクトはスケジュール優先 だし、誰も自動テストを書いたことがな いんだよな……。 余裕ができたら自動化すればいいよね? よくある話④

Slide 43

Slide 43 text

スケジュールの優先と人の性 ● スケジュールを優先 した結果、設計やコーディングに十分な時間を とれず、最適とは言えないコードが生まれてしまう。 ● さらに人は弱い生き物 なので、楽な方へと自然に流れていく。 ● 強い意志を持った人であっても、疲労や納期のプレッシャー に気 付かない内に負けてしまう。 ● そうやって生まれたコードがコピーされ、増殖していく 。

Slide 44

Slide 44 text

プロトタイプの本番運用

Slide 45

Slide 45 text

とあるスタートアップにて…… フィードバックを集めたいから、とりあえず動くものを用意したい。 スピード最優先で雑にプロトタイプを作ってくれないか! わかりました!実際に製品開発を開始するときは作り直す必要があり ますが、問題ないですよね? もちろん! その時は予算も時間もちゃんと確保するよ!

Slide 46

Slide 46 text

とあるスタートアップにて…… フィードバックを集めたいから、とりあえず動くものを用意したい。 スピード最優先で雑にプロトタイプを作ってくれないか! わかりました!実際に製品開発を開始するときは作り直す必要があり ますが、問題ないですよね? もちろん! その時は予算も時間もちゃんと確保するよ! 数週間後...

Slide 47

Slide 47 text

とあるスタートアップにて…… 評判は上々! このまま一気に本格運用するぞ!! ちょっと待ってください! 実際の製品版は作り直すって約束でしたよね!? この機を逃したら先を越されてしまうかもしれない!今回はあきらめ てくれ!ところでこの機能を追加してくれないか、明日までに!

Slide 48

Slide 48 text

プロトタイプの本番運用 ● 「プロトタイプだから〜」「後で作り直せるから〜」という約束が 守られることはない 。 ● さらに初期フェーズでは頻繁かつ短納期での機能追加・仕様変更 が頻発し、さらにコードが複雑化していく。 ● プロトタイプだと思って自動テストを書いていない 場合、日々の 変更によって状況はどんどん悪化していく。 ● そうやって生まれたコードがコピーされ、増殖していく 。

Slide 49

Slide 49 text

技術的負債とどう付き合っていくべきか

Slide 50

Slide 50 text

● スキルの不足や事業ドメインの理解不足 ● 技術の進歩・環境の変化 ● フレームワーク・ライブラリの導入 ● スケジュールの優先と人の性 ● プロトタイプの本番運用 おさらい:技術的負債はなぜ生まれるのか

Slide 51

Slide 51 text

● つよつよエンジニアだけを集めて…… ● 最初からあらゆる変化に対応できるように備えて…… ● フレームワークや外部ライブラリを導入せずに…… ● スケジュールはめっちゃ余裕をもって…… ● プロトタイプ検証が終わったらゼロから作り直そう! それなら……

Slide 52

Slide 52 text

● つよつよエンジニアだけを集めて…… ● 最初からあらゆる変化に対応できるように備えて…… ● フレームワークや外部ライブラリを導入せずに…… ● スケジュールはめっちゃ余裕をもって…… ● プロトタイプ検証が終わったらゼロから作り直そう! それなら…… なるほど完璧な作戦っスねーッ

Slide 53

Slide 53 text

● つよつよエンジニアだけを集めて…… ● 最初からあらゆる変化に対応できるように備えて…… ● フレームワークや外部ライブラリを導入せずに…… ● スケジュールはめっちゃ余裕をもって…… ● プロトタイプ検証が終わったらゼロから作り直そう! それなら…… 不可能だという点に 目をつぶればよぉ

Slide 54

Slide 54 text

● 仮につよつよエンジニアだけを集めたとしても、あらゆる変化 に備えることは不可能 に近い。 ● フレームワークやライブラリを一切使わない場合、それらに相当 する機能を自分達で作り、メンテする コストが発生する。 ● 現代のビジネス環境では、すばやく仮説検証サイクルを回し、市 場投入のタイミングを逃さないことが極めて重要。のんびり開発 している暇はない 。 技術的負債は必ず生まれる!

Slide 55

Slide 55 text

● ビジネスにおいてリスクは必ずしも避けるべきものではなく、適 切に管理すべきもの。 ● 負債=借金もその内のひとつ。もちろん借金には様々なリスクが 伴うが、それによって大きな成長に繋げることもできる。 ● 技術的負債 も同様で、過度に回避しようとするあまり、機動性や スピードを犠牲にしすぎると、逆にそれがネックとなる。 負債のリスクを把握し、適切にコントロールすることが重要 。 ● 技術的負債はビジネス的なリスクである。つまり開発者だけの問 題ではなく、組織全体で理解し、立ち向かう必要がある。 おさらい:技術的負債=リスク=悪?

Slide 56

Slide 56 text

● ビジネスで成果を生むため、必要な技術的負債は受け入れてい く必要がある。 ● 無策に・無闇矢鱈に負債を抱えていい訳ではない。不要な負債を 抱えないためにも、計画的な管理と返済を前提とした意思決定 が必要。 技術的負債をコントロールする

Slide 57

Slide 57 text

No content

Slide 58

Slide 58 text

技術的負債を最小限に抑える取り組み・テクニック

Slide 59

Slide 59 text

● 機能追加や修正の度に影響範囲を調べ、手動でテストをするのはとても大 変な作業。プロダクトが大きくなればなるほどそのコストは増大 。 ● ランタイムやフレームワーク、ライブラリのバージョンアップ作業は影響 範囲が大きくなりがち。 (全体のリグレッションテストを手動で……?😱) ● 自動テストを導入 することで、機能追加はもちろん、ランタイムのバー ジョンアップなども短時間かつ自信を持って 行うことができるようにな る。 ● もちろん継続的インテグレーション(CI) もご一緒に。 自動テストを導入する

Slide 60

Slide 60 text

自動テストを書く余裕がない……? https://zenn.dev/coconala/articles/write-tests-in-parallel https://speakerdeck.com/o0h/phpcon-nagoya-2025

Slide 61

Slide 61 text

● 先に述べたとおり、フレームワークやライブラリを導入すること で、バージョンアップ対応のコスト や、破壊的変更・開発終了の リスクが生じる。 ● そのため、フレームワークやライブラリの導入の際は、まず必要 性や導入によるメリットを十分に検討し、場合によっては導入を 見送る決断 も必要。 ● 導入する場合も、将来性や安定性、他パッケージへの移行のしや すさなどをしっかりと見極め、適切なパッケージを選ぶようにす る。 依存を最小限に抑える・厳選する

Slide 62

Slide 62 text

● 「○○さんが作ったところだから」「□□さんが詳しいから」で 任せきりになっていると、ボトルネックになる し、退職時に詰 む。 ● 属人性を排除し、チーム全員がコードに責任を持ち、誰でも変更・ 改善できるようにすることでボトルネックは解消 する。 ● また、知識がチーム全体で共有 され、メンバーの退職や異動によ るリスクを最小化 できる。 ● ペアプロやモブプロもオススメです。 コードの共同所有

Slide 63

Slide 63 text

● 「クラス名とメソッド名を見れば、みんなわかるでしょ」「やって ることがシンプルだし、コメントいらないよね?」は危険! ● コードの意図 をコメントなしで100%表現するのはとても難しい。 実装時の背景や経緯が残ることで、リファクタリングも容易に。 ● 論理名(日本語)と物理名(英語)の関係を全員が理解できている とは限らないため、クラスやプロパティの説明も大事 。 ● チーム全体での知識共有・コードの共同所有が促進され、新規参画 したメンバーもスムーズに作業に参加可能に。 コメントやドキュメントをちゃんと書く

Slide 64

Slide 64 text

● 腐敗防止層: 外部やレガシーシステムの複雑さを吸収し、内部をクリー ンに保つための設計パターン。 ● 外部依存との間に: 依存するパッケージや外部 API などとの間に抽象化 された腐敗防止層を置くことで、破壊的変更への対応や、将来的な乗り 換えが容易 になる。 ● レガシーコードとの間に: 新しい機能を開発する際、レガシーコードを 直接参照せずに腐敗防止層を挟むことで、新しいコードをクリーンに保 ち、リファクタリングも容易 になる。 腐敗防止層

Slide 65

Slide 65 text

腐敗防止層 https://speakerdeck.com/okashoi/interface-and-anti-corruption-layer

Slide 66

Slide 66 text

● 返済せずに放置すれば負債は増え続ける 。 ● 整理・整頓・リファクタリングを「いつかやる 」ではなく日常の ルーティン に組み込み、文化を醸成 することで、コードをクリー ンに保つ。 ● ボーイスカウトルール: コードに手を入れる際、ちょっとだけで もコードをキレイにする。 ● リファクタリングデー: 毎月必ずリファクタリングのための日 を 設ける。 ● 20%ルール: スプリントの20%を開発者目線の改善 に充てる。 日常的な整理・整頓・リファクタリング

Slide 67

Slide 67 text

リファクタリングデーについて https://developers.prtimes.jp/2021/12/13/introducing-refactoring-day/

Slide 68

Slide 68 text

まとめ

Slide 69

Slide 69 text

● 技術的負債はビジネス的なリスク であり、開発者だけの問題では ない。 ● 無闇に敵視したり回避したりするのではなく、必要な負債は受け入 れつつ、最小限に抑えることが重要 。 ● 放置すると負債が膨らみ、手に負えなくなる。適切にコントロー ルすることで、スピードと柔軟性を維持するのが吉。 まとめ

Slide 70

Slide 70 text

THANK YOU!!

Slide 71

Slide 71 text

● 【翻訳】技術的負債という概念の生みの親 Ward Cunningham 自身による説明 - t-wada のブログ ● よし、技術的負債について知ろう - Qiita ● 『テスト書いた方が開発が早いじゃん』を解き明かす #phpcon_nagoya ● 時間がないからこそ、テストを書く ● 設計の考え方 - インターフェースと腐敗防止層編 #phpconfuk Appendix: 参考資料