大事ではないことを大事だと錯覚した結果、オーバーエンジニアリングになる

本ブログは Recruit Advent Calendar 2021 - Adventarの25日の記事になります。

ITビジネスやサービスにおけるプロダクト開発で良くある、作りすぎ。やりすぎ。

無駄なく、効率的にと思っても、ついつい発生しちゃう。

こういうの、オーバーエンジニアリングって言うらしいよ!?

でも、どこからオーバーで、どこまではオーバーじゃないんだ!!

ということで、勝手にオーバーエンジニアリングを定義してみようと思います。

作り過ぎて、時間や金を無駄にすること????

とっかかりとして・・・まずは一般用語としてのオーバーエンジニアリングの意味をwikiで調べてみると以下のように記述されています。

wikipedia(英語版) Overengineering - Wikipedia 一部抜粋。

Overengineering (or over-engineering,[1] or over-kill) is the act of designing a product or providing a solution to a problem in an overly complicated manner, where a simpler solution can be demonstrated to exist with the same efficiency and effectiveness as that of the original design.[2] Overengineering differs from Planned Obsolescence which seeks to alter a design to produce an artificial limit on a product's lifespan or otherwise make it unfashionable. Overengineering is often identified with design changes that increase a factor of safety, add functionality, or overcome perceived design flaws that most users would accept. Overengineering can be desirable when safety or performance is critical (e.g. in aerospace vehicles and luxury road vehicles), or when extremely broad functionality is required (e.g. diagnostic and medical tools, power users of products), but it is generally criticized in terms of value engineering as wasteful of resources such as materials, time and money.

wikipedia(英語版) → DeepL

オーバーエンジニアリング(またはオーバーエンジニアリング[1]、オーバーキル)とは、製品を設計したり、問題の解決策を提供したりする際に、元の設計と同等の効率や効果を持つ、よりシンプルな解決策が存在することを証明できるのにもかかわらず、過度に複雑な方法で設計することである[2]。 オーバーエンジニアリングは、製品の寿命を人為的に制限したり、流行遅れにしたりするために設計を変更しようとする計画的陳腐化とは異なります。オーバーエンジニアリングは、安全率を高めたり、機能を追加したり、ほとんどのユーザーが受け入れるであろう設計上の欠陥を克服するような設計変更と同一視されることが多い。 オーバーエンジニアリングは、安全性や性能が極めて重要な場合(航空宇宙用車両や高級ロードカーなど)や、極めて広範な機能性が要求される場合(診断ツールや医療機器、製品のパワーユーザーなど)には望ましいが、バリューエンジニアリングの観点からは、材料や時間、お金などの資源を無駄にしていると一般的に批判されている。

大事そうなものを赤字にしましたが、つまりは、やりすぎてしまった結果、リソースや時間、お金などの資源を無駄にしているって読み取れます。 また、青字の部分は、逆に性能オリンピックになっても問題ないというか逆にそれが望ましいケースもあるよ。といってます。 とはいえ、私が携わっているITビジネスにおいては、どちらかというと赤字側の文脈が強いですが、全体的には良いことなのか悪いことなのかよくわからないですね。

ただ、どうやら本当に必要だったものに対して、なにかオーバーなやりすぎが発生してしまい、全体として当初想定していたものよりはブクブク膨れ上がる感じ。 そんなイメージ。

いろいろなことがあって膨れ上がる

膨れ上がるといっても、いきなりドカンと倍になるとかそういう話ではない気がしていて、徐々に・・・、何かいろいろなことがあって、本当に必要だったものよりも大きくなってしまうんだろうなと。 こんなイメージです。

f:id:i2key:20211221142811p:plain

いろいろなことがあるんだけど、そのいろいろなことが発生するタイミングはシステム開発のケースでいうと各開発工程において発生している気がする。なお、多くのことをまとめて一括でやるようなウォーターフォールと言われているようなケースや小さく1つずつクルクル回してやっていくアジャイルと言われているようなケース、いろいろあると思うけど、一般的にV字の工程はどれもやることは同じであるため、便宜上ひとくくりにして表現しています。

f:id:i2key:20211221143338p:plain

では、いろいろなことがある、色々ってなんだろう?を列挙してみる。あくまで全てではないけど、開発の現場にいるとよく遭遇しそうなあれこれ。

f:id:i2key:20211221143956p:plain

例えば・・・・・

  • 要求定義

存在しないユーザを想定して、仕様を増やしちゃう。そもそもそんなユーザーはいないかもしれないのに、脳内に存在する実在しないペルソナに対して仕様を増やしにいってしまう。

  • 要件定義

大事な気がする仕様が問題になって、更なる解決が必要になっちゃう

  • 設計

