Articles

入社して初めての失敗

はじめに

これまで自身のブログでは、自分がやってきたことの中でも成果が上がったことだったり、ポジティブな内容を投稿することが多かったです。

ただ、その成果に繋げる上で、過去の渋い失敗経験が生きているなと感じましたので、棚卸してブログ投稿しようと思います。

新卒エンジニア1年目のある日

金融系のシステムのバックエンドエンジニアを勤めていた私は、新卒1年目のある日、チームリーダーから以下のようなタスクを振られました。

「ちょっと自分が忙しいからあんまり手助けできないんだけど、この機能のリファクタリング(ほぼ作り直し)やっといてくれない?大体こんな構造を目指して欲しい」

これまでリーダーにおんぶに抱っこで開発をしてきたと思っていた私は、1人で仕事を任せてもらえるとなり、リーダーが大変なら私がゴリっと頑張ろうと息巻いていました。

しかし、後にこのリファクタリングにより半年ほどバグが頻出し、色々な人の工数を奪うことになりました。

コードの分析

リファクタリングするということで、まずはコードの分析をしようとコードリーディングを始めました。

「クラスが1万行以上になってるなぁ、、、、複雑だけど業務レベルのコードってそういうものなのかなぁ、、、(そんなことはない)」

このような感じで、ダラダラコードの分析をしていたら、痺れを切らしたリーダーから「とりあえず前提示したゴールの構造を目標にリファクタリングやってみてよ」と言われました。

そう言われた私は、「じゃそのままリファクタリングしちゃうか〜」「何事もやってみてわかることがあるよな!」と流されるように開発が進行していきました。

1つ目の失敗: 仕様に詳しい人に十分なヒアリングをしていなかった

ここで既に一つ私は失敗をしていました。

まずはリファクタリング前に詳しい人から仕様確認をするのを怠っていました。

今振り返ると、この機能は、「テストコードが一切ない」「行数が1万行を超える複雑なクラスがあった」「関連するテーブルは30テーブル以上」という複雑怪奇な機能でした。

今から振り返ると、コードを書いた人なら分かるポイントや落とし穴、またコードを書いた人に構造を図解してもらうなど仕様を簡単に把握する上でのやりようが色々あったように思います。

しかしながら私はそこで馬鹿正直に1万行越えのクラスを頑張って読み解く選択をしてしまいます。

「せっかく自分に任せてもらったから自分でやり切ろう!」という誤った選択をしてしまい、他の人の知識を引っ張り出すということをサボってしまったわけですね。

これにより様々な見落としが発生したり、分析のための無駄な時間を浪費することで後続のテストにかけられる時間が減ったりして、結果として様々なデグレを招くことになりました。

未知の複雑な機能を扱う際は、先に有識者にヒアリングした方が良いケースがある。

今ならAIに聞くのもありだが、ドメイン知識を持っていてその機能にも詳しい人がいるなら、最初のうちにヒアリングしておくことで、コード分析にかける時間や見落としによる手戻りを少なくできる。

リファクタリングスタート!

「さぁリファクタリングスタートだ!」となり、リーダーが提示してくれた構造を目指して新しくコードを書いていきました。

2つ目の失敗: リファクタリング前にテストコードを書いていない

ここでも直ぐに失敗をしていました。

このコードはかなり複雑なコードであり、下手に触ると高確率でデグレするようなものでした。

それにも関わらず私はテストコードを書くという工程をスキップしてそのままコードを書き始めてしまいました。

後にKent BeckのTDDやMartin FowlerのRefactoringを読んだ私は何というリスキーな事をしていたんだろうと深く反省しました。

「リファクタリングは振る舞いを変えずに構造を変えること」「振る舞いが変わってないことを保証するためにテストコードを先に書く」といった基本的な事ができていなかったのです。

その結果、以下のような酷い状況になりました。

  • 実装後テストコードを書くが、そのテストコードではリグレッションを検知する役割を果たせない無駄なものに労力を使っていた

  • テストコードがないことで実装の振る舞いをわかりやすく説明するものがなく、レビュアーのレビュー精度がおそらく落ちた。それによりデグレを招きやすい状態に陥っていた

  • 後続の手動テストにかかる時間が伸びた

リファクタリングの前には必ずテストコードを書いて、振る舞いが変わらないことを保証しよう。

急かされてもこの工程をスキップすると後々痛い目を見るので必ずやろう。

マジで。

3つ目の失敗: 大きな変更を入れてしまう

同時に私は超巨大な変更を入れることもしてしまっていました。

コードレビューをする側になるとわかりますが、大きな変更をレビューするのはかなり大変で、骨が折れます。

結果として重大なバグを見逃してしまうみたいな確率が上がります。

また大きな変更を入れた場合、リリース時に問題の切り分けが難しくなるという問題もあります。

この開発ではリリース頻度が3ヶ月に1回とかだったので、後者の問題は避けられませんが、可能であればリリースを細かく分けていく方がリスクを抑えつつ開発を進められるのかなと思います。

変更は小さく入れよう。

レビュー漏れや問題発生時の切り分けが困難になるビッグバンリリースに繋がる。

その他失敗

その他にも以下のような失敗をやらかしていました

  • 非機能要件を擦り合わせていない

  • 早過ぎる性能最適化による保守性の低下

その結果バグが頻出

その結果、半年ほどバグが頻出する状況になりました。

この苦い経験がきっかけとなり、「安全にソフトウェアを作るにはどうしたら良いか」ということを考えるようになり、Kent BeckやMartin Fowlerなどが執筆した名著を読みつつ、ベストプラクティスを学ぶようになりました。

ex) TDD, Refactoring, 「推測するな計測せよ」, ビッグバンリリースを避ける, 早過ぎる最適化は避ける…etc

おわりに

色々な人に迷惑をかけることになった経験ですが、この経験から学んだことを活かしてSQL ServerからTiDB(NewSQL)への移行という1.5年越しのプロジェクトをリードして、大きな障害なく終えることができました。

https://yukiotechblog.com/tidb-poc/

「愚者は経験から学び、賢者は歴史から学ぶ」という名言がある通り、先人のプラクティスを学びながらこれからも精進していきたいと思いました。

おしまい

番外編: ドメイン知識が詳しくない人でも開発できる設計を目指す

クソ複雑なコードを読み解かなければならないという経験をしたことで、なるべくドメイン知識がなくても開発できるようにするにはどうしたら良いか? という事を考えるようになり、以下の取り組みをしました。

https://ic-techblog.hatenablog.com/entry/2025/02/19/113901

やったこととしては参照用テーブルを作成して、CQRSチックな事をしたというものですが、よければご参照ください。