プログラミング
不適切な抽象化よりも重複を優先する (2016)
Prefer duplication over the wrong abstraction (2016) (sandimetz.com)
要約
この記事は、「不適切な抽象化は重複よりもはるかにコストがかかる」という主張を展開しています。プログラマーが安易に抽象化を行うと、後の要件変更で複雑な条件分岐やパラメーターが増え、コードが理解不能になる問題を指摘しています。著者は、不適切な抽象化に直面した際は、重複を再導入してコードを単純化し、正しい抽象化を再検討することを推奨しています。
全文翻訳
不適切な抽象化について私は元々、この内容をChainlineニュースレターに書きましたが、このアイデアについて引き続きツイートが寄せられるため、私のブログにこの記事を再公開します。このバージョンは軽く編集されています。\n私は「不適切な抽象化」の結果について考えてきました。私のRailsConf 2014での「all the little things」という講演には、「不適切な抽象化は重複よりもはるかにコストがかかる」と主張したセクションが含まれていました。そして要約では、「不適切な抽象化よりも重複を優先する」とアドバイスしました。ずっと大きな講演の中のこの小さなセクションは、驚くほど強い反響を呼びました。\n数人の人は私が正気を失ったと示唆しましたが、それよりもはるかに多くの人が「これだ、これこそ百万回言いたいことだ!」といった意見を表明しました。"@BonzoESC: "Duplication is far cheaper than the wrong abstraction" @sandimetz @rbonales pic.twitter.com/3qMI0waqWb"— 41 shades of blue (@pims) March 7, 2014\nその反響の強さから、私は「不適切な抽象化」の問題がどれほど広範で手に負えないものかを痛感しました。私は質問を始め、以下のパターンを認識するようになりました。プログラマーAは重複を見つけます。プログラマーAは重複を抽出し、それに名前を付けます。これにより新しい抽象化が作成されます。それは新しいメソッドかもしれないし、おそらく新しいクラスかもしれません。プログラマーAは重複を新しい抽象化に置き換えます。ああ、コードは完璧だ。プログラマーAは満足して立ち去ります。時間が経ちます。現在の抽象化がほぼ完璧である新しい要件が現れます。プログラマーBはこの要件を実装するようタスクを与えられます。プログラマーBは既存の抽象化を維持する義務を感じますが、すべてのケースでまったく同じではないため、パラメーターを受け取るようにコードを変更し、そのパラメーターの値に基づいて条件付きで適切な処理を行うロジックを追加します。かつては普遍的だった抽象化が、異なるケースに対して異なる振る舞いをするようになります。\nまた新しい要件が届きます。プログラマーX。さらに別の追加パラメーター。また新しい条件分岐。コードが理解不能になるまで繰り返されます。\nあなたはこの物語のこの辺りで登場し、あなたの人生は劇的に悪い方向へと向かいます。\n既存のコードは強力な影響力を持っています。その存在自体が、それが正しく必要であると主張します。私たちはコードが費やされた努力の結晶であることを知っており、この努力の価値を維持することに強く動機付けられています。そして、残念ながら悲しい真実は、コードが複雑で理解不能であるほど、つまりそれを作成するための投資が深ければ深いほど、それを保持する圧力(「サンクコストの誤謬」)を感じてしまうということです。まるで私たちの無意識が「なんてこった、これはとても混乱している、正しくするのに膨大な時間がかかったに違いない。きっと本当に本当に重要なものだ。そのすべての努力を無駄にするのは罪だろう」と語りかけているかのようです。\nあなたが上記のステップ8でこの物語に登場するとき、このプレッシャーはあなたを前進させ、つまり既存のコードを変更して新しい要件を実装するように駆り立てるかもしれません。しかし、そうしようとすることは過酷です。そのコードはもはや単一の共通の抽象化を表しておらず、代わりに曖昧に関連する多数のアイデアが入り混じった条件だらけのプロシージャとなっています。理解するのが難しく、壊れやすいのです。\nこの状況に陥った場合、サンクコストに突き動かされることに抵抗してください。不適切な抽象化に対処する場合、最も速い前進方法は「後退」することです。以下を実行してください:抽象化されたコードをすべての呼び出し元にインライン化することで、重複を再導入します。各呼び出し元内で、渡されるパラメーターを使用して、この特定の呼び出し元が実行するインライン化されたコードのサブセットを決定します。この特定の呼び出し元に不要な部分を削除します。これにより、抽象化と条件分岐の両方が削除され、各呼び出し元が必要なコードのみに削減されます。このように決定を巻き戻すと、各呼び出し元が見た目上は共有の抽象化を呼び出していたとしても、実際に実行されていたコードはかなりユニークだったということがよくあります。古い抽象化を完全に削除すれば、新しくやり直し、重複を再分離し、抽象化を再抽出することができます。\n人々が不適切な抽象化を使って懸命に前進しようとしていたにもかかわらず、ほとんど成功していない問題を見てきました。新機能の追加は信じられないほど困難で、成功するたびにコードがさらに複雑になり、次の機能の追加はさらに難しくなりました。彼らが視点を「このコードへの投資を維持しなければならない」から「このコードはしばらくの間意味があったが、おそらくそこから学べることはすべて学んだ」に変え、現在の要件に照らして抽象化を再考する許可を自分自身に与えたとき、すべてが簡単になりました。コードをインライン化すると、前進の道が明らかになり、新機能の追加がより速く、より簡単になりました。\nこの物語の教訓は?サンクコストの誤謬に囚われないでください。共有コードにパラメーターを渡し、条件付きパスを追加していることに気づいたら、その抽象化は間違っています。最初は正しかったかもしれませんが、その日は過ぎ去りました。抽象化が間違っていると判明したら、最善の戦略は重複を再導入し、何が正しいかを示させることです。何が起こっているかを理解するためにいくつかの条件を蓄積することは時々意味がありますが、間違った抽象化を遅かれ早かれ放棄すれば、より苦しみが少なくて済むでしょう。抽象化が間違っている場合、最も速い前進方法は「後退」することです。これは撤退ではなく、より良い方向への前進です。そうしてください。あなたは自分自身の人生を改善し、後に続くすべての人の人生を改善するでしょう。\nニュース: 『99 Bottles of OOP』がJS、PHP、Rubyで!『99 Bottles of OOP』の第2版がリリースされました!第2版には3つの新しい章が含まれており、第1版よりも約50%長くなっています。また、『99 Bottles of OOP』は特定の言語ではなく、一般的なオブジェクト指向設計に関するものであるため、今回は技術的には同じでありながら、例に異なるプログラミング言語を使用した別の書籍を作成しました。『99 Bottles of OOP』は現在、Ruby、JavaScript、PHP版が利用可能で、ビールとミルクの飲み物(これは冗談か、あるいは特別なバンドルかも)に対応しています。epub、kepub、mobi、pdf形式で提供されます。これにより、6つの異なる書籍と(3x2x4) 24種類のダウンロードが可能となります。すべてがユニークでありながら、内容は同じです。一度購入すれば、いずれかまたはすべてをダウンロードする権利が得られます。2016年1月20日、Sandi Metzが投稿。