将来に備えようとして、備え過ぎちゃう。拡張性とか柔軟性とかを過度に必要だと思い盛り込んでしまう。備えること自体は良いのだけど、、、、備え過ぎてしまう。

必要以上のレビューや文書化といったプロセスを行ってしまう。誰が見るんだっけ?それ今後も使うんだっけ?みたいな。

  • コード

全体の性能ネックではないところが、大事な気がして高性能にしちゃう。別にそこシステム全体からみたらボトルネックじゃなくない?とか。

  • テスト

直さなくて良いバグを直しちゃう。リスクに対する考え方や事業のコンテキストにもよるけど、目についたバグを全て確実になおしてしまう。とか。

大事だと錯覚してしまう

もういちだん、解像度を高めるために要件定義を例に深ぼってみます。

大事な気がする仕様が問題になって、更なる解決が必要になっちゃう の深堀り

f:id:i2key:20211221151835p:plain

例えば、「ボタンAを押したらベローンとなる。」という要求があったとして、、、このときの要件は「(システムは)ボタンAが押されたらベローンとする。」と定義されたとする。ただ、このときにベローンとするとボタンBが隠れてしまうという問題が起きる。こういうことありますよね。要件を実現するのに障壁となる問題が発生するケース。現実世界では、こんなベローンとしたら隠れちゃいましたーみたいなしょぼい話ではないと思うのだけど、あくまでわかりやすくという意味での極端な話として。

f:id:i2key:20211221153306p:plain

こうなると要件実現のためにこの問題を解決しないといけない。ということで新たな要求がここで発生する。「ベローンってなってもボタンBを押せるようにしたい」って。これがすごく現場で発生してる気がする。で、その新たら要求に対して、新たな要件がうまれる。「ベローンのときはボタンBを右へずらす」。そして、ベローンのときにボタンBを右にずらすと・・・・・「ボタンBが画面からはみでちゃう」という新たな問題が発生・・・・。

f:id:i2key:20211221153912p:plain

同じようにこの地獄の構造は続いていく・・・・。何かを作ろうとしたら、それを作るために何か問題が発生して、それを解決するために新しい要求が生まれて・・・・の連鎖。もりもりやることが膨れ上がっていく。やりすぎてる感ある。

これを発生させないためにはどうすればよかったのだろうか???

「ボタンAを押したらベローンとなる。」という要求定義の時点で、「ただし、ボタンBは隠れないようにする。」とまで定義しなければならなかったのか。しかし、そうなると、起こりうる問題を事前に全て想定しきらないとならないというなかなかの無理ゲー感がでてくる。ベローンくらいなら想定可能だと思うけど、実際は、影響範囲を全て把握した上での最強の要求定義要件定義をすることになるのは、あまり現実的ではない気もする。

では、これはなるべくしてなるオーバーエンジニアリングなのだろうか・・・・。

そうではない気がする。 そもそも要求に立ち返って考えたときに、「ボタンAを押したらベローンとなる」は、本当にベローンとしたかったのか。何かの得たい情報がベローンと表示されていればよかったのかもしれない。仮に「ボタンAを押したら画面上にホニャララって情報が表示される」みたいな要求であれば、この問題は起きなかったのかもしれない。要求の段階で「ベローン」(HOW)を指定してしまったがために、それ以降の工程では、「ベローン」は大事なものに見えてしまい、要求を受けた側はそれをどうしても実現せねば。となってしまっているように見える。要求を出した本人は、なんとなく「ホニャララ情報をさ、ベローンって感じでもいいから、なんかだしてよ」という温度感であって、ベローンにこだわりはなかったのだけど。みたいな。

f:id:i2key:20211221160217p:plain

これをシャープに言語化すると、要求に手段が混じってしまっているが故に、その手段が重要だと思ってしまった。と言える。

そして、最初の問題以降の淡い青色の部分は全てそんなに重要ではないベローンに向き合ってしまったことになる。そこの問題をどんなに解決してもそもそも重要ではないというか。意味がないというか、、、、つまり、、、、無駄。問題発生時に、要件に対して、「じゃあ、ベローンじゃなくて、ペロンでよくね?」で発生しなかった話であり、ベローンが重要だと錯覚してしまったことが全てのはじまりなのかもしれない。 要求の段階で「ボタンAを押したらベローンとなる。(けど、ベローンは実はそんな重要じゃないです。こだわりも1ミリもありません。)」ってなっていたら「あ、これそんな大事じゃないだwww」ってなりこれは錯覚を防げたのかもしれない。濃淡の話。

