「誰だこのコード書いた奴は!」と叫ぶ前に――深夜のVS Codeと、見えない幽霊たち
はじめに:異国の空の下、スパゲッティコードと対峙する
やあ、みんな。今日もコンパイラと格闘してる?
僕は今、日本から遠く離れた海外のオフィス(といっても、今日は在宅でコーヒー片手にこのブログを書いてるけど)で、いつものようにVisual Studioを立ち上げている。ここでの生活も長くなってきたけど、エンジニアとしての悩みは世界共通だね。
今日はちょっと、いつもとは違う話をしたいと思う。技術的なTipsとか、最新の.NETの機能紹介とか、そういう「明日使えるコード」の話じゃない。もっと根本的で、でも僕らの精神衛生に直結する大事な話。「技術的負債(Technical Debt)」についてだ。
正直に言おう。僕らはみんな、他人のコードが嫌いだ。
特に、自分が書いたわけじゃない、ドキュメントもない、テストコードも不十分な「レガシーコード」を見た瞬間、胃がキリキリするあの感覚。わかるよね?
WPF(Windows Presentation Foundation)をやっている人なら共感してくれると思うけど、XAMLとViewModelが複雑怪奇に絡み合い、本来あるべきMVVMパターンが崩壊し、Code-behindにビジネスロジックがねじ込まれているのを見た時の、あの絶望感。「なんでICommandを使わずにClickイベントハンドラに全部書いてるんだよ!」「このBindingのパス、魔法の文字列すぎるだろ!」って叫びたくなる瞬間。
海外で働いていると、日本よりも人の入れ替わりが激しい分、こういう「誰が書いたかわからないコード」に遭遇する確率は格段に高い。まるでジャングルの奥地で、前の文明が遺した謎の遺跡を発掘しているような気分になることもしばしばだ。
でもね、最近思うんだ。
「技術的負債=悪」と決めつけて、過去のエンジニアを心の中で罵倒するのは、実はすごく損をしているんじゃないかって。今日は、僕がこっちに来て、数多の「クソコード(あえて愛を込めてこう呼ぶよ)」と格闘する中で気づいた、技術的負債の本当の姿について話していくよ。
技術的負債という言葉の「罠」
まず、「技術的負債」という言葉自体が、ちょっと誤解を招きやすいと思わない?
「負債」って聞くと、借金とか、マイナスのイメージしかない。まるで、前の担当者がサボったツケを、今の僕らが払わされているような被害者意識を生みやすい言葉だ。
僕も昔はそう思っていた。「前のエンジニアがもっときれいに設計していれば」「なんでここで継承を使ったんだ、コンポジションでいいだろ」って、モニターに向かって文句を言っていた時期がある。特に日本にいた頃は、完璧主義なところがあったから、少しでも汚いコードを見ると許せなかったんだ。
でも、海外のチームに入って、考え方がガラッと変わった。
こっちのエンジニア、特にスタートアップ界隈の連中は、「動くものが正義(Working software is the primary measure of progress)」というアジャイルの原則を、骨の髄まで理解している。彼らにとってコードは「作品」じゃなくて「手段」なんだ。
ある時、ものすごく入り組んだ非同期処理(async/awaitの使い方がめちゃくちゃで、デッドロック寸前のコード)を見つけて、同僚のデイビッド(仮名)に「これ、ひどくない? リファクタリングが必要だよ」って言ったんだ。
そうしたら彼はこう言った。
「ああ、それね。去年のブラックフライデーのセール直前に、サーバーが落ちかけて、急遽パッチを当てた時のやつだよ。あのコードのおかげで、会社は数百万ドルの損失を出さずに済んだんだ。英雄的なコードだよ」
その時、ハッとしたんだ。
僕が見ていたのは「汚いコード」という結果だけ。でも、その背後には「絶体絶命の危機を救うために、なりふり構わず戦ったエンジニアのドラマ」があったんだ。
技術的な観点だけで見れば、それは間違いなく「負債」だ。返済(リファクタリング)が必要な借金だ。でも、その借金のおかげで、今の僕らの仕事があるとも言える。
「バグ修正」の先にあるもの
よく、技術的負債の解消を「バグ修正」と同じ文脈で語る人がいるけど、僕はそれは違うと思う。
バグ修正は、マイナスをゼロに戻す作業だ。仕様通りに動かないものを、動くようにする。
でも、技術的負債と向き合うこと、つまり「Deconstructing(解体)」することは、ゼロをプラスにする作業であり、もっと言えば「過去の文脈を理解し、未来への投資に変える」プロセスなんだ。
このブログのフックにも書いたけど、「Moving beyond just “fixing bugs” to acknowledging the human effort behind the code.(単なるバグ修正を超えて、コードの背後にある人間の努力を認めること)」。これが、今日僕が一番伝えたいテーマだ。
なぜコードが汚くなるのか?
ただ単にエンジニアのスキルが低かったから? もちろん、そういうケースもある。WPFのDispatcherの挙動を理解せずにUIスレッドをブロックしちゃう初心者もいるだろう。
でも、多くの場合、理由はもっと人間臭いところにある。
- 理不尽な締め切り: 「来週のデモまでにこの機能を入れてくれ、デザインはまだ決まってないけど」というPMからの無茶振り。
- 仕様変更の嵐: 作っては捨て、作っては捨てを繰り返す中で、継ぎ接ぎだらけになったアーキテクチャ。
- 未知の技術への挑戦: 当時はベストだと思ったライブラリが、半年後には非推奨になってしまった悲劇。
- 家庭の事情や体調不良: 徹夜続きで頭が回らない中で、なんとかコンパイルを通した明け方のコミット。
画面上のコードという無機質なテキストの向こう側には、生身の人間がいる。
コーヒーを飲み過ぎて胃を痛めながら、あるいは家族との時間を犠牲にしながら、キーボードを叩いていた誰かがいる。
技術的負債を「解体」するというのは、そのコードを書いた時の彼らの「仮定(Assumptions)」や「苦悩(Challenges)」、そして「費やした時間(Time invested)」を想像することから始まるんだ。
海外エンジニアとして見た「過程」の重要性
日本で働いていた頃は、「結果」が全てだった気がする。きれいなコード、バグのない製品。それがエンジニアの価値だと思っていた。
でも海外に出て、多様なバックグラウンドを持つ人たちと働くと、「なぜその判断をしたのか?」というプロセスやコンテキストがすごく重視されることに気づいた。
例えば、インド出身のエンジニアとペアプロをした時のこと。彼の書くコードは、正直言って冗長だった。C#のLINQを使えば一行で書けるところを、わざわざforeachで回していたりする。
最初は「勉強不足かな?」と思った。でも、よくよく話を聞いてみると、彼は以前、組み込み系のメモリ制約が厳しい環境でC++を書いていた経験が長かった。「LINQの内部的なアロケーションやイテレータの生成コストが無意識に気になってしまうんだ」と彼は笑った。
その瞬間、彼の「冗長なコード」は、単なる「悪いコード」から、「彼のエンジニアとしての歴史が刻まれたコード」に変わった。
もちろん、今のプロジェクトはWPFだし、そこまでメモリにシビアじゃないからLINQに書き直すべきだ。でも、その背景を知った上で「ここはLINQで書くと読みやすいよ、パフォーマンスも問題ないし」と伝えるのと、ただ「これ書き直して」と言うのとでは、相手へのリスペクトが全然違う。
技術的負債を「誰かの失敗」として処理するのではなく、「その時の最適解(だったかもしれないもの)」として受け入れる。
このマインドセットの切り替えができるかどうかが、シニアエンジニアになれるか、あるいは海外で多様なチームの中でリーダーシップを発揮できるかの分かれ道だと、僕は確信している。
想像力というデバッグツール
僕らが普段使っているデバッガは、変数の値やコールスタックは見せてくれるけど、「なぜプログラマがその行を書いたのか」という意図までは表示してくれない。
だからこそ、僕らには想像力が必要なんだ。
WPFで言えば、不自然なUpdateSourceTrigger=PropertyChangedがついているTextBoxがあったとする。
「重くなるだけじゃん、LostFocusでいいよ」と即座に消すのは簡単だ。
でも、そこで一瞬立ち止まる。「もしかして、ユーザーが入力している最中にリアルタイムでバリデーションを出さないと、業務フローが回らないという要件があったんじゃないか?」と想像する。
Gitの履歴を見てみる。コミットメッセージに「Fix issue #1234: リアルタイム検索の要望対応」とあるかもしれない。
そうすれば、ただプロパティを変えるだけじゃなくて、Throttle(間引き処理)を入れてパフォーマンスを確保しつつ要件を満たす、というより高度な解決策が見えてくる。
「過去のコードを否定しない」というのは、何も変更しないということじゃない。
過去の経緯をリスペクトした上で、現在の状況に合わせて、より良い形に昇華させることだ。これができないと、リファクタリングのつもりが、実は重要なビジネスロジックを破壊していた、なんていう「エンバグ(Regression)」を引き起こすことになる。これ、本当に怖いよね。海外の現場でこれをやると、ミーティングで強烈な詰められ方をすることになるから注意が必要だ(実体験済み)。
コードの考古学――「妥協」という名の地層から、当時の必死さと情熱を掘り起こす
そのコードは「腐っている」のではない、「化石」なのだ
やあ、また会ったね。
前回の話で、目の前のスパゲッティコードに対して、少しだけ「慈悲の心」を持てるようになったかな? まだ無理? まあ、そう急がないで。
今回は、スコップとブラシを持って、もっと深く潜っていこう。そう、僕らはエンジニアであると同時に、「コード考古学者」になるんだ。
海外の現場で「Legacy Code(レガシーコード)」という言葉が使われるとき、そこには二つのニュアンスがある。一つは単に「古い、厄介なもの」。もう一つは、「遺産(Legacy)」という本来の意味、「先人が残してくれた価値ある資産」というニュアンスだ。
僕らが直面する「技術的負債」は、多くの場合、この二つが複雑に混ざり合って地層のように積み重なっている。
新しくプロジェクトに参画して、リポジトリをクローンし、初めてビルドを通す。そして、主要なクラスファイルを開いた瞬間、モニターから異臭が漂ってくる(気がする)。
メソッドは長大で、ネストは深く、変数名は temp1, temp2 のオンパレード。
WPFで言えば、ViewModelの中に MessageBox.Show() が直書きされていたり、ViewのコードビハインドでSQLを叩いているような、「MVVM警察」が見たら即逮捕レベルのコードだ。
ここで「うわ、汚ねえ!」と吐き捨てるのは簡単だ。でも、それでは三流のままだ。
一流の「コード考古学者」はこう考える。
「なぜ、彼らはここでMVVMを破ったんだ? ここには、そうせざるを得なかった『何か』が埋まっているはずだ」と。
「前提(Assumptions)」のミスマッチを探せ
技術的負債の多くは、実は「間違い」ではなく、「前提の変化」によって生まれる。
例えば、あるリスト表示の処理がめちゃくちゃ遅いとする。コードを見ると、非同期(Async/Await)を使わずに、UIスレッドで重い計算処理を回している。
「バカだなあ、Task.Runを使えよ」と思うかもしれない。
でも、Gitのログを遡って、そのコードが書かれたのが5年前だとわかったら?
5年前の要件定義書(もし残っていればラッキーだ)や、当時のチケットを探してみる。すると、「データ件数は最大でも10件程度」という記述が見つかったりする。
そう、当時の開発者にとって、その処理は一瞬で終わるものだったんだ。だから、わざわざ複雑な非同期処理を実装して、スレッド間の競合リスクを負うよりも、シンプルに同期処理で書く方が「正解」だった。
彼らの「前提(Assumption)」は、「データは少ない」だった。
しかし、ビジネスが成功し、データが数万件に膨れ上がった今、その「正解」は「負債」に変わった。
これは彼らのスキル不足じゃない。ビジネスの成長という喜ばしい変化が、コードを陳腐化させたんだ。
これを理解せずに、「前の奴は非同期も知らなかったのか」と嘲笑するのは、天動説を信じていた昔の人を、現代の知識だけで馬鹿にするのと同じくらいナンセンスだ。
僕らがやるべきは、彼らを馬鹿にすることじゃなく、「前提が変わったのだから、実装もアップデートしよう」と、敬意を持って修正することなんだ。
「課題(Challenges)」という名のモンスターの痕跡
次に注目すべきは、不自然に複雑なロジックだ。
なぜかここだけ try-catch が三重になっているとか、Thread.Sleep(100) という謎のウェイトが入っているとか。
WPFだと、DispatcherUtil.DoEvents() みたいな、禁じ手のような拡張メソッドが無理やりねじ込まれているのを見ることがある。
これらは、当時のエンジニアが強大なモンスター(課題)と戦った傷跡だ。
僕の実体験を話そう。
以前、ある医療系アプリの改修をしていた時、画像の読み込み処理に奇妙な再試行ロジックが入っているのを見つけた。
「画像ファイルがないならエラーでいいじゃん、なんで5回もリトライして、しかもウェイトを入れてるんだ?」
僕はこれを「無駄なコード」と判断して削除し、すっきりさせた。
結果、現場で大惨事が起きた。
実はその現場のネットワーク環境は非常に不安定で、しかも古いNAS(ストレージ)を使っていたため、アクセスが集中すると一瞬だけ「ファイルが見つからない」という嘘のエラーを返す癖があったんだ。
あの「汚いリトライロジック」は、その理不尽なハードウェアの挙動という「課題(Challenge)」を回避するための、苦肉の策だったんだよ。
削除した瞬間、僕は「前のエンジニアがどれだけ現場で苦労してその解に辿り着いたか」を痛感した。
コードが汚いのには理由がある。そこには、ライブラリのバグ、OSの仕様、ハードウェアの制約、あるいは「仕様書にはない現場の運用ルール」という魔物が潜んでいる。
その魔物を倒すために、彼らはあえて「美しいコード」を捨て、泥臭い「動くコード」を選んだのかもしれない。
その苦闘の痕跡を読み取ることこそが、真の技術力と言えるんじゃないかな。
「投資された時間(Time invested)」に思いを馳せる
「時は金なり」と言うけれど、エンジニアにとって「時は命」だ。
納期前のデスマーチ。終わらない仕様変更。増え続けるバグ報告。
コードの中に、// TODO: あとでリファクタリングする というコメントを見つけたことはないかい?
そして、その日付が3年前だった時の、あの何とも言えない切なさ。
このコメントは、怠慢の証じゃない。敗北の記録だ。
彼らだって、本当はきれいに書きたかったんだ。ViewModelとModelをきれいに分離し、ユニットテストを完備したかったはずだ。
でも、「時間は待ってくれない」。
PMが「明日リリースだ、とにかく動くようにしてくれ!」と叫ぶ中で、涙を飲んで「TODO」という墓標を立て、理想を埋葬したんだ。
また、逆に「過剰に作り込まれたコード」に遭遇することもあるだろう。
必要以上に抽象化されたクラス階層、使われていない汎用ユーティリティメソッド。
これは「オーバーエンジニアリング」と呼ばれる負債の一種だけど、ここにも「時間と情熱」が投資されている。
きっとそのエンジニアは、「このシステムを長く使える素晴らしいものにしたい」という情熱を持っていたんだ。あるいは、新しい技術パターンを学んで、それを試したくてウズウズしていた若手だったのかもしれない。
その情熱が空回りした結果だとしても、そこにある「善意」は否定しちゃいけない。
彼らが投資した時間は、今のシステムを動かすための礎になっている。
そのコードが今動いているからこそ、僕らの給料が出ている。
その事実に、少しだけ感謝してもいいんじゃないかと思う。
Git Blameの向こう側に見える景色
僕はVS Codeの拡張機能で、行ごとに「誰がいつコミットしたか」が見えるGit Lensを入れている。
これを使って、問題のあるコードの行にカーソルを合わせる。
Author: Kenji, 3 years ago
コミットメッセージ:Fix critical bug #999: 深夜対応、とりあえずこれで凌ぐ
この一行を見ただけで、ドラマが見えてこないか?
3年前の深夜、ケンジさんは眠い目をこすりながら、必死にバグと戦っていた。オフィスの電気は消えていたかもしれないし、家で赤ちゃんの泣き声を聞きながらだったかもしれない。
「とりあえずこれで凌ぐ」という言葉に込められた、焦りと安堵。
Git Blame(非難)というコマンド名だけど、僕はこれを「Git Praise(称賛)」とか「Git Empathy(共感)」と読み替えるようにしている。
このコマンドは、犯人探しのためのものじゃない。タイムマシンの窓なんだ。
その窓から、当時の状況、彼らの感情、そしてチームの状況を覗き見る。
「ああ、この時期は確か、大規模なレイオフがあって人が減ってた時期だな」
「このコミットの直後に、大型アップデートがあったんだな」
コンテキスト(文脈)を理解することで、コードの見え方は劇的に変わる。
ただの「クソコード」が、「激動の時代を生き抜いたサバイバー」に見えてくるはずだ。
まとめ:解体への第一歩は「理解」から
「承」のパートでは、コードの背後にある背景事情――前提、課題、時間の制約――を読み解くことの重要性を話してきた。
技術的負債を解体する(Deconstructing)ためには、いきなりハンマーで叩き壊してはいけない。
まずはブラシで砂を払い、それがどんな文脈で作られたのかを理解する。
「なぜこうなったのか?」を知ることで、初めて「どう直すべきか(あるいは直すべきでないか)」の正しい判断ができるようになる。
- 前提の確認: 当時と今で何が変わったのか?
- 課題の特定: 汚いコードが隠している「真の問題」は何か?
- 敬意を持つ: そのコードが今日まで稼働してきたという事実に敬意を払う。
ここまで来れば、君はもう単なる「コーダー」ではない。システムの歴史を受け継ぐ「継承者」だ。
さて、歴史を理解し、前任者への共感も芽生えた。
でも、待ってほしい。
「理解する」ことと、「そのコードを許容して使い続ける」こととは別問題だ。
そして何より、次は**「君自身」**がその歴史の一部になる番だ。
次回の「転」では、視点をガラリと変えよう。
他人のコードをどうこう言う前に、**「君が書いたコードが、未来の誰かに罵倒される恐怖」**について話そうか。
そして、コードレビューという名の公開処刑場で、僕らがいかにして自尊心を削られ、それでも立ち上がらなければならないのか。
エンジニアの精神(メンタル)の深淵に触れる、「見えない感情労働(Emotional Labor)」の話をしよう。
準備はいいかい? ハンカチを用意しておいた方がいいかもしれないよ。
Git Blameの向こう側――プルリクに込められた「震える指先」と承認欲求
エンターキーが一番重くなる瞬間
やあ。コードの化石発掘作業は順調かい?
前回は、過去のエンジニアたちに少しだけ思いを馳せて、彼らを許すことの大切さを話したね。
でもね、本当に怖いのはここからだ。
「他人のクソコード」を笑っているうちは、まだ安全地帯にいる。観客席から野次を飛ばしているだけの気楽な立場だ。
だが、僕らエンジニアの仕事は、批評することじゃない。作ることだ。
それはつまり、**「いつか誰かに批評される対象を、今この瞬間に生み出し続けている」**ということでもある。
GitHubでプルリクエスト(PR)を作成し、Create Pull Request の緑色のボタンを押す瞬間。
君はどんな気持ちになる?
「よっしゃ、完璧な仕事をしたぜ!」と自信満々なことなんて、稀じゃないかな。
多くのエンジニア、特に真面目で責任感の強い人ほど、あのボタンを押す指先は微かに震えているはずだ。
「この設計で本当によかったのか?」
「エッジケースを見落としていないか?」
「もっとスマートな書き方があったんじゃないか?」
「あの口うるさいシニアエンジニアに、またボコボコにされるんじゃないか?」
この不安。これこそが、エンジニアリングにおける「見えない感情労働(Unseen Emotional Labor)」の正体だ。
僕らは単にロジックを組み立てているだけじゃない。自分のプライド、技術者としての価値、そしてチーム内での立ち位置……そういった重たいものを全部背負い込んで、たった数行のコードをコミットしているんだ。
コードは「自分自身」ではない、と頭ではわかっていても
海外のテック企業では、「Code is not you.(コードは君自身ではない)」という言葉がよく使われる。
コードレビューで厳しい指摘を受けても、それはコードに対する指摘であって、君の人格攻撃ではないよ、という戒めの言葉だ。
素晴らしいマインドセットだ。論理的には完全に正しい。
でもさ、人間ってそんなにうまく割り切れる生き物じゃないよね?
僕の実体験を話そう。
以前、WPFのプロジェクトで、かなり複雑なUIコンポーネントを作った時のことだ。
標準のコントロールでは実現できない動きだったので、僕は張り切って「Attached Property(添付プロパティ)」と「Behavior(ビヘイビア)」を駆使し、XAML側から宣言的に制御できる、自分でも惚れ惚れするような汎用的な仕組みを作り上げた。
「これはすごいぞ、チームのみんなも驚くはずだ」
意気揚々とPRを出した。
翌朝、チャットツールの通知音で目が覚めた。
テックリードのジェイソン(仮名)からのコメントだ。
「Over-engineered.(作り込みすぎだ)」
「これだけの機能のために、この複雑さは正当化できない。普通のイベントハンドラとCode-behindで十分だ。KISS(Keep It Simple, Stupid)原則を忘れたのか?」
「メンテナンスコストが高すぎる。書き直してくれ」
画面の前で、顔から血の気が引いていくのがわかった。
「Over-engineered」という言葉が、まるで「お前は独りよがりなバカだ」と言われているように響く。
一生懸命考えたアーキテクチャ、汎用性を考慮した設計、それらに費やした三日間の時間。それらが全て否定されたように感じた。
頭ではわかっている。「コードへの指摘」だと。
でも心は叫んでいる。「俺の努力を認めろよ!」「お前にはこの高尚な設計思想がわからないのか!」
そして次に襲ってくるのは、強烈な自己嫌悪だ。
「ああ、やっぱり俺はダメなエンジニアなんだ。調子に乗ってただけなんだ……」
この、自信と不安、プライドと自己嫌悪の間で揺れ動くジェットコースターのような感情の起伏。
これが、コードを書くという行為の裏側にある「痛み」だ。
技術的負債の話をする時、僕らはつい「結果としてのコード」ばかりを見るけれど、そのコードが世に出るまでには、作者のこうした葛藤や葛藤のドラマがあったことを忘れてはいけない。
「完璧主義」という名の病と、未来の負債
さらに残酷な現実を突きつけよう。
ジェイソンに指摘されて、僕は泣く泣くその「高尚なコード」を捨て、泥臭いイベントハンドラで書き直した。
結果、コードはシンプルになり、誰でも読めるようになった。
その時は「負けた」と思ったけれど、今ならわかる。あれはジェイソンが正しかった。
でも、逆のパターンもある。
もしあの時、ジェイソンがいなくて、僕の複雑怪奇なコードがそのままマージされていたら?
その瞬間は「素晴らしい汎用ライブラリ」として称賛されたかもしれない。
しかし1年後、僕がプロジェクトを去った後、そのコードを見た後任者はこう言うだろう。
「なんだこの意味不明な添付プロパティの嵐は! 誰だこんな黒魔術を書いたのは!」
そう、今日の「最高傑作」は、明日の「技術的負債」になり得るんだ。
特に僕らエンジニアは、新しい技術やパターンを覚えると、それを使いたくてたまらなくなる習性がある。
「C#の新しいレコード型を使いたい」
「Rx(Reactive Extensions)ですべてをストリームとして扱いたい」
「Prismの最新機能を入れたい」
その知的好奇心こそが成長の源泉だけど、同時にそれが「文脈にそぐわない複雑さ」を生み出す元凶にもなる。
自分が良かれと思って書いたコードが、未来の誰かを苦しめる。
この「加害者になる可能性」への恐怖と向き合うこと。これもまた、技術的負債を考える上で避けては通れない道だ。
僕たちは常に、未来の負債を作っている。
どんなにきれいに書いても、ビジネス要件が変われば、その設計は「足かせ」になる。
フレームワークがアップデートされれば、その書き方は「非推奨」になる。
コードを書くということは、未来への借金を積み上げる行為そのものなのかもしれない。
そう考えると、キーボードを叩く手が止まってしまいそうになるよね。
「どうせ負債になるなら、何もしない方がいいんじゃないか?」なんて虚無感に襲われることもある。
インポスターシンドロームとの戦い
海外で働いていると、この恐怖はさらに増幅される。
言葉の壁、文化の壁がある中で、「自分は本当にここでやっていけるのか?」という不安――いわゆる「インポスターシンドローム(詐欺師症候群)」と常に隣り合わせだ。
「あなたのコードはわかりにくい」
この一言が、英語で言われると、日本語の3倍くらいの威力で心に突き刺さる。
「英語が下手だから、変数名のニュアンスが伝わってないのかな?」
「日本の開発文化とは違う文脈を見落としてるのかな?」
疑心暗鬼が止まらなくなる。
だからこそ、僕らは時として「防御的」になる。
自分のコードを守るために、頑なに正当性を主張したり、逆に指摘を恐れて無難な(でも汚い)コピー&ペーストに逃げたりする。
かつて僕らが「クソコード」と罵ったあのコードの作者も、もしかしたらそんな心理状態だったのかもしれない。
「怒られたくない」「早く終わらせて楽になりたい」「自分の能力不足を悟られたくない」
そんな、人間としてあまりに当たり前で、切実な防衛本能が、あのスパゲッティコードを生み出したのだとしたら……。
そう思うと、もう「誰だこのコード書いた奴は!」なんて怒る気にはなれないはずだ。
そこにあるのは、かつての、あるいは今の、震えながら戦っている「僕たち自身」の姿なのだから。
コードレビューは「公開処刑」ではなく「ギフト」へ
ここまで、暗い話ばかりしてごめんね。
でも、この「痛み」を直視することが、転換点(ターニングポイント)になるんだ。
自分が傷つくのが怖いと知っているからこそ、他人のコードに対して優しくなれる。
自分のコードがいずれ負債になると知っているからこそ、未来の誰かのために「道しるべ(ドキュメントやコメント)」を残そうと思える。
コードレビューは、自分の脆弱性(Vulnerability)をさらけ出す場だ。
それは怖いことだけど、同時に、チームとの絆を深めるチャンスでもある。
僕はある時から、PRの出し方を変えた。
以前は「完璧です、見てください(だから文句言うなよ)」というスタンスだった。
今はこう書く。
「この実装、A案とB案で迷って、今はA案で書いてます。でもB案の方が将来的にメンテしやすいかもと悩んでます。どう思う?」
こうやって、自分の「迷い」や「弱さ」を先に開示してしまうんだ。
すると不思議なことに、レビュワーの態度も変わる。
「間違い探し」のスタンスから、「一緒に悩みを解決するパートナー」のスタンスに変わるんだ。
「なるほどね、確かに迷うけど、今の要件ならA案でいいと思うよ。ただ、ここはこう変えた方が安全かな」
攻撃と防御の関係ではなく、対話(Dialogue)の関係へ。
これが成立した時、技術的負債は「個人の恥」から「チームで管理すべき資産」へと昇華される。
僕らが書くコードには、僕らの感情が乗っている。
不安、焦り、プライド、そして「良いものを作りたい」という情熱。
それら全てをひっくるめて、コードは人間そのものだ。
だから、コードを提出する時の「震える指先」を恥じることはない。
その震えこそが、君が真剣に仕事に向き合っている証拠であり、プロフェッショナルである証なのだから。
さあ、いよいよ次は最終章「結」だ。
技術的負債が「人間ドラマ」であり、自分自身の「弱さ」ともリンクしていることを理解した僕たちが、明日から具体的にどう行動すればいいのか。
リファクタリングを単なる「掃除」で終わらせず、チームの文化を変え、自分自身のエンジニア人生を豊かにするための「未来への投資術」として提案したい。
涙を拭いて、もう少しだけ付き合ってくれ。
僕らの戦いは、まだ続くのだから。
リファクタリングは「供養」ではなく「対話」だ――未来の自分とチームへの投資術
負債を「返済」するのではなく、「資産」に組み換える
やあ、ここまで長い旅に付き合ってくれてありがとう。
「起」「承」「転」を通じて、僕たちは技術的負債という名の「幽霊」の正体を見てきた。それは怠慢の化け物ではなく、かつてそこで戦った人間たちの「生きた証」だったね。
さて、いよいよ結論だ。
僕たちは、目の前に積み上がったこの「負債」と、どう付き合っていくべきだろうか?
「見なかったことにして逃げる」? それも一つの手だ(笑)。でも、プロフェッショナルとしては、もう少し建設的なアプローチを取りたい。
僕が海外で尊敬するシニアエンジニア、仮にアレックスと呼ぼうか。彼はいつもこう言っていた。
「Refactoring is a conversation with the past and the future.(リファクタリングとは、過去と未来との対話だ)」
日本にいた頃の僕は、リファクタリングを「掃除」とか「供養」だと思っていた。汚いものをきれいにする、死んだコードを成仏させる、みたいな感覚だ。
でも、アレックスの考えは違う。
彼は、スパゲッティコードを見つけると、まず「対話」を始める。
「なるほど、ここではスレッドセーフにしたかったんだね。でも、この書き方だとデッドロックのリスクがあるよ」
と、過去のコード(=過去のエンジニア)に語りかける。
そして、修正しながら今度は未来に向かって語りかける。
「未来の誰かさん、ここはあえてlockを使わずにSemaphoreSlimに変えておいたよ。非同期で待ちたいだろうからね」
このマインドセットの変化は劇的だ。
単なる「マイナスをゼロにする作業(掃除)」だとモチベーションは上がらないけれど、「過去の意図を汲み取り、未来のために翻訳し直す作業(対話)」だと捉えると、そこにはクリエイティブな価値が生まれる。
技術的負債の解消は、借金の返済なんかじゃない。レガシーな遺産を、現代の通貨に両替して、未来への「投資」に変えるプロセスなんだ。
「ボーイスカウト・ルール」の真髄は “Empathy(共感)” にあり
プログラミングの世界には有名な「ボーイスカウト・ルール」がある。「来た時よりも美しくして去れ」というやつだ。
ファイルを触ったら、触った箇所周辺だけでも少しきれいにしてコミットしよう、という教えだね。
でも、海外の現場でこれを実践する時、一つだけ大事なスパイスが必要になる。
それは “Empathy(共感)” だ。
ただ機械的にフォーマットをかけたり、変数をリネームしたりするだけじゃ足りない。
「次にここを通る人が、何に躓(つまず)くだろうか?」と想像力を働かせることが、真のボーイスカウト・ルールだ。
例えば、C#のWPFで、複雑なコンバーター(IValueConverter)があったとする。
ロジックをきれいに書き直すのも良いけれど、もっと効果的なのは、そこにたった一行のコメント、あるいは要約(Summary)を残すことかもしれない。
/// <summary>このコンバーターは、サーバーからのUTC時間を、ユーザーのローカル設定に基づいて表示用に整形します。ただし、夏時間のエッジケースに対応するために特別な分岐が入っています。</summary>
この3行があるだけで、未来の誰か(あるいは半年後の君自身)は、3時間のデバッグ地獄から救われることになる。
コードをきれいにするというのは、見た目を整えることじゃない。「認知負荷(Cognitive Load)」を下げることだ。
「読めばわかる」は不親切だ。「読まなくても意図が伝わる」のが、本当の親切(Kindness)なんだ。
僕はこれを「徳を積むコーディング」と呼んでいる。
画面の向こうの見知らぬ誰かのために、ちょっとした親切を残しておく。
海外では特に、この「徳」が巡り巡って自分の評価として返ってくることが多い。
「あの人のコードは、なぜか読みやすい」「あの人が触った後は、バグが減る」
そういう信頼(Trust)こそが、エンジニアとしての最強のキャリアパスポートになるんだ。
「完璧」を目指すな、「より良く(Better)」を目指せ
技術的負債と向き合う時、真面目なエンジニアほど陥る罠がある。
「ビッグバン・リライト」の誘惑だ。
「もうだめだ、このシステムは腐ってる! 全部捨てて、ゼロから作り直そう!」
断言するけど、これは99%失敗する。
新しいシステムを作っている間も、古いシステムは動き続け、仕様変更は発生し続ける。
結局、いつまで経ってもリプレースは終わらず、気付いた時には「中途半端な新システム」という新たな巨大負債が誕生している……という地獄絵図を、僕は何度見てきたことか。
大事なのは「完璧(Perfect)」ではなく「より良く(Better)」だ。
100点のアーキテクチャを目指して足踏みするより、今の30点を31点にするコミットを積み重ねる方が尊い。
WPFのMVVMが崩れている画面がある?
いきなり全部直さなくていい。まずは、Code-behindにある巨大なロジックを、せめてメソッドとして切り出す(Extract Method)だけでいい。
次は、そのメソッドを別のクラスに移す(Extract Class)だけでいい。
ViewModelへの結合は、その次でいい。
「漸進的(Incremental)な改善」こそが、唯一の勝利への道だ。
今日できる小さな一歩を馬鹿にしないでほしい。
その一歩は、確実に「負債」を減らし、「資産」を増やしているのだから。
「心理的安全性」を作るのはリーダーだけじゃない、君だ
「転」の話で、コードレビューが怖いという話をしたね。
技術的負債を生まない組織を作るために一番必要なもの、それは最新のフレームワークでも、静的解析ツールでもない。
**「心理的安全性(Psychological Safety)」**だ。
「ここ、よくわからないので教えてください」
「この設計、自信がないので早めに見てくれませんか?」
「すみません、バグを出してしまいました」
こういう弱音を、恐怖を感じずに言える環境かどうか。
もし、「そんなことも知らないのか」と嘲笑されたり、「バグを出した犯人は誰だ」と吊るし上げられる環境なら、エンジニアは防衛的になり、隠蔽工作に走る。
そして生まれるのが、誰も触れない「開かずの間」のようなブラックボックスコードだ。
海外で働いて気づいたのは、心理的安全性はマネージャーから与えられるものじゃなく、エンジニア同士が作るものだということ。
コードレビューで、厳しい指摘をする前に、まずは良いところを見つけて褒める(Praise)。
「このロジックの切り出し方はいいね! でも、ここの命名はもう少し具体的にできるかも」
「複雑な要件をよくここまで実装したね。ありがとう。ただ、パフォーマンスの観点で一つ提案があるんだ」
“Code with Kindness.”(優しさを持ってコードを書け)
“Review with Empathy.”(共感を持ってレビューせよ)
これができるエンジニアが一人いるだけで、チームの雰囲気はガラリと変わる。
そして、そういうチームから生まれるコードは、不思議ときれいになっていくんだ。
技術的負債の特効薬は、実は「チームの人間関係を良くすること」だったりするんだよ。
最後に:海外を目指す君へ、そして全てのエンジニアへ
最後に、ここまで読んでくれた君に伝えたいことがある。
僕が海外に出て、WPFやC#という技術を通じて得た一番大きな収穫は、技術力そのものじゃない。
**「コードは世界共通言語だが、それを操るのは感情を持った人間である」**という当たり前の事実を、肌で感じられたことだ。
言葉や文化が違っても、汚いコードに苦しむ気持ちは一緒だし、きれいなコードに感動する心も一緒だ。
技術的負債というテーマを通じて、僕たちは時空を超えて、顔も知らないエンジニアたちと繋がっている。
これから海外を目指す人、あるいは日本で技術を磨いている人へ。
技術力(Hard Skills)を磨くのはもちろん大事だ。最新の.NETの機能を追いかけるのも楽しい。
でも、それと同じくらい、いやそれ以上に、**「人間の不完全さを愛する力(Soft Skills)」**を磨いてほしい。
不完全な人間が作るものだから、コードは汚くなる。負債は生まれる。
それを「許し」、「理解し」、そして少しずつ「良くしていく」。
そのプロセスそのものを楽しめるようになった時、君はもう「コードを書くだけの人」じゃない。
カオスの中に秩序をもたらし、チームを前進させる、真の「エンジニア(Engineering=工学する人)」になっているはずだ。
さあ、明日もVS Codeを開こう。
そこには、過去からのメッセージと、君が未来へ残す手紙が待っている。
「誰だこのコード書いた奴は!」と笑いながら、愛を込めてリファクタリングを始めようじゃないか。
Have a good coding life!

コメント