Why Extending Through Subclassing (a framework’s classes) is a Bad Idea (翻訳)

(フレームワーククラスの)サブクラス化による拡張はなぜ悪いアイデアか

Original text is written by Ben Bangert, on October 18, 2010.

Author:Ben Bangert
Translator:Nozomu Kaneko <nozom.kaneko@gmail.com>

Note

この文書は Ben Bangert の blog 記事 の翻訳です。 原文はこの文書のソースコードに含めてあります。

オーケー、認めよう。これが過度に野心的なブログポストであることを。だか らもう少し洗練した言い方をすると、これは、ツール開発者 (他のプログラマ が利用するツール / フレームワークを作る人) として、サブクラス化によって 拡張が可能なオブジェクトを実装することが、なぜ悪いアイデアなのかに関す る私の考えを主として意図している。このアイデアは実際に私が書いたウェブ フレームワーク (Pylons) で、開発者にその拡張性を提供し、フレームワーク の機能を変更させる方法である。

この説明が短く、そして恐らく不完全なことを許してほしい。これは主として 私が最近行った tweet を説明する quick post だ。

最初に背景を少し...

Pylons 1.0 とそれ以前に欠けているものの一つは、 Pylons プロジェクトを容 易に拡張する方法だ。それは可能だが、非常に ad-hoc で kludgy (いいかげん) そして一般にあまりよく tought-out (考え抜かれる) されていない。あるいは 実際には全く thougt-out (されていない)。多少 thought-out されたことは、 フレームワークの拡張およびカスタマイズを開発者がどのように行うかという ことだった。

Pylons プロジェクトでは、プロジェクトは PylonsApp WSGI オブジェクトを 作成し、すべてのプロジェクトコントローラは WSGIController をサブクラス化 する。これは、とてもうまくいくように見えたし、実際、多くのユーザが カスタマイズに必要なメソッドを拡張/オーバーライドするために喜んで PylonsApp をインポートして、それをサブクラス化した。また、個別の アクションがどのように呼ばれるかを変更するために、 WSGIController サブクラスがどのように働くかを変更した。

すべてはうまくいっているように見えた... あのときはまだ...

Pylons を改善する

しばらく前に、少し時間があったので、私は Pylons に欠けているもの、すな わち拡張性を強化するために Pylons を拡張し改善する方法について調査に着 手した。すぐに分かったのは、Pylons ディスパッチがどのように働くか、また コントローラメソッドがどのように呼ばれるかに関して、それらをより容易 に拡張可能にするためにはかなりドラスティックな変更が必要だということだ。 しかし、次第に恐怖感とともにサブクラス化の問題が私を苦しめるようになった。 私の実装した PylonsApp と WSGIController のすべては、 事実上凍結 され ていたのだ。

Pylons を使用するすべての開発者は WSGIController をサブクラス化していて、 またそれよりも頻度は少ないが PylonsApp もサブクラス化されることがある。 そのため、主要なメソッドのどれかに対するどのような変更も、それらを何気 なくカスタマイズしたすべての Pylons ユーザのアプリに即座の breakage を もたらすだろう (このようなカスタマイズができることは、まさにサブクラス 化が使用された理由だ!)。これは、設計を修正するために実際のクラス実装を あまり変更することができない、ということを意味している。なぜなら、 すぐに完全な breakage を引き起こすからだ。げっ!

それで、さらに調査した結果、これ (サブクラス化による拡張) をすべきでな い明らかに悪い理由のリストができあがった。これに対して、 Pylons 2 では コントローラは何もサブクラス化しない。また、カスタマイズはすべてフレー ムワークに対するフックにより行われる。サブクラス化はどこにもない!

それがなぜ悪いかの短いリスト

フレームワークメンテナーの観点から

  1. すべてのクラスメソッドが API なので、クラスの実装は事実上凍結される。
  1. ポイント #1 により、設計上の欠陥あるいは実装上の欠陥の修正が大きな breakage なしでは不可能な場合、そのような修正は非常に困難である。
  1. 重度にサブクラス化された/巨大な階層クラスにはパフォーマンス上の ペナルティを受けることがある。

クラスを「拡張」する開発者の観点から

  1. 完全な実装が自分自身のコードの中にはないので (それはフレームワーク コードの中にある)、どうやって単体テストをすればいいのか理解することが より困難である。
  1. フレームワークをさらにサブクラス化した mix-in や他のクラスを使用した 場合、奇妙な衝突あるいはオーバーライドが生じる。これらは全く明白では なく、デバッグ/トラブルシュートするのが簡単でない。

この結論に至るまでには、これ以外にも若干の理由があったと思うが、今はそ れらを思い出せない。手短に言えば、サブクラス化して良いのは常に自分自身 のクラスだけ (できれば同じパッケージの中で、あるいはその近くで)、という のが今の私の比較的確固とした意見である。