つまり、・・・・本来は大事じゃないものを大事だと錯覚した結果、作りすぎて(やりすぎて)、時間や金を無駄にしてしまう。ということなのかもしれない。

無駄は錯覚によってうまれる

上記での錯覚がオーバーエンジニアリングを引き起こしているのでは?という気づきをもとに、前述の各工程毎に出した「いろいろあって」もりもりやることが膨れ上がる例に対して、「ほにゃららだと錯覚してしまう」という表記にしてみると・・・・。

f:id:i2key:20211221161725p:plain

  • 要求定義

存在しないユーザを想定して、仕様を増やしちゃう。そもそもそんなユーザーはいないかもしれないのに、脳内に存在する実在しないペルソナに対して仕様を増やしにいってしまう。

→ 大きな少数の声が、全体であるかの様に錯覚してしまう。

  • 要件定義

大事な気がする仕様が問題になって、更なる解決が必要になっちゃう

→ HOWが大事であると錯覚してしまう。 (さっきのベローン)

  • 設計

将来に備えようとして、備え過ぎちゃう。拡張性とか柔軟性とかを過度に必要だと思い盛り込んでしまう。備えること自体は良いのだけど、、、、備え過ぎてしまう。

→ 数年後の状態が、明日くらいに錯覚してしまう。 (5年後には1億ユーザーなんだけど、なぜかそれが明日だと思ってしまった。みたいな。流行ってから悩めばいい系。)

必要以上のレビューや文書化といったプロセスを行ってしまう。誰が見るんだっけ?それ今後も使うんだっけ?みたいな。

→ 取捨選択が重要なのに、教科書に書いてあることは、全部やるのが正しいと錯覚してしまう。 (文脈を意識してない型に当てはめるタイプのやりかただと起こる感じ。目的意識不在のプラクティス全部盛り的な。)

  • コード

全体の性能ネックではないところが、大事な気がして高性能にしちゃう。別にそこシステム全体からみたらボトルネックじゃなくない?とか。

→ 起こるかもしれないことは、全部起きると錯覚してしまう。

  • テスト

直さなくて良いバグを直しちゃう。リスクに対する考え方や事業のコンテキストにもよるけど、目についたバグを全て確実になおしてしまう。とか。

→ 目の前で起こった問題は、全部大問題と錯覚してしまう。 (冷静になって考えると大した問題じゃないのに目の前でおこるとまあまあバイアス発生するよね。)

まとめ

つまり、オーバーエンジニアリングとは・・・・本来は大事じゃないものを大事だと錯覚した結果、作りすぎて(やりすぎて)、時間や金を無駄にしてしまう。ということであり、それを引き起こすトリガーとなる錯覚は例えば以下のようなものがある。と言えそうである。

  • 要求にHOWが入ってる(HOWが大事であると錯覚してしまう)
  • 少数ユーザの意見(少数の意見が、全体の意見であると錯覚してしまう)
  • とてつもなくグロースするサービス(数年後の状態が、明日のことのように錯覚してしまう)
  • リスクを取らない(目の前で起きた問題が、すべて大問題であると錯覚してしまう)
  • リスクを取らない(起きるかもしれないことは、大抵起きると錯覚してしまう)
  • 教科書をなぞる(取捨選択こそが大事なのに、全部やらないとダメだと錯覚してしまう)

という、勝手にオーバーエンジニアリングを定義してみた!でした。

余談

開発における文脈と時間軸を正しく理解していないと、錯覚によりオーバーエンジニアリングが発生する。
全ての可能性が全て発生した世界が多分オーバーエンジニアリングの理論上最大拡張幅。前述の図のブクブク膨れ上がったやつ。
つまり、リスクテイクできていない世界。
例えば、この機能は事業的に致命的ではないためバグってもよくない?がいえると縮小する。
このプロダクトが流行ってから悩めばよくない?がいえると縮小する。
このコードは1年に一度くらいしか触った実績ないから、工数かけてまでキレイにしなくてもよくない?がいえると縮小する。1年に1度あるかないかみたいな時間軸が抜け落ちると、目についた汚らわしいものすべてがキレイにする対象になってしまう。無限にお金と時間があるなら良いのだけど、基本的には限られた資源で日々活動をしているため、そんな状況にはなりにくい。

そのためこれらのリスクを取れない、つまり、「事業理解のない提案」になるとどうしてもコストが最大化する。
全部のリスクをヘッジする実装をするから。

リスクをマネジメント対象にすることってこういうことなんだろうな。(感想)

おまけ

このような勝手な定義を毎週youtubeでスライド作りながらしております。

今回のオーバーエンジニアリングついて。

PIMBOK第7版について

技術的負債について

俺のプロダクト開発用語辞典 www.youtube.com