設計と思想

失敗から学んだ設計判断
「正しかったはず」が壊れるとき

受託開発の現場で踏んだ設計ミスと、そこから得た勘所。

2026年3月 読了 約10分 中堅エンジニア・設計判断に悩む方向け

この記事のポイント

  • 「正しい設計」をしたはずなのに壊れた、転職直後の3つの実体験
  • 失敗の原因は技術力ではなく「前提の見誤り」だったこと
  • 失敗を繰り返さないために身についた「設計前にやる3つの問い」
SECTION 1

「正解」を疑えなかった頃

インフラエンジニアとして7年。サーバーの構築、監視、障害対応をひたすらやってきた自分が、「何かを作る側」になりたくて受託開発の世界に飛び込んだ。

転職直後、自分がまずやったのは本を読むことだった。デザインパターン、クリーンアーキテクチャ、SOLID原則。読めば読むほど「正しいやり方」が見えてくる気がした。教科書が示す構造に従えば、良いコードが書けるはずだと信じていた。

現場に入ってすぐ、先輩から衝撃的なことを言われた。「分かっていないのに書くより、分からないから書かないほうがマシだよ」と。当時の自分は「とにかく手を動かさなきゃ」と焦っていたが、先輩は「理解してから書け」と教えてくれた。

振り返ると、転職してすぐの自分は毎日が発見の連続だった。インフラの世界では「設計」といえばネットワーク構成図やサーバースペックの話だったが、Web開発の「設計」はもっと抽象的で、もっと自由度が高かった。

自由度が高いということは、間違える余地も大きいということだ。等身大のコードを書くことの大切さに気づくまでに、いくつかの痛い経験が必要だった。背伸びしたコードは、書いた本人にすら読めなくなる。

学ぶ速度と実践のギャップ。本で知識を入れるスピードに、現場で使いこなす力が追いつかない。そのギャップが、これから話す3つの失敗を生んだ。

SECTION 2

失敗①——過剰な抽象化

最初の失敗は、小規模な受託案件でのことだった。

機能としてはシンプルな業務システム。CRUD操作が中心で、ユーザー数も限られている。にもかかわらず、自分は教科書通りにService層、Repository層を細かく分離した。「将来の拡張に備えて」という理由で。

結果はどうなったか。クラス数が膨れ上がり、ひとつの機能を改修するのに5つも6つもファイルを追う必要が出た。コントローラーからサービスを呼び、サービスからリポジトリを呼び、リポジトリからエンティティを……と、処理の流れを追うだけで疲弊する構造になっていた。

チームメンバーから「どこに何があるかわからない」と言われたときの衝撃は、今でも覚えている。自分は「きれいに分離できた」と思っていたのに、他の人から見ると「迷路」だった。

「資料を書くと管理コストが発生する」——現場で学んだこの教訓は、抽象化にもそのまま当てはまる。レイヤーを増やせば、レイヤー間の整合性を維持するコストが発生する。

YAGNIという原則は知っていた。「You Aren't Gonna Need It」——今必要でないものは作るな。頭では理解していたのに、「将来の拡張に備えて」という免罪符が、YAGNIを無力化していた。

「将来」は来なかった。そのプロジェクトは初期リリース後、大きな機能追加なく安定運用に入った。過剰に分離されたレイヤーは、誰にも使われないまま残り続けた。

教訓

抽象化はコストである。今必要な分だけ導入する。 レイヤーを増やすことは「整理」ではなく「投資」だ。リターンが見込めない投資は、負債にしかならない。

SECTION 3

失敗②——テストが守ってくれなかった

2つ目の失敗は、医療系ドメインの在庫管理システムの保守で起きた。

既存の在庫管理ロジックに機能追加を行う担当になった。入出庫の履歴表示や発注データの出力など、新しい機能を実装してテストを書いた。正常系のテストは全部グリーン。自分の追加分は問題ないと安心していた。

