ルビーで基本クラスを拡張するのが得策ではない理由の例を探しています。なぜそれが慎重に使用される武器であるのかを何人かの人々に示す必要があります。
共有できるホラーストーリーはありますか?
ルビーで基本クラスを拡張するのが得策ではない理由の例を探しています。なぜそれが慎重に使用される武器であるのかを何人かの人々に示す必要があります。
共有できるホラーストーリーはありますか?
約2。5年前にルビニウスでモンキーパッチがひどく間違っていたというかなり有名な例がありました。
このケースの興味深い点は、問題のあるコードと被害者の両方が非常に目立ち、非常に珍しいことです。通常、違反者は、1337メタプログラミングh4X0rスキルに酔ったPHPスクリプトキディによって書かれたコードの一部です。ArgumentError
また、元の方法とモンキーパッチのアリティが異なるため、失敗モードは単純な例外です。
ただし、この場合、違反者はstdlib(mathn
)内のライブラリであり、障害モードはRubiniusVMが完全に爆発したことでした。
どうしたの?さて、mathn
monkeypatchesはFixnum
クラスにパッチを当て、Fixnum
算術の動作を変更します。特に、結果といくつかのコアメソッドのタイプの両方が変更されます。例えば:
r = 4/3 # => 1
r.class # => Fixnum
require 'mathn'
r = 4/3 # => (4/3)
r.class # => Rational
もちろん問題は、Rubiniusでは、Rubyコンパイラ全体、Rubyカーネル全体、Rubyコアライブラリの大部分、Rubinius VMの一部、およびRubiniusインフラストラクチャの他の部分がすべてRubyで記述されていることです。そしてもちろん、それらのFixnum
すべては至る所で算術を使用します。
このHash
クラスはRubyで記述されており、Fixnum
算術演算を使用してハッシュバケットのサイズを計算したり、ハッシュ関数を計算したりします。Array
Rubyで記述されており、要素のサイズと配列の長さを計算する必要があります。FFIライブラリはRubyで記述されており、メモリアドレス(!)と構造体のサイズを計算する必要があります。Rubiniusの多くの部分は、何らかのFixnum
算術演算を実行し、その結果をポインターまたはとしてC関数に渡すことができると想定していますint
。
また、Rubyはセレクターの名前空間やクラスボクシングなどをサポートしていないため(Ruby 2.0ではそのようなものが計画されていますが)、ランダムなユーザーコードでmathn
ライブラリが必要になるとすぐに、これらすべての要素が見事に爆発します。突然、Fixnum
操作の結果はFixnum
(基本的にマシンint
と同じであり、そのように渡すことができる)ではなく、Rational
(本格的なRubyオブジェクト)になります。
基本的に、何が起こるかというと、あるコードがrequire 'mathn'
(または、それをIRbに入力すると)、すぐにVMが停止するということです。
この場合の解決策は、コンパイラーにとって安全な数学プラグインでした。コンパイラーは、カーネルまたはRubiniusの他のコア部分をコンパイルしていることを検出すると、Fixnum
メソッドの呼び出しをそれらのメソッドのプライベートな不変コピーの呼び出しに自動的に書き換えます。[注:現在のバージョンのRubiniusでは、問題は別の方法で解決されると思います。]
FAILの三連勝。または、Ruby 1.8.7 用に Rails 2.0 にパッチString
を適用する方法には、メソッドを追加するためにモンキーパッチを適用したために問題が発生した Rails (大規模で精査されたプロジェクト) の例がありますchars
。
明らかな落とし穴の 1 つは、名前の競合です。2 つ以上のパッケージが、異なる動作をするメソッドに同じ名前を選択した場合です。