技術的負債ってなんやねん?──「しゃあない」を積んだ未来、自分にツケが回ってくる話
技術的負債ってなんやねん?──「しゃあない」を積んだ未来、自分にツケが回ってくる話
みなさん、こんにちは!フロントエンドエンジニアの @nyaomaru です!
最近は、AI と共に快適な開発ライフをお過ごしでしょうか?僕は、めっちゃ仲良しです。ズッ友です。
「今はこれでええか……」
「リファクタはあとでな……」
── そんな “しゃあない” を積み上げた経験、ありますよね?
今回は、そんな“借金”がどう積もって、どう返すのが現実的か、
👉 なるべく実務ベースで、ゆるく深掘りしていきます。
ほんなら、一緒に見てこな!
💸 技術的負債(Technical debt)とは
Strategic な実装ではなく、Tactical な実装の積み重ねによって、認知負荷の高い複雑なコードが生まれていること。
つまり、質よりも量を求めた結果、生まれてしまう「しゃあない」ポイントの積み重ねやな。
ほんで、「借金(debt)」って言葉が使われてるのは、そのまま放置しつづけると、「利子(=負担)」が溜まるからや。
どんなことかというと ──
- 「今はとりあえず、この書き方でええか…でも本当はこうするべきやねんけど、しゃあない!」って思いつつ急いで書いたコード
- 「よ~わからんけど、動いてるしリリースしちゃお、しゃあない!」って深い理解をせずにコピペしたコード
- 「本番間に合わせるためにテストは後回しや、しゃあない!」って判断したテストのないコード
→ これらの「しゃあない」ポイントが溜まっていくと、未来の自分(やチーム)にツケが回ってくる可能性がある。つまり、短期的にはええんやけど、長期的には「ドマイナス」や!
🧠 技術的負債の実情
でもな、知ってる。
みんな書きたくて負債コードを書いてるわけじゃないし、サボりたくてコピペしてるわけやない。同調圧力があることもわかる。
スタートアップやと、多大な借金してまで急いでリリースするほうがビジネス的に成功することがあるのもわかる。大きな企業だって、急いでリリースしないと競合他社に負けてまう。
他の人の実装をリスペクトしてるし、
期限も決まってるし、
ちょっとサボりたいし、
「せやから、しゃあない!」
・・・ってなったら負けや!!!
そこから、技術的負債は始まってるねん。そのしゃあない、誰が片づけるん?
「諦めたら、そこで試合終了やで。」(言いたいだけ)
🚨 ところで、何が問題なん?
ここまで読んで、「ほ~ん、で?」となってる人もおるやろうから、具体的に何が問題なのかを見ていこうと思うで
- 新機能が追加しにくくなる
- 新しいメンバーがコード理解しづらい
- デバッグ・修正に時間がかかる
- アラート対応に追われる
- ライブラリの更新ができない
つまり、運用・保守がしんどくなるってことやな。
🧱 新機能が追加しにくくなる
簡単そうに見える改修の裏に、大量のリファクタがひそむようになる。
リファクタを後回しにして場当たり対応を続けると、負債は指数関数的に膨らむねん。
🧭 新しいメンバーがコード理解しづらい
ドキュメントも型もない実装やと、新規参画者は
「これ、なんで any 型なん?」
「ここで使ってる関数とあそこで使ってる関数って、何が違うん?」
「API のレスポンスの想定が実際と違うんやけど、何で動いてるん?」
みたいな認知負荷がとんでもなく肥大化して、コード全体を理解して生産性を出せるようになるのに2~3か月くらいかかるようになるねん。
🐌 デバッグ・修正に時間がかかる
不要なコードがそのままやったり、ライブラリが古いまま放置されることで、ビルド時間が長時間化し、ローカルでの検証やデプロイの速度が低下してまう。シンプルに時間かかるやつやな。
例えば
- STG 環境への deploy が終わったあとの動作検証を手動で行う。
- E2E のメンテがされておらず、落ちまくるし信用できなくなる。
- コンポーネントテストが意図しないところで落ちる
そうなると、もう何を信用したらええかわからんようなって、動作検証を念入りにやらなあかんようになる。ほんで、既存のバグ見つけたりして、さらに時間かかったりするねん。
🔔 アラート対応に追われる
Sentry や Datadog にバンバン、アラートが飛んでくる。特に Cannot read properties of undefined
とかな。本番のエラーは対応優先度が高いから、モグラ叩きのように、次から次へと終わりが見えない対応に追われてしまう。単純な null check や optional chain にするだけで解消できるやつとかやねんけどな。
その中でも、業務的に必須な対応がまぐれこんでるから、油断できひん。やから、本質的な対応がどんどん後回しにされていくねん。
🧟 ライブラリの更新ができない
気づいたら依存しているライブラリの幅が広すぎて、最新のライブラリに更新できひんようになる。
業務の要件のみを進めた結果、さらに傷口が広がって手に負えなくなる。
そうすると、いわゆるレガシーコードがどんどん生まれていくねんけど、どうしようもなくなる。
でも、時代はどんどん進んでいくから、ライブラリの更新してる間に業務は山ほど溜まるし、載せ替えの間も開発は進むから、コンフリクトしまくって、想定よりもはるかに時間が取られてしまうねん。
☠️ 最終的に
本番稼働してるシステムを優先せなアカンから、大胆な変更はできひんくなって、肥大化した「大きな泥だんご」ができる。
どんどんパフォーマンスが劣化していき、根本改善ができず、単一機能の改修のみにとどまってくる。
そうすると、顧客もいつまでも待ってくれへんから、新しい企業が出した新しいシステムに飛びついて去ってしまう。
ほんで、これらのレガシーコードを触り続けるのに辟易として、優秀なエンジニアが組織を去ってしまう。
でも逆に言えば、ちゃんと手を打てば、優秀な人材も、信頼も、プロダクトも ── 守れるかもしれへん、ってことや。
🛠️ じゃあどないすんの?
借金は一気に返済できひん。コツコツ返していかなあかん。辛いけど、コツコツ。それが最短ルートや。もしくは、一撃でフルリプレイスするギャンブルって手もあるけど、オススメせえへん。銀の弾丸はこの世にないねん。
ほな、以下にどないしたらええかを書き出してみたで~
- リファクタリングする(小さくても OK)
- テストやドキュメントを追加する
- 「負債リスト」をチームで明示化して、計画的に返す
- そもそも急ぎすぎないスケジュール設計
- 当たり前品質を上げる
🧼 リファクタリングする
これに尽きる。
基本はチケットベースやらイシューベースで開発すると思うねん。せやから影響範囲のスコープを絞って対応する。それは正解や。(ちなみ hotfix は例外や。範囲絞って対応したほうが絶対にええ。急いでるし、ミスしやすい)
やけど、それはパーフェクトな実装を続けてきた前提での理想論や。
実装してる中で、
「あ、ここ型ついてへんやん、any なってもうてるなぁ」
「早期リターンすれば、もっと短く書けそうなロジックあるなぁ」
「DRY にできそうな実装がいっぱいあるなぁ」
って思ったら、ちょっとめんどくさいけど、直そ。
ちいさいリファクタの積み重ね。めっちゃ大事。
📑 テストやドキュメントを追加する
テストがあると、安心できる。
逆にテストがないロジックを、本番稼働中のシステムで修正しようとすると、意図しないバグが生まれるリスクがあるわけやから、それなりに動作検証せなアカン。
せやから、できる範囲でテストを追加していくのも、将来的な技術的負債を減らすことに貢献するんやな。
ドキュメントを追加するのも、いい手やと思う。なんでその実装をしたのか?の WHY を書いておくと、後で読む人はすごく助かる。コメント一行あるだけで救われる人がおる。
ドキュメントって、未来のチームメンバーへの手紙やねん。
「なんでこうしたか」があるだけで、無駄なリバースエンジニアリングが減って、余計な時間を使わんで済む。結果的に、未来の自分を救うことになる。
せやから、テストとドキュメント、積極的に書いてこな。めっちゃ大事。
📋 「負債リスト」をチームで明示化して、計画的に返す
そもそも、どんなことが「負債」に感じてて、どうやって対応していけばいいのか?がチームの中で共通認識ないと、傷口がさらに広がっていくばかりや。
開発は一人でやるもんやないから、みんなで目線揃えないと、中々良くなっていかへん。
全員にとって正しい書き方みたいなものはないんやと思うけど、それでも「ここは絶対守ろな!」って取り決めを eslint
で rule として追加したり、コーディング規約やガイドラインとして記載したりして、認識を揃えるのがええな。
チケットや issue で可視化できたら、あとは順番にみんなで対応していくだけや。一人で対応する必要はあらへん。みんなで一緒にやっていく。めっちゃ大事。
🕰️ 急ぎすぎないスケジュール設計
リリーススケジュールがカツカツやと、どうしても焦ってまう。
エンジニアは真面目な人が多いから、頑張って間に合わせようとする。
やけど、急いで作った実装は粗くて、下手したら「とりあえず動いた!」レベルで本番までリリースされてまう。
ド短期では課題を解決できるけど、長期的にはその負債が残り続けるし、いつか返済しないと破綻してまう。
この潜在的な負債のリスクを盛り込んだスケジュール設計ができないと、持続可能なシステムは作れへんし、下手したら5年くらいでおじゃんになってまう。
先を見据えて、カツカツ過ぎずに、リファクタが少しできるくらいの余裕があるスケジュールを組む。めっちゃ大事。
📏 当たり前品質を上げる
ある組織では、型は zod
でバチバチに書くし、テストは unit test から E2E test までもちろん書くし、定常的にリファクタするのも当たり前で、human readable な code を提供することが、最低限のベースラインのとこもある。
一方で、納品期限優先でとにかく動けばええから、見た目上動いてれば OK!の基準で実装していくとこもある。
期限の問題もあると思うけど、まずは基本的な品質のベースラインをある程度明確にするのが大切や。
例えば
- lint error は無視しない
- test 書く
- CI/CD で lint と test を検証する
とかでもええ。最低限の品質基準を設けて、それは準拠するような組織作りをする。めっちゃ大事。
🎯 最後に
負債は、いつか返さな破綻する。
でも、一気に返せなくても、積み重ねていけばちゃんと返せる。
せやから、ちょっとだけサボらんようにしよ。
未来の自分のために。チームのために。な。
小さく返す、が最強やで。
あとがき
ここまで読んでくれてありがとう!
実はこれ、ちょっと前の自分に言いたかったことばっかりなんよな。
負債って、放置すると消耗戦になるし、でも向き合い方さえ間違えなければ、ちゃんと味方になる。
あなたのチームが、ほんの少しでも「しゃあない」を減らすことができたらうれしいです!
今後、技術的負債の返済について、さらに具体的な記事を書いていこうと思ってるで~、期待せんと待っててな!
👉 待たせたな!これも見てってや~!
🔧 おまけの宣伝
文字列や配列の分割、地味に毎回書いてへん?
そこで、divider
っていうユーティリティライブラリを作ったで〜
気に入ったら ☆ してな!
🔗 GitHub: nyaomaru/divider
🎮 Playground: divider-docs.vercel.app
他の記事もあるで〜:
Discussion