💸

技術的負債ってなんやねん?──「しゃあない」を積んだ未来、自分にツケが回ってくる話

に公開

技術的負債ってなんやねん?──「しゃあない」を積んだ未来、自分にツケが回ってくる話

みなさん、こんにちは!フロントエンドエンジニアの @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 を検証する

とかでもええ。最低限の品質基準を設けて、それは準拠するような組織作りをする。めっちゃ大事。

🎯 最後に

負債は、いつか返さな破綻する。
でも、一気に返せなくても、積み重ねていけばちゃんと返せる。

せやから、ちょっとだけサボらんようにしよ。
未来の自分のために。チームのために。な。

小さく返す、が最強やで。

あとがき

ここまで読んでくれてありがとう!
実はこれ、ちょっと前の自分に言いたかったことばっかりなんよな。

負債って、放置すると消耗戦になるし、でも向き合い方さえ間違えなければ、ちゃんと味方になる。

あなたのチームが、ほんの少しでも「しゃあない」を減らすことができたらうれしいです!

今後、技術的負債の返済について、さらに具体的な記事を書いていこうと思ってるで~、期待せんと待っててな!

👉 待たせたな!これも見てってや~!

https://zenn.dev/nyaomaru/articles/technical-debt-structure


🔧 おまけの宣伝

文字列や配列の分割、地味に毎回書いてへん?

そこで、divider っていうユーティリティライブラリを作ったで〜
気に入ったら してな!

🔗 GitHub: nyaomaru/divider
🎮 Playground: divider-docs.vercel.app

他の記事もあるで〜:

Discussion