ところが、運用中に問題が浮上した。在庫計算ロジックにエッジケースで不正な結果を返す不具合が潜んでいた。自分が追加した機能ではなく、既存のロジックに元々あった問題だった。結果的に既存コードを丹念に読み解いて原因を特定し、修正することになった。

このとき痛感したのは、自分が書いた部分だけテストして安心していたということだ。先輩に言われた言葉が刺さった。「テストを書くということは、データの動きが正しいかどうかを捉えることだ。自分が書いたコードだけでなく、データが通る道全体を見ないといけない」と。

自分のテストは「自分の追加分が動くこと」を証明するためのものだった。「システム全体として壊れないこと」を証明するためのものではなかった。この違いは大きい。

全パターンを網羅するのは現実的に無理だ。だからこそ「枝刈り」の考え方が必要になる。全部テストするのではなく、壊れやすい箇所を見極めて、そこに集中する。

テストケースの優先順位を完全に誤っていた。正常系100本書くよりも、境界値10本のほうが価値がある場面がある。特に金額や数量を扱うロジックでは、ゼロ、マイナス、最大値、同時アクセスといったエッジケースが最も危険だ。

この経験以降、テストを書くときの順番が変わった。まず「どこが壊れやすいか」を考え、そこから書き始める。正常系は後回しでいい。正常系が動くことは実装中にだいたい分かるからだ。

教訓

「最初に壊れるのはどこか」を考え、そこにテストを集中させる。 テストの目的は「動くことの確認」ではなく「壊れないことの証明」だ。

SECTION 4

失敗③——前提が崩れたAPI設計

3つ目の失敗は、外部API統合の設計で起きた。

複数の外部サービスからデータを取得し、統一的に扱う必要があった。Adapterパターンを採用した。これ自体は正しい判断だった。各APIの差異をAdapterで吸収し、ビジネスロジック側は統一インターフェースだけを知っていればよい、きれいな設計だ。

最初の2社のAPIはうまくいった。レスポンス形式が似ていたからだ。JSONのフラットな構造で、フィールド名が違うだけ。Adapterのマッピングも単純だった。

問題は3社目のAPIが追加されたときに起きた。レスポンス構造が根本的に異なっていた。ネストされたオブジェクト、ページネーションの仕組みが独自、データの粒度も違う。既存のAdapterの抽象化レイヤーが前提としていた「レスポンスはフラットなJSON」という暗黙の仮定が、完全に崩れた。

「1箇所コードを直すことの恐ろしさ」——現場で痛感した「変更の重み」が、まさにこの瞬間に現実になった。Adapterの共通部分に手を入れると、既存2社の動作にも影響が出る。

自分が暗黙に置いていた前提は「APIのレスポンス形式は、ある程度似ている」だった。最初の2社がたまたま似ていたから、この前提を疑わなかった。しかしそれは偶然であり、3社目が現れた瞬間に崩壊した。

結局、Adapterの設計を見直した。「変換ルール」と「共通インターフェース」を明確に分離し、変換ルール側をAPIごとに完全に独立させる形にリファクタリングした。共通インターフェースは最小限にし、各Adapterが自由に変換処理を書ける余地を残した。

教訓

設計の前提を明文化し、「この前提が崩れたら何が壊れるか」を事前に問う。 暗黙の仮定は、崩れるまで気づけない。だからこそ、意識的に言語化する必要がある。

SECTION 5

共通点——「前提の見誤り」

3つの失敗を並べてみると、共通するパターンが見えてくる。

過剰な抽象化では、「将来拡張がある」という前提を疑わなかった。テストの不備では、「正常系が通れば大丈夫」という前提を疑わなかった。API設計では、「レスポンス形式は似ている」という前提を疑わなかった。

どの失敗も、技術力の不足が原因ではなかった。自分が置いた前提を疑わなかったことが原因だった。

現場の先輩から学んだ「仮説思考」の大切さが、ここに繋がる。「動かない」という事実に引っ張られるのではなく、「なぜ動かないのか」「自分は何を前提にしていたのか」を紐解く。この思考の習慣があれば、失敗の芽を早い段階で摘める。

「良い設計は良い数式に通じる。例外がないことが美しい数式の条件だ」——先輩のこの言葉が、後の設計判断を変えた。

StrengthsFinderでいう「慎重さ」は、設計の強みになる。リスクを事前に洗い出し、防御的に構造を作る力だ。しかし、一度「正しい」と信じた設計を疑う方向には、慎重さは働きにくい。自分の慎重さは「新しいリスク」には敏感だが、「自分が作ったもの」には甘い。

だからこそ、意識的に自分の設計を疑う仕組みが必要だった。それが次のセクションで話す「3つの問い」だ。

SECTION 6

設計前にやる3つの問い

3つの失敗を経て、設計に取りかかる前に自然と習慣になった問いがある。大げさなフレームワークではない。自分への問いかけだ。

問い①:この設計の前提は何か? それが崩れたら何が壊れるか?

API設計の失敗から生まれた問い。設計には必ず「暗黙の前提」がある。それを言語化し、崩れたときの影響範囲を事前に把握する。前提をドキュメントに書き残すだけで、将来の自分やチームメンバーが同じ轍を踏むリスクを大幅に減らせる。

問い②:この抽象化は今必要か? 未来の自分への借金ではないか?

過剰抽象化の失敗から生まれた問い。レイヤーを増やすたびに管理コストが発生する。「将来のため」という理由は、ほとんどの場合「今は不要」の言い換えだ。抽象化は「投資」であり、リターンが見込めるときだけ行う。

問い③:最初に壊れるのはどこか? そこにテストはあるか?

テスト不備の失敗から生まれた問い。正常系から書き始めるのではなく、「壊れやすい場所」から考える。境界値、同時アクセス、外部依存——壊れるポイントを先に潰す。テストの優先順位を決める基準は「カバレッジ」ではなく「リスク」だ。

この3つの問いは、「段階的詳細化」の考え方にも通じる。いきなりコードを書き始めるのではなく、まず全体像を俯瞰し、前提を確認し、リスクを洗い出してから詳細に入る。

特別なことではない。ただ、失敗しないと身につかなかった。本で読んだだけでは、自分ごとにならなかった。手を動かし、痛い目を見て、初めて骨身に染みた。

失敗を語れるようになるまで

失敗談を書くのは、正直に言えば恥ずかしい。転職直後の自分は「できない自分」を認めるのが辛かった。インフラの世界では一人前だったのに、Web開発の現場では新人と同じスタートライン。そのギャップが、プライドを削った。

でもPLになった今、後輩に伝えるべきは成功体験よりも「踏まなくていい地雷の場所」だと思っている。自分が踏んだ地雷を共有すれば、チームの誰かが同じ痛みを味わわずに済む。

現場で学んだ「準備8割、実行2割」という言葉がある。設計の失敗も、突き詰めれば準備——つまり前提の検証——が足りなかったことから来ている。コードを書く前の30分が、書いた後の30時間を救う。

もうひとつ、現場で教わった考え方がある。「Find One Fix All」——1つの失敗を見つけたら、同じパターンが他にないか全部チェックする。過剰抽象化を1箇所で見つけたなら、他のモジュールも同じ問題を抱えていないか。テストの漏れを1箇所で見つけたなら、他のロジックも同じ観点が抜けていないか。

失敗は、ただ反省するだけでは「経験」にならない。なぜ失敗したのか、どんな前提を見誤ったのか、同じパターンが他にないか。そこまで掘り下げて初めて、次に使える知見になる。

失敗は、構造化できたとき「経験」になる。

設計判断 失敗談 テスト デザインパターン 受託開発

著者: しきぴょんた / 2026年3月

関連